KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > ristretto > message > BasicHeader


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.message;
37
38 import java.nio.charset.Charset JavaDoc;
39 import java.util.Date JavaDoc;
40 import java.util.LinkedList JavaDoc;
41 import java.util.regex.Matcher JavaDoc;
42 import java.util.regex.Pattern JavaDoc;
43
44 import org.columba.ristretto.coder.EncodedWord;
45 import org.columba.ristretto.parser.AddressParser;
46 import org.columba.ristretto.parser.DateParser;
47 import org.columba.ristretto.parser.ParserException;
48
49 /**
50  * Wrapper around the {@link Header} to provide a convienient
51  * way to access all important headerfields defined in RFC822.
52  *
53  *
54  */

55 public class BasicHeader {
56     
57     /**
58      * Priority value
59      */

60     public final static int HIGHEST = 5;
61     /**
62      * Priority value
63      */

64     public final static int HIGH = 4;
65     /**
66      * Priority value
67      */

68     public final static int NORMAL = 3;
69     /**
70      * Priority value
71      */

72     public final static int LOW = 2;
73     /**
74      * Priority value
75      */

76     public final static int LOWEST = 1;
77     
78     private static final Pattern JavaDoc whiteSpaceTokenizer = Pattern.compile("\\s*([^\\s]+)");
79     
80     private Header header;
81     
82     /**
83      * Constructs a BasicHeader from a {@link Header}
84      *
85      * @param header parsed
86      */

87     public BasicHeader( Header header ) {
88         this.header = header;
89     }
90
91     /**
92      * Gets the field "From" from the header and uses the {@link AddressParser}
93      * to return a parsed {@link Address} list
94      *
95      * @return {[@link Adress} list
96      */

97     public Address getFrom() {
98         return getAddress(header.get("From"));
99     }
100     
101     /**
102      * Gets the field "X-BeenThere" from the header and uses the {@link AddressParser}
103      * to return a parsed {@link Address} list
104      *
105      * @return {[@link Adress} list
106      */

107     public Address getBeenThere() {
108         Address result = getAddress(header.get("X-BeenThere"));
109         if( result == null ) {
110             result = getAddress(header.get("X-Beenthere"));
111         }
112         
113         return result;
114     }
115
116     /**
117      * Gets the field "To" from the header and uses the {@link AddressParser}
118      * to return a parsed {@link Address} list
119      *
120      * @return {[@link Adress} list
121      */

122     public Address[] getTo() {
123         return getMailboxlist(header.get("To"));
124     }
125
126     /**
127      * Gets the field "Cc" from the header and uses the {@link AddressParser}
128      * to return a parsed {@link Address} list
129      *
130      * @return {[@link Adress} list
131      */

132     public Address[] getCc() {
133         return getMailboxlist(header.get("Cc"));
134     }
135     
136     /**
137      * Gets the field "Bcc" from the header and uses the {@link AddressParser}
138      * to return a parsed {@link Address} list
139      *
140      * @return {[@link Adress} list
141      */

142     public Address[] getBcc() {
143         return getMailboxlist(header.get("Bcc"));
144     }
145     
146     /**
147      * Gets the field "Reply-To" from the header and uses the {@link AddressParser}
148      * to return a parsed {@link Address} list
149      *
150      * @return {[@link Adress} list
151      */

152     public Address[] getReplyTo() {
153         return getMailboxlist(header.get("Reply-To"));
154     }
155
156     /**
157      * Gets the field "Subject" from the header and uses the {@link EncodedWord} to
158      * decode an encoded subject.
159      *
160      * @return human-readable subject
161      */

162     public String JavaDoc getSubject() {
163         String JavaDoc subject = header.get("Subject");
164         if( subject != null) return EncodedWord.decode( subject ).toString();
165         else return null;
166     }
167     
168     /**
169      * Gets the field "Message-ID" from the header
170      *
171      * @return the message-id
172      */

173     public String JavaDoc getMessageID() {
174         return header.get("Message-ID");
175     }
176     
177     /**
178      * Gets the field "References" from the header and splits the list
179      * in an Array of message-ids
180      *
181      * @return list of message-ids
182      */

183     public String JavaDoc[] getReferences() {
184         String JavaDoc references = header.get("References");
185         return getWhitespaceSeparatedList(references);
186     }
187
188     /**
189      * Gets the field "In-Reply-To" from the header and splits the list
190      * in an Array of message-ids
191      *
192      * @return list of message-ids
193      */

194     public String JavaDoc[] getInReplyTo() {
195         String JavaDoc references = header.get("In-Reply-To");
196         return getWhitespaceSeparatedList(references);
197     }
198
199     /**
200      * Gets the field "X-Priority" from the header and
201      * converts the value to an int. Constants for the priorities
202      * are also defined in this class.
203      * If an error occurs while converting or no "X-Priority" field
204      * is defined, {@link #NORMAL} priority is returned.
205      *
206      * @return priority of the message
207      */

208     public int getPriority() {
209         String JavaDoc priority = header.get("X-Priority");
210         if( priority != null ) {
211             try {
212                 return Integer.parseInt(priority);
213             } catch (NumberFormatException JavaDoc e) {
214                 return NORMAL;
215             }
216         }
217         return NORMAL;
218     }
219     
220     /**
221      * Gets the field "Date" from the header and uses the {@link DateParser}
222      * to parse it into a {@link Date} object.
223      * If an error occurs the current date is returned.
224      *
225      * @return sent date of the message
226      */

227     public Date JavaDoc getDate() {
228         String JavaDoc date = header.get("Date");
229         if( date != null ) {
230             try {
231                 return DateParser.parse( removeComments(date) );
232             } catch (ParserException e) {
233                 return new Date JavaDoc();
234             }
235         }
236         return new Date JavaDoc();
237     }
238
239     /**
240      * Sets the field "From" of the header and uses {@link EncodedWord}
241      * to encode names if needed in UTF-8 using QuotedPrintable encoding.
242      * We chose UTF-8 to cover any possible characters.
243      *
244      * @param address mailaddresses with or without names
245      */

246     public void setFrom( Address address ) {
247         header.set("From", address.toString() );
248     }
249
250     /**
251      * Sets the field "To" of the header and uses {@link EncodedWord}
252      * to encode names if needed in UTF-8 using QuotedPrintable encoding.
253      * We chose UTF-8 to cover any possible characters.
254      *
255      * @param addresses mailaddresses with or without names
256      */

257     public void setTo( Address[] addresses ) {
258         setAddressList(addresses, "To");
259     }
260
261     /**
262      * Sets the field "Cc" of the header and uses {@link EncodedWord}
263      * to encode names if needed in UTF-8 using QuotedPrintable encoding.
264      * We chose UTF-8 to cover any possible characters.
265      *
266      * @param addresses mailaddresses with or without names
267      */

268     public void setCc( Address[] addresses ) {
269         setAddressList(addresses, "Cc");
270     }
271
272     /**
273      * Sets the field "Bcc" of the header and uses {@link EncodedWord}
274      * to encode names if needed in UTF-8 using QuotedPrintable encoding.
275      * We chose UTF-8 to cover any possible characters.
276      *
277      * @param addresses mailaddresses with or without names
278      */

279     public void setBcc( Address[] addresses ) {
280         setAddressList(addresses, "Bcc");
281     }
282
283     /**
284      * Sets the field "Reply-To" of the header and uses {@link EncodedWord}
285      * to encode names if needed in UTF-8 using QuotedPrintable encoding.
286      * We chose UTF-8 to cover any possible characters.
287      *
288      * @param addresses mailaddresses with or without names
289      */

290     public void setReplyTo( Address[] addresses ) {
291         setAddressList(addresses, "Reply-To");
292     }
293
294     /**
295      * Sets the field "Date" of the header by using {@link MessageDate}
296      * to convert the {@link Date} object into a RFC2822 compatible
297      * date string
298      *
299      * @param date of the message creation
300      */

301     public void setDate( Date JavaDoc date ) {
302         header.set("Date",MessageDate.toString(date));
303     }
304     
305     /**
306      * Sets the field "Message-ID" of the header. This should be
307      * a unique ID that only this message has. RFC2822 says the
308      * following about this field:
309      * "The "Message-ID:" field provides a unique message identifier that
310      * refers to a particular version of a particular message. The
311      * uniqueness of the message identifier is guaranteed by the host that
312      * generates it (see below). This message identifier is intended to be
313      * machine readable and not necessarily meaningful to humans. A message
314      * identifier pertains to exactly one instantiation of a particular
315      * message; subsequent revisions to the message each receive new message
316      * identifiers." (RFC2822, p.23)
317      *
318      * @param messageid unique id of this message
319      */

320     public void setMessageID(String JavaDoc messageid) {
321         header.set( "Message-ID", messageid);
322     }
323     
324     /**
325      * Sets the field "References" of the header. The messageids are
326      * the references this message refers to. The information of this
327      * and the "In-Repy-To" field can be used by mailclients e.g. to create a threaded view of
328      * a discussion
329      *
330      * @param messageids the messageids of the messages this message refers to
331      *
332      * @see #setInReplyTo
333      */

334     public void setReferences( String JavaDoc[] messageids ) {
335         setMessageIDList( "References", messageids );
336     }
337     
338     /**
339      * Sets the field "In-Reply-To" of the header. The messageids are
340      * the references this message refers to. The information of this
341      * and the "In-Repy-To" field can be used by mailclients e.g. to create a threaded view of
342      * a discussion
343      *
344      * @param messageids the messageids of the messages this message refers to
345      *
346      * @see #setReferences
347      */

348     public void setInReplyTo( String JavaDoc[] messageids ) {
349         setMessageIDList( "In-Reply-To", messageids );
350     }
351
352     /**
353      * Sets the field "X-Priority" of the header. Use the provided constants
354      * to specify the priority.
355      *
356      * @param priority of the message
357      */

358     public void setPriority( int priority ) {
359         header.set( "X-Priority", Integer.toString(priority));
360     }
361     
362     /**
363      * Sets the field "Subject" of the header using {@link EncodedWord} to
364      * encode the subject with the given charset (e.g. ISO-8859-1) and Quoted-
365      * Printable encoding.
366      *
367      * @param subject of the message
368      * @param charset the subject is encoded in
369      */

370     public void setSubject( String JavaDoc subject, Charset JavaDoc charset ) {
371         header.set("Subject", EncodedWord.encode(subject, charset,EncodedWord.QUOTED_PRINTABLE));
372     }
373
374     private void setMessageIDList( String JavaDoc key, String JavaDoc[] messageids) {
375         StringBuffer JavaDoc field = new StringBuffer JavaDoc( messageids[0] );
376         for( int i=1; i<messageids.length; i++) {
377             field.append(' ');
378             field.append(messageids[i]);
379         }
380         
381         header.set(key, EncodedWord.encode(field, Charset.forName("UTF-8"), EncodedWord.QUOTED_PRINTABLE).toString());
382     }
383
384     private void setAddressList(Address[] addresses, String JavaDoc fieldKey) {
385         StringBuffer JavaDoc addressfield = new StringBuffer JavaDoc(addresses[0].toString());
386         
387         for( int i=1; i<addresses.length; i++) {
388             addressfield.append( ", ");
389             addressfield.append( addresses[i].toString() );
390         }
391         
392         header.set( fieldKey, addressfield.toString());
393     }
394
395     private String JavaDoc[] getWhitespaceSeparatedList(String JavaDoc references) {
396         if( references != null ) {
397             LinkedList JavaDoc referenceList = new LinkedList JavaDoc();
398             Matcher JavaDoc matcher = whiteSpaceTokenizer.matcher(references);
399             while( matcher.matches() ) {
400                 referenceList.add(matcher.group(1));
401             }
402             String JavaDoc[] result = new String JavaDoc[referenceList.size()];
403             referenceList.toArray((Object JavaDoc[]) result);
404             return result;
405         }
406         return new String JavaDoc[0];
407     }
408
409     private Address[] getMailboxlist(String JavaDoc from) {
410         if( from != null) {
411             try {
412                 return AddressParser.parseMailboxList( EncodedWord.decode(removeComments(from)) );
413             } catch (ParserException e) {
414                 e.printStackTrace();
415             }
416         }
417         return new Address[] {};
418     }
419
420     private Address getAddress(String JavaDoc from) {
421         if( from != null) {
422             try {
423                 return AddressParser.parseAddress( EncodedWord.decode(removeComments(from)) );
424             } catch (ParserException e) {
425                 e.printStackTrace();
426             }
427         }
428         return null;
429     }
430
431
432     /**
433      * @return the number of headers
434      */

435     public int count() {
436         return header.count();
437     }
438
439     /**
440      * Get the header with the specified key.
441      *
442      * @param key
443      * @return the header
444      */

445     public String JavaDoc get(String JavaDoc key) {
446         return header.get(key);
447     }
448
449     /**
450      * Set the header with the specified key.
451      *
452      * @param key
453      * @param value
454      */

455     public void set(String JavaDoc key, Object JavaDoc value) {
456         header.set(key, value);
457     }
458
459     private static final int PLAIN = 0;
460     private static final int QUOTED = 1;
461     private static final int COMMENT = 2;
462     
463     
464     /**
465      * Remove any comments as defined in RFC2822 from the
466      * String.
467      *
468      * @param value
469      * @return the comment-free String
470      */

471     public static final String JavaDoc removeComments(String JavaDoc value) {
472         StringBuffer JavaDoc result = new StringBuffer JavaDoc( value.length() );
473         
474         int state = PLAIN;
475         int depth = 0;
476         char current;
477         
478         for( int i=0; i < value.length(); i++) {
479             current = value.charAt(i);
480
481             switch( current ) {
482                 case( '\"' ) : {
483                     if( state == COMMENT ) break;
484                     
485                     if( state == QUOTED ) state = PLAIN;
486                     else state = QUOTED;
487                     result.append(current);
488                     break;
489                 }
490                 
491                 case( '(' ) : {
492                     if( state == QUOTED ) {
493                         result.append(current);
494                         break;
495                     }
496                     
497                     if( state == COMMENT ) {
498                         depth++;
499                     } else {
500                         state = COMMENT;
501                         depth = 1;
502                     }
503                     break;
504                 }
505                 
506                 case( ')') : {
507                     if( state == QUOTED ) {
508                         result.append(current);
509                         break;
510                     }
511                     if( state == COMMENT ) {
512                         depth--;
513                         if( depth == 0) state = PLAIN;
514                         break;
515                     }
516                     result.append(current);
517                     break;
518                 }
519                 
520                 default : {
521                     if( state != COMMENT ) result.append( current);
522                 }
523                 
524             }
525         }
526                 
527         return result.toString();
528     }
529     
530
531 }
532
Popular Tags