KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > mail > folder > command > PrintMessageCommand


1 //The contents of this file are subject to the Mozilla Public License Version 1.1
2
//(the "License"); you may not use this file except in compliance with the
3
//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
4
//
5
//Software distributed under the License is distributed on an "AS IS" basis,
6
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
7
//for the specific language governing rights and
8
//limitations under the License.
9
//
10
//The Original Code is "The Columba Project"
11
//
12
//The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
13
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
14
//
15
//All Rights Reserved.
16
package org.columba.mail.folder.command;
17
18 import java.awt.Color JavaDoc;
19 import java.awt.Font JavaDoc;
20 import java.io.ByteArrayInputStream JavaDoc;
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.lang.reflect.Array JavaDoc;
25 import java.net.MalformedURLException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.nio.charset.Charset JavaDoc;
28 import java.text.DateFormat JavaDoc;
29 import java.text.ParsePosition JavaDoc;
30 import java.text.SimpleDateFormat JavaDoc;
31 import java.util.Date JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.logging.Logger JavaDoc;
34
35 import org.columba.api.command.ICommandReference;
36 import org.columba.api.command.IWorkerStatusController;
37 import org.columba.core.command.Command;
38 import org.columba.core.command.StatusObservableImpl;
39 import org.columba.core.command.Worker;
40 import org.columba.core.config.Config;
41 import org.columba.core.io.DiskIO;
42 import org.columba.core.io.StreamUtils;
43 import org.columba.core.print.cCmUnit;
44 import org.columba.core.print.cDocument;
45 import org.columba.core.print.cHGroup;
46 import org.columba.core.print.cHTMLPart;
47 import org.columba.core.print.cLine;
48 import org.columba.core.print.cParagraph;
49 import org.columba.core.print.cPrintObject;
50 import org.columba.core.print.cPrintVariable;
51 import org.columba.core.print.cVGroup;
52 import org.columba.core.util.TempFileStore;
53 import org.columba.core.xml.XmlElement;
54 import org.columba.mail.command.IMailFolderCommandReference;
55 import org.columba.mail.config.MailConfig;
56 import org.columba.mail.folder.IMailbox;
57 import org.columba.mail.gui.message.viewer.AttachmentModel;
58 import org.columba.mail.parser.text.HtmlParser;
59 import org.columba.mail.util.MailResourceLoader;
60 import org.columba.ristretto.coder.Base64DecoderInputStream;
61 import org.columba.ristretto.coder.CharsetDecoderInputStream;
62 import org.columba.ristretto.coder.QuotedPrintableDecoderInputStream;
63 import org.columba.ristretto.message.Header;
64 import org.columba.ristretto.message.MimeHeader;
65 import org.columba.ristretto.message.MimePart;
66 import org.columba.ristretto.message.MimeTree;
67 import org.columba.ristretto.message.StreamableMimePart;
68
69
70 /**
71  * Print the selected message.
72  *
73  * @author karlpeder
74  */

75 public class PrintMessageCommand extends Command {
76
77     /** JDK 1.4+ logging framework logger, used for logging. */
78     private static final Logger JavaDoc LOG = Logger.getLogger("org.columba.mail.folder.command");
79
80     private cPrintObject mailHeader;
81     private cPrintObject mailFooter;
82     private DateFormat JavaDoc mailDateFormat;
83     private String JavaDoc[] headerKeys = {"From", "To", "Date", "Subject"};
84     private String JavaDoc dateHeaderKey = "Date"; // the header key for date field
85
private String JavaDoc attHeaderKey = "attachment";
86     private Charset JavaDoc charset;
87
88     
89     private MimeHeader bodyHeader;
90     private InputStream JavaDoc bodyStream;
91     /**
92      * Constructor for PrintMessageCommdn.
93      *
94      * @param frameMediator
95      * @param references
96      */

97     public PrintMessageCommand(ICommandReference reference, Charset JavaDoc charset) {
98         super(reference);
99         this.charset = charset;
100
101         // Header
102
cParagraph columbaParagraph = new cParagraph();
103         columbaParagraph.setText("The Columba Project");
104         columbaParagraph.setColor(Color.lightGray);
105         columbaParagraph.setFontStyle(Font.BOLD);
106
107         cParagraph link = new cParagraph();
108         link.setText(" - http://www.columbamail.org");
109         link.setTextAlignment(cParagraph.LEFT);
110         link.setLeftMargin(columbaParagraph.getSize(new cCmUnit(100)).getWidth());
111         link.setColor(Color.lightGray);
112
113         cPrintVariable date = new cPrintVariable();
114         date.setCodeString("%DATE_TODAY%");
115         date.setTextAlignment(cParagraph.RIGHT);
116         date.setColor(Color.lightGray);
117
118         cHGroup headerText = new cHGroup();
119         headerText.add(columbaParagraph);
120         headerText.add(link);
121         headerText.add(date);
122
123         cLine headerLine = new cLine();
124
125         headerLine.setThickness(1);
126         headerLine.setColor(Color.lightGray);
127         headerLine.setTopMargin(new cCmUnit(0.1));
128
129         cVGroup header = new cVGroup();
130         header.add(headerText);
131         header.add(headerLine);
132         header.setBottomMargin(new cCmUnit(0.5));
133
134         mailHeader = header;
135
136         // Footer
137
cPrintVariable footer = new cPrintVariable();
138         footer.setTextAlignment(cParagraph.CENTER);
139         footer.setCodeString("%PAGE_NR% / %PAGE_COUNT%");
140         footer.setTopMargin(new cCmUnit(0.5));
141         footer.setColor(Color.lightGray);
142
143         mailFooter = footer;
144
145         // DateFormat
146
mailDateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG,
147                 DateFormat.MEDIUM);
148     }
149
150     public cPrintObject getMailHeader() {
151         return mailHeader;
152     }
153
154     public cPrintObject getMailFooter() {
155         return mailFooter;
156     }
157
158     public String JavaDoc[] getHeaderKeys() {
159         return headerKeys;
160     }
161
162     public DateFormat JavaDoc getMailDateFormat() {
163         return mailDateFormat;
164     }
165
166     /**
167          * @see org.columba.api.command.Command#updateGUI()
168          */

169     public void updatedGUI() throws Exception JavaDoc {
170     }
171
172     /**
173      * This method executes the print action, i.e. it prints the selected
174      * messages.
175      *
176      * @see org.columba.api.command.Command#execute(Worker)
177      */

178     public void execute(IWorkerStatusController worker)
179         throws Exception JavaDoc {
180         /*
181                  * *20030604, karlpeder* Fixed minor flaws to be able to print text
182                  * messages. Further more added support for html messages.
183                  */

184         IMailFolderCommandReference r = (IMailFolderCommandReference) getReference();
185
186         Object JavaDoc[] uids = r.getUids(); // uid for messages to print
187

188         IMailbox srcFolder = (IMailbox) r.getSourceFolder();
189
190         //register for status events
191
((StatusObservableImpl) srcFolder.getObservable()).setWorker(worker);
192
193         // Print each message
194
for (int j = 0; j < uids.length; j++) {
195             Object JavaDoc uid = uids[j];
196             LOG.info("Printing UID=" + uid);
197
198             Header header = srcFolder.getHeaderFields(uids[j], getHeaderKeys());
199
200             setupMessageBodyPart(uid, srcFolder, worker);
201             
202             
203             
204             
205             // Setup print document for message
206
cDocument messageDoc = new cDocument();
207             messageDoc.setHeader(getMailHeader());
208             messageDoc.setFooter(getMailFooter());
209
210             String JavaDoc[] headerKeys = getHeaderKeys();
211             cParagraph hKey;
212             cParagraph hValue;
213             cHGroup hLine;
214             Object JavaDoc value;
215
216             // Add header information to print
217
for (int i = 0; i < Array.getLength(headerKeys); i++) {
218                 hKey = new cParagraph();
219
220                 // *20030531, karlpeder* setting headerKeys to lowercase for
221
// lookup!
222
hKey.setText(MailResourceLoader.getString("header",
223                         headerKeys[i].toLowerCase()));
224                 hKey.setFontStyle(Font.BOLD);
225
226                 hValue = new cParagraph();
227
228                 /*
229                  * *20031216, karlpeder* Changed handling of dates.
230                  * Previously columba.date header was used. Now we
231                  * use the Date header instead
232                  */

233                 //if (headerKeys[i].equalsIgnoreCase("date")) {
234
// value = header.get("columba.date");
235
//} else {
236
//value = header.get(headerKeys[i]);
237
//}
238
value = header.get(headerKeys[i]);
239
240                 if (headerKeys[i].equalsIgnoreCase(dateHeaderKey)) {
241                     // special handling for dates
242
SimpleDateFormat JavaDoc formatter = new SimpleDateFormat JavaDoc(
243                             "d MMM yyyy HH:mm:ss Z");
244                     String JavaDoc dateStr = (String JavaDoc) value;
245
246                     // ignore leading weekday name (e.g. "Mon,"), since this
247
// seems to give problems during parsing
248
ParsePosition JavaDoc pos = new ParsePosition JavaDoc(dateStr.indexOf(',') + 1);
249                     Date JavaDoc d = formatter.parse((String JavaDoc) value, pos);
250
251                     if (d != null) {
252                         hValue.setText(getMailDateFormat().format(d));
253                     } else {
254                         // fall back to use the Date header contents directly
255
hValue.setText((String JavaDoc) value);
256                     }
257                 } else {
258                     hValue.setText((String JavaDoc) value);
259                 }
260
261                 hValue.setLeftMargin(new cCmUnit(3.0));
262
263                 hLine = new cHGroup();
264                 hLine.add(hKey);
265                 hLine.add(hValue);
266
267                 messageDoc.appendPrintObject(hLine);
268             }
269
270             // Add list of attachments if applicable
271
AttachmentModel attMod = new AttachmentModel();
272             attMod.setCollection(srcFolder.getMimePartTree(uid));
273
274             List JavaDoc attachments = attMod.getDisplayedMimeParts();
275
276             for (int i = 0; i < attachments.size(); i++) {
277                 StreamableMimePart mp = (StreamableMimePart) attachments.get(i);
278                 if (mp.getHeader().getFileName() != null) {
279                     // one line is added to the header for each attachment
280
// (which has a filename defined)
281
hKey = new cParagraph();
282                     hKey.setText(MailResourceLoader.getString("header",
283                             attHeaderKey));
284                     hKey.setFontStyle(Font.BOLD);
285
286                     hValue = new cParagraph();
287                     hValue.setText(mp.getHeader().getFileName());
288                     hValue.setLeftMargin(new cCmUnit(3.0));
289
290                     hLine = new cHGroup();
291                     hLine.add(hKey);
292                     hLine.add(hValue);
293
294                     messageDoc.appendPrintObject(hLine);
295                 }
296             }
297
298             // Add body of message to print
299
String JavaDoc mimesubtype = bodyHeader.getMimeType().getSubtype();
300
301             if (mimesubtype.equals("html")) {
302                 messageDoc.appendPrintObject(getHTMLBodyPrintObject());
303             } else {
304                 messageDoc.appendPrintObject(getPlainBodyPrintObject());
305             }
306
307             // print the print document (i.e. the message)
308
messageDoc.print();
309         }
310
311         // end of for loop over uids to print
312
}
313
314     /**
315      * Private utility to create a print object representing the body of a
316      * plain text message. The messagebody is decoded according to present
317      * charset. <br>Precondition: Mime subtype is "plain".
318      *
319      * @param bodyPart
320      * Body part of message
321      * @return Print object ready to be appended to the print document
322      * @author Karl Peder Olesen (karlpeder), 20030531
323      */

324     private cPrintObject getPlainBodyPrintObject()
325         throws IOException JavaDoc {
326         // decode message body with respect to charset
327
String JavaDoc decodedBody = getDecodedMessageBody();
328
329         // create a print object and return it
330
cParagraph printBody = new cParagraph();
331         printBody.setTopMargin(new cCmUnit(1.0));
332         printBody.setText(decodedBody);
333
334         return printBody;
335     }
336
337     /**
338          * retrieve printer options from configuration file
339          *
340          * @return true, if scaling is allowed false, otherwise
341          */

342     protected boolean isScalingAllowed() {
343         XmlElement options = Config.getInstance().get("options").getElement("/options");
344         XmlElement printer = null;
345
346         if (options != null) {
347             printer = options.getElement("/printer");
348         }
349
350         // no configuration available, create default config
351
if (printer == null) {
352             // create new local xml treenode
353
LOG.info("printer config node not found - creating new");
354             printer = new XmlElement("printer");
355             printer.addAttribute("allow_scaling", "true");
356
357             // add to options if possible (so it will be saved)
358
if (options != null) {
359                 LOG.info("storing new printer config node");
360                 options.addElement(printer);
361             }
362         }
363
364         return Boolean.valueOf(printer.getAttribute("allow_scaling", "true"))
365                       .booleanValue();
366     }
367
368     /**
369          * Private utility to create a print object representing the body of a html
370          * message. <br>Precondition: Mime subtype is "html".
371          *
372          * @param bodyPart
373          * Body part of message
374          * @return Print object ready to be appended to the print document
375          * @author Karl Peder Olesen (karlpeder), 20030531
376          */

377     private cPrintObject getHTMLBodyPrintObject()
378         throws IOException JavaDoc {
379         // decode message body with respect to charset
380
String JavaDoc decodedBody = getDecodedMessageBody();
381
382         // try to fix broken html-strings
383
String JavaDoc validated = HtmlParser.validateHTMLString(decodedBody);
384
385         try {
386             // create temporary file and save validated body
387
File JavaDoc tempFile = TempFileStore.createTempFileWithSuffix("html");
388             DiskIO.saveStringInFile(tempFile, validated);
389
390             URL JavaDoc url = tempFile.toURL();
391
392             boolean allowScaling = isScalingAllowed();
393             cHTMLPart htmlBody = new cHTMLPart(allowScaling);
394
395             // true ~ scaling allowed
396
htmlBody.setTopMargin(new cCmUnit(1.0));
397             htmlBody.setHTML(url);
398
399             return htmlBody;
400         } catch (MalformedURLException JavaDoc e) {
401             LOG.warning("Error loading html for print: " + e.getMessage());
402
403             return null;
404         } catch (IOException JavaDoc e) {
405             LOG.warning("Error loading html for print: " + e.getMessage());
406
407             return null;
408         }
409     }
410
411     /**
412      * Private utility to decode the message body with the proper charset
413      *
414      * @param bodyPart
415      * The body of the message
416      * @return Decoded message body
417      * @author Karl Peder Olesen (karlpeder), 20030601
418      */

419     private String JavaDoc getDecodedMessageBody()
420         throws IOException JavaDoc {
421         int encoding = bodyHeader.getContentTransferEncoding();
422
423         switch (encoding) {
424         case MimeHeader.QUOTED_PRINTABLE: {
425             bodyStream = new QuotedPrintableDecoderInputStream(bodyStream);
426
427             break;
428         }
429
430         case MimeHeader.BASE64: {
431             bodyStream = new Base64DecoderInputStream(bodyStream);
432
433             break;
434         }
435         }
436
437         // First determine which charset to use
438
if (charset == null) {
439             try {
440                 // get charset from message
441
charset = Charset.forName(bodyHeader.getContentParameter("charset"));
442             } catch (Exception JavaDoc ex) {
443                 // decode using default charset
444
charset = Charset.forName(System.getProperty("file.encoding"));
445             }
446         }
447
448         bodyStream = new CharsetDecoderInputStream(bodyStream, charset);
449
450         return StreamUtils.readCharacterStream(bodyStream).toString();
451     }
452     
453     /**
454      * Private utility to get body part of a message. User preferences
455      * regarding html messages is used to select what to retrieve. If the body
456      * part retrieved is null, a fake one containing a simple text is returned
457      *
458      * @param uid
459      * ID of message
460      * @param srcFolder
461      * AbstractMessageFolder containing the message
462      * @param worker
463      * @return body part of message
464      */

465     private void setupMessageBodyPart(Object JavaDoc uid, IMailbox srcFolder,
466         IWorkerStatusController worker) throws Exception JavaDoc {
467         // Does the user prefer html or plain text?
468
XmlElement html = MailConfig.getInstance().getMainFrameOptionsConfig()
469                                               .getRoot().getElement("/options/html");
470
471         // Get body of message depending on user preferences
472
MimeTree mimePartTree = srcFolder.getMimePartTree(uid);
473
474         MimePart bodyPart = null;
475
476         if (Boolean.valueOf(html.getAttribute("prefer")).booleanValue()) {
477             bodyPart = mimePartTree.getFirstTextPart("html");
478         } else {
479             bodyPart = mimePartTree.getFirstTextPart("plain");
480         }
481         
482         if (bodyPart == null) {
483             bodyHeader = new MimeHeader();
484             bodyStream = new ByteArrayInputStream JavaDoc(new byte[0]);
485         } else {
486             bodyHeader = bodyPart.getHeader();
487             bodyStream = srcFolder.getMimePartBodyStream(uid, bodyPart.getAddress());
488         }
489     }
490     
491 }
492
Popular Tags