/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://oss.oracle.com/licenses/CDDL+GPL-1.1
* or LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.mail;
import java.util.
Date;
import java.io.*;
import javax.mail.search.
SearchTerm;
/**
* This class models an email message. This is an abstract class.
* Subclasses provide actual implementations. <p>
*
* Message implements the Part interface. Message contains a set of
* attributes and a "content". Messages within a folder also have a
* set of flags that describe its state within the folder.<p>
*
* Message defines some new attributes in addition to those defined
* in the <code>Part</code> interface. These attributes specify meta-data
* for the message - i.e., addressing and descriptive information about
* the message. <p>
*
* Message objects are obtained either from a Folder or by constructing
* a new Message object of the appropriate subclass. Messages that have
* been received are normally retrieved from a folder named "INBOX". <p>
*
* A Message object obtained from a folder is just a lightweight
* reference to the actual message. The Message is 'lazily' filled
* up (on demand) when each item is requested from the message. Note
* that certain folder implementations may return Message objects that
* are pre-filled with certain user-specified items.
* To send a message, an appropriate subclass of Message (e.g.,
* MimeMessage) is instantiated, the attributes and content are
* filled in, and the message is sent using the <code>Transport.send</code>
* method. <p>
*
* @author John Mani
* @author Bill Shannon
* @author Max Spivak
* @see javax.mail.Part
*/
public abstract class
Message implements
Part {
/**
* The number of this message within its folder, or zero if
* the message was not retrieved from a folder.
*/
protected int
msgnum = 0;
/**
* True if this message has been expunged.
*/
protected boolean
expunged = false;
/**
* The containing folder, if this message is obtained from a folder
*/
protected
Folder folder = null;
/**
* The Session object for this Message
*/
protected
Session session = null;
/**
* No-arg version of the constructor.
*/
protected
Message() { }
/**
* Constructor that takes a Folder and a message number.
* Used by Folder implementations.
*
* @param folder containing folder
* @param msgnum this message's sequence number within this folder
*/
protected
Message(
Folder folder, int
msgnum) {
this.
folder =
folder;
this.
msgnum =
msgnum;
session =
folder.
store.
session;
}
/**
* Constructor that takes a Session. Used for client created
* Message objects.
*
* @param session A Session object
*/
protected
Message(
Session session) {
this.
session =
session;
}
/**
* Return the Session used when this message was created.
*
* @return the message's Session
* @since JavaMail 1.5
*/
public
Session getSession() {
return
session;
}
/**
* Returns the "From" attribute. The "From" attribute contains
* the identity of the person(s) who wished this message to
* be sent. <p>
*
* In certain implementations, this may be different
* from the entity that actually sent the message. <p>
*
* This method returns <code>null</code> if this attribute
* is not present in this message. Returns an empty array if
* this attribute is present, but contains no addresses.
*
* @return array of Address objects
* @exception MessagingException for failures
*/
public abstract
Address[]
getFrom() throws
MessagingException;
/**
* Set the "From" attribute in this Message. The value of this
* attribute is obtained from the property "mail.user". If this
* property is absent, the system property "user.name" is used.
*
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
*/
public abstract void
setFrom() throws
MessagingException;
/**
* Set the "From" attribute in this Message.
*
* @param address the sender
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
*/
public abstract void
setFrom(
Address address)
throws
MessagingException;
/**
* Add these addresses to the existing "From" attribute
*
* @param addresses the senders
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
*/
public abstract void
addFrom(
Address[]
addresses)
throws
MessagingException;
/**
* This inner class defines the types of recipients allowed by
* the Message class. The currently defined types are TO,
* CC and BCC.
*
* Note that this class only has a protected constructor, thereby
* restricting new Recipient types to either this class or subclasses.
* This effectively implements an enumeration of the allowed Recipient
* types.
*
* The following code sample shows how to use this class to obtain
* the "TO" recipients from a message.
* <blockquote><pre>
*
* Message msg = folder.getMessages(1);
* Address[] a = m.getRecipients(Message.RecipientType.TO);
*
* </pre></blockquote>
*
* @see javax.mail.Message#getRecipients
* @see javax.mail.Message#setRecipients
* @see javax.mail.Message#addRecipients
*/
public static class
RecipientType implements
Serializable {
/**
* The "To" (primary) recipients.
*/
public static final
RecipientType TO = new
RecipientType("To");
/**
* The "Cc" (carbon copy) recipients.
*/
public static final
RecipientType CC = new
RecipientType("Cc");
/**
* The "Bcc" (blind carbon copy) recipients.
*/
public static final
RecipientType BCC = new
RecipientType("Bcc");
/**
* The type of recipient, usually the name of a corresponding
* Internet standard header.
*
* @serial
*/
protected
String type;
private static final long
serialVersionUID = -7479791750606340008L;
/**
* Constructor for use by subclasses.
*
* @param type the recipient type
*/
protected
RecipientType(
String type) {
this.
type =
type;
}
/**
* When deserializing a RecipientType, we need to make sure to
* return only one of the known static final instances defined
* in this class. Subclasses must implement their own
* <code>readResolve</code> method that checks for their known
* instances before calling this super method.
*
* @return the RecipientType object instance
* @exception ObjectStreamException for object stream errors
*/
protected
Object readResolve() throws
ObjectStreamException {
if (
type.
equals("To"))
return
TO;
else if (
type.
equals("Cc"))
return
CC;
else if (
type.
equals("Bcc"))
return
BCC;
else
throw new
InvalidObjectException(
"Attempt to resolve unknown RecipientType: " +
type);
}
@
Override
public
String toString() {
return
type;
}
}
/**
* Get all the recipient addresses of the given type. <p>
*
* This method returns <code>null</code> if no recipients of
* the given type are present in this message. It may return an
* empty array if the header is present, but contains no addresses.
*
* @param type the recipient type
* @return array of Address objects
* @exception MessagingException for failures
* @see Message.RecipientType#TO
* @see Message.RecipientType#CC
* @see Message.RecipientType#BCC
*/
public abstract
Address[]
getRecipients(
RecipientType type)
throws
MessagingException;
/**
* Get all the recipient addresses for the message.
* The default implementation extracts the TO, CC, and BCC
* recipients using the <code>getRecipients</code> method. <p>
*
* This method returns <code>null</code> if none of the recipient
* headers are present in this message. It may Return an empty array
* if any recipient header is present, but contains no addresses.
*
* @return array of Address objects
* @exception MessagingException for failures
* @see Message.RecipientType#TO
* @see Message.RecipientType#CC
* @see Message.RecipientType#BCC
* @see #getRecipients
*/
public
Address[]
getAllRecipients() throws
MessagingException {
Address[]
to =
getRecipients(
RecipientType.
TO);
Address[]
cc =
getRecipients(
RecipientType.
CC);
Address[]
bcc =
getRecipients(
RecipientType.
BCC);
if (
cc == null &&
bcc == null)
return
to; // a common case
int
numRecip =
(
to != null ?
to.length : 0) +
(
cc != null ?
cc.length : 0) +
(
bcc != null ?
bcc.length : 0);
Address[]
addresses = new
Address[
numRecip];
int
pos = 0;
if (
to != null) {
System.
arraycopy(
to, 0,
addresses,
pos,
to.length);
pos +=
to.length;
}
if (
cc != null) {
System.
arraycopy(
cc, 0,
addresses,
pos,
cc.length);
pos +=
cc.length;
}
if (
bcc != null) {
System.
arraycopy(
bcc, 0,
addresses,
pos,
bcc.length);
// pos += bcc.length;
}
return
addresses;
}
/**
* Set the recipient addresses. All addresses of the specified
* type are replaced by the addresses parameter.
*
* @param type the recipient type
* @param addresses the addresses
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
*/
public abstract void
setRecipients(
RecipientType type,
Address[]
addresses)
throws
MessagingException;
/**
* Set the recipient address. All addresses of the specified
* type are replaced by the address parameter. <p>
*
* The default implementation uses the <code>setRecipients</code> method.
*
* @param type the recipient type
* @param address the address
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception MessagingException for other failures
*/
public void
setRecipient(
RecipientType type,
Address address)
throws
MessagingException {
if (
address == null)
setRecipients(
type, null);
else {
Address[]
a = new
Address[1];
a[0] =
address;
setRecipients(
type,
a);
}
}
/**
* Add these recipient addresses to the existing ones of the given type.
*
* @param type the recipient type
* @param addresses the addresses
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
*/
public abstract void
addRecipients(
RecipientType type,
Address[]
addresses)
throws
MessagingException;
/**
* Add this recipient address to the existing ones of the given type. <p>
*
* The default implementation uses the <code>addRecipients</code> method.
*
* @param type the recipient type
* @param address the address
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception MessagingException for other failures
*/
public void
addRecipient(
RecipientType type,
Address address)
throws
MessagingException {
Address[]
a = new
Address[1];
a[0] =
address;
addRecipients(
type,
a);
}
/**
* Get the addresses to which replies should be directed.
* This will usually be the sender of the message, but
* some messages may direct replies to a different address. <p>
*
* The default implementation simply calls the <code>getFrom</code>
* method. <p>
*
* This method returns <code>null</code> if the corresponding
* header is not present. Returns an empty array if the header
* is present, but contains no addresses.
*
* @return addresses to which replies should be directed
* @exception MessagingException for failures
* @see #getFrom
*/
public
Address[]
getReplyTo() throws
MessagingException {
return
getFrom();
}
/**
* Set the addresses to which replies should be directed.
* (Normally only a single address will be specified.)
* Not all message types allow this to be specified separately
* from the sender of the message. <p>
*
* The default implementation provided here just throws the
* MethodNotSupportedException.
*
* @param addresses addresses to which replies should be directed
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MethodNotSupportedException if the underlying
* implementation does not support setting this
* attribute
* @exception MessagingException for other failures
*/
public void
setReplyTo(
Address[]
addresses) throws
MessagingException {
throw new
MethodNotSupportedException("setReplyTo not supported");
}
/**
* Get the subject of this message.
*
* @return the subject
* @exception MessagingException for failures
*/
public abstract
String getSubject() throws
MessagingException;
/**
* Set the subject of this message.
*
* @param subject the subject
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
*/
public abstract void
setSubject(
String subject)
throws
MessagingException;
/**
* Get the date this message was sent.
*
* @return the date this message was sent
* @exception MessagingException for failures
*/
public abstract
Date getSentDate() throws
MessagingException;
/**
* Set the sent date of this message.
*
* @param date the sent date of this message
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
*/
public abstract void
setSentDate(
Date date) throws
MessagingException;
/**
* Get the date this message was received.
*
* @return the date this message was received
* @exception MessagingException for failures
*/
public abstract
Date getReceivedDate() throws
MessagingException;
/**
* Returns a <code>Flags</code> object containing the flags for
* this message. <p>
*
* Modifying any of the flags in this returned Flags object will
* not affect the flags of this message. Use <code>setFlags()</code>
* to do that. <p>
*
* @return Flags object containing the flags for this message
* @see javax.mail.Flags
* @see #setFlags
* @exception MessagingException for failures
*/
public abstract
Flags getFlags() throws
MessagingException;
/**
* Check whether the flag specified in the <code>flag</code>
* argument is set in this message. <p>
*
* The default implementation uses <code>getFlags</code>.
*
* @param flag the flag
* @return value of the specified flag for this message
* @see javax.mail.Flags.Flag
* @see javax.mail.Flags.Flag#ANSWERED
* @see javax.mail.Flags.Flag#DELETED
* @see javax.mail.Flags.Flag#DRAFT
* @see javax.mail.Flags.Flag#FLAGGED
* @see javax.mail.Flags.Flag#RECENT
* @see javax.mail.Flags.Flag#SEEN
* @exception MessagingException for failures
*/
public boolean
isSet(
Flags.
Flag flag) throws
MessagingException {
return
getFlags().
contains(
flag);
}
/**
* Set the specified flags on this message to the specified value.
* Note that any flags in this message that are not specified in
* the given <code>Flags</code> object are unaffected. <p>
*
* This will result in a <code>MessageChangedEvent</code> being
* delivered to any MessageChangedListener registered on this
* Message's containing folder.
*
* @param flag Flags object containing the flags to be set
* @param set the value to be set
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values.
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
* @see javax.mail.event.MessageChangedEvent
*/
public abstract void
setFlags(
Flags flag, boolean
set)
throws
MessagingException;
/**
* Set the specified flag on this message to the specified value.
*
* This will result in a <code>MessageChangedEvent</code> being
* delivered to any MessageChangedListener registered on this
* Message's containing folder. <p>
*
* The default implementation uses the <code>setFlags</code> method.
*
* @param flag Flags.Flag object containing the flag to be set
* @param set the value to be set
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values.
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception MessagingException for other failures
* @see javax.mail.event.MessageChangedEvent
*/
public void
setFlag(
Flags.
Flag flag, boolean
set)
throws
MessagingException {
Flags f = new
Flags(
flag);
setFlags(
f,
set);
}
/**
* Get the Message number for this Message.
* A Message object's message number is the relative
* position of this Message in its Folder. Note that the message
* number for a particular Message can change during a session
* if other messages in the Folder are deleted and expunged. <p>
*
* Valid message numbers start at 1. Messages that do not belong
* to any folder (like newly composed or derived messages) have 0
* as their message number.
*
* @return the message number
*/
public int
getMessageNumber() {
return
msgnum;
}
/**
* Set the Message number for this Message. This method is
* invoked only by the implementation classes.
*
* @param msgnum the message number
*/
protected void
setMessageNumber(int
msgnum) {
this.
msgnum =
msgnum;
}
/**
* Get the folder from which this message was obtained. If
* this is a new message or nested message, this method returns
* null.
*
* @return the containing folder
*/
public
Folder getFolder() {
return
folder;
}
/**
* Checks whether this message is expunged. All other methods except
* <code>getMessageNumber()</code> are invalid on an expunged
* Message object. <p>
*
* Messages that are expunged due to an explict <code>expunge()</code>
* request on the containing Folder are removed from the Folder
* immediately. Messages that are externally expunged by another source
* are marked "expunged" and return true for the isExpunged() method,
* but they are not removed from the Folder until an explicit
* <code>expunge()</code> is done on the Folder. <p>
*
* See the description of <code>expunge()</code> for more details on
* expunge handling.
*
* @return true if the message is expunged
* @see Folder#expunge
*/
public boolean
isExpunged() {
return
expunged;
}
/**
* Sets the expunged flag for this Message. This method is to
* be used only by the implementation classes.
*
* @param expunged the expunged flag
*/
protected void
setExpunged(boolean
expunged) {
this.
expunged =
expunged;
}
/**
* Get a new Message suitable for a reply to this message.
* The new Message will have its attributes and headers
* set up appropriately. Note that this new message object
* will be empty, that is, it will <strong>not</strong> have a "content".
* These will have to be suitably filled in by the client. <p>
*
* If <code>replyToAll</code> is set, the new Message will be addressed
* to all recipients of this message. Otherwise, the reply will be
* addressed to only the sender of this message (using the value
* of the <code>getReplyTo</code> method). <p>
*
* The "Subject" field is filled in with the original subject
* prefixed with "Re:" (unless it already starts with "Re:"). <p>
*
* The reply message will use the same session as this message.
*
* @param replyToAll reply should be sent to all recipients
* of this message
* @return the reply Message
* @exception MessagingException for failures
*/
public abstract
Message reply(boolean
replyToAll) throws
MessagingException;
/**
* Save any changes made to this message into the message-store
* when the containing folder is closed, if the message is contained
* in a folder. (Some implementations may save the changes
* immediately.) Update any header fields to be consistent with the
* changed message contents. If any part of a message's headers or
* contents are changed, saveChanges must be called to ensure that
* those changes are permanent. If saveChanges is not called, any
* such modifications may or may not be saved, depending on the
* message store and folder implementation. <p>
*
* Messages obtained from folders opened READ_ONLY should not be
* modified and saveChanges should not be called on such messages.
*
* @exception IllegalStateException if this message is
* obtained from a READ_ONLY folder.
* @exception IllegalWriteException if the underlying
* implementation does not support modification
* of existing values.
* @exception MessagingException for other failures
*/
public abstract void
saveChanges() throws
MessagingException;
/**
* Apply the specified Search criterion to this message.
*
* @param term the Search criterion
* @return true if the Message matches this search
* criterion, false otherwise.
* @exception MessagingException for failures
* @see javax.mail.search.SearchTerm
*/
public boolean
match(
SearchTerm term) throws
MessagingException {
return
term.
match(this);
}
}