1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.mercury.imap.cmd;
14
15 import java.io.IOException;
16 import java.text.SimpleDateFormat;
17 import java.util.ArrayList;
18 import java.util.List;
19 import javax.mail.Folder;
20 import javax.mail.MessagingException;
21 import javax.mail.internet.MimeMessage;
22
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import org.abstracthorizon.mercury.common.command.CommandException;
27 import org.abstracthorizon.mercury.imap.IMAPSession;
28 import org.abstracthorizon.mercury.imap.response.FetchResponse;
29 import org.abstracthorizon.mercury.imap.util.ComposedSequence;
30 import org.abstracthorizon.mercury.imap.util.FlagUtilities;
31 import org.abstracthorizon.mercury.imap.util.MessageUtilities;
32 import org.abstracthorizon.mercury.imap.util.ParserException;
33 import org.abstracthorizon.mercury.imap.util.IMAPScanner;
34 import org.abstracthorizon.mercury.imap.util.section.Body;
35 import org.abstracthorizon.mercury.imap.util.section.BodyStructure;
36 import org.abstracthorizon.mercury.imap.util.section.Envelope;
37 import org.abstracthorizon.mercury.imap.util.section.Flags;
38 import org.abstracthorizon.mercury.imap.util.section.HeaderSection;
39 import org.abstracthorizon.mercury.imap.util.section.Internaldate;
40 import org.abstracthorizon.mercury.imap.util.section.RFC822Size;
41 import org.abstracthorizon.mercury.imap.util.section.TextSection;
42 import org.abstracthorizon.mercury.imap.util.section.UID;
43
44
45
46
47
48
49
50 public class Fetch extends UIDCommand {
51
52
53 protected static final Logger logger = LoggerFactory.getLogger(Fetch.class);
54
55
56 protected static SimpleDateFormat internalDate = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z");
57
58
59 protected boolean tagSent = false;
60
61
62 protected List<Object> attrs;
63
64
65
66
67
68 public Fetch(String mnemonic) {
69 super(mnemonic);
70 unilateral = IMAPCommand.ALWAYS_SUPRESS_UNILATERAL_DATA;
71 }
72
73
74
75
76 public void setAsUID() {
77 asuid = true;
78 }
79
80
81
82
83
84
85
86
87
88 protected void execute(IMAPSession session) throws ParserException, MessagingException, CommandException, IOException {
89 fetch(session);
90 }
91
92
93
94
95
96
97
98
99
100 public void fetch(IMAPSession session) throws IOException, ParserException, MessagingException {
101 IMAPScanner scanner = session.getScanner();
102 attrs = new ArrayList<Object>();
103
104 ComposedSequence sequenceSet = new ComposedSequence();
105 if (!scanner.sequence_set(sequenceSet)) {
106 throw new ParserException("<sequence_set>");
107 }
108
109 if (!scanner.is_char(' ')) {
110 throw new ParserException("<SP>");
111 }
112
113 if (scanner.keyword("ALL")) {
114 attrs.add(new Flags());
115 attrs.add(new Internaldate());
116 RFC822Size rfc822 = new RFC822Size();
117 attrs.add(rfc822);
118 attrs.add(new Envelope());
119 } else if (scanner.keyword("FULL")) {
120 attrs.add(new Flags());
121 attrs.add(new Internaldate());
122 RFC822Size rfc822 = new RFC822Size();
123 attrs.add(rfc822);
124 attrs.add(new Envelope());
125 attrs.add(new Body());
126 } else if (scanner.keyword("FAST")) {
127 attrs.add(new Flags());
128 attrs.add(new Internaldate());
129 RFC822Size rfc822 = new RFC822Size();
130 attrs.add(rfc822);
131 } else if (scanner.is_char('(')) {
132 if (fetch_att(scanner, attrs)) {
133 boolean ok = true;
134 while (ok && scanner.is_char(' ')) {
135 ok = fetch_att(scanner, attrs);
136 }
137 if (ok && !scanner.is_char(')')) {
138 throw new ParserException("')'");
139 }
140 }
141 } else {
142 if (!fetch_att(scanner, attrs)) {
143 throw new ParserException("'ALL','FULL', 'FAST', '('");
144 }
145 }
146
147 if (asuid) {
148 if (!attrs.contains(UID.instance)) {
149 attrs.add(0, UID.instance);
150 }
151 }
152 checkEOL(session);
153
154 Folder f = session.getSelectedFolder();
155
156 MessageUtilities.sequenceIterator(session, this, f, sequenceSet, asuid);
157 sendOK(session);
158 }
159
160
161
162
163
164
165
166
167
168 public static boolean fetch_att(IMAPScanner scanner, List<Object> atts) throws IOException, ParserException {
169 if (scanner.keyword("ENVELOPE")) {
170 atts.add(new Envelope());
171 } else if (scanner.keyword("FLAGS")) {
172 atts.add(new Flags());
173 } else if (scanner.keyword("INTERNALDATE")) {
174 atts.add(new Internaldate());
175 } else if (scanner.keyword("RFC822")) {
176 if (scanner.is_char('.')) {
177 if (scanner.keyword("HEADER")) {
178 Body body = new Body();
179 body.peek = true;
180 body.rfc822 = true;
181 HeaderSection hs = new HeaderSection();
182 body.child = hs;
183 if (scanner.is_char('.')) {
184 if (scanner.keyword("LINES")) {
185 hs.fields = new ArrayList<String>();
186 if (scanner.is_char(' ')) {
187 if (scanner.header_list(hs.fields)) {
188 }
189 }
190 }
191 }
192 atts.add(body);
193 } else if (scanner.keyword("SIZE")) {
194 RFC822Size rfc822 = new RFC822Size();
195 atts.add(rfc822);
196 } else if (scanner.keyword("TEXT")) {
197 Body body = new Body();
198 body.rfc822 = true;
199 body.child = new TextSection();
200 atts.add(body);
201 } else if (scanner.keyword("PEEK")) {
202
203 Body body = new Body();
204 body.rfc822 = true;
205 body.peek = true;
206 atts.add(body);
207 } else {
208 throw new ParserException("'HEADER', 'SIZE', 'TEXT'");
209 }
210 } else {
211 Body body = new Body();
212 body.rfc822 = true;
213 atts.add(body);
214 }
215 } else if (scanner.keyword("BODY")) {
216
217
218 if (scanner.keyword("STRUCTURE")) {
219 BodyStructure b = new BodyStructure();
220 b.structure = true;
221 atts.add(b);
222 } else {
223 boolean peek = false;
224 if (scanner.keyword(".PEEK")) {
225 peek = true;
226 }
227 Body body = new Body();
228 if (scanner.section(body)) {
229 body.peek = peek;
230 atts.add(body);
231
232 if (scanner.is_char('<')) {
233 IMAPScanner.Number num1 = new IMAPScanner.Number();
234 if (!scanner.number(num1)) {
235 throw new ParserException("<number>");
236 }
237 body.from = num1.number;
238 if (!scanner.is_char('.')) {
239 throw new ParserException("'.'");
240 }
241 IMAPScanner.Number num2 = new IMAPScanner.Number();
242 if (!scanner.nz_number(num2)) {
243 throw new ParserException("<number>");
244 }
245 if (!scanner.is_char('>')) {
246 throw new ParserException("'>'");
247 }
248 body.from = num2.number;
249 }
250 } else {
251 BodyStructure b = new BodyStructure();
252 b.structure = false;
253 atts.add(b);
254 }
255 }
256 } else if (scanner.keyword("UID")) {
257 atts.add(UID.instance);
258 } else {
259 throw new ParserException("'ENVELOPE', 'FLAGS', 'INTERNALDATE', 'RFC822', 'BODY', 'UID'");
260 }
261 return true;
262 }
263
264
265
266
267
268
269
270 public void process(IMAPSession session, MimeMessage m) throws IOException, MessagingException {
271 try {
272
273 boolean first = true;
274
275
276 boolean expunged = m.isExpunged();
277 int msgNo = m.getMessageNumber();
278 FetchResponse response = new FetchResponse(session, msgNo);
279 response.append('(');
280 for (int j = 0; j < attrs.size(); j++) {
281 Object o = attrs.get(j);
282 if (o instanceof UID) {
283 first = spaceSeparator(first, response);
284 response.append("UID ");
285 response.append(MessageUtilities.findUID(m));
286 } else if (o instanceof Flags) {
287 first = spaceSeparator(first, response);
288 response.append("FLAGS (").append(FlagUtilities.toString(m.getFlags())).append(')');
289 } else if (o instanceof Envelope) {
290 if (!expunged) {
291 first = spaceSeparator(first, response);
292 response.append("ENVELOPE ");
293 response.createEnvelope(m);
294 }
295 } else if (o instanceof Internaldate) {
296 if (!expunged) {
297 first = spaceSeparator(first, response);
298 response.append("INTERNALDATE ");
299 response.append('"');
300 response.append(internalDate.format(m.getReceivedDate()));
301 response.append('"');
302 }
303 } else if (o instanceof RFC822Size) {
304 if (!expunged) {
305 first = spaceSeparator(first, response);
306 int size = m.getSize();
307 if (size < 0) {
308
309
310 size = 0;
311 }
312 String headers = MessageUtilities.createHeaders(m);
313 int headersSize = headers.getBytes().length;
314 size = size + headersSize;
315
316
317 response.append("RFC822.SIZE ");
318 response.append(size);
319 }
320 } else if (o instanceof Body) {
321 if (!expunged) {
322 first = spaceSeparator(first, response);
323 Body b = (Body) o;
324 response.append(b, m);
325 if (!b.peek) {
326 if (!m.getFlags().contains(javax.mail.Flags.Flag.RECENT)) {
327 m.setFlag(javax.mail.Flags.Flag.RECENT, false);
328 }
329 if (!m.getFlags().contains(javax.mail.Flags.Flag.SEEN)) {
330 m.setFlag(javax.mail.Flags.Flag.SEEN, true);
331 }
332 }
333 }
334 } else if (o instanceof BodyStructure) {
335 if (!expunged) {
336 first = spaceSeparator(first, response);
337 response.append("BODYSTRUCTURE ");
338
339 response.createBodyStructure(m, true);
340 }
341 }
342
343 }
344
345 response.append(')');
346 response.submit();
347 tagSent = false;
348 } catch (MessagingException e) {
349 session.setKeepLog(true);
350 logger.error("Fetch processing message error", e);
351
352 }
353 }
354
355
356
357
358
359
360
361 protected boolean spaceSeparator(boolean flag, FetchResponse response) {
362 if (flag) {
363 flag = false;
364 } else {
365 response.append(' ');
366 }
367 return flag;
368 }
369 }