Source Code Cross Referenced for MessageComposer.java in  » Mail-Clients » columba-1.4 » org » columba » mail » composer » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Mail Clients » columba 1.4 » org.columba.mail.composer 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // The contents of this file are subject to the Mozilla Public License Version
002:        // 1.1
003:        //(the "License"); you may not use this file except in compliance with the
004:        //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
005:        //
006:        //Software distributed under the License is distributed on an "AS IS" basis,
007:        //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
008:        //for the specific language governing rights and
009:        //limitations under the License.
010:        //
011:        //The Original Code is "The Columba Project"
012:        //
013:        //The Initial Developers of the Original Code are Frederik Dietz and Timo
014:        // Stich.
015:        //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
016:        //
017:        //All Rights Reserved.
018:
019:        package org.columba.mail.composer;
020:
021:        import java.io.BufferedReader;
022:        import java.io.File;
023:        import java.io.FileReader;
024:        import java.io.IOException;
025:        import java.io.InputStream;
026:        import java.nio.charset.Charset;
027:        import java.util.ArrayList;
028:        import java.util.Date;
029:        import java.util.Iterator;
030:        import java.util.List;
031:        import java.util.logging.Logger;
032:
033:        import org.columba.api.command.IWorkerStatusController;
034:        import org.columba.core.logging.Logging;
035:        import org.columba.core.versioninfo.VersionInfo;
036:        import org.columba.core.xml.XmlElement;
037:        import org.columba.mail.config.AccountItem;
038:        import org.columba.mail.config.Identity;
039:        import org.columba.mail.config.MailConfig;
040:        import org.columba.mail.config.SecurityItem;
041:        import org.columba.mail.gui.composer.ComposerModel;
042:        import org.columba.mail.message.PGPMimePart;
043:        import org.columba.mail.message.SendableHeader;
044:        import org.columba.mail.parser.ListBuilder;
045:        import org.columba.mail.parser.ListParser;
046:        import org.columba.mail.parser.text.HtmlParser;
047:        import org.columba.ristretto.coder.EncodedWord;
048:        import org.columba.ristretto.composer.MimeTreeRenderer;
049:        import org.columba.ristretto.io.CharSequenceSource;
050:        import org.columba.ristretto.message.Address;
051:        import org.columba.ristretto.message.LocalMimePart;
052:        import org.columba.ristretto.message.MessageDate;
053:        import org.columba.ristretto.message.MessageIDGenerator;
054:        import org.columba.ristretto.message.MimeHeader;
055:        import org.columba.ristretto.message.MimePart;
056:        import org.columba.ristretto.message.StreamableMimePart;
057:        import org.columba.ristretto.parser.ParserException;
058:
059:        public class MessageComposer {
060:            /** JDK 1.4+ logging framework logger, used for logging. */
061:            private static final Logger LOG = Logger
062:                    .getLogger("org.columba.mail.composer");
063:
064:            private static final Charset headerCharset = Charset
065:                    .forName("UTF-8");
066:
067:            private ComposerModel model;
068:
069:            private int accountUid;
070:
071:            public MessageComposer(ComposerModel model) {
072:                this .model = model;
073:            }
074:
075:            protected SendableHeader initHeader() {
076:                SendableHeader header = new SendableHeader();
077:
078:                // RFC822 - Header
079:                if (model.getToList() != null) {
080:                    String s = ListParser.createStringFromList(ListBuilder
081:                            .createFlatList(model.getToList()), ",");
082:                    if (s.length() != 0)
083:                        header.set("To", EncodedWord.encode(s, headerCharset,
084:                                EncodedWord.QUOTED_PRINTABLE).toString());
085:                }
086:
087:                if (model.getCcList() != null) {
088:                    String s = ListParser.createStringFromList(ListBuilder
089:                            .createFlatList(model.getCcList()), ",");
090:                    if (s.length() != 0)
091:                        header.set("Cc", EncodedWord.encode(s, headerCharset,
092:                                EncodedWord.QUOTED_PRINTABLE).toString());
093:                }
094:
095:                header.getAttributes().put("columba.subject",
096:                        model.getSubject());
097:
098:                //header.set("Subject",
099:                //	EncodedWord.encode(model.getSubject(),
100:                //		Charset.forName(model.getCharsetName()),
101:                //		EncodedWord.QUOTED_PRINTABLE).toString());
102:                header
103:                        .set("Subject", EncodedWord.encode(model.getSubject(),
104:                                headerCharset, EncodedWord.QUOTED_PRINTABLE)
105:                                .toString());
106:
107:                AccountItem item = model.getAccountItem();
108:                Identity identity = item.getIdentity();
109:
110:                //mod: 20040629 SWITT for redirecting feature
111:                //If FROM value was set, take this as From, else take Identity
112:                if (model.getMessage().getHeader().getHeader().get("From") != null) {
113:                    header.set("From", EncodedWord.encode(
114:                            model.getMessage().getHeader().getHeader().get(
115:                                    "From"), headerCharset,
116:                            EncodedWord.QUOTED_PRINTABLE).toString());
117:                } else {
118:                    header.set("From", EncodedWord.encode(
119:                            identity.getAddress().toString(), headerCharset,
120:                            EncodedWord.QUOTED_PRINTABLE).toString());
121:                }
122:
123:                header.set("X-Priority", model.getPriority());
124:
125:                /*
126:                 * String priority = controller.getModel().getPriority();
127:                 * 
128:                 * if (priority != null) { header.set("columba.priority", new
129:                 * Integer(priority)); } else { header.set("columba.priority", new
130:                 * Integer(3)); }
131:                 */
132:                header.set("Mime-Version", "1.0");
133:
134:                String organisation = identity.getOrganisation();
135:
136:                if (organisation != null && organisation.length() > 0) {
137:                    header.set("Organisation", organisation);
138:                }
139:
140:                // reply-to
141:                Address replyAddress = identity.getReplyToAddress();
142:
143:                if (replyAddress != null) {
144:                    header.set("Reply-To", EncodedWord.encode(
145:                            replyAddress.getMailAddress(), headerCharset,
146:                            EncodedWord.QUOTED_PRINTABLE).toString());
147:                }
148:
149:                String messageID = MessageIDGenerator.generate();
150:                header.set("Message-ID", messageID);
151:
152:                String inreply = model.getHeaderField("In-Reply-To");
153:
154:                if (inreply != null) {
155:                    header.set("In-Reply-To", EncodedWord.encode(inreply,
156:                            headerCharset, EncodedWord.QUOTED_PRINTABLE)
157:                            .toString());
158:                }
159:
160:                String references = model.getHeaderField("References");
161:
162:                if (references != null) {
163:                    header.set("References", references);
164:                }
165:
166:                header.set("X-Mailer", "Columba (" + VersionInfo.getVersion()
167:                        + ")");
168:
169:                header.getAttributes().put("columba.from",
170:                        identity.getAddress());
171:
172:                // date
173:                Date date = new Date();
174:                header.getAttributes().put("columba.date", date);
175:                header.set("Date", MessageDate.toString(date));
176:
177:                //attachments
178:                header.getAttributes().put("columba.attachment",
179:                        new Boolean(model.getAttachments().size() > 0));
180:
181:                // copy flags
182:                header.setFlags(model.getMessage().getHeader().getFlags());
183:
184:                return header;
185:            }
186:
187:            private boolean needQPEncoding(String input) {
188:                for (int i = 0; i < input.length(); i++) {
189:                    if (input.charAt(i) > 127) {
190:                        return true;
191:                    }
192:                }
193:
194:                return false;
195:            }
196:
197:            /**
198:             * gives the signature for this Mail back. This signature is NOT a
199:             * pgp-signature but a real mail-signature.
200:             * 
201:             * @param item
202:             *            The item wich holds the signature-file
203:             * @return The signature for the mail as a String. The Signature is
204:             *         character encoded with the caracter set from the model
205:             */
206:            protected String getSignature(File file) {
207:                StringBuffer strbuf = new StringBuffer();
208:
209:                try {
210:                    BufferedReader in = new BufferedReader(new FileReader(file));
211:
212:                    /*
213:                     * BufferedReader in = new BufferedReader( new InputStreamReader(
214:                     * new FileInputStream(file), model.getCharsetName()));
215:                     */
216:                    String str;
217:
218:                    while ((str = in.readLine()) != null) {
219:                        strbuf.append(str + "\n");
220:                    }
221:
222:                    in.close();
223:
224:                    return strbuf.toString();
225:                } catch (IOException ex) {
226:                    ex.printStackTrace();
227:
228:                    return "";
229:                }
230:            }
231:
232:            /**
233:             * Composes a multipart/alternative mime part for the body of a message
234:             * containing a text part and a html part. <br>
235:             * This is to be used for sending html messages, when an alternative text
236:             * part - to be read by users not able to read html - is required. <br>
237:             * Pre-condition: It is assumed that the model contains a message in html
238:             * format.
239:             * 
240:             * @return The composed mime part for the message body
241:             * @author Karl Peder Olesen (karlpeder)
242:             */
243:            private StreamableMimePart composeMultipartAlternativeMimePart(
244:                    boolean appendSignature) {
245:                // compose text part
246:                StreamableMimePart textPart = composeTextMimePart(appendSignature);
247:
248:                // compose html part
249:                StreamableMimePart htmlPart = composeHtmlMimePart(appendSignature);
250:
251:                // merge mimeparts and return
252:                LocalMimePart bodyPart = new LocalMimePart(new MimeHeader(
253:                        "multipart", "alternative"));
254:                bodyPart.addChild(textPart);
255:                bodyPart.addChild(htmlPart);
256:
257:                return bodyPart;
258:            }
259:
260:            /**
261:             * Composes a text/html mime part from the body contained in the composer
262:             * model. This could be for a pure html message or for the html part of a
263:             * multipart/alternative. <br>
264:             * If a signature is defined, it is added to the body. <br>
265:             * Pre-condition: It is assumed that the model contains a html message.
266:             * 
267:             * @return The composed text/html mime part
268:             * @author Karl Peder Olesen (karlpeder)
269:             */
270:            private StreamableMimePart composeHtmlMimePart(
271:                    boolean appendSignature) {
272:                // Init Mime-Header with Default-Values (text/html)
273:                LocalMimePart bodyPart = new LocalMimePart(new MimeHeader(
274:                        "text", "html"));
275:
276:                // Set Default Charset or selected
277:                String charsetName = model.getCharset().name();
278:
279:                StringBuffer buf = new StringBuffer();
280:                String body = model.getBodyText();
281:
282:                // insert link tags for urls and email addresses
283:                body = HtmlParser.substituteURL(body, false);
284:                body = HtmlParser.substituteEmailAddress(body, false);
285:
286:                String lcase = body.toLowerCase(); // for text comparisons
287:
288:                // insert document type decl.
289:                if (lcase.indexOf("<!doctype") == -1) {
290:                    // FIXME (@author karlpeder): Is 3.2 the proper version of html to refer to?
291:                    buf.append("<!DOCTYPE HTML PUBLIC "
292:                            + "\"-//W3C//DTD HTML 3.2//EN\">\r\n");
293:                }
294:
295:                // insert head section with charset def.
296:                String meta = "<meta " + "http-equiv=\"Content-Type\" "
297:                        + "content=\"text/html; charset=" + charsetName + "\">";
298:                int pos = lcase.indexOf("<head");
299:                int bodyStart;
300:
301:                if (pos == -1) {
302:                    // add <head> section
303:                    pos = lcase.indexOf("<html") + 6;
304:                    buf.append(body.substring(0, pos));
305:                    buf.append("<head>");
306:                    buf.append(meta);
307:                    buf.append("</head>");
308:
309:                    bodyStart = pos;
310:                } else {
311:                    // replace <head> section
312:                    pos = lcase.indexOf('>', pos) + 1;
313:                    buf.append(body.substring(0, pos));
314:                    buf.append(meta);
315:
316:                    // TODO (@author karlpeder): If existing meta tags are to be kept, code changes are
317:                    // necessary
318:                    bodyStart = lcase.indexOf("</head");
319:                }
320:
321:                // add rest of body until start of </body>
322:                int bodyEnd = lcase.indexOf("</body");
323:                buf.append(body.substring(bodyStart, bodyEnd));
324:
325:                // add signature if defined
326:                AccountItem item = model.getAccountItem();
327:                Identity identity = item.getIdentity();
328:                File signatureFile = identity.getSignature();
329:
330:                if (signatureFile != null) {
331:                    String signature = getSignature(signatureFile);
332:
333:                    if (signature != null) {
334:                        buf.append("\r\n\r\n");
335:
336:                        // TODO: Should we take some action to ensure signature is valid
337:                        // html?
338:                        buf.append(signature);
339:                    }
340:                }
341:
342:                // add the rest of the original body - and transfer back to body var.
343:                buf.append(body.substring(bodyEnd));
344:                body = buf.toString();
345:
346:                // add encoding if necessary
347:                if (needQPEncoding(body)) {
348:                    bodyPart.getHeader().setContentTransferEncoding(
349:                            "quoted-printable");
350:
351:                    // check if the charset is US-ASCII then there is something wrong
352:                    // -> switch to UTF-8 and write to log-file
353:                    if (charsetName.equalsIgnoreCase("us-ascii")) {
354:                        charsetName = "UTF-8";
355:                        LOG
356:                                .info("Charset was US-ASCII but text has 8-bit chars -> switched to UTF-8");
357:                    }
358:                }
359:
360:                bodyPart.getHeader()
361:                        .putContentParameter("charset", charsetName);
362:
363:                // to allow empty messages
364:                if (body.length() == 0) {
365:                    body = " ";
366:                }
367:
368:                bodyPart.setBody(new CharSequenceSource(body));
369:
370:                return bodyPart;
371:            }
372:
373:            /**
374:             * Composes a text/plain mime part from the body contained in the composer
375:             * model. This could be for a pure text message or for the text part of a
376:             * multipart/alternative. <br>
377:             * If the model contains a html message, tags are stripped to get plain
378:             * text. <br>
379:             * If a signature is defined, it is added to the body.
380:             * @param appendSignature 
381:             * 
382:             * @return The composed text/plain mime part
383:             */
384:            private StreamableMimePart composeTextMimePart(
385:                    boolean appendSignature) {
386:                // Init Mime-Header with Default-Values (text/plain)
387:                LocalMimePart bodyPart = new LocalMimePart(new MimeHeader(
388:                        "text", "plain"));
389:
390:                // Set Default Charset or selected
391:                String charsetName = model.getCharset().name();
392:
393:                String body = model.getBodyText();
394:
395:                /*
396:                 * *20030918, karlpeder* Tags are stripped if the model contains a html
397:                 * message (since we are composing a plain text message here.
398:                 */
399:                if (model.isHtml()) {
400:                    body = HtmlParser.htmlToText(body);
401:                }
402:
403:                AccountItem item = model.getAccountItem();
404:                Identity identity = item.getIdentity();
405:                File signatureFile = identity.getSignature();
406:
407:                if (appendSignature && signatureFile != null) {
408:                    String signature = getSignature(signatureFile);
409:
410:                    if (signature != null) {
411:                        body = body + "\r\n\r\n" + signature;
412:                    }
413:                }
414:
415:                if (needQPEncoding(body)) {
416:                    bodyPart.getHeader().setContentTransferEncoding(
417:                            "quoted-printable");
418:
419:                    // check if the charset is US-ASCII then there is something wrong
420:                    // -> switch to UTF-8 and write to log-file
421:                    if (charsetName.equalsIgnoreCase("us-ascii")) {
422:                        charsetName = "UTF-8";
423:                        LOG
424:                                .info("Charset was US-ASCII but text has 8-bit chars -> switched to UTF-8");
425:                    }
426:                }
427:
428:                // write charset to header
429:                bodyPart.getHeader()
430:                        .putContentParameter("charset", charsetName);
431:
432:                // to allow empty messages
433:                if (body.length() == 0) {
434:                    body = " ";
435:                }
436:
437:                bodyPart.setBody(new CharSequenceSource(body));
438:
439:                return bodyPart;
440:            }
441:
442:            public SendableMessage compose(
443:                    IWorkerStatusController workerStatusController,
444:                    boolean appendSignature) throws Exception {
445:                this .accountUid = model.getAccountItem().getUid();
446:
447:                workerStatusController.setDisplayText("Composing Message...");
448:
449:                MimeTreeRenderer renderer = MimeTreeRenderer.getInstance();
450:                SendableMessage message = new SendableMessage();
451:                SendableHeader header = initHeader();
452:                MimePart root = null;
453:
454:                /*
455:                 * *20030921, karlpeder* The old code was (accidentially!?) modifying
456:                 * the attachment list of the model. This affects the composing when
457:                 * called a second time for saving the message after sending!
458:                 */
459:
460:                //List mimeParts = model.getAttachments();
461:                List attachments = model.getAttachments();
462:                List mimeParts = new ArrayList();
463:                Iterator ite = attachments.iterator();
464:
465:                while (ite.hasNext()) {
466:                    mimeParts.add(ite.next());
467:                }
468:
469:                // *20030919, karlpeder* Added handling of html messages
470:                StreamableMimePart body;
471:
472:                if (model.isHtml()) {
473:                    // compose message body as multipart/alternative
474:                    XmlElement composerOptions = MailConfig.getInstance()
475:                            .getComposerOptionsConfig().getRoot().getElement(
476:                                    "/options");
477:                    XmlElement html = composerOptions.getElement("html");
478:
479:                    if (html == null) {
480:                        html = composerOptions.addSubElement("html");
481:                    }
482:
483:                    String multipart = html.getAttribute("send_as_multipart",
484:                            "true");
485:
486:                    if (multipart.equals("true")) {
487:                        // send as multipart/alternative
488:                        body = composeMultipartAlternativeMimePart(appendSignature);
489:                    } else {
490:                        // send as text/html
491:                        body = composeHtmlMimePart(appendSignature);
492:                    }
493:                } else {
494:                    // compose message body as text/plain
495:                    body = composeTextMimePart(appendSignature);
496:                }
497:
498:                if (body != null) {
499:                    mimeParts.add(0, body);
500:                }
501:
502:                // Create Multipart/Mixed if necessary
503:                if (mimeParts.size() > 1) {
504:                    root = new MimePart(new MimeHeader("multipart", "mixed"));
505:
506:                    for (int i = 0; i < mimeParts.size(); i++) {
507:                        root.addChild((StreamableMimePart) mimeParts.get(i));
508:                    }
509:                } else {
510:                    root = (MimePart) mimeParts.get(0);
511:                }
512:
513:                if (model.isSignMessage()) {
514:                    SecurityItem item = model.getAccountItem().getPGPItem();
515:                    String idStr = item.get("id");
516:
517:                    // if the id not currently set (for example in the security panel in
518:                    // the account-config
519:                    if ((idStr == null) || (idStr.length() == 0)) {
520:                        //  Set id on from address
521:                        item.setString("id", model.getAccountItem()
522:                                .getIdentity().getAddress().getMailAddress());
523:                    }
524:
525:                    PGPMimePart signPart = new PGPMimePart(new MimeHeader(
526:                            "multipart", "signed"), item);
527:
528:                    signPart.addChild(root);
529:                    root = signPart;
530:                }
531:
532:                if (model.isEncryptMessage()) {
533:                    SecurityItem item = model.getAccountItem().getPGPItem();
534:
535:                    // Set recipients from the recipients vector
536:                    List recipientList = model.getRCPTVector();
537:                    StringBuffer recipientBuf = new StringBuffer();
538:
539:                    for (Iterator it = recipientList.iterator(); it.hasNext();) {
540:                        recipientBuf.append((String) it.next());
541:                    }
542:
543:                    item.setString("recipients", recipientBuf.toString());
544:
545:                    PGPMimePart signPart = new PGPMimePart(new MimeHeader(
546:                            "multipart", "encrypted"), item);
547:
548:                    signPart.addChild(root);
549:                    root = signPart;
550:                }
551:
552:                header.setRecipients(model.getRCPTVector());
553:
554:                List headerItemList;
555:
556:                headerItemList = model.getToList();
557:
558:                if ((headerItemList != null) && (headerItemList.size() > 0)) {
559:                    Address adr = null;
560:                    try {
561:                        adr = Address.parse((String) headerItemList.get(0));
562:                        header.getAttributes().put("columba.to", adr);
563:                    } catch (ParserException e) {
564:                        if (Logging.DEBUG)
565:                            e.printStackTrace();
566:                    }
567:                }
568:
569:                headerItemList = model.getCcList();
570:
571:                if ((headerItemList != null) && (headerItemList.size() > 0)) {
572:                    Address adr = null;
573:                    try {
574:                        adr = Address.parse((String) headerItemList.get(0));
575:                        header.getAttributes().put("columba.cc", adr);
576:                    } catch (ParserException e) {
577:                        if (Logging.DEBUG)
578:                            e.printStackTrace();
579:                    }
580:
581:                }
582:
583:                root.getHeader().getHeader().merge(header.getHeader());
584:
585:                InputStream in = renderer.renderMimePart(root);
586:
587:                // size
588:                int size = in.available() / 1024;
589:                header.getAttributes().put("columba.size", new Integer(size));
590:
591:                message.setHeader(header);
592:
593:                message.setAccountUid(accountUid);
594:
595:                //Do not access the inputstream after this line!
596:                message.setSourceStream(in);
597:
598:                return message;
599:            }
600:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.