001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: /*
038: * @(#)Message.java 1.39 07/05/04
039: */
040:
041: package javax.mail;
042:
043: import java.util.Vector;
044: import java.util.Date;
045: import java.util.Properties;
046: import java.io.*;
047: import javax.mail.search.SearchTerm;
048:
049: /**
050: * This class models an email message. This is an abstract class.
051: * Subclasses provide actual implementations. <p>
052: *
053: * Message implements the Part interface. Message contains a set of
054: * attributes and a "content". Messages within a folder also have a
055: * set of flags that describe its state within the folder.<p>
056: *
057: * Message defines some new attributes in addition to those defined
058: * in the <code>Part</code> interface. These attributes specify meta-data
059: * for the message - i.e., addressing and descriptive information about
060: * the message. <p>
061: *
062: * Message objects are obtained either from a Folder or by constructing
063: * a new Message object of the appropriate subclass. Messages that have
064: * been received are normally retrieved from a folder named "INBOX". <p>
065: *
066: * A Message object obtained from a folder is just a lightweight
067: * reference to the actual message. The Message is 'lazily' filled
068: * up (on demand) when each item is requested from the message. Note
069: * that certain folder implementations may return Message objects that
070: * are pre-filled with certain user-specified items.
071:
072: * To send a message, an appropriate subclass of Message (e.g.,
073: * MimeMessage) is instantiated, the attributes and content are
074: * filled in, and the message is sent using the <code>Transport.send</code>
075: * method. <p>
076: *
077: * @author John Mani
078: * @author Bill Shannon
079: * @author Max Spivak
080: * @see javax.mail.Part
081: */
082:
083: public abstract class Message implements Part {
084:
085: /**
086: * The number of this message within its folder, or zero if
087: * the message was not retrieved from a folder.
088: */
089: protected int msgnum = 0;
090:
091: /**
092: * True if this message has been expunged.
093: */
094: protected boolean expunged = false;
095:
096: /**
097: * The containing folder, if this message is obtained from a folder
098: */
099: protected Folder folder = null;
100:
101: /**
102: * The Session object for this Message
103: */
104: protected Session session = null;
105:
106: /**
107: * No-arg version of the constructor.
108: */
109: protected Message() {
110: }
111:
112: /**
113: * Constructor that takes a Folder and a message number.
114: * Used by Folder implementations.
115: *
116: * @param folder containing folder
117: * @param msgnum this message's sequence number within this folder
118: */
119: protected Message(Folder folder, int msgnum) {
120: this .folder = folder;
121: this .msgnum = msgnum;
122: session = folder.store.session;
123: }
124:
125: /**
126: * Constructor that takes a Session. Used for client created
127: * Message objects.
128: *
129: * @param session A Session object
130: */
131: protected Message(Session session) {
132: this .session = session;
133: }
134:
135: /**
136: * Returns the "From" attribute. The "From" attribute contains
137: * the identity of the person(s) who wished this message to
138: * be sent. <p>
139: *
140: * In certain implementations, this may be different
141: * from the entity that actually sent the message. <p>
142: *
143: * This method returns <code>null</code> if this attribute
144: * is not present in this message. Returns an empty array if
145: * this attribute is present, but contains no addresses.
146: *
147: * @return array of Address objects
148: * @exception MessagingException
149: */
150: public abstract Address[] getFrom() throws MessagingException;
151:
152: /**
153: * Set the "From" attribute in this Message. The value of this
154: * attribute is obtained from the property "mail.user". If this
155: * property is absent, the system property "user.name" is used.
156: *
157: * @exception MessagingException
158: * @exception IllegalWriteException if the underlying
159: * implementation does not support modification
160: * of existing values
161: * @exception IllegalStateException if this message is
162: * obtained from a READ_ONLY folder.
163: */
164: public abstract void setFrom() throws MessagingException;
165:
166: /**
167: * Set the "From" attribute in this Message.
168: *
169: * @param address the sender
170: * @exception MessagingException
171: * @exception IllegalWriteException if the underlying
172: * implementation does not support modification
173: * of existing values
174: * @exception IllegalStateException if this message is
175: * obtained from a READ_ONLY folder.
176: */
177: public abstract void setFrom(Address address)
178: throws MessagingException;
179:
180: /**
181: * Add these addresses to the existing "From" attribute
182: *
183: * @param addresses the senders
184: * @exception IllegalWriteException if the underlying
185: * implementation does not support modification
186: * of existing values
187: * @exception IllegalStateException if this message is
188: * obtained from a READ_ONLY folder.
189: * @exception MessagingException
190: */
191: public abstract void addFrom(Address[] addresses)
192: throws MessagingException;
193:
194: /**
195: * This inner class defines the types of recipients allowed by
196: * the Message class. The currently defined types are TO,
197: * CC and BCC.
198: *
199: * Note that this class only has a protected constructor, thereby
200: * restricting new Recipient types to either this class or subclasses.
201: * This effectively implements an enumeration of the allowed Recipient
202: * types.
203: *
204: * The following code sample shows how to use this class to obtain
205: * the "TO" recipients from a message.
206: * <blockquote><pre>
207: *
208: * Message msg = folder.getMessages(1);
209: * Address[] a = m.getRecipients(Message.RecipientType.TO);
210: *
211: * </pre></blockquote><p>
212: *
213: * @see javax.mail.Message#getRecipients
214: * @see javax.mail.Message#setRecipients
215: * @see javax.mail.Message#addRecipients
216: */
217: public static class RecipientType implements Serializable {
218: /**
219: * The "To" (primary) recipients.
220: */
221: public static final RecipientType TO = new RecipientType("To");
222: /**
223: * The "Cc" (carbon copy) recipients.
224: */
225: public static final RecipientType CC = new RecipientType("Cc");
226: /**
227: * The "Bcc" (blind carbon copy) recipients.
228: */
229: public static final RecipientType BCC = new RecipientType("Bcc");
230:
231: /**
232: * The type of recipient, usually the name of a corresponding
233: * Internet standard header.
234: *
235: * @serial
236: */
237: protected String type;
238:
239: private static final long serialVersionUID = -7479791750606340008L;
240:
241: /**
242: * Constructor for use by subclasses.
243: */
244: protected RecipientType(String type) {
245: this .type = type;
246: }
247:
248: /**
249: * When deserializing a RecipientType, we need to make sure to
250: * return only one of the known static final instances defined
251: * in this class. Subclasses must implement their own
252: * <code>readResolve</code> method that checks for their known
253: * instances before calling this super method.
254: */
255: protected Object readResolve() throws ObjectStreamException {
256: if (type.equals("To"))
257: return TO;
258: else if (type.equals("Cc"))
259: return CC;
260: else if (type.equals("Bcc"))
261: return BCC;
262: else
263: throw new InvalidObjectException(
264: "Attempt to resolve unknown RecipientType: "
265: + type);
266: }
267:
268: public String toString() {
269: return type;
270: }
271: }
272:
273: /**
274: * Get all the recipient addresses of the given type. <p>
275: *
276: * This method returns <code>null</code> if no recipients of
277: * the given type are present in this message. It may return an
278: * empty array if the header is present, but contains no addresses.
279: *
280: * @param type the recipient type
281: * @return array of Address objects
282: * @exception MessagingException
283: * @see Message.RecipientType#TO
284: * @see Message.RecipientType#CC
285: * @see Message.RecipientType#BCC
286: */
287: public abstract Address[] getRecipients(RecipientType type)
288: throws MessagingException;
289:
290: /**
291: * Get all the recipient addresses for the message.
292: * The default implementation extracts the TO, CC, and BCC
293: * recipients using the <code>getRecipients</code> method. <p>
294: *
295: * This method returns <code>null</code> if none of the recipient
296: * headers are present in this message. It may Return an empty array
297: * if any recipient header is present, but contains no addresses.
298: *
299: * @return array of Address objects
300: * @exception MessagingException
301: * @see Message.RecipientType#TO
302: * @see Message.RecipientType#CC
303: * @see Message.RecipientType#BCC
304: * @see #getRecipients
305: */
306: public Address[] getAllRecipients() throws MessagingException {
307: Address[] to = getRecipients(RecipientType.TO);
308: Address[] cc = getRecipients(RecipientType.CC);
309: Address[] bcc = getRecipients(RecipientType.BCC);
310:
311: if (cc == null && bcc == null)
312: return to; // a common case
313:
314: int numRecip = (to != null ? to.length : 0)
315: + (cc != null ? cc.length : 0)
316: + (bcc != null ? bcc.length : 0);
317: Address[] addresses = new Address[numRecip];
318: int pos = 0;
319: if (to != null) {
320: System.arraycopy(to, 0, addresses, pos, to.length);
321: pos += to.length;
322: }
323: if (cc != null) {
324: System.arraycopy(cc, 0, addresses, pos, cc.length);
325: pos += cc.length;
326: }
327: if (bcc != null) {
328: System.arraycopy(bcc, 0, addresses, pos, bcc.length);
329: pos += bcc.length;
330: }
331: return addresses;
332: }
333:
334: /**
335: * Set the recipient addresses. All addresses of the specified
336: * type are replaced by the addresses parameter.
337: *
338: * @param type the recipient type
339: * @param addresses the addresses
340: * @exception MessagingException
341: * @exception IllegalWriteException if the underlying
342: * implementation does not support modification
343: * of existing values
344: * @exception IllegalStateException if this message is
345: * obtained from a READ_ONLY folder.
346: */
347: public abstract void setRecipients(RecipientType type,
348: Address[] addresses) throws MessagingException;
349:
350: /**
351: * Set the recipient address. All addresses of the specified
352: * type are replaced by the address parameter. <p>
353: *
354: * The default implementation uses the <code>setRecipients</code> method.
355: *
356: * @param type the recipient type
357: * @param address the address
358: * @exception MessagingException
359: * @exception IllegalWriteException if the underlying
360: * implementation does not support modification
361: * of existing values
362: */
363: public void setRecipient(RecipientType type, Address address)
364: throws MessagingException {
365: Address[] a = new Address[1];
366: a[0] = address;
367: setRecipients(type, a);
368: }
369:
370: /**
371: * Add these recipient addresses to the existing ones of the given type.
372: *
373: * @param type the recipient type
374: * @param addresses the addresses
375: * @exception MessagingException
376: * @exception IllegalWriteException if the underlying
377: * implementation does not support modification
378: * of existing values
379: * @exception IllegalStateException if this message is
380: * obtained from a READ_ONLY folder.
381: */
382: public abstract void addRecipients(RecipientType type,
383: Address[] addresses) throws MessagingException;
384:
385: /**
386: * Add this recipient address to the existing ones of the given type. <p>
387: *
388: * The default implementation uses the <code>addRecipients</code> method.
389: *
390: * @param type the recipient type
391: * @param address the address
392: * @exception MessagingException
393: * @exception IllegalWriteException if the underlying
394: * implementation does not support modification
395: * of existing values
396: */
397: public void addRecipient(RecipientType type, Address address)
398: throws MessagingException {
399: Address[] a = new Address[1];
400: a[0] = address;
401: addRecipients(type, a);
402: }
403:
404: /**
405: * Get the addresses to which replies should be directed.
406: * This will usually be the sender of the message, but
407: * some messages may direct replies to a different address. <p>
408: *
409: * The default implementation simply calls the <code>getFrom</code>
410: * method. <p>
411: *
412: * This method returns <code>null</code> if the corresponding
413: * header is not present. Returns an empty array if the header
414: * is present, but contains no addresses.
415: *
416: * @return addresses to which replies should be directed
417: * @exception MessagingException
418: * @see #getFrom
419: */
420: public Address[] getReplyTo() throws MessagingException {
421: return getFrom();
422: }
423:
424: /**
425: * Set the addresses to which replies should be directed.
426: * (Normally only a single address will be specified.)
427: * Not all message types allow this to be specified separately
428: * from the sender of the message. <p>
429: *
430: * The default implementation provided here just throws the
431: * MethodNotSupportedException.
432: *
433: * @param addresses addresses to which replies should be directed
434: * @exception MessagingException
435: * @exception IllegalWriteException if the underlying
436: * implementation does not support modification
437: * of existing values
438: * @exception IllegalStateException if this message is
439: * obtained from a READ_ONLY folder.
440: * @exception MethodNotSupportedException if the underlying
441: * implementation does not support setting this
442: * attribute
443: */
444: public void setReplyTo(Address[] addresses)
445: throws MessagingException {
446: throw new MethodNotSupportedException(
447: "setReplyTo not supported");
448: }
449:
450: /**
451: * Get the subject of this message.
452: *
453: * @return the subject
454: * @exception MessagingException
455: */
456: public abstract String getSubject() throws MessagingException;
457:
458: /**
459: * Set the subject of this message.
460: *
461: * @param subject the subject
462: * @exception MessagingException
463: * @exception IllegalWriteException if the underlying
464: * implementation does not support modification
465: * of existing values
466: * @exception IllegalStateException if this message is
467: * obtained from a READ_ONLY folder.
468: */
469: public abstract void setSubject(String subject)
470: throws MessagingException;
471:
472: /**
473: * Get the date this message was sent.
474: *
475: * @return the date this message was sent
476: * @exception MessagingException
477: */
478: public abstract Date getSentDate() throws MessagingException;
479:
480: /**
481: * Set the sent date of this message.
482: *
483: * @param date the sent date of this message
484: * @exception MessagingException
485: * @exception IllegalWriteException if the underlying
486: * implementation does not support modification
487: * of existing values
488: * @exception IllegalStateException if this message is
489: * obtained from a READ_ONLY folder.
490: */
491: public abstract void setSentDate(Date date)
492: throws MessagingException;
493:
494: /**
495: * Get the date this message was received.
496: *
497: * @return the date this message was received
498: * @exception MessagingException
499: */
500: public abstract Date getReceivedDate() throws MessagingException;
501:
502: /**
503: * Returns a <code>Flags</code> object containing the flags for
504: * this message. <p>
505: *
506: * Modifying any of the flags in this returned Flags object will
507: * not affect the flags of this message. Use <code>setFlags()</code>
508: * to do that. <p>
509: *
510: * @return Flags object containing the flags for this message
511: * @see javax.mail.Flags
512: * @see #setFlags
513: * @exception MessagingException
514: */
515: public abstract Flags getFlags() throws MessagingException;
516:
517: /**
518: * Check whether the flag specified in the <code>flag</code>
519: * argument is set in this message. <p>
520: *
521: * The default implementation uses <code>getFlags</code>.
522: *
523: * @param flag the flag
524: * @return value of the specified flag for this message
525: * @see javax.mail.Flags.Flag
526: * @see javax.mail.Flags.Flag#ANSWERED
527: * @see javax.mail.Flags.Flag#DELETED
528: * @see javax.mail.Flags.Flag#DRAFT
529: * @see javax.mail.Flags.Flag#FLAGGED
530: * @see javax.mail.Flags.Flag#RECENT
531: * @see javax.mail.Flags.Flag#SEEN
532: * @exception MessagingException
533: */
534: public boolean isSet(Flags.Flag flag) throws MessagingException {
535: return getFlags().contains(flag);
536: }
537:
538: /**
539: * Set the specified flags on this message to the specified value.
540: * Note that any flags in this message that are not specified in
541: * the given <code>Flags</code> object are unaffected. <p>
542: *
543: * This will result in a <code>MessageChangedEvent</code> being
544: * delivered to any MessageChangedListener registered on this
545: * Message's containing folder.
546: *
547: * @param flag Flags object containing the flags to be set
548: * @param set the value to be set
549: * @exception MessagingException
550: * @exception IllegalWriteException if the underlying
551: * implementation does not support modification
552: * of existing values.
553: * @exception IllegalStateException if this message is
554: * obtained from a READ_ONLY folder.
555: * @see javax.mail.event.MessageChangedEvent
556: */
557: public abstract void setFlags(Flags flag, boolean set)
558: throws MessagingException;
559:
560: /**
561: * Set the specified flag on this message to the specified value.
562: *
563: * This will result in a <code>MessageChangedEvent</code> being
564: * delivered to any MessageChangedListener registered on this
565: * Message's containing folder. <p>
566: *
567: * The default implementation uses the <code>setFlags</code> method.
568: *
569: * @param flag Flags.Flag object containing the flag to be set
570: * @param set the value to be set
571: * @exception MessagingException
572: * @exception IllegalWriteException if the underlying
573: * implementation does not support modification
574: * of existing values.
575: * @exception IllegalStateException if this message is
576: * obtained from a READ_ONLY folder.
577: * @see javax.mail.event.MessageChangedEvent
578: */
579: public void setFlag(Flags.Flag flag, boolean set)
580: throws MessagingException {
581: Flags f = new Flags(flag);
582: setFlags(f, set);
583: }
584:
585: /**
586: * Get the Message number for this Message.
587: * A Message object's message number is the relative
588: * position of this Message in its Folder. Note that the message
589: * number for a particular Message can change during a session
590: * if other messages in the Folder are deleted and expunged. <p>
591: *
592: * Valid message numbers start at 1. Messages that do not belong
593: * to any folder (like newly composed or derived messages) have 0
594: * as their message number.
595: *
596: * @return the message number
597: */
598: public int getMessageNumber() {
599: return msgnum;
600: }
601:
602: /**
603: * Set the Message number for this Message. This method is
604: * invoked only by the implementation classes.
605: */
606: protected void setMessageNumber(int msgnum) {
607: this .msgnum = msgnum;
608: }
609:
610: /**
611: * Get the folder from which this message was obtained. If
612: * this is a new message or nested message, this method returns
613: * null.
614: *
615: * @return the containing folder
616: */
617: public Folder getFolder() {
618: return folder;
619: }
620:
621: /**
622: * Checks whether this message is expunged. All other methods except
623: * <code>getMessageNumber()</code> are invalid on an expunged
624: * Message object. <p>
625: *
626: * Messages that are expunged due to an explict <code>expunge()</code>
627: * request on the containing Folder are removed from the Folder
628: * immediately. Messages that are externally expunged by another source
629: * are marked "expunged" and return true for the isExpunged() method,
630: * but they are not removed from the Folder until an explicit
631: * <code>expunge()</code> is done on the Folder. <p>
632: *
633: * See the description of <code>expunge()</code> for more details on
634: * expunge handling.
635: *
636: * @see Folder#expunge
637: */
638: public boolean isExpunged() {
639: return expunged;
640: }
641:
642: /**
643: * Sets the expunged flag for this Message. This method is to
644: * be used only by the implementation classes.
645: *
646: * @param expunged the expunged flag
647: */
648: protected void setExpunged(boolean expunged) {
649: this .expunged = expunged;
650: }
651:
652: /**
653: * Get a new Message suitable for a reply to this message.
654: * The new Message will have its attributes and headers
655: * set up appropriately. Note that this new message object
656: * will be empty, that is, it will <strong>not</strong> have a "content".
657: * These will have to be suitably filled in by the client. <p>
658: *
659: * If <code>replyToAll</code> is set, the new Message will be addressed
660: * to all recipients of this message. Otherwise, the reply will be
661: * addressed to only the sender of this message (using the value
662: * of the <code>getReplyTo</code> method). <p>
663: *
664: * The "Subject" field is filled in with the original subject
665: * prefixed with "Re:" (unless it already starts with "Re:"). <p>
666: *
667: * The reply message will use the same session as this message.
668: *
669: * @param replyToAll reply should be sent to all recipients
670: * of this message
671: * @return the reply Message
672: * @exception MessagingException
673: */
674: public abstract Message reply(boolean replyToAll)
675: throws MessagingException;
676:
677: /**
678: * Save any changes made to this message into the message-store
679: * when the containing folder is closed, if the message is contained
680: * in a folder. (Some implementations may save the changes
681: * immediately.) Update any header fields to be consistent with the
682: * changed message contents. If any part of a message's headers or
683: * contents are changed, saveChanges must be called to ensure that
684: * those changes are permanent. If saveChanges is not called, any
685: * such modifications may or may not be saved, depending on the
686: * message store and folder implementation. <p>
687: *
688: * Messages obtained from folders opened READ_ONLY should not be
689: * modified and saveChanges should not be called on such messages.
690: *
691: * @exception MessagingException
692: * @exception IllegalStateException if this message is
693: * obtained from a READ_ONLY folder.
694: * @exception IllegalWriteException if the underlying
695: * implementation does not support modification
696: * of existing values.
697: */
698: public abstract void saveChanges() throws MessagingException;
699:
700: /**
701: * Apply the specified Search criterion to this message.
702: *
703: * @param term the Search criterion
704: * @return true if the Message matches this search
705: * criterion, false otherwise.
706: * @exception MessagingException
707: * @see javax.mail.search.SearchTerm
708: */
709: public boolean match(SearchTerm term) throws MessagingException {
710: return term.match(this);
711: }
712: }
|