001: /***
002: * jwma Java WebMail
003: * Copyright (c) 2000-2003 jwma team
004: *
005: * jwma is free software; you can distribute and use this source
006: * under the terms of the BSD-style license received along with
007: * the distribution.
008: ***/package dtw.webmail.model;
009:
010: import java.util.*;
011: import java.io.IOException;
012: import javax.mail.*;
013: import javax.mail.internet.*;
014:
015: import org.apache.log4j.Logger;
016:
017: //import dtw.webmail.JwmaKernel;
018: import dtw.webmail.util.EntityHandler;
019:
020: /**
021: * Class implementing the JwmaMessage model.
022: * <p>
023: * This implementation is specialized to wrap a
024: * <tt>javax.mail.Message</tt> for displaying it.
025: *
026: * @author Dieter Wimberger
027: * @version 0.9.7 07/02/2003
028: */
029: public class JwmaDisplayMessage implements JwmaMessage {
030:
031: //logging
032: private static Logger log = Logger
033: .getLogger(JwmaDisplayMessage.class);
034:
035: //instance attributes
036: private Message m_Message;
037: private boolean m_Received;
038: private String m_FullHeader;
039: private int m_Number;
040: private Date m_SentDate;
041: private Date m_ReceivedDate;
042: private String m_From;
043: private String m_ReplyTo;
044: private String m_To;
045: private String m_Subject;
046: private String m_Body;
047: private boolean m_Singlepart;
048: private String m_CC;
049: private String m_BCC;
050: private JwmaMessagePart[] m_MessageParts;
051:
052: /**
053: * Constructs a <tt>JwmaDisplayMessage</tt> instance.
054: *
055: * @param number the number of the message as <tt>int</tt>
056: */
057: protected JwmaDisplayMessage(Message msg, int number) {
058: m_Message = msg;
059: m_Number = number;
060: }//constructor
061:
062: public Message getMessage() {
063: return m_Message;
064: }//getMessage
065:
066: /**
067: * Returns the full message header as <tt>String</tt>.
068: *
069: * @return Full message header as <tt>String</tt>.
070: */
071: public String getFullHeader() {
072: return m_FullHeader;
073: }//getFullHeader
074:
075: /**
076: * Sets the full message header.
077: *
078: * @param header the full message header as <tt>String</tt>.
079: */
080: private void setFullHeader(String header) {
081: m_FullHeader = header;
082: }//setFullHeader
083:
084: public int getMessageNumber() {
085: return m_Number;
086: }//getMessageNumber
087:
088: public boolean isReceived() {
089: return m_Received;
090: }//isReceived
091:
092: /**
093: * Flags the message as a received message.
094: *
095: * @param true if the message was received,
096: * false otherwise.
097: */
098: private void setReceived(boolean b) {
099: m_Received = b;
100: }//setReceived
101:
102: public boolean isSent() {
103: return !m_Received;
104: }//isSent
105:
106: public Date getReceivedDate() {
107: return m_ReceivedDate;
108: }//getDate
109:
110: /**
111: * Sets the received date of this message.
112: *
113: * @param d the date when this message was received.
114: */
115: private void setReceivedDate(Date d) {
116: m_ReceivedDate = d;
117: }//setReceivedDate
118:
119: public Date getSentDate() {
120: return m_SentDate;
121: }//getSentDate
122:
123: /**
124: * Sets the <tt>date</tt> associated with this message.
125: *
126: * @param d the <tt>Date</tt> associated with this message.
127: */
128: private void setSentDate(Date d) {
129: m_SentDate = d;
130: }//setSentDate
131:
132: public Date getDate() {
133: if (isReceived() && m_ReceivedDate != null) {
134: return m_ReceivedDate;
135: } else if (isSent() && m_SentDate != null) {
136: return m_SentDate;
137: } else {
138: return new Date();
139: }
140: }//getDate
141:
142: public String getFrom() {
143: return m_From;
144: }//getFrom
145:
146: /**
147: * Sets the sender's address(es) of the message as
148: * <tt>String</tt>.
149: *
150: * @param from the sender(s) address(es) of the message as String.
151: */
152: private void setFrom(String from) {
153: m_From = from;
154: }//setFrom
155:
156: public String getReplyTo() {
157: return m_ReplyTo;
158: }//getReplyTo
159:
160: /**
161: * Set the Reply-To address(es) of the message.
162: *
163: * @param from the Reply-To address(es) of the message
164: * as <tt>String</tt>.
165: */
166: public void setReplyTo(String replyto) {
167: m_ReplyTo = replyto;
168: }//setReplyTo
169:
170: public String getTo() {
171: return m_To;
172: }//getTo
173:
174: /**
175: * Sets the receiver's address(es) of the message as
176: * <tt>String</tt>.
177: *
178: * @param to the receiver(s) address(es) of the message as String.
179: */
180: private void setTo(String to) {
181: m_To = to;
182: }//setTo
183:
184: public String getCCTo() {
185: return m_CC;
186: }//getCC
187:
188: /**
189: * Sets the carbon copy receiver's address(es) of the message.
190: *
191: * @param to the carbon copy receiver(s) address(es) of the
192: * message as String.
193: */
194: private void setCCTo(String cc) {
195: m_CC = cc;
196: }//setCC
197:
198: public String getBCCTo() {
199: return m_BCC;
200: }//getBCCTo
201:
202: /**
203: * Sets the blind carbon copy receiver's address(es) of the message.
204: *
205: * @param to the blind carbon copy receiver(s) address(es) of the
206: * message as String.
207: */
208: private void setBCCTo(String bcc) {
209: m_BCC = bcc;
210: }//setBCC
211:
212: public String getSubject() {
213: return m_Subject;
214: }//getSubject
215:
216: /**
217: * Sets the subject of the message.
218: *
219: * @param subject the subject of the message as <tt>String</tt>.
220: */
221: private void setSubject(String subject) {
222: try {
223: if (subject == null) {
224: m_Subject = "";
225: } else {
226: m_Subject = MimeUtility.decodeText(subject);
227: }
228: } catch (Exception ex) {
229: m_Subject = "";
230: }
231: }//setSubject
232:
233: public boolean isSinglepart() {
234: return m_Singlepart;
235: }//isSinglepart
236:
237: /**
238: * Flags the message as a singlepart message.
239: *
240: * @param true if the message should be flagged singlepart,
241: * false otherwise.
242: */
243: private void setSinglepart(boolean b) {
244: m_Singlepart = b;
245: }//setSinglepart
246:
247: public boolean isMultipart() {
248: return !m_Singlepart;
249: }//isMultipart
250:
251: public String getBody() {
252: return m_Body;
253: }//getBody
254:
255: /**
256: * Sets the body of the message.
257: *
258: * @param body the text/plain content of the message as
259: * <tt>String</tt>.
260: */
261: public void setBody(String body) {
262: m_Body = body;
263: }//setBody;
264:
265: /**
266: * Returns the message part with the given number.
267: *
268: * @param number the number of the requested part as <tt>int</tt>.
269: *
270: * @return the reference to wrapper instance of the requested part.
271: *
272: * @throws JwmaException if the part does not exist.
273: */
274: public JwmaMessagePart getMessagePart(int number)
275: throws JwmaException {
276: if (number < 0 || number > getMessageParts().length) {
277: throw new JwmaException("message.displaypart.failed");
278: } else {
279: return getMessageParts()[number];
280: }
281: }//getMessagePart
282:
283: public JwmaMessagePart[] getMessageParts() {
284: return m_MessageParts;
285: }//getMessageParts
286:
287: /**
288: * Sets the associated <tt>JwmaMessagePart</tt> objects.
289: *
290: * @param parts an array of JwmaMessagePart objects each representing
291: * information about a part of this message.
292: *
293: * @see dtw.webmail.model.JwmaMessagePart
294: */
295: private void setMessageParts(JwmaMessagePart[] parts) {
296: m_MessageParts = parts;
297: }//setMessageParts
298:
299: private static void buildPartInfoList(List partlist, Multipart mp)
300: throws Exception, JwmaException {
301: for (int i = 0; i < mp.getCount(); i++) {
302: //Get part
303: Part apart = mp.getBodyPart(i);
304: //handle single & multiparts
305: if (apart.isMimeType("multipart/*")) {
306: //recurse
307: buildPartInfoList(partlist, (Multipart) apart
308: .getContent());
309: } else {
310: //append the part
311: partlist.add(JwmaMessagePartImpl
312: .createJwmaMessagePartImpl(apart, partlist
313: .size()));
314: }
315: }
316: }//buildPartList
317:
318: private static String getAddressesAsString(Address[] addr)
319: throws Exception {
320: if (addr != null && addr.length > 0) {
321: return EntityHandler.encode(MimeUtility
322: .decodeText(InternetAddress.toString(addr)));
323: } else {
324: return "";
325: }
326: }//getAddressAsString
327:
328: /**
329: * Creates a <tt>JwmaDisplayMessage</tt> instance.
330: * At the moment it just delegates the call to
331: * <tt>createJwmaDisplayMessage(Message,boolean)</tt>, but the
332: * idea is to recycle the passed in <tt>JwmaMessageInfoImpl</tt> instance
333: * somewhen.
334: *
335: * @param msginfo the <tt>JwmaMessageInfoImpl</tt> to create
336: * this instance from.
337: * @param msg the <tt>Message</tt> to create this instance from.
338: * @param prefs the user's preferences.
339: *
340: * @return the created <tt>JwmaDisplayMessage</tt> instance.
341: *
342: * @throws JwmaException if it fails to create the new instance.
343: */
344: public static JwmaDisplayMessage createJwmaDisplayMessage(
345: JwmaMessageInfoImpl msginfo, Message msg,
346: JwmaPreferences prefs) throws JwmaException {
347:
348: //FIXME: recycle existing information once!
349: return createJwmaDisplayMessage(msg, prefs);
350: }//create JwmaDisplayMessage
351:
352: /**
353: * Creates a <tt>JwmaDisplayMessage</tt> instance.
354: *
355: * @param msg the <tt>Message</tt> to create this instance from.
356: * @param prefs the user's preferences.
357: *
358: * @return the newly created instance.
359: *
360: * @throws JwmaException if it fails to create the new instance.
361: */
362: public static JwmaDisplayMessage createJwmaDisplayMessage(Message msg,
363: JwmaPreferences prefs)
364: throws JwmaException {
365:
366: JwmaDisplayMessage message = null;
367:
368: try {
369:
370: //create instance with number
371: message = new JwmaDisplayMessage(msg, msg.getMessageNumber());
372:
373: //retrieve full header
374: StringBuffer fullhead = new StringBuffer();
375: for (Enumeration enum = ((MimeMessage) msg).getAllHeaderLines();
376: enum.hasMoreElements();) {
377: fullhead.append((String) enum.nextElement())
378: .append("\n");
379: }
380: //probably is better to see the "raw" headers, instead of
381: //decoded ones.
382: message.setFullHeader(
383: EntityHandler.encode(
384: fullhead.toString()
385: )
386: );
387: //senders and receivers
388: message.setFrom(getAddressesAsString(
389: msg.getFrom())
390: );
391: message.setReplyTo(getAddressesAsString(
392: msg.getReplyTo())
393: );
394:
395: message.setTo(getAddressesAsString(
396: msg.getRecipients(Message.RecipientType.TO))
397: );
398: message.setCCTo(getAddressesAsString(
399: msg.getRecipients(Message.RecipientType.CC))
400: );
401: message.setBCCTo(getAddressesAsString(
402: msg.getRecipients(Message.RecipientType.BCC))
403: );
404:
405: //determine if received, will have a header named Received
406: message.setReceived(
407: (msg.getHeader("Received") != null)
408: );
409:
410: message.setReceivedDate(msg.getReceivedDate());
411: message.setSentDate(msg.getSentDate());
412:
413:
414: //set encoded subject
415: String subject = msg.getSubject();
416: if (subject != null) {
417: message.setSubject(
418: EntityHandler.encode(MimeUtility.decodeText(subject))
419: );
420: }
421:
422: //flag attachments or none
423: message.setSinglepart(!msg.isMimeType("multipart/*"));
424:
425: //handle alternatetively
426: if (message.isSinglepart()) {
427: //set body as String processed with the users msgprocessor
428: try {
429: message.setBody(
430: prefs.getMessageProcessor().process(
431: msg.getContent().toString()
432: )
433: );
434:
435: } catch (IOException ex) {
436: //handle!?
437: message.setBody(
438: "System puzzled by corrupt singlepart message."
439: );
440: }
441: } else {
442: try {
443: //get main body part
444: Multipart mp = (Multipart) msg.getContent();
445:
446: //build flatlist
447: List partlist = new ArrayList(10);
448: buildPartInfoList(partlist, mp);
449:
450: //set flatlist
451: JwmaMessagePart[] parts = new JwmaMessagePart[partlist.size()];
452: message.setMessageParts(
453: (JwmaMessagePart[]) partlist.toArray(parts)
454: );
455: } catch (IOException ex) {
456: //handle!?
457: message.setSinglepart(true);
458: message.setBody("System puzzled by corrupt multipart message.");
459: }
460: }
461: return message;
462: } catch (Exception mex) {
463: throw new JwmaException("jwma.displaymessage.failedcreation", true).setException(mex);
464: }
465: }//createJwmaDisplayMessage
466: }//class JwmaDisplayMessage
|