KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > mail > ImapMailboxEntry


1 /*
2  * ImapMailboxEntry.java
3  *
4  * Copyright (C) 2000-2002 Peter Graves
5  * $Id: ImapMailboxEntry.java,v 1.1.1.1 2002/09/24 16:10:10 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j.mail;
23
24 import java.io.Serializable JavaDoc;
25 import java.text.SimpleDateFormat JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Date JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.TimeZone JavaDoc;
30 import org.armedbear.j.FastStringBuffer;
31 import org.armedbear.j.Log;
32 import org.armedbear.j.StringPair;
33 import org.armedbear.j.Utilities;
34
35 /*package*/ final class ImapMailboxEntry extends MailboxEntry implements Serializable JavaDoc
36 {
37     private transient ImapMailbox mailbox;
38
39     private int uid;
40     private RFC822Date arrival;
41
42     private ImapMailboxEntry()
43     {
44     }
45
46     // For testing only!
47
/*package*/ ImapMailboxEntry(int uid)
48     {
49         this.uid = uid;
50     }
51
52     public final ImapMailbox getMailbox()
53     {
54         return mailbox;
55     }
56
57     public final void setMailbox(ImapMailbox mailbox)
58     {
59         this.mailbox = mailbox;
60     }
61
62     public final int getUid()
63     {
64         return uid;
65     }
66
67     public final RFC822Date getArrival()
68     {
69         return arrival;
70     }
71
72     private static final String JavaDoc INTERNALDATE_START = "INTERNALDATE ";
73     private static final String JavaDoc RFC822_SIZE_START = "RFC822.SIZE ";
74     private static final String JavaDoc ENVELOPE_START = "ENVELOPE (";
75     private static final String JavaDoc REFERENCES_START =
76         "BODY[HEADER.FIELDS (\"REFERENCES\")]";
77
78     public static ImapMailboxEntry parseEntry(ImapMailbox mailbox, final String JavaDoc s)
79     {
80         ImapMailboxEntry entry = new ImapMailboxEntry();
81         entry.mailbox = mailbox;
82         entry.messageNumber = parseMessageNumber(s);
83         if (entry.messageNumber < 1) {
84             Log.error("can't parse message number");
85             return null;
86         }
87         entry.uid = parseUid(s);
88         if (entry.uid < 1) {
89             Log.error("can't parse uid");
90             return null;
91         }
92         entry.flags = parseFlags(s);
93         int index = s.indexOf(INTERNALDATE_START);
94         if (index < 0) {
95             Log.error("can't find INTERNALDATE");
96             return null;
97         }
98         StringPair p =
99             parseQuoted(s.substring(index + INTERNALDATE_START.length()));
100         if (p == null) {
101             Log.error("can't parse INTERNALDATE");
102             return null;
103         }
104         entry.arrival = entry.parseInternalDate(p.first.trim());
105         String JavaDoc remaining = p.second;
106         index = remaining.indexOf(RFC822_SIZE_START);
107         if (index < 0) {
108             Log.error("can't find RFC822.SIZE");
109             return null;
110         }
111         remaining = remaining.substring(index + RFC822_SIZE_START.length());
112         entry.size = -1;
113         try {
114             entry.size = Utilities.parseInt(remaining);
115         }
116         catch(NumberFormatException JavaDoc e) {
117             Log.error("can't parse RFC822.SIZE");
118             Log.error("|" + remaining + "|");
119             Log.error(e);
120             return null;
121         }
122         index = remaining.indexOf(ENVELOPE_START);
123         if (index < 0) {
124             Log.error("can't find ENVELOPE");
125             return null;
126         }
127         remaining = remaining.substring(index + ENVELOPE_START.length());
128         // Next field is date (quoted string).
129
p = parseQuoted(remaining);
130         if (p == null) {
131             Log.error("can't parse date");
132             return null;
133         }
134         entry.date = RFC822Date.parseDate(p.first);
135         remaining = p.second;
136         // Next field is subject (quoted string).
137
p = parseQuoted(remaining);
138         if (p == null) {
139             Log.error("can't parse subject");
140             return null;
141         }
142         entry.subject = p.first == null ? "" : RFC2047.decode(p.first);
143         remaining = p.second;
144         // Next field is "From" (parenthesized list).
145
p = parseParenthesizedList(remaining);
146         if (p == null) {
147             Log.error("can't parse \"From\" list");
148             return null;
149         }
150         if (p.first != null)
151             entry.from = parseAddressList(p.first);
152         remaining = p.second;
153         do {
154             // Sender
155
p = parseParenthesizedList(remaining);
156             if (p == null) {
157                 Log.error("can't parse \"Sender\" list");
158                 break;
159             }
160             remaining = p.second;
161             // Reply-To
162
p = parseParenthesizedList(remaining);
163             if (p == null) {
164                 Log.error("can't parse \"Reply-To\" list");
165                 break;
166             }
167             if (p.first != null)
168                 entry.replyTo = parseAddressList(p.first);
169             remaining = p.second;
170             // To
171
p = parseParenthesizedList(remaining);
172             if (p == null) {
173                 Log.error("can't parse \"To\" list");
174                 break;
175             }
176             if (p.first != null)
177                 entry.to = parseAddressList(p.first);
178             remaining = p.second;
179             // Cc
180
p = parseParenthesizedList(remaining);
181             if (p == null) {
182                 Log.error("can't parse \"Cc\" list");
183                 break;
184             }
185             if (p.first != null)
186                 entry.cc = parseAddressList(p.first);
187             remaining = p.second;
188             // Bcc
189
p = parseParenthesizedList(remaining);
190             if (p == null) {
191                 Log.error("can't parse \"Bcc\" list");
192                 break;
193             }
194             remaining = p.second;
195             // In-Reply-To (quoted string)
196
p = parseQuoted(remaining);
197             if (p == null) {
198                 Log.error("can't parse \"In-Reply-To\"");
199                 break;
200             }
201             entry.inReplyTo = parseInReplyTo(p.first);
202             remaining = p.second;
203             p = parseQuoted(remaining);
204             if (p == null) {
205                 Log.error("can't parse \"Message-ID\"");
206                 break;
207             }
208             entry.messageId = p.first;
209         } while (false);
210         remaining = p.second;
211         index = remaining.indexOf(REFERENCES_START);
212         if (index >= 0) {
213             remaining = remaining.substring(index + REFERENCES_START.length());
214             p = parseQuoted(remaining);
215             if (p != null) {
216                 String JavaDoc refs = p.first.trim();
217                 if (refs.length() > 0)
218                     entry.references = parseReferences(refs);
219             }
220         }
221         if (entry.subject != null)
222             return entry;
223         Log.error("skipping entry");
224         return null;
225     }
226
227     private static int parseMessageNumber(String JavaDoc s)
228     {
229         final int length = s.length();
230         if (length < 2)
231             return 0; // Error.
232
// String must start with "* ".
233
if (s.charAt(0) != '*' || s.charAt(1) != ' ')
234             return 0; // Error.
235
FastStringBuffer sb = new FastStringBuffer();
236         for (int i = 2; i < length; i++) {
237             char c = s.charAt(i);
238             if (c >= '0' && c <= '9')
239                 sb.append(c);
240             else
241                 break;
242         }
243         try {
244             return Integer.parseInt(sb.toString());
245         }
246         catch (NumberFormatException JavaDoc e) {
247             Log.error(e);
248             return 0;
249         }
250     }
251
252     public static int parseUid(String JavaDoc s)
253     {
254         final int length = s.length();
255         if (length < 2)
256             return 0; // Error.
257
// String must start with "* ".
258
if (s.charAt(0) != '*' || s.charAt(1) != ' ')
259             return 0; // Error.
260
int index = s.indexOf("UID ");
261         if (index < 0)
262             return 0;
263         FastStringBuffer sb = new FastStringBuffer();
264         for (int i = index+4; i < length; i++) {
265             char c = s.charAt(i);
266             if (c >= '0' && c <= '9')
267                 sb.append(c);
268             else
269                 break;
270         }
271         try {
272             return Integer.parseInt(sb.toString());
273         }
274         catch (NumberFormatException JavaDoc e) {
275             Log.error(e);
276             return 0;
277         }
278     }
279
280     private static final String JavaDoc FLAGS_START = "FLAGS (";
281
282     public static int parseFlags(String JavaDoc s)
283     {
284         int flags = 0;
285         final int index = s.indexOf(FLAGS_START);
286         if (index >= 0) {
287             StringPair p = parseParenthesized(s.substring(index));
288             if (p != null && p.first != null) {
289                 String JavaDoc flagsList = p.first.toLowerCase();
290                 if (flagsList.length() > 0) {
291                     if (flagsList.indexOf("seen") >= 0)
292                         flags |= SEEN;
293                     if (flagsList.indexOf("answered") >= 0)
294                         flags |= ANSWERED;
295                     if (flagsList.indexOf("recent") >= 0)
296                         flags |= RECENT;
297                     if (flagsList.indexOf("deleted") >= 0)
298                         flags |= DELETED;
299                     if (flagsList.indexOf("flagged") >= 0)
300                         flags |= FLAGGED;
301                 }
302             }
303         }
304         return flags;
305     }
306
307     private static StringPair parseQuoted(String JavaDoc s)
308     {
309         s = s.trim();
310         if (s.length() == 0)
311             return null;
312         String JavaDoc quoted = null;
313         String JavaDoc remaining = null;
314         if (s.charAt(0) == '{') {
315             int end = s.indexOf('}', 1);
316             if (end < 0) {
317                 Log.error("parseQuoted: bad literal");
318                 return null;
319             }
320             int length = 0;
321             try {
322                 length = Integer.parseInt(s.substring(1, end));
323             }
324             catch (NumberFormatException JavaDoc e) {
325                 Log.error(e);
326             }
327             if (length == 0) {
328                 Log.error("parseQuoted: length of literal is zero");
329                 return null;
330             }
331             int begin = s.indexOf('\n', end+1);
332             if (begin < 0) {
333                 Log.error("parseQuoted: no LF after literal");
334                 return null;
335             }
336             ++begin; // Skip LF.
337
end = begin + length;
338             if (end > s.length()) {
339                 Log.error("parseQuoted end > s.length()");
340                 return null;
341             }
342             quoted = s.substring(begin, end);
343             remaining = s.substring(end);
344         } else if (s.startsWith("NIL")) {
345             quoted = null;
346             remaining = s.substring(3).trim();
347         } else {
348             int begin = s.indexOf('"');
349             if (begin < 0)
350                 return null;
351             int end = s.indexOf('"', begin + 1);
352             if (end < 0)
353                 return null;
354             quoted = s.substring(begin + 1, end);
355             remaining = s.substring(end + 1);
356         }
357         return new StringPair(quoted, remaining);
358     }
359
360     private static StringPair parseParenthesized(String JavaDoc s)
361     {
362         int begin = s.indexOf('(');
363         if (begin < 0)
364             return null;
365         int end = -1;
366         final int limit = s.length();
367         boolean inQuote = false;
368         char quoteChar = '\0';
369         for (int i = begin + 1; i < limit; i++) {
370             char c = s.charAt(i);
371             if (inQuote) {
372                 if (c == quoteChar)
373                     inQuote = false;
374             } else {
375                 // Not in quote.
376
if (c == '"' || c == '\'') {
377                     inQuote = true;
378                     quoteChar = c;
379                 } else if (c == ')') {
380                     end = i;
381                     break;
382                 }
383             }
384         }
385         if (end < 0)
386             return null;
387         String JavaDoc parenthesized = s.substring(begin+1, end);
388         String JavaDoc remaining = s.substring(end+1);
389         return new StringPair(parenthesized, remaining);
390     }
391
392     static private StringPair parseParenthesizedList(String JavaDoc s)
393     {
394         s = s.trim();
395         if (s.startsWith("NIL"))
396            return new StringPair(null, s.substring(3).trim());
397         int begin = s.indexOf("((");
398         if (begin < 0)
399             return null;
400         int end = s.indexOf("))");
401         if (end < 0)
402             return null;
403         String JavaDoc list = s.substring(begin, end + 2);
404         String JavaDoc remaining = s.substring(end + 2);
405         return new StringPair(list, remaining);
406     }
407
408     private static MailAddress[] parseAddressList(String JavaDoc list)
409     {
410         if (list == null)
411             return null;
412         ArrayList JavaDoc addresses = new ArrayList JavaDoc();
413         String JavaDoc remaining = list.substring(1, list.length()-1);
414         while (remaining.length() > 0) {
415             StringPair p = parseParenthesized(remaining);
416             if (p == null) {
417                 Log.error("parseAddressList error");
418                 Log.error("list = |" + list + "|");
419                 Log.error("remaining = |" + remaining + "|");
420                 return null;
421             }
422             String JavaDoc s = p.first; // The address.
423
MailAddress address = parseAddress(s);
424             if (address == null) {
425                 Log.error("**** parseAddress returned null");
426                 Log.error("s = |" + s + "|");
427             }
428             if (address != null)
429                 addresses.add(address);
430             remaining = p.second;
431         }
432         if (addresses.size() == 0)
433             return null;
434         MailAddress[] array = new MailAddress[addresses.size()];
435         return (MailAddress[]) addresses.toArray(array);
436     }
437
438     private static MailAddress parseAddress(String JavaDoc s)
439     {
440         StringPair p = parseQuoted(s);
441         if (p == null) // Error.
442
return null;
443         String JavaDoc encodedPersonal = p.first;
444         String JavaDoc remaining = p.second;
445         p = parseQuoted(remaining);
446         if (p == null) // Error.
447
return null;
448         String JavaDoc sourceRoute = p.first;
449         remaining = p.second;
450         p = parseQuoted(remaining);
451         if (p == null) // Error.
452
return null;
453         String JavaDoc mailName = p.first;
454         remaining = p.second;
455         p = parseQuoted(remaining);
456         if (p == null) // Error.
457
return null;
458         String JavaDoc domainName = p.first;
459         remaining = p.second;
460         if (remaining.length() > 0)
461             Log.error("**** parseAddress: unexpected string remaining ****");
462         return new MailAddress(encodedPersonal, mailName + '@' + domainName);
463     }
464
465     private static SimpleDateFormat JavaDoc internalDateFormat = new SimpleDateFormat JavaDoc("dd-MMM-yyyy HH:mm:ss");
466
467     private static RFC822Date parseInternalDate(String JavaDoc internalDate)
468     {
469         Date JavaDoc date = null;
470         int index = internalDate.indexOf(' ');
471         if (index >= 0) {
472             index = internalDate.indexOf(' ', index+1);
473             if (index >= 0) {
474                 String JavaDoc dateString = internalDate.substring(0, index);
475                 String JavaDoc timeZone = internalDate.substring(index + 1);
476                 TimeZone JavaDoc tz = TimeZone.getTimeZone("GMT" + timeZone);
477                 if (tz != null)
478                     internalDateFormat.setTimeZone(tz);
479                 try {
480                     date = internalDateFormat.parse(dateString);
481                 }
482                 catch (Throwable JavaDoc t) {
483                     Log.error(t);
484                 }
485             }
486         }
487         return new RFC822Date(date);
488     }
489 }
490
Popular Tags