KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > mail > composer > MessageBuilderHelper


1 // The contents of this file are subject to the Mozilla Public License Version
2
// 1.1
3
//(the "License"); you may not use this file except in compliance with the
4
//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
5
//
6
//Software distributed under the License is distributed on an "AS IS" basis,
7
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
8
//for the specific language governing rights and
9
//limitations under the License.
10
//
11
//The Original Code is "The Columba Project"
12
//
13
//The Initial Developers of the Original Code are Frederik Dietz and Timo
14
// Stich.
15
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
16
//
17
//All Rights Reserved.
18
package org.columba.mail.composer;
19
20 import java.io.IOException JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.nio.charset.Charset JavaDoc;
23 import java.nio.charset.UnsupportedCharsetException JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.regex.Matcher JavaDoc;
28 import java.util.regex.Pattern JavaDoc;
29
30 import org.columba.addressbook.facade.IContactFacade;
31 import org.columba.addressbook.facade.IContactItem;
32 import org.columba.addressbook.facade.IFolder;
33 import org.columba.addressbook.facade.IFolderFacade;
34 import org.columba.addressbook.facade.IModelFacade;
35 import org.columba.api.exception.ServiceNotFoundException;
36 import org.columba.api.exception.StoreException;
37 import org.columba.core.io.StreamUtils;
38 import org.columba.core.xml.XmlElement;
39 import org.columba.mail.config.AccountItem;
40 import org.columba.mail.config.AccountList;
41 import org.columba.mail.config.MailConfig;
42 import org.columba.mail.connector.FacadeUtil;
43 import org.columba.mail.connector.ServiceConnector;
44 import org.columba.mail.gui.composer.ComposerModel;
45 import org.columba.ristretto.coder.Base64DecoderInputStream;
46 import org.columba.ristretto.coder.CharsetDecoderInputStream;
47 import org.columba.ristretto.coder.QuotedPrintableDecoderInputStream;
48 import org.columba.ristretto.message.Address;
49 import org.columba.ristretto.message.Header;
50 import org.columba.ristretto.message.MimeHeader;
51 import org.columba.ristretto.message.MimePart;
52 import org.columba.ristretto.message.StreamableMimePart;
53
54 /**
55  *
56  * The <code>MessageBuilderHelper</code> class is responsible for creating the
57  * information for the <code>ComposerModel</class>class.
58  * <p>
59  * It generates appropriate header-information, mimeparts and
60  * quoted bodytext, etc.
61  * <p>
62  * These helper class is primarly used by the commands in org.columba.composer.command
63  * *
64  * @author fdietz, tstich
65  */

66 public class MessageBuilderHelper {
67
68     /**
69      *
70      * Check if the subject headerfield already starts with a pattern like "Re:"
71      * or "Fwd:"
72      *
73      * @param subject
74      * A <code>String</code> containing the subject
75      * @param pattern
76      * A <code>String</code> specifying the pattern to search for.
77      */

78     public static boolean isAlreadyReply(String JavaDoc subject, String JavaDoc pattern) {
79         if (subject == null) {
80             return false;
81         }
82
83         if (subject.length() == 0) {
84             return false;
85         }
86
87         String JavaDoc str = subject.toLowerCase();
88
89         // for example: "Re: this is a subject"
90
if (str.startsWith(pattern) == true) {
91             return true;
92         }
93
94         // for example: "[columba-users]Re: this is a subject"
95
int index = str.indexOf(pattern);
96
97         if (index != -1) {
98             return true;
99         }
100
101         return false;
102     }
103
104     /**
105      *
106      * create subject headerfield in using the senders message subject and
107      * prepending "Re:" if not already there
108      *
109      * @param header
110      * A <code>ColumbaHeader</code> which contains the headerfields
111      * of the message we want reply/forward.
112      *
113      * FIXME (@author fdietz): we need to i18n this!
114      */

115     public static String JavaDoc createReplySubject(String JavaDoc subject) {
116         // if subject doesn't start already with "Re:" prepend it
117
if (!isAlreadyReply(subject, "re:")) {
118             subject = "Re: " + subject;
119         }
120
121         return subject;
122     }
123
124     /**
125      *
126      * create Subject headerfield in using the senders message subject and
127      * prepending "Fwd:" if not already there
128      *
129      * @param header
130      * A <code>ColumbaHeader</code> which contains the headerfields
131      * of the message we want reply/forward.
132      *
133      * FIXME (@author fdietz): we need to i18n this!
134      *
135      */

136     public static String JavaDoc createForwardSubject(String JavaDoc subject) {
137         // if subject doesn't start already with "Fwd:" prepend it
138
if (!isAlreadyReply(subject, "fwd:")) {
139             subject = "Fwd: " + subject;
140         }
141
142         return subject;
143     }
144
145     /**
146      *
147      * create a To headerfield in using the senders message Reply-To or From
148      * headerfield
149      *
150      * @param header
151      * A <code>Header</code> which contains the headerfields of the
152      * message we want reply/forward.
153      *
154      */

155     public static String JavaDoc createTo(Header header) {
156         String JavaDoc replyTo = (String JavaDoc) header.get("Reply-To");
157         String JavaDoc from = (String JavaDoc) header.get("From");
158
159         if (replyTo == null) {
160             // Reply-To headerfield isn't specified, try to use From instead
161
if (from != null) {
162                 return from;
163             } else {
164                 return "";
165             }
166         } else {
167             return replyTo;
168         }
169     }
170
171     /**
172      *
173      * This is for creating the "Reply To All recipients" To headerfield.
174      *
175      * It is different from the <code>createTo</code> method in that it also
176      * appends the recipients specified in the To headerfield
177      *
178      * @param header
179      * A <code>ColumbaHeader</code> which contains the headerfields
180      * of the message we want reply/forward.
181      *
182      */

183     public static String JavaDoc createToAll(Header header) {
184         String JavaDoc sender = "";
185         String JavaDoc replyTo = (String JavaDoc) header.get("Reply-To");
186         String JavaDoc from = (String JavaDoc) header.get("From");
187         String JavaDoc to = (String JavaDoc) header.get("To");
188         String JavaDoc cc = (String JavaDoc) header.get("Cc");
189
190         // if Reply-To headerfield isn't specified, try to use from
191
if (replyTo == null) {
192             sender = from;
193         } else {
194             sender = replyTo;
195         }
196
197         // create To headerfield
198
StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
199         buf.append(sender);
200
201         if (to != null) {
202             buf.append(", ");
203             buf.append(to);
204         }
205
206         if (cc != null) {
207             buf.append(", ");
208             buf.append(cc);
209         }
210
211         return buf.toString();
212     }
213
214     /**
215      *
216      * This method creates a To headerfield for the "Reply To MailingList"
217      * action. It uses the X-BeenThere headerfield and falls back to Reply-To or
218      * From if needed
219      *
220      * @param header
221      * A <code>Header</code> which contains the headerfields of the
222      * message we want reply/forward.
223      */

224     public static String JavaDoc createToMailinglist(Header header) {
225         // example: X-BeenThere: columba-devel@lists.sourceforge.net
226
String JavaDoc sender = (String JavaDoc) header.get("X-BeenThere");
227
228         if (sender == null) {
229             sender = (String JavaDoc) header.get("X-Beenthere");
230         }
231
232         if (sender == null) {
233             sender = (String JavaDoc) header.get("Reply-To");
234         }
235
236         if (sender == null) {
237             sender = (String JavaDoc) header.get("From");
238         }
239
240         return sender;
241     }
242
243     /**
244      *
245      * Creates In-Reply-To and References headerfields. These are useful for
246      * mailing-list threading.
247      *
248      * @param header
249      * A <code>Header</code> which contains the headerfields of the
250      * message we want reply/forward.
251      *
252      * @param model
253      * The <code>ComposerModel</code> we want to pass the
254      * information to.
255      *
256      * TODO (@author fdietz): if the References headerfield contains to many
257      * characters, we have to remove some of the first References, before
258      * appending another one. (RFC822 headerfields are not allowed to become
259      * that long)
260      *
261      */

262     public static void createMailingListHeaderItems(Header header,
263             ComposerModel model) {
264         String JavaDoc messageId = (String JavaDoc) header.get("Message-ID");
265
266         if (messageId == null) {
267             messageId = (String JavaDoc) header.get("Message-Id");
268         }
269
270         if (messageId != null) {
271             model.setHeaderField("In-Reply-To", messageId);
272
273             String JavaDoc references = (String JavaDoc) header.get("References");
274
275             if (references != null) {
276                 references = references + " " + messageId;
277                 references = removeDoubleEntries(references);
278
279                 model.setHeaderField("References", references);
280             }
281         }
282     }
283
284     private static String JavaDoc removeDoubleEntries(String JavaDoc input) {
285         Pattern JavaDoc separatorPattern = Pattern.compile("\\s*(<[^\\s<>]+>)\\s*");
286         ArrayList JavaDoc entries = new ArrayList JavaDoc();
287         Matcher JavaDoc matcher = separatorPattern.matcher(input);
288         while (matcher.find()) {
289             entries.add(matcher.group(1));
290         }
291
292         Collections.sort(entries);
293
294         Iterator JavaDoc it = entries.iterator();
295         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
296
297         String JavaDoc last = (String JavaDoc) it.next();
298         result.append(last);
299
300         while (it.hasNext()) {
301             String JavaDoc next = (String JavaDoc) it.next();
302             if (!next.equals(last)) {
303                 last = next;
304                 result.append(' ');
305                 result.append(last);
306             }
307         }
308
309         return result.toString();
310     }
311
312     /**
313      *
314      * Search the correct Identity for replying to someone
315      * <p>
316      *
317      */

318     public static AccountItem getAccountItem(Integer JavaDoc accountUid) {
319         if (MailConfig.getInstance() == null)
320             return null;
321
322         AccountList list = MailConfig.getInstance().getAccountList();
323         AccountItem accountItem = null;
324         list.getDefaultAccount();
325
326         if (accountUid != null) {
327             accountItem = list.uidGet(accountUid.intValue());
328         }
329
330         // *20040229, karlpeder* Use default account as fall back
331
if (accountItem == null) {
332             accountItem = list.getDefaultAccount();
333         }
334
335         // if (accountUid != null) {
336
// accountItem = list.getDefaultAccount();
337
// }
338

339         return accountItem;
340     }
341
342     /**
343      *
344      * create bodytext
345      *
346      * @param message
347      * A <code>Message</code> which contains the bodytext of the
348      * message we want reply/forward.
349      */

350     public static String JavaDoc createBodyText(MimePart mimePart) throws IOException JavaDoc {
351         StreamableMimePart bodyPart = (StreamableMimePart) mimePart;
352         String JavaDoc charsetName = bodyPart.getHeader()
353                 .getContentParameter("charset");
354         int encoding = bodyPart.getHeader().getContentTransferEncoding();
355
356         InputStream JavaDoc body = bodyPart.getInputStream();
357
358         switch (encoding) {
359         case MimeHeader.QUOTED_PRINTABLE: {
360             body = new QuotedPrintableDecoderInputStream(body);
361
362             break;
363         }
364
365         case MimeHeader.BASE64: {
366             body = new Base64DecoderInputStream(body);
367
368             break;
369         }
370         }
371
372         if (charsetName != null) {
373             Charset JavaDoc charset;
374
375             try {
376                 charset = Charset.forName(charsetName);
377             } catch (UnsupportedCharsetException JavaDoc e) {
378                 charset = Charset.forName(System.getProperty("file.encoding"));
379             }
380
381             body = new CharsetDecoderInputStream(body, charset);
382         }
383
384         String JavaDoc bodyMsg = StreamUtils.readCharacterStream(body).toString();
385         return bodyMsg;
386     }
387
388     /**
389      *
390      * prepend "> " characters to the bodytext to specify we are quoting
391      *
392      * @param message
393      * A <code>Message</code> which contains the bodytext of the
394      * message we want reply/forward.
395      * @param html
396      * True for html messages (a different quoting is necessary)
397      *
398      * TODO (@author fdietz): we should make this configureable
399      *
400      */

401     public static String JavaDoc createQuotedBodyText(CharSequence JavaDoc bodyText,
402             boolean html) throws IOException JavaDoc {
403         // Quote according model type (text/html)
404
String JavaDoc quotedBodyText;
405
406         if (html) {
407             // html - quoting is done by inserting a div around the
408
// message formattet with a blue line at left edge
409
// TODO (@author fdietz): Implement quoting (font color, stylesheet,
410
// blockquote???)
411

412             /*
413              * String lcase = bodyText.toLowerCase(); StringBuffer buf = new
414              * StringBuffer(); String quoteStart = " <blockquote> "; String
415              * quoteEnd = " </blockquote> ";
416              *
417              * int pos = lcase.indexOf(" <body"); pos = lcase.indexOf("> ", pos) +
418              * 1; buf.append(bodyText.substring(0, pos));
419              * buf.append(quoteStart); int end = lcase.indexOf(" </body");
420              * buf.append(bodyText.substring(pos, end)); buf.append(quoteEnd);
421              * buf.append(bodyText.substring(end));
422              *
423              * Logging.log.info("Source:\n" + bodyText);
424              * Logging.log.info("Result:\n" + buf.toString());
425              *
426              * quotedBodyText = buf.toString();
427              */

428             quotedBodyText = bodyText.toString();
429         } else {
430             // plain text
431
quotedBodyText = bodyText.toString().replaceAll("(?m)^(.*)$",
432                     "> $1");
433         }
434
435         return quotedBodyText;
436     }
437
438     /**
439      * Check if HTML support should be enabled in model.
440      *
441      * @return true, if enabled. false, otherwise
442      */

443     public static boolean isHTMLEnabled() {
444         if (MailConfig.getInstance() == null)
445             return false;
446
447         // get configuration
448
XmlElement optionsElement = MailConfig.getInstance().get(
449                 "composer_options").getElement("/options");
450         XmlElement htmlElement = optionsElement.getElement("html");
451
452         // create html element, if it doesn't exist
453
if (htmlElement == null) {
454             htmlElement = optionsElement.addSubElement("html");
455         }
456
457         // get enable attribute
458
String JavaDoc enableHtml = htmlElement.getAttribute("enable", "false");
459
460         return Boolean.valueOf(enableHtml).booleanValue();
461     }
462
463     /** ******************** addressbook stuff ********************** */
464     /**
465      *
466      * add automatically every person we'll send a message to the "Collected
467      * Addresses" Addressbook
468      *
469      */

470     public static void addAddressesToAddressbook(Address[] addresses) {
471
472         try {
473             IContactFacade contactFacade = ServiceConnector.getContactFacade();
474             IFolderFacade folderFacade = ServiceConnector.getFolderFacade();
475             IModelFacade modelFacade = ServiceConnector.getModelFacade();
476             IFolder folder = folderFacade.getCollectedAddresses();
477             for (int i = 0; i < addresses.length; i++) {
478                 try {
479                     IContactItem contactItem = modelFacade.createContactItem();
480                     Address addr = addresses[i];
481                     FacadeUtil.getInstance().initContactItem(contactItem, addr.getDisplayName(), addr.getMailAddress());
482                     contactFacade.addContact(folder.getId(), contactItem);
483                 } catch (StoreException e) {
484                     e.printStackTrace();
485                 }
486
487             }
488         } catch (ServiceNotFoundException e) {
489             e.printStackTrace();
490         }
491
492     }
493 }
Popular Tags