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