- /*
- * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package javax.mail.internet;
-
- import javax.mail.*;
- import javax.activation.*;
- import java.lang.*;
- import java.io.*;
- import java.util.*;
- import java.text.ParseException;
- import com.sun.mail.util.ASCIIUtility;
- import com.sun.mail.util.LineOutputStream;
- import com.sun.mail.util.SharedByteArrayInputStream;
-
- /**
- * This class represents a MIME style email message. It implements
- * the <code>Message</code> abstract class and the <code>MimePart</code>
- * interface. <p>
- *
- * Clients wanting to create new MIME style messages will instantiate
- * an empty MimeMessage object and then fill it with appropriate
- * attributes and content. <p>
- *
- * Service providers that implement MIME compliant backend stores may
- * want to subclass MimeMessage and override certain methods to provide
- * specific implementations. The simplest case is probably a provider
- * that generates a MIME style input stream and leaves the parsing of
- * the stream to this class. <p>
- *
- * MimeMessage uses the <code>InternetHeaders</code> class to parse and
- * store the toplevel RFC 822 headers of a message. <p>
- *
- * <hr><strong>A note on RFC 822 and MIME headers</strong><p>
- *
- * RFC 822 header fields <strong>must</strong> contain only
- * US-ASCII characters. MIME allows non ASCII characters to be present
- * in certain portions of certain headers, by encoding those characters.
- * RFC 2047 specifies the rules for doing this. The MimeUtility
- * class provided in this package can be used to to achieve this.
- * Callers of the <code>setHeader</code>, <code>addHeader</code>, and
- * <code>addHeaderLine</code> methods are responsible for enforcing
- * the MIME requirements for the specified headers. In addition, these
- * header fields must be folded (wrapped) before being sent if they
- * exceed the line length limitation for the transport (1000 bytes for
- * SMTP). Received headers may have been folded. The application is
- * responsible for folding and unfolding headers as appropriate. <p>
- *
- * @author John Mani
- * @author Bill Shannon
- * @author Max Spivak
- * @see javax.mail.internet.MimeUtility
- * @see javax.mail.Part
- * @see javax.mail.Message
- * @see javax.mail.internet.MimePart
- */
-
- public class MimeMessage extends Message implements MimePart {
-
- /**
- * The DataHandler object representing this Message's content.
- */
- protected DataHandler dh;
-
- /**
- * Byte array that holds the bytes of this Message's content.
- */
- protected byte[] content;
-
- /**
- * If the data for this message was supplied by an
- * InputStream that implements the SharedInputStream interface,
- * <code>contentStream</code> is another such stream representing
- * the content of this message. In this case, <code>content</code>
- * will be null.
- *
- * @since JavaMail 1.2
- */
- protected InputStream contentStream;
-
- /**
- * The InternetHeaders object that stores the header
- * of this message.
- */
- protected InternetHeaders headers;
-
- /**
- * The Flags for this message.
- */
- protected Flags flags;
-
- /**
- * A flag indicating whether the message has been modified.
- * If the message has not been modified, any data in the
- * <code>content</code> array is assumed to be valid and is used
- * directly in the <code>writeTo</code> method. This flag is
- * set to true when an empty message is created or when the
- * <code>saveChanges</code> method is called.
- *
- * @since JavaMail 1.2
- */
- protected boolean modified = false;
-
- /**
- * Does the <code>saveChanges</code> method need to be called on
- * this message? This flag is set to false by the public constructor
- * and set to true by the <code>saveChanges</code> method. The
- * <code>writeTo</code> method checks this flag and calls the
- * <code>saveChanges</code> method as necessary. This avoids the
- * common mistake of forgetting to call the <code>saveChanges</code>
- * method on a newly constructed message.
- *
- * @since JavaMail 1.2
- */
- protected boolean saved = false;
-
- // Used to parse dates
- private static MailDateFormat mailDateFormat = new MailDateFormat();
-
- /**
- * Default constructor. An empty message object is created.
- * The <code>headers</code> field is set to an empty InternetHeaders
- * object. The <code>flags</code> field is set to an empty Flags
- * object. The <code>modified</code> flag is set to true.
- */
- public MimeMessage(Session session) {
- super(session);
- modified = true;
- headers = new InternetHeaders();
- flags = new Flags(); // empty flags object
- }
-
- /**
- * Constructs a MimeMessage by reading and parsing the data from the
- * specified MIME InputStream. The InputStream will be left positioned
- * at the end of the data for the message. Note that the input stream
- * parse is done within this constructor itself.
- *
- * @param session Session object for this message
- * @param is the message input stream
- * @exception MessagingException
- */
- public MimeMessage(Session session, InputStream is)
- throws MessagingException {
- super(session);
- flags = new Flags(); // empty Flags object
- parse(is);
- saved = true;
- }
-
- /**
- * Constructs a new MimeMessage with content initialized from the
- * <code>source</code> MimeMessage. The new message is independent
- * of the original. <p>
- *
- * Note: The current implementation is rather inefficient, copying
- * the data more times than strictly necessary.
- *
- * @param source the message to copy content from
- * @exception MessagingException
- * @since JavaMail 1.2
- */
- public MimeMessage(MimeMessage source) throws MessagingException {
- super(source.session);
- flags = source.getFlags();
- ByteArrayOutputStream bos;
- int size = source.getSize();
- if (size > 0)
- bos = new ByteArrayOutputStream(size);
- else
- bos = new ByteArrayOutputStream();
- try {
- source.writeTo(bos);
- bos.close();
- SharedByteArrayInputStream bis =
- new SharedByteArrayInputStream(bos.toByteArray());
- parse(bis);
- bis.close();
- saved = true;
- } catch (IOException ex) {
- // should never happen, but just in case...
- throw new MessagingException("IOException while copying message",
- ex);
- }
- }
-
- /**
- * Constructs an empty MimeMessage object with the given Folder
- * and message number. <p>
- *
- * This method is for providers subclassing <code>MimeMessage</code>.
- */
- protected MimeMessage(Folder folder, int msgnum) {
- super(folder, msgnum);
- flags = new Flags(); // empty Flags object
- saved = true;
- }
-
- /**
- * Constructs a MimeMessage by reading and parsing the data from the
- * specified MIME InputStream. The InputStream will be left positioned
- * at the end of the data for the message. Note that the input stream
- * parse is done within this constructor itself. <p>
- *
- * This method is for providers subclassing <code>MimeMessage</code>.
- *
- * @param folder The containing folder.
- * @param is the message input stream
- * @param msgnum Message number of this message within its folder
- * @exception MessagingException
- */
- protected MimeMessage(Folder folder, InputStream is, int msgnum)
- throws MessagingException {
- this(folder, msgnum);
- parse(is);
- }
-
- /**
- * Constructs a MimeMessage from the given InternetHeaders object
- * and content.
- *
- * This method is for providers subclassing <code>MimeMessage</code>.
- *
- * @param folder The containing folder.
- * @param is the message input stream
- * @param msgnum Message number of this message within its folder
- * @exception MessagingException
- */
- protected MimeMessage(Folder folder, InternetHeaders headers,
- byte[] content, int msgnum) throws MessagingException {
- this(folder, msgnum);
- this.headers = headers;
- this.content = content;
- }
-
- /**
- * Parse the InputStream setting the <code>headers</code> and
- * <code>content</code> fields appropriately. Also resets the
- * <code>modified</code> flag. <p>
- *
- * This method is intended for use by subclasses that need to
- * control when the InputStream is parsed.
- *
- * @param is The message input stream
- * @exception MessagingException
- */
- protected void parse(InputStream is) throws MessagingException {
-
- if (!(is instanceof ByteArrayInputStream) &&
- !(is instanceof BufferedInputStream))
- is = new BufferedInputStream(is);
-
- headers = createInternetHeaders(is);
-
- if (is instanceof SharedInputStream) {
- SharedInputStream sis = (SharedInputStream)is;
- contentStream = sis.newStream(sis.getPosition(), -1);
- } else {
- try {
- content = ASCIIUtility.getBytes(is);
- } catch (IOException ioex) {
- throw new MessagingException("IOException", ioex);
- }
- }
-
- modified = false;
- }
-
- /**
- * Returns the value of the RFC 822 "From" header fields. If this
- * header field is absent, the "Sender" header field is used.
- * If the "Sender" header field is also absent, <code>null</code>
- * is returned.<p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return Address object
- * @exception MessagingException
- * @see #headers
- */
- public Address[] getFrom() throws MessagingException {
- Address[] a = getAddressHeader("From");
- if (a == null)
- a = getAddressHeader("Sender");
-
- return a;
- }
-
- /**
- * Set the RFC 822 "From" header field. Any existing values are
- * replaced with the given address. If address is <code>null</code>,
- * this header is removed.
- *
- * @param address the sender 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
- */
- public void setFrom(Address address) throws MessagingException {
- if (address == null)
- removeHeader("From");
- else
- setHeader("From", address.toString());
- }
-
- /**
- * Set the RFC 822 "From" header field using the value of the
- * <code>InternetAddress.getLocalAddress</code> method.
- *
- * @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
- */
- public void setFrom() throws MessagingException {
- InternetAddress me = InternetAddress.getLocalAddress(session);
- if (me != null)
- setFrom(me);
- else
- throw new MessagingException("No From address");
- }
-
- /**
- * Add the specified addresses to the existing "From" field. If
- * the "From" field does not already exist, it is created.
- *
- * @param addresses the senders 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
- */
- public void addFrom(Address[] addresses) throws MessagingException {
- addAddressHeader("From", addresses);
- }
-
- /**
- * This inner class extends the javax.mail.Message.RecipientType
- * class to add additional RecipientTypes. The one additional
- * RecipientType currently defined here is NEWSGROUPS.
- *
- * @see javax.mail.Message.RecipientType
- */
- public static class RecipientType extends Message.RecipientType {
- /**
- * The "Newsgroup" (Usenet news) recipients.
- */
- public static final RecipientType NEWSGROUPS =
- new RecipientType("Newsgroups");
- protected RecipientType(String type) {
- super(type);
- }
-
- protected Object readResolve() throws ObjectStreamException {
- if (type.equals("Newsgroups"))
- return NEWSGROUPS;
- else
- return super.readResolve();
- }
- }
-
- /**
- * Returns the recepients specified by the type. The mapping
- * between the type and the corresponding RFC 822 header is
- * as follows:
- * <pre>
- * Message.RecipientType.TO "To"
- * Message.RecipientType.CC "Cc"
- * Message.RecipientType.BCC "Bcc"
- * MimeMessage.RecipientType.NEWSGROUPS "Newsgroups"
- * </pre><br>
- *
- * Returns null if the header specified by the type is not found
- * or if its value is empty. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @param Type of recepient
- * @return array of Address objects
- * @exception MessagingException if header could not
- * be retrieved
- * @exception AddressException if the header is misformatted
- * @see #headers
- * @see javax.mail.Message.RecipientType#TO
- * @see javax.mail.Message.RecipientType#CC
- * @see javax.mail.Message.RecipientType#BCC
- * @see javax.mail.internet.MimeMessage.RecipientType#NEWSGROUPS
- */
- public Address[] getRecipients(Message.RecipientType type)
- throws MessagingException {
- if (type == RecipientType.NEWSGROUPS) {
- String s = getHeader("Newsgroups", ",");
- return (s == null) ? null : NewsAddress.parse(s);
- } else
- return getAddressHeader(getHeaderName(type));
- }
-
- /**
- * Get all the recipient addresses for the message.
- * Extracts the TO, CC, BCC, and NEWSGROUPS recipients.
- *
- * @return array of Address objects
- * @exception MessagingException
- * @see javax.mail.Message.RecipientType#TO
- * @see javax.mail.Message.RecipientType#CC
- * @see javax.mail.Message.RecipientType#BCC
- * @see javax.mail.internet.MimeMessage.RecipientType#NEWSGROUPS
- */
- public Address[] getAllRecipients() throws MessagingException {
- Address[] all = super.getAllRecipients();
- Address[] ng = getRecipients(RecipientType.NEWSGROUPS);
-
- if (ng == null)
- return all; // the common case
-
- int numRecip =
- (all != null ? all.length : 0) +
- (ng != null ? ng.length : 0);
- Address[] addresses = new Address[numRecip];
- int pos = 0;
- if (all != null) {
- System.arraycopy(all, 0, addresses, pos, all.length);
- pos += all.length;
- }
- if (ng != null) {
- System.arraycopy(ng, 0, addresses, pos, ng.length);
- pos += ng.length;
- }
- return addresses;
- }
-
- /**
- * Set the specified recipient type to the given addresses.
- * If the address parameter is <code>null</code>, the corresponding
- * recipient field is removed.
- *
- * @param type Recipient type
- * @param addresses 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
- * @see #getRecipients
- */
- public void setRecipients(Message.RecipientType type, Address[] addresses)
- throws MessagingException {
- if (type == RecipientType.NEWSGROUPS) {
- if (addresses == null || addresses.length == 0)
- removeHeader("Newsgroups");
- else
- setHeader("Newsgroups", NewsAddress.toString(addresses));
- } else
- setAddressHeader(getHeaderName(type), addresses);
- }
-
- /**
- * Set the specified recipient type to the given addresses.
- * If the address parameter is <code>null</code>, the corresponding
- * recipient field is removed.
- *
- * @param type Recipient type
- * @param addresses Addresses
- * @exception AddressException if the attempt to parse the
- * addresses String fails
- * @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
- * @see #getRecipients
- * @since JavaMail 1.2
- */
- public void setRecipients(Message.RecipientType type, String addresses)
- throws MessagingException {
- if (type == RecipientType.NEWSGROUPS) {
- if (addresses == null || addresses.length() == 0)
- removeHeader("Newsgroups");
- else
- setHeader("Newsgroups", addresses);
- } else
- setAddressHeader(getHeaderName(type), InternetAddress.parse(addresses));
- }
-
- /**
- * Add the given addresses to the specified recipient type.
- *
- * @param type Recipient type
- * @param addresses 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
- */
- public void addRecipients(Message.RecipientType type, Address[] addresses)
- throws MessagingException {
- if (type == RecipientType.NEWSGROUPS) {
- String s = NewsAddress.toString(addresses);
- if (s != null)
- addHeader("Newsgroups", s);
- } else
- addAddressHeader(getHeaderName(type), addresses);
- }
-
- /**
- * Add the given addresses to the specified recipient type.
- *
- * @param type Recipient type
- * @param addresses Addresses
- * @exception AddressException if the attempt to parse the
- * addresses String fails
- * @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
- * @since JavaMail 1.2
- */
- public void addRecipients(Message.RecipientType type, String addresses)
- throws MessagingException {
- if (type == RecipientType.NEWSGROUPS) {
- if (addresses != null && addresses.length() != 0)
- addHeader("Newsgroups", addresses);
- } else
- addAddressHeader(getHeaderName(type), InternetAddress.parse(addresses));
- }
-
- /**
- * Return the value of the RFC 822 "Reply-To" header field. If
- * this header is unavailable or its value is absent, then
- * the <code>getFrom</code> method is called and its value is returned.
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @exception MessagingException
- * @see #headers
- */
- public Address[] getReplyTo() throws MessagingException {
- Address[] a = getAddressHeader("Reply-To");
- if (a == null)
- a = getFrom();
- return a;
- }
-
- /**
- * Set the RFC 822 "Reply-To" header field. If the address
- * parameter is <code>null</code>, this header is removed.
- *
- * @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
- */
- public void setReplyTo(Address[] addresses) throws MessagingException {
- setAddressHeader("Reply-To", addresses);
- }
-
- // Convenience method to get addresses
- private Address[] getAddressHeader(String name)
- throws MessagingException {
- String s = getHeader(name, ",");
- return (s == null) ? null : InternetAddress.parse(s);
- }
-
- // Convenience method to set addresses
- private void setAddressHeader(String name, Address[] addresses)
- throws MessagingException {
- String s = InternetAddress.toString(addresses);
- if (s == null)
- removeHeader(name);
- else
- setHeader(name, s);
- }
-
- private void addAddressHeader(String name, Address[] addresses)
- throws MessagingException {
- String s = InternetAddress.toString(addresses);
- if (s == null)
- return;
- addHeader(name, s);
- }
-
- /**
- * Returns the value of the "Subject" header field. Returns null
- * if the subject field is unavailable or its value is absent. <p>
- *
- * If the subject is encoded as per RFC 2047, it is decoded and
- * converted into Unicode. If the decoding or conversion fails, the
- * raw data is returned as is. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return Subject
- * @exception MessagingException
- * @see #headers
- */
- public String getSubject() throws MessagingException {
- String rawvalue = getHeader("Subject", null);
-
- if (rawvalue == null)
- return null;
-
- try {
- return MimeUtility.decodeText(rawvalue);
- } catch (UnsupportedEncodingException ex) {
- return rawvalue;
- }
- }
-
- /**
- * Set the "Subject" header field. If the subject contains
- * non US-ASCII characters, it will be encoded using the
- * platform's default charset. If the subject contains only
- * US-ASCII characters, no encoding is done and it is used
- * as-is. If the subject is null, the existing "Subject" field
- * is removed. <p>
- *
- * Note that if the charset encoding process fails, a
- * MessagingException is thrown, and an UnsupportedEncodingException
- * is included in the chain of nested exceptions within the
- * MessagingException.
- *
- * @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. An
- * UnsupportedEncodingException may be included
- * in the exception chain if the charset
- * conversion fails.
- */
- public void setSubject(String subject) throws MessagingException {
- setSubject(subject, null);
- }
-
- /**
- * Set the "Subject" header field. If the subject contains non
- * US-ASCII characters, it will be encoded using the specified
- * charset. If the subject contains only US-ASCII characters, no
- * encoding is done and it is used as-is. If the subject is null,
- * the existing "Subject" header field is removed. <p>
- *
- * Note that if the charset encoding process fails, a
- * MessagingException is thrown, and an UnsupportedEncodingException
- * is included in the chain of nested exceptions within the
- * MessagingException.
- *
- * @param subject The subject
- * @param charset The charset
- * @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. An
- * UnsupportedEncodingException may be included
- * in the exception chain if the charset
- * conversion fails.
- */
- public void setSubject(String subject, String charset)
- throws MessagingException {
- if (subject == null)
- removeHeader("Subject");
-
- try {
- setHeader("Subject",
- MimeUtility.encodeText(subject, charset, null));
- } catch (UnsupportedEncodingException uex) {
- throw new MessagingException("Encoding error", uex);
- }
- }
-
- /**
- * Returns the value of the RFC 822 "Date" field. This is the date
- * on which this message was sent. Returns null if this field is
- * unavailable or its value is absent. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return The sent Date
- * @exception MessagingException
- */
- public Date getSentDate() throws MessagingException {
- String s = getHeader("Date", null);
- if (s != null) {
- try {
- synchronized (mailDateFormat) {
- return mailDateFormat.parse(s);
- }
- } catch (ParseException pex) {
- return null;
- }
- }
-
- return null;
- }
-
- /**
- * Set the RFC 822 "Date" header field. This is the date on which the
- * creator of the message indicates that the message is complete
- * and ready for delivery. If the date parameter is
- * <code>null</code>, the existing "Date" field is removed.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void setSentDate(Date d) throws MessagingException {
- if (d == null)
- removeHeader("Date");
- else {
- synchronized (mailDateFormat) {
- setHeader("Date", mailDateFormat.format(d));
- }
- }
- }
-
- /**
- * Returns the Date on this message was received. Returns
- * <code>null</code> if this date cannot be obtained. <p>
- *
- * Note that RFC 822 does not define a field for the received
- * date. Hence only implementations that can provide this date
- * need return a valid value. <p>
- *
- * This implementation returns <code>null</code>.
- *
- * @return the date this message was received
- * @exception MessagingException
- */
- public Date getReceivedDate() throws MessagingException {
- return null;
- }
-
- /**
- * Return the size of the content of this message in bytes.
- * Return -1 if the size cannot be determined. <p>
- *
- * Note that this number may not be an exact measure of the
- * content size and may or may not account for any transfer
- * encoding of the content. <p>
- *
- * This implementation returns the size of the <code>content</code>
- * array (if not null), or, if <code>contentStream</code> is not
- * null, and the <code>available</code> method returns a positive
- * number, it returns that number as the size. Otherwise, it returns
- * -1.
- *
- * @return size of content in bytes
- * @exception MessagingException
- */
- public int getSize() throws MessagingException {
- if (content != null)
- return content.length;
- if (contentStream != null) {
- try {
- int size = contentStream.available();
- // only believe the size if it's greate than zero, since zero
- // is the default returned by the InputStream class itself
- if (size > 0)
- return size;
- } catch (IOException ex) {
- // ignore it
- }
- }
- return -1;
- }
-
- /**
- * Return the number of lines for the content of this message.
- * Return -1 if this number cannot be determined. <p>
- *
- * Note that this number may not be an exact measure of the
- * content length and may or may not account for any transfer
- * encoding of the content. <p>
- *
- * This implementation returns -1.
- *
- * @return number of lines in the content.
- * @exception MessagingException
- */
- public int getLineCount() throws MessagingException {
- return -1;
- }
-
- /**
- * Returns the value of the RFC 822 "Content-Type" header field.
- * This represents the content-type of the content of this
- * message. This value must not be null. If this field is
- * unavailable, "text/plain" should be returned. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return The ContentType of this part
- * @exception MessagingException
- * @see javax.activation.DataHandler
- */
- public String getContentType() throws MessagingException {
- String s = getHeader("Content-Type", null);
- if (s == null)
- return "text/plain";
- return s;
- }
-
- /**
- * Is this Part of the specified MIME type? This method
- * compares <strong>only the <code>primaryType</code> and
- * <code>subType</code></strong>.
- * The parameters of the content types are ignored. <p>
- *
- * For example, this method will return <code>true</code> when
- * comparing a Part of content type <strong>"text/plain"</strong>
- * with <strong>"text/plain; charset=foobar"</strong>. <p>
- *
- * If the <code>subType</code> of <code>mimeType</code> is the
- * special character '*', then the subtype is ignored during the
- * comparison.
- */
- public boolean isMimeType(String mimeType) throws MessagingException {
- return MimeBodyPart.isMimeType(this, mimeType);
- }
-
- /**
- * Returns the value of the "Content-Disposition" header field.
- * This represents the disposition of this part. The disposition
- * describes how the part should be presented to the user. <p>
- *
- * If the Content-Disposition field is unavailable,
- * <code>null</code> is returned. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return disposition of this part, or null if unknown
- * @exception MessagingException
- */
- public String getDisposition() throws MessagingException {
- return MimeBodyPart.getDisposition(this);
- }
-
- /**
- * Set the "Content-Disposition" header field of this Message.
- * If <code>disposition</code> is null, any existing "Content-Disposition"
- * header field is removed.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void setDisposition(String disposition) throws MessagingException {
- MimeBodyPart.setDisposition(this, disposition);
- }
-
- /**
- * Returns the content transfer encoding from the
- * "Content-Transfer-Encoding" header
- * field. Returns <code>null</code> if the header is unavailable
- * or its value is absent. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return content-transfer-encoding
- * @exception MessagingException
- */
- public String getEncoding() throws MessagingException {
- return MimeBodyPart.getEncoding(this);
- }
-
- /**
- * Returns the value of the "Content-ID" header field. Returns
- * <code>null</code> if the field is unavailable or its value is
- * absent. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return content-ID
- * @exception MessagingException
- */
- public String getContentID() throws MessagingException {
- return getHeader("Content-Id", null);
- }
-
- /**
- * Set the "Content-ID" header field of this Message.
- * If the <code>cid</code> parameter is null, any existing
- * "Content-ID" is removed.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void setContentID(String cid) throws MessagingException {
- if (cid == null)
- removeHeader("Content-ID");
- else
- setHeader("Content-ID", cid);
- }
-
- /**
- * Return the value of the "Content-MD5" header field. Returns
- * <code>null</code> if this field is unavailable or its value
- * is absent. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return content-MD5
- * @exception MessagingException
- */
- public String getContentMD5() throws MessagingException {
- return getHeader("Content-MD5", null);
- }
-
- /**
- * Set the "Content-MD5" header field of this Message.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void setContentMD5(String md5) throws MessagingException {
- setHeader("Content-MD5", md5);
- }
-
- /**
- * Returns the "Content-Description" header field of this Message.
- * This typically associates some descriptive information with
- * this part. Returns null if this field is unavailable or its
- * value is absent. <p>
- *
- * If the Content-Description field is encoded as per RFC 2047,
- * it is decoded and converted into Unicode. If the decoding or
- * conversion fails, the raw data is returned as-is <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return content-description
- * @exception MessagingException
- */
- public String getDescription() throws MessagingException {
- return MimeBodyPart.getDescription(this);
- }
-
- /**
- * Set the "Content-Description" header field for this Message.
- * If the description parameter is <code>null</code>, then any
- * existing "Content-Description" fields are removed. <p>
- *
- * If the description contains non US-ASCII characters, it will
- * be encoded using the platform's default charset. If the
- * description contains only US-ASCII characters, no encoding
- * is done and it is used as-is. <p>
- *
- * Note that if the charset encoding process fails, a
- * MessagingException is thrown, and an UnsupportedEncodingException
- * is included in the chain of nested exceptions within the
- * MessagingException.
- *
- * @param description content-description
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException. An
- * UnsupportedEncodingException may be included
- * in the exception chain if the charset
- * conversion fails.
- */
- public void setDescription(String description) throws MessagingException {
- setDescription(description, null);
- }
-
- /**
- * Set the "Content-Description" header field for this Message.
- * If the description parameter is <code>null</code>, then any
- * existing "Content-Description" fields are removed. <p>
- *
- * If the description contains non US-ASCII characters, it will
- * be encoded using the specified charset. If the description
- * contains only US-ASCII characters, no encoding is done and
- * it is used as-is. <p>
- *
- * Note that if the charset encoding process fails, a
- * MessagingException is thrown, and an UnsupportedEncodingException
- * is included in the chain of nested exceptions within the
- * MessagingException.
- *
- * @param description Description
- * @param charset Charset for encoding
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException. An
- * UnsupportedEncodingException may be included
- * in the exception chain if the charset
- * conversion fails.
- */
- public void setDescription(String description, String charset)
- throws MessagingException {
- MimeBodyPart.setDescription(this, description, charset);
- }
-
- /**
- * Get the languages specified in the "Content-Language" header
- * field of this message. The Content-Language header is defined by
- * RFC 1766. Returns <code>null</code> if this field is unavailable
- * or its value is absent. <p>
- *
- * This implementation uses the <code>getHeader</code> method
- * to obtain the requisite header field.
- *
- * @return value of content-language header.
- * @exception MessagingException
- */
- public String[] getContentLanguage() throws MessagingException {
- return MimeBodyPart.getContentLanguage(this);
- }
-
- /**
- * Set the "Content-Language" header of this MimePart. The
- * Content-Language header is defined by RFC 1766.
- *
- * @param languages array of language tags
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void setContentLanguage(String[] languages)
- throws MessagingException {
- MimeBodyPart.setContentLanguage(this, languages);
- }
-
- /**
- * Returns the value of the "Message-ID" header field. Returns
- * null if this field is unavailable or its value is absent. <p>
- *
- * The default implementation provided here uses the
- * <code>getHeader</code> method to return the value of the
- * "Message-ID" field.
- *
- * @return Message-ID
- * @exception MessagingException if the retrieval of this field
- * causes any exception.
- * @see javax.mail.search.MessageIDTerm
- * @since JavaMail 1.1
- */
- public String getMessageID() throws MessagingException {
- return getHeader("Message-ID", null);
- }
-
- /**
- * Get the filename associated with this Message. <p>
- *
- * Returns the value of the "filename" parameter from the
- * "Content-Disposition" header field of this message. If it's
- * not available, returns the value of the "name" parameter from
- * the "Content-Type" header field of this BodyPart.
- * Returns <code>null</code> if both are absent.
- *
- * @return filename
- * @exception MessagingException
- */
- public String getFileName() throws MessagingException {
- return MimeBodyPart.getFileName(this);
- }
-
- /**
- * Set the filename associated with this part, if possible. <p>
- *
- * Sets the "filename" parameter of the "Content-Disposition"
- * header field of this message.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void setFileName(String filename) throws MessagingException {
- MimeBodyPart.setFileName(this, filename);
- }
-
- private String getHeaderName(Message.RecipientType type)
- throws MessagingException {
- String headerName;
-
- if (type == Message.RecipientType.TO)
- headerName = "To";
- else if (type == Message.RecipientType.CC)
- headerName = "Cc";
- else if (type == Message.RecipientType.BCC)
- headerName = "Bcc";
- else if (type == MimeMessage.RecipientType.NEWSGROUPS)
- headerName = "Newsgroups";
- else
- throw new MessagingException("Invalid Recipient Type");
- return headerName;
- }
-
-
- /**
- * Return a decoded input stream for this Message's "content". <p>
- *
- * This implementation obtains the input stream from the DataHandler,
- * that is, it invokes <code>getDataHandler().getInputStream()</code>.
- *
- * @return an InputStream
- * @exception MessagingException
- * @exception IOException this is typically thrown by the
- * DataHandler. Refer to the documentation for
- * javax.activation.DataHandler for more details.
- *
- * @see #getContentStream
- * @see javax.activation.DataHandler#getInputStream
- */
- public InputStream getInputStream()
- throws IOException, MessagingException {
- return getDataHandler().getInputStream();
- }
-
- /**
- * Produce the raw bytes of the content. This method is used during
- * parsing, to create a DataHandler object for the content. Subclasses
- * that can provide a separate input stream for just the message
- * content might want to override this method. <p>
- *
- * This implementation just returns a ByteArrayInputStream constructed
- * out of the <code>content</code> byte array.
- *
- * @see #content
- */
- protected InputStream getContentStream() throws MessagingException {
- if (contentStream != null)
- return ((SharedInputStream)contentStream).newStream(0, -1);
- if (content != null)
- return new SharedByteArrayInputStream(content);
-
- throw new MessagingException("No content");
- }
-
- /**
- * Return an InputStream to the raw data with any Content-Transfer-Encoding
- * intact. This method is useful if the "Content-Transfer-Encoding"
- * header is incorrect or corrupt, which would prevent the
- * <code>getInputStream</code> method or <code>getContent</code> method
- * from returning the correct data. In such a case the application may
- * use this method and attempt to decode the raw data itself. <p>
- *
- * This implementation simply calls the <code>getContentStream</code>
- * method.
- *
- * @see #getInputStream
- * @see #getContentStream
- * @since JavaMail 1.2
- */
- public InputStream getRawInputStream() throws MessagingException {
- return getContentStream();
- }
-
- /**
- * Return a DataHandler for this Message's content. <p>
- *
- * The implementation provided here works as follows. Note the use of
- * the <code>getContentStream</code> method to
- * generate the byte stream for the content. Also note that
- * any transfer-decoding is done automatically within this method.<p>
- *
- * <blockquote><pre>
- * getDataHandler() {
- * if (dh == null) {
- * dh = new DataHandler(new MimePartDataSource(this));
- * }
- * return dh;
- * }
- * <p>
- * class MimePartDataSource implements DataSource {
- * public getInputStream() {
- * return MimeUtility.decode(
- * getContentStream(), getEncoding());
- * }
- *
- * .... <other DataSource methods>
- * }
- * </pre></blockquote><p>
- *
- * @exception MessagingException
- */
- public synchronized DataHandler getDataHandler()
- throws MessagingException {
- if (dh == null)
- dh = new DataHandler(new MimePartDataSource(this));
- return dh;
- }
-
- /**
- * Return the content as a Java object. The type of this
- * object is dependent on the content itself. For
- * example, the native format of a "text/plain" content
- * is usually a String object. The native format for a "multipart"
- * message is always a Multipart subclass. For content types that are
- * unknown to the DataHandler system, an input stream is returned
- * as the content. <p>
- *
- * This implementation obtains the content from the DataHandler,
- * that is, it invokes <code>getDataHandler().getContent()</code>.
- *
- * @return Object
- * @see javax.mail.Part
- * @see javax.activation.DataHandler#getContent
- * @exception MessagingException
- * @exception IOException this is typically thrown by the
- * DataHandler. Refer to the documentation for
- * javax.activation.DataHandler for more details.
- */
- public Object getContent() throws IOException, MessagingException {
- return getDataHandler().getContent();
- }
-
- /**
- * This method provides the mechanism to set this part's content.
- * The given DataHandler object should wrap the actual content.
- *
- * @param dh The DataHandler for the content.
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void setDataHandler(DataHandler dh)
- throws MessagingException {
- this.dh = dh;
- MimeBodyPart.invalidateContentHeaders(this);
- }
-
- /**
- * A convenience method for setting this Message's content. <p>
- *
- * The content is wrapped in a DataHandler object. Note that a
- * DataContentHandler class for the specified type should be
- * available to the JavaMail implementation for this to work right.
- * i.e., to do <code>setContent(foobar, "application/x-foobar")</code>,
- * a DataContentHandler for "application/x-foobar" should be installed.
- * Refer to the Java Activation Framework for more information.
- *
- * @param o the content object
- * @param type Mime type of the object
- * @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
- */
- public void setContent(Object o, String type)
- throws MessagingException {
- setDataHandler(new DataHandler(o, type));
- }
-
- /**
- * Convenience method that sets the given String as this
- * part's content, with a MIME type of "text/plain". If the
- * string contains non US-ASCII characters. it will be encoded
- * using the platform's default charset. The charset is also
- * used to set the "charset" parameter.<p>
- *
- * Note that there may be a performance penalty if
- * <code>text</code> is large, since this method may have
- * to scan all the characters to determine what charset to
- * use. <p>
- *
- * If the charset is already known, use the
- * <code>setText</code> method that takes the charset parameter.
- *
- * @see #setText(String text, String charset)
- */
- public void setText(String text) throws MessagingException {
- setText(text, null);
- }
-
- /**
- * Convenience method that sets the given String as this part's
- * content, with a MIME type of "text/plain" and the specified
- * charset. The given Unicode string will be charset-encoded
- * using the specified charset. The charset is also used to set
- * the "charset" parameter.
- */
- public void setText(String text, String charset)
- throws MessagingException {
- MimeBodyPart.setText(this, text, charset);
- }
-
- /**
- * This method sets the Message's content to a Multipart object.
- *
- * @param mp The multipart object that is the Message's content
- * @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
- */
- public void setContent(Multipart mp) throws MessagingException {
- setDataHandler(new DataHandler(mp, mp.getContentType()));
- mp.setParent(this);
- }
-
- /**
- * 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, i.e., 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:").
- * The "In-Reply-To" header is set in the new message if this
- * message has a "Message-Id" header. The <code>ANSWERED</code>
- * flag is set in this message.
- *
- * @param replyToAll reply should be sent to all recipients
- * of this message
- * @return the reply Message
- * @exception MessagingException
- */
- public Message reply(boolean replyToAll) throws MessagingException {
- MimeMessage reply = new MimeMessage(session);
- /*
- * Have to manipulate the raw Subject header so that we don't lose
- * any encoding information. This is safe because "Re:" isn't
- * internationalized and (generally) isn't encoded. If the entire
- * Subject header is encoded, prefixing it with "Re: " still leaves
- * a valid and correct encoded header.
- */
- String subject = getHeader("Subject", null);
- if (subject != null) {
- if (!subject.regionMatches(true, 0, "Re: ", 0, 4))
- subject = "Re: " + subject;
- reply.setHeader("Subject", subject);
- }
- Address a[] = getReplyTo();
- reply.setRecipients(Message.RecipientType.TO, a);
- if (replyToAll) {
- Vector v = new Vector();
- // add my own address to list
- InternetAddress me = InternetAddress.getLocalAddress(session);
- if (me != null)
- v.addElement(me);
- // add any alternate names I'm known by
- String alternates = session.getProperty("mail.alternates");
- if (alternates != null)
- eliminateDuplicates(v,
- InternetAddress.parse(alternates, false));
- // should we Cc all other original recipients?
- String replyallccStr = session.getProperty("mail.replyallcc");
- boolean replyallcc =
- replyallccStr != null && replyallccStr.equalsIgnoreCase("true");
- // add the recipients from the To field so far
- eliminateDuplicates(v, a);
- a = getRecipients(Message.RecipientType.TO);
- a = eliminateDuplicates(v, a);
- if (a != null && a.length > 0) {
- if (replyallcc)
- reply.addRecipients(Message.RecipientType.CC, a);
- else
- reply.addRecipients(Message.RecipientType.TO, a);
- }
- a = getRecipients(Message.RecipientType.CC);
- a = eliminateDuplicates(v, a);
- if (a != null && a.length > 0)
- reply.addRecipients(Message.RecipientType.CC, a);
- // don't eliminate duplicate newsgroups
- a = getRecipients(RecipientType.NEWSGROUPS);
- if (a != null && a.length > 0)
- reply.setRecipients(RecipientType.NEWSGROUPS, a);
- }
- String msgId = getHeader("Message-Id", null);
- if (msgId != null)
- reply.setHeader("In-Reply-To", msgId);
- try {
- setFlags(answeredFlag, true);
- } catch (MessagingException mex) {
- // ignore it
- }
- return reply;
- }
-
- // used above in reply()
- private static final Flags answeredFlag = new Flags(Flags.Flag.ANSWERED);
-
- /**
- * Check addrs for any duplicates that may already be in v.
- * Return a new array without the duplicates. Add any new
- * addresses to v. Note that the input array may be modified.
- */
- private Address[] eliminateDuplicates(Vector v, Address[] addrs) {
- if (addrs == null)
- return null;
- int gone = 0;
- for (int i = 0; i < addrs.length; i++) {
- boolean found = false;
- // search the vector for this address
- for (int j = 0; j < v.size(); j++) {
- if (((InternetAddress)v.elementAt(j)).equals(addrs[i])) {
- // found it; count it and remove it from the input array
- found = true;
- gone++;
- addrs[i] = null;
- break;
- }
- }
- if (!found)
- v.addElement(addrs[i]); // add new address to vector
- }
- // if we found any duplicates, squish the array
- if (gone != 0) {
- Address[] a;
- // new array should be same type as original array
- // XXX - there must be a better way, perhaps reflection?
- if (addrs instanceof InternetAddress[])
- a = new InternetAddress[addrs.length - gone];
- else
- a = new Address[addrs.length - gone];
- for (int i = 0, j = 0; i < addrs.length; i++)
- if (addrs[i] != null)
- a[j++] = addrs[i];
- addrs = a;
- }
- return addrs;
- }
-
- /**
- * Output the message as an RFC 822 format stream. <p>
- *
- * Note that, depending on how the messag was constructed, it may
- * use a variety of line termination conventions. Generally the
- * output should be sent through an appropriate FilterOutputStream
- * that converts the line terminators to the desired form, either
- * CRLF for MIME compatibility and for use in Internet protocols,
- * or the local platform's line terminator for storage in a local
- * text file. <p>
- *
- * This implementation calls the <code>writeTo(OutputStream,
- * String[])</code> method with a null ignore list.
- *
- * @exception IOException if an error occurs writing to the stream
- * or if an error is generated by the
- * javax.activation layer.
- * @exception MessagingException
- * @see javax.activation.DataHandler#writeTo
- */
- public void writeTo(OutputStream os)
- throws IOException, MessagingException {
- writeTo(os, null);
- }
-
- /**
- * Output the message as an RFC 822 format stream, without
- * specified headers. If the <code>saved</code> flag is not set,
- * the <code>saveChanges</code> method is called.
- * If the <code>modified</code> flag is not
- * set and the <code>content</code> array is not null, the
- * <code>content</code> array is written directly, after
- * writing the appropriate message headers.
- *
- * @exception javax.mail.MessagingException
- * @exception IOException if an error occurs writing to the stream
- * or if an error is generated by the
- * javax.activation layer.
- * @see javax.activation.DataHandler#writeTo
- */
- public void writeTo(OutputStream os, String[] ignoreList)
- throws IOException, MessagingException {
- if (!saved)
- saveChanges();
-
- if (modified || (content == null && contentStream == null)) {
- MimeBodyPart.writeTo(this, os, ignoreList);
- return;
- }
-
- // Else, the content is untouched, so we can just output it
- // First, write out the header
- Enumeration hdrLines = getNonMatchingHeaderLines(ignoreList);
- LineOutputStream los = new LineOutputStream(os);
- while (hdrLines.hasMoreElements())
- los.writeln((String)hdrLines.nextElement());
-
- // The CRLF separator between header and content
- los.writeln();
-
- // Finally, the content.
- if (contentStream != null) {
- // copy the data to the output stream
- InputStream is =
- ((SharedInputStream)contentStream).newStream(0, -1);
- byte[] buf = new byte[8192];
- int len;
- while ((len = is.read(buf)) > 0)
- os.write(buf, 0, len);
- is.close();
- buf = null;
- } else {
- os.write(content);
- }
- os.flush();
- }
-
- /**
- * Get all the headers for this header_name. Note that certain
- * headers may be encoded as per RFC 2047 if they contain
- * non US-ASCII characters and these should be decoded. <p>
- *
- * This implementation obtains the headers from the
- * <code>headers</code> InternetHeaders object.
- *
- * @param name name of header
- * @return array of headers
- * @exception MessagingException
- * @see javax.mail.internet.MimeUtility
- */
- public String[] getHeader(String name)
- throws MessagingException {
- return headers.getHeader(name);
- }
-
- /**
- * Get all the headers for this header name, returned as a single
- * String, with headers separated by the delimiter. If the
- * delimiter is <code>null</code>, only the first header is
- * returned.
- *
- * @param header_name the name of this header
- * @return the value fields for all headers with
- * this name
- * @exception MessagingException
- */
- public String getHeader(String name, String delimiter)
- throws MessagingException {
- return headers.getHeader(name, delimiter);
- }
-
- /**
- * Set the value for this header_name. Replaces all existing
- * header values with this new value. Note that RFC 822 headers
- * must contain only US-ASCII characters, so a header that
- * contains non US-ASCII characters must have been encoded by the
- * caller as per the rules of RFC 2047.
- *
- * @param name header name
- * @param value header value
- * @see javax.mail.internet.MimeUtility
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void setHeader(String name, String value)
- throws MessagingException {
- headers.setHeader(name, value);
- }
-
- /**
- * Add this value to the existing values for this header_name.
- * Note that RFC 822 headers must contain only US-ASCII
- * characters, so a header that contains non US-ASCII characters
- * must have been encoded as per the rules of RFC 2047.
- *
- * @param name header name
- * @param value header value
- * @see javax.mail.internet.MimeUtility
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void addHeader(String name, String value)
- throws MessagingException {
- headers.addHeader(name, value);
- }
-
- /**
- * Remove all headers with this name.
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void removeHeader(String name)
- throws MessagingException {
- headers.removeHeader(name);
- }
-
- /**
- * Return all the headers from this Message as an enumeration
- * of Header objects. <p>
- *
- * Note that certain headers may be encoded as per RFC 2047
- * if they contain non US-ASCII characters and these should
- * be decoded. <p>
- *
- * This implementation obtains the headers from the
- * <code>headers</code> InternetHeaders object.
- *
- * @return array of header objects
- * @exception MessagingException
- * @see javax.mail.internet.MimeUtility
- */
- public Enumeration getAllHeaders() throws MessagingException {
- return headers.getAllHeaders();
- }
-
- /**
- * Return matching headers from this Message as an Enumeration of
- * Header objects. This implementation obtains the headers from
- * the <code>headers</code> InternetHeaders object.
- *
- * @exception MessagingException
- */
- public Enumeration getMatchingHeaders(String[] names)
- throws MessagingException {
- return headers.getMatchingHeaders(names);
- }
-
- /**
- * Return non-matching headers from this Message as an
- * Enumeration of Header objects. This implementation
- * obtains the header from the <code>headers</code> InternetHeaders object.
- *
- * @exception MessagingException
- */
- public Enumeration getNonMatchingHeaders(String[] names)
- throws MessagingException {
- return headers.getNonMatchingHeaders(names);
- }
-
- /**
- * Add a raw RFC 822 header-line.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void addHeaderLine(String line) throws MessagingException {
- headers.addHeaderLine(line);
- }
-
- /**
- * Get all header lines as an Enumeration of Strings. A Header
- * line is a raw RFC 822 header-line, containing both the "name"
- * and "value" field.
- *
- * @exception MessagingException
- */
- public Enumeration getAllHeaderLines() throws MessagingException {
- return headers.getAllHeaderLines();
- }
-
- /**
- * Get matching header lines as an Enumeration of Strings.
- * A Header line is a raw RFC 822 header-line, containing both
- * the "name" and "value" field.
- *
- * @exception MessagingException
- */
- public Enumeration getMatchingHeaderLines(String[] names)
- throws MessagingException {
- return headers.getMatchingHeaderLines(names);
- }
-
- /**
- * Get non-matching header lines as an Enumeration of Strings.
- * A Header line is a raw RFC 822 header-line, containing both
- * the "name" and "value" field.
- *
- * @exception MessagingException
- */
- public Enumeration getNonMatchingHeaderLines(String[] names)
- throws MessagingException {
- return headers.getNonMatchingHeaderLines(names);
- }
-
- /**
- * Return a <code>Flags</code> object containing the flags for
- * this message. <p>
- *
- * Note that a clone of the internal Flags object is returned, so
- * modifying the returned Flags object will not affect the flags
- * of this message.
- *
- * @return Flags object containing the flags for this message
- * @exception MessagingException
- * @see javax.mail.Flags
- */
- public synchronized Flags getFlags() throws MessagingException {
- return (Flags)flags.clone();
- }
-
- /**
- * Check whether the flag specified in the <code>flag</code>
- * argument is set in this message. <p>
- *
- * This implementation checks this message's internal
- * <code>flags</code> object.
- *
- * @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
- */
- public synchronized boolean isSet(Flags.Flag flag)
- throws MessagingException {
- return (flags.contains(flag));
- }
-
- /**
- * Set the flags for this message. <p>
- *
- * This implementation modifies the <code>flags</code> field.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public synchronized void setFlags(Flags flag, boolean set)
- throws MessagingException {
- if (set)
- flags.add(flag);
- else
- flags.remove(flag);
- }
-
- /**
- * Updates the appropriate header fields of this message to be
- * consistent with the message's contents. If this message is
- * contained in a Folder, any changes made to this message are
- * committed to the containing folder. <p>
- *
- * If any part of a message's headers or contents are changed,
- * <code>saveChanges</code> must be called to ensure that those
- * changes are permanent. Otherwise, any such modifications may or
- * may not be saved, depending on the folder implementation. <p>
- *
- * Messages obtained from folders opened READ_ONLY should not be
- * modified and saveChanges should not be called on such messages. <p>
- *
- * This method sets the <code>modified</code> flag to true, the
- * <code>save</code> flag to true, and then calls the
- * <code>updateHeaders<code> method.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- public void saveChanges() throws MessagingException {
- modified = true;
- saved = true;
- updateHeaders();
- }
-
- /**
- * Called by the <code>saveChanges</code> method to actually
- * update the MIME headers. The implementation here sets the
- * <code>Content-Transfer-Encoding</code> header (if needed
- * and not already set), the <code>Mime-Version</code> header
- * and the <code>Message-ID</code> header. Also, if the content
- * of this message is a <code>MimeMultipart</code>, it's
- * <code>updateHeaders</code> method is called.
- *
- * @exception IllegalWriteException if the underlying
- * implementation does not support modification
- * @exception IllegalStateException if this message is
- * obtained from a READ_ONLY folder.
- * @exception MessagingException
- */
- protected void updateHeaders() throws MessagingException {
- MimeBodyPart.updateHeaders(this);
- setHeader("Mime-Version", "1.0");
- setHeader("Message-ID",
- "<" + UniqueValue.getUniqueMessageIDValue(session) + ">");
- }
-
- /**
- * Create and return an InternetHeaders object that loads the
- * headers from the given InputStream. Subclasses can override
- * this method to return a subclass of InternetHeaders, if
- * necessary. This implementation simply constructs and returns
- * an InternetHeaders object.
- *
- * @param is the InputStream to read the headers from
- * @exception MessagingException
- * @since JavaMail 1.2
- */
- protected InternetHeaders createInternetHeaders(InputStream is)
- throws MessagingException {
- return new InternetHeaders(is);
- }
- }