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