KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > ristretto > imap > parser > MimeTreeParser


1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is Ristretto Mail API.
15  *
16  * The Initial Developers of the Original Code are
17  * Timo Stich and Frederik Dietz.
18  * Portions created by the Initial Developers are Copyright (C) 2004
19  * All Rights Reserved.
20  *
21  * Contributor(s):
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either the GNU General Public License Version 2 or later (the "GPL"), or
25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the MPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the MPL, the GPL or the LGPL.
34  *
35  * ***** END LICENSE BLOCK ***** */

36 package org.columba.ristretto.imap.parser;
37
38 import org.columba.ristretto.imap.IMAPResponse;
39 import org.columba.ristretto.message.Attributes;
40 import org.columba.ristretto.message.Header;
41 import org.columba.ristretto.message.LocalMimePart;
42 import org.columba.ristretto.message.Message;
43 import org.columba.ristretto.message.MessageMimePart;
44 import org.columba.ristretto.message.MimeHeader;
45 import org.columba.ristretto.message.MimePart;
46 import org.columba.ristretto.message.MimeTree;
47 import org.columba.ristretto.message.MimeType;
48 import org.columba.ristretto.message.StreamableMimePart;
49 import org.columba.ristretto.parser.ParserException;
50
51 /**
52  * Parser for the BodyStructure of a message.
53  *
54  * @author Timo Stich <tstich@users.sourceforge.net>
55  */

56 public class MimeTreeParser {
57
58     /**
59      * Parse the Bodystructure of the IMAPResponse.
60      *
61      * @param response
62      * @return the MimeTree representing the Bodystructure.
63      * @throws ParserException
64      */

65     public static MimeTree parse(IMAPResponse response) throws ParserException {
66         String JavaDoc message = response.getResponseMessage();
67             
68         // first parse the message attributes
69
Attributes attributes =
70             MessageAttributeParser.parse(message);
71
72         String JavaDoc bodystructure = (String JavaDoc) attributes.get("BODYSTRUCTURE");
73         if( bodystructure == null ) throw new ParserException(message);
74         
75         MimeTree mptree =
76             parseBodyStructure(response , bodystructure);
77
78         return mptree;
79     }
80
81     private static MimeTree parseBodyStructure(
82         IMAPResponse response,
83         String JavaDoc input) throws ParserException {
84         int openParenthesis = input.indexOf("(");
85
86         String JavaDoc bodystructure =
87             input.substring(
88                 openParenthesis + 1,
89                 ParenthesisParser.getClosingPos(
90                     input,
91                     openParenthesis));
92
93         return new MimeTree(parseBS(response, bodystructure));
94     }
95
96     protected static MimePart parseBS(IMAPResponse response, String JavaDoc input) throws ParserException {
97         MimePart result;
98
99         if (input.charAt(0) == '(') {
100             result = new MimePart();
101
102             BodystructureTokenizer tokenizer =
103                 new BodystructureTokenizer(response, input);
104             BodystructureTokenizer subtokenizer;
105
106             Item nextItem = tokenizer.getNextItem();
107             Item valueItem;
108
109             while (nextItem != null) {
110                 if (nextItem.getType() != Item.PARENTHESIS)
111                     break;
112
113                 result.addChild(
114                     parseBS(response, (String JavaDoc) nextItem.getValue()));
115                 nextItem = tokenizer.getNextItem();
116             }
117
118             // Parse the Rest of the Multipart
119

120             // Subtype / nextItem is already filled from break in while-block
121
result.getHeader().setMimeType(
122                 new MimeType(
123                     "multipart",
124                     ((String JavaDoc) nextItem.getValue()).toLowerCase()));
125
126             // Search for any ContentParameters
127
nextItem = tokenizer.getNextItem();
128             if (nextItem.getType() == Item.PARENTHESIS) {
129                 subtokenizer =
130                     new BodystructureTokenizer(
131                         response,
132                         (String JavaDoc) nextItem.getValue());
133
134                 nextItem = subtokenizer.getNextItem();
135                 while (nextItem != null) {
136                     valueItem = subtokenizer.getNextItem();
137
138                     result.getHeader().putContentParameter(
139                         ((String JavaDoc) nextItem.getValue()).toLowerCase(),
140                         (String JavaDoc) valueItem.getValue());
141
142                     nextItem = subtokenizer.getNextItem();
143                 }
144             }
145
146             // ID
147
nextItem = tokenizer.getNextItem();
148             if (nextItem == null)
149                 return result;
150             if (nextItem.getType() == Item.STRING)
151                 result.getHeader().setContentID(
152                     ((String JavaDoc) nextItem.getValue()).toLowerCase());
153
154             // Description
155
nextItem = tokenizer.getNextItem();
156             if (nextItem == null)
157                 return result;
158             if (nextItem.getType() == Item.STRING)
159                 result.getHeader().setContentDescription(
160                     ((String JavaDoc) nextItem.getValue()).toLowerCase());
161
162         } else {
163
164             result = parseMimeStructure(response, input);
165         }
166
167         return result;
168     }
169
170     private static Header parseEnvelope(
171         IMAPResponse response,
172         String JavaDoc envelope) throws ParserException {
173
174         Header result = new Header();
175
176         BodystructureTokenizer tokenizer =
177             new BodystructureTokenizer(response, envelope);
178         Item nextItem;
179
180         // Date
181
nextItem = tokenizer.getNextItem();
182         if (nextItem.getType() == Item.STRING)
183             result.set("Date", (String JavaDoc) nextItem.getValue());
184
185         // Subject
186
nextItem = tokenizer.getNextItem();
187         if (nextItem.getType() == Item.STRING)
188             result.set("Subject", (String JavaDoc) nextItem.getValue());
189
190         // From
191
nextItem = tokenizer.getNextItem();
192         if (nextItem.getType() == Item.PARENTHESIS);
193
194         // Sender
195
nextItem = tokenizer.getNextItem();
196         if (nextItem.getType() == Item.PARENTHESIS);
197
198         // Reply-To
199
nextItem = tokenizer.getNextItem();
200         if (nextItem.getType() == Item.PARENTHESIS);
201
202         // To
203
nextItem = tokenizer.getNextItem();
204         if (nextItem.getType() == Item.PARENTHESIS);
205
206         // Cc
207
nextItem = tokenizer.getNextItem();
208         if (nextItem.getType() == Item.PARENTHESIS);
209
210         // Bcc
211
nextItem = tokenizer.getNextItem();
212         if (nextItem.getType() == Item.PARENTHESIS);
213
214         // In-Reply-To
215
nextItem = tokenizer.getNextItem();
216         if (nextItem.getType() == Item.STRING)
217             result.set("In-Reply-To", (String JavaDoc) nextItem.getValue());
218
219         // Message-ID
220
nextItem = tokenizer.getNextItem();
221         if (nextItem.getType() == Item.STRING)
222             result.set("Message-ID", (String JavaDoc) nextItem.getValue());
223
224         return result;
225     }
226
227     private static MimePart parseMimeStructure (
228         IMAPResponse response,
229         String JavaDoc structure) throws ParserException {
230         MimeHeader header = new MimeHeader();
231         BodystructureTokenizer tokenizer =
232             new BodystructureTokenizer(response, structure);
233         BodystructureTokenizer subtokenizer;
234         Item nextItem, valueItem;
235         MimeType type = null;
236         StreamableMimePart result = null;
237
238         String JavaDoc contentType = "text";
239         // Content-Type
240
nextItem = tokenizer.getNextItem();
241         if (nextItem.getType() == Item.STRING)
242             contentType = ((String JavaDoc) nextItem.getValue()).toLowerCase();
243
244         // ContentSubtype
245
nextItem = tokenizer.getNextItem();
246         if (nextItem.getType() == Item.STRING) {
247             type =
248                 new MimeType(
249                     contentType,
250                     ((String JavaDoc) nextItem.getValue()).toLowerCase());
251             header.setMimeType(type);
252         }
253
254         // are there some Content Parameters ?
255
nextItem = tokenizer.getNextItem();
256         if (nextItem.getType() == Item.PARENTHESIS) {
257             subtokenizer =
258                 new BodystructureTokenizer(
259                     response,
260                     (String JavaDoc) nextItem.getValue());
261
262             nextItem = subtokenizer.getNextItem();
263             while (nextItem != null) {
264                 valueItem = subtokenizer.getNextItem();
265
266                 header.putContentParameter(
267                     ((String JavaDoc) nextItem.getValue()).toLowerCase(),
268                     (String JavaDoc) valueItem.getValue());
269
270                 nextItem = subtokenizer.getNextItem();
271             }
272         }
273
274         // ID
275
nextItem = tokenizer.getNextItem();
276         if (nextItem.getType() == Item.STRING)
277             header.setContentID(((String JavaDoc) nextItem.getValue()).toLowerCase());
278
279         // Description
280
nextItem = tokenizer.getNextItem();
281         if (nextItem.getType() == Item.STRING)
282             header.setContentDescription(
283                 ((String JavaDoc) nextItem.getValue()).toLowerCase());
284
285         // Encoding
286
nextItem = tokenizer.getNextItem();
287         if (nextItem.getType() == Item.STRING)
288             header.setContentTransferEncoding(
289                 ((String JavaDoc) nextItem.getValue()).toLowerCase());
290
291         // Size
292
int size = 0;
293         nextItem = tokenizer.getNextItem();
294         if (nextItem.getType() == Item.NUMBER)
295             size = ((Integer JavaDoc) nextItem.getValue()).intValue();
296
297         // Is this a Message/RFC822 Part ?
298
if (type.getType().equals("message")
299             && type.getSubtype().equals("rfc822")) {
300             result = new MessageMimePart(header);
301
302             Message subMessage = new Message();
303
304             // Envelope
305

306             nextItem = tokenizer.getNextItem();
307             if (nextItem.getType() == Item.PARENTHESIS) {
308                 subMessage.setHeader(
309                     parseEnvelope(response, (String JavaDoc) nextItem.getValue()));
310             }
311
312             // Bodystrucuture of Sub-Message
313

314             nextItem = tokenizer.getNextItem();
315             if (nextItem.getType() == Item.PARENTHESIS) {
316                 MimePart subStructure =
317                     parseBS(response, (String JavaDoc) nextItem.getValue());
318                 subStructure.setParent(result);
319                 subMessage.setMimePartTree(new MimeTree(subStructure));
320             }
321
322             ((MessageMimePart) result).setMessage(subMessage);
323
324             // Number of lines
325
nextItem = tokenizer.getNextItem();
326         }
327         // Is this a Text - Part ?
328
else if (type.getType().equals("text")) {
329             result = new LocalMimePart(header);
330
331             // Number of lines
332
nextItem = tokenizer.getNextItem();
333             // DONT CARE
334
} else {
335             result = new LocalMimePart(header);
336         }
337
338         // Set size
339
result.setSize(size);
340
341         // Are there Extensions ?
342
// MD5
343
nextItem = tokenizer.getNextItem();
344         if (nextItem == null)
345             return new MimePart(header);
346         // DONT CARE
347

348         // are there some Disposition Parameters ?
349
nextItem = tokenizer.getNextItem();
350         if (nextItem == null)
351             return new MimePart(header);
352
353         if (nextItem.getType() == Item.STRING) {
354             header.setContentDisposition(
355                 ((String JavaDoc) nextItem.getValue()).toLowerCase());
356         } else if (nextItem.getType() == Item.PARENTHESIS) {
357             subtokenizer =
358                 new BodystructureTokenizer(
359                     response,
360                     (String JavaDoc) nextItem.getValue());
361
362             nextItem = subtokenizer.getNextItem();
363             header.setContentDisposition(
364                 ((String JavaDoc) nextItem.getValue()).toLowerCase());
365
366             nextItem = subtokenizer.getNextItem();
367             // Are there Disposition Parameters?
368
if (nextItem.getType() == Item.PARENTHESIS) {
369                 subtokenizer =
370                     new BodystructureTokenizer(
371                         response,
372                         (String JavaDoc) nextItem.getValue());
373
374                 nextItem = subtokenizer.getNextItem();
375
376                 while (nextItem != null) {
377                     valueItem = subtokenizer.getNextItem();
378
379                     header.putDispositionParameter(
380                         ((String JavaDoc) nextItem.getValue()).toLowerCase(),
381                         (String JavaDoc) valueItem.getValue());
382
383                     nextItem = subtokenizer.getNextItem();
384                 }
385             }
386         }
387
388         // WE DO NOT GATHER FURTHER INFORMATION
389

390         return result;
391     }
392
393 }
394
395 class BodystructureTokenizer {
396
397     private String JavaDoc s;
398     private Interval i;
399     private IMAPResponse response;
400
401     /**
402      * Constructs the BodystructureTokenizer.
403      *
404      * @param response
405      * @param s
406      */

407     public BodystructureTokenizer(IMAPResponse response, String JavaDoc s) {
408         this.s = s;
409         this.response = response;
410         i = new Interval();
411     }
412
413     /**
414      * Gets the next item of the structure.
415      *
416      * @return the next Item
417      * @throws ParserException
418      */

419     public Item getNextItem() throws ParserException {
420         Item result = new Item();
421
422         // Search for next Item
423
i.a = i.b + 1;
424         // ..but Check Bounds!!
425
if (i.a >= s.length())
426             return null;
427         while (s.charAt(i.a) == ' ') {
428             i.a++;
429             if (i.a >= s.length())
430                 return null;
431         }
432
433         // Quoted
434

435         if (s.charAt(i.a) == '\"') {
436             i.b = s.indexOf("\"", i.a + 1);
437
438             result.setType(Item.STRING);
439             result.setValue(s.substring(i.a + 1, i.b));
440         }
441
442         // Literal
443

444         else if (s.charAt(i.a) == '{') {
445             i.b = s.indexOf("}", i.a);
446
447             result.setType(Item.STRING);
448             result.setValue(response.getData(s.substring(i.a, i.b+1)).toString());
449         }
450
451         // Parenthesized
452

453         else if (s.charAt(i.a) == '(') {
454             i.b = ParenthesisParser.getClosingPos(s, i.a);
455
456             result.setType(Item.PARENTHESIS);
457             result.setValue(s.substring(i.a + 1, i.b));
458         }
459
460         // NIL or Number
461

462         else {
463             i.b = s.indexOf(" ", i.a + 1);
464             if (i.b == -1)
465                 i.b = s.length();
466
467             String JavaDoc item = s.substring(i.a, i.b);
468             i.b--;
469
470             if (item.equals("NIL")) {
471                 result.setType(Item.NIL);
472             } else {
473                 result.setValue(new Integer JavaDoc(item));
474                 result.setType(Item.NUMBER);
475             }
476         }
477
478         return result;
479     }
480 }
481
482 class Item {
483     /**
484      * Itemtype
485      */

486     public static final int STRING = 0;
487     /**
488      * Itemtype
489      */

490     public static final int PARENTHESIS = 1;
491     /**
492      * Itemtype
493      */

494     public static final int NIL = 2;
495     /**
496      * Itemtype
497      */

498     public static final int NUMBER = 3;
499
500     private Object JavaDoc value;
501     private int type;
502     /**
503      * Returns the type.
504      *
505      * @return int
506      */

507     public int getType() {
508         return type;
509     }
510
511     /**
512      * Returns the value.
513      *
514      * @return Object
515      */

516     public Object JavaDoc getValue() {
517         return value;
518     }
519
520     /**
521      * Sets the type.
522      *
523      * @param type
524      * The type to set
525      */

526     public void setType(int type) {
527         this.type = type;
528     }
529
530     /**
531      * Sets the value.
532      *
533      * @param value
534      * The value to set
535      */

536     public void setValue(Object JavaDoc value) {
537         this.value = value;
538     }
539
540 }
541
542 class Interval {
543     /**
544      * The start position.
545      */

546     public int a;
547     /**
548      * The end position.
549      */

550     public int b;
551
552     /**
553      * Constructs the Interval.
554      *
555      * @param a
556      * @param b
557      */

558     public Interval(int a, int b) {
559         this.a = a;
560         this.b = b;
561     }
562
563     /**
564      * Constructs the Interval.
565      */

566     public Interval() {
567         a = -1;
568         b = -1;
569     }
570
571     /**
572      * Reset the Interval.
573      */

574     public void reset() {
575         a = -1;
576         b = -2;
577     }
578 }
579
Popular Tags