Save This Page
Home » glassfish-v2ur2-b04-src » javax » mail » internet » [javadoc | source]
    1   /*
    2    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    3    *
    4    * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
    5    *
    6    * The contents of this file are subject to the terms of either the GNU
    7    * General Public License Version 2 only ("GPL") or the Common Development
    8    * and Distribution License("CDDL") (collectively, the "License").  You
    9    * may not use this file except in compliance with the License. You can obtain
   10    * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
   11    * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
   12    * language governing permissions and limitations under the License.
   13    *
   14    * When distributing the software, include this License Header Notice in each
   15    * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
   16    * Sun designates this particular file as subject to the "Classpath" exception
   17    * as provided by Sun in the GPL Version 2 section of the License file that
   18    * accompanied this code.  If applicable, add the following below the License
   19    * Header, with the fields enclosed by brackets [] replaced by your own
   20    * identifying information: "Portions Copyrighted [year]
   21    * [name of copyright owner]"
   22    *
   23    * Contributor(s):
   24    *
   25    * If you wish your version of this file to be governed by only the CDDL or
   26    * only the GPL Version 2, indicate your decision by adding "[Contributor]
   27    * elects to include this software in this distribution under the [CDDL or GPL
   28    * Version 2] license."  If you don't indicate a single choice of license, a
   29    * recipient has the option to distribute your version of this file under
   30    * either the CDDL, the GPL Version 2 or to extend the choice of license to
   31    * its licensees as provided above.  However, if you add GPL Version 2 code
   32    * and therefore, elected the GPL Version 2 license, then the option applies
   33    * only if the new code is made subject to such option by the copyright
   34    * holder.
   35    */
   36   
   37   /*
   38    * @(#)MimeMessage.java	1.95 07/05/14
   39    */
   40   
   41   package javax.mail.internet;
   42   
   43   import javax.mail;
   44   import javax.activation;
   45   import java.lang;
   46   import java.io;
   47   import java.util;
   48   import java.text.ParseException;
   49   import com.sun.mail.util;
   50   import javax.mail.util.SharedByteArrayInputStream;
   51   
   52   /**
   53    * This class represents a MIME style email message. It implements
   54    * the <code>Message</code> abstract class and the <code>MimePart</code>
   55    * interface. <p>
   56    *
   57    * Clients wanting to create new MIME style messages will instantiate
   58    * an empty MimeMessage object and then fill it with appropriate 
   59    * attributes and content. <p>
   60    * 
   61    * Service providers that implement MIME compliant backend stores may
   62    * want to subclass MimeMessage and override certain methods to provide
   63    * specific implementations. The simplest case is probably a provider
   64    * that generates a MIME style input stream and leaves the parsing of
   65    * the stream to this class. <p>
   66    *
   67    * MimeMessage uses the <code>InternetHeaders</code> class to parse and
   68    * store the top level RFC 822 headers of a message. <p>
   69    *
   70    * The <code>mail.mime.address.strict</code> session property controls
   71    * the parsing of address headers.  By default, strict parsing of address
   72    * headers is done.  If this property is set to <code>"false"</code>,
   73    * strict parsing is not done and many illegal addresses that sometimes
   74    * occur in real messages are allowed.  See the <code>InternetAddress</code>
   75    * class for details. <p>
   76    *
   77    * <hr><strong>A note on RFC 822 and MIME headers</strong><p>
   78    *
   79    * RFC 822 header fields <strong>must</strong> contain only 
   80    * US-ASCII characters. MIME allows non ASCII characters to be present
   81    * in certain portions of certain headers, by encoding those characters.
   82    * RFC 2047 specifies the rules for doing this. The MimeUtility
   83    * class provided in this package can be used to to achieve this.
   84    * Callers of the <code>setHeader</code>, <code>addHeader</code>, and
   85    * <code>addHeaderLine</code> methods are responsible for enforcing
   86    * the MIME requirements for the specified headers.  In addition, these
   87    * header fields must be folded (wrapped) before being sent if they
   88    * exceed the line length limitation for the transport (1000 bytes for
   89    * SMTP).  Received headers may have been folded.  The application is
   90    * responsible for folding and unfolding headers as appropriate. <p>
   91    *
   92    * @author John Mani
   93    * @author Bill Shannon
   94    * @author Max Spivak
   95    * @author Kanwar Oberoi
   96    * @see	javax.mail.internet.MimeUtility
   97    * @see	javax.mail.Part
   98    * @see	javax.mail.Message
   99    * @see	javax.mail.internet.MimePart
  100    * @see	javax.mail.internet.InternetAddress
  101    */
  102   
  103   public class MimeMessage extends Message implements MimePart {
  104   
  105       /**
  106        * The DataHandler object representing this Message's content.
  107        */
  108       protected DataHandler dh;
  109   
  110       /**
  111        * Byte array that holds the bytes of this Message's content.
  112        */
  113       protected byte[] content;
  114   
  115       /**
  116        * If the data for this message was supplied by an
  117        * InputStream that implements the SharedInputStream interface,
  118        * <code>contentStream</code> is another such stream representing
  119        * the content of this message.  In this case, <code>content</code>
  120        * will be null.
  121        *
  122        * @since	JavaMail 1.2
  123        */
  124       protected InputStream contentStream;
  125   
  126       /**
  127        * The InternetHeaders object that stores the header
  128        * of this message.
  129        */
  130       protected InternetHeaders headers;
  131   
  132       /**
  133        * The Flags for this message. 
  134        */
  135       protected Flags flags;
  136   
  137       /**
  138        * A flag indicating whether the message has been modified.
  139        * If the message has not been modified, any data in the
  140        * <code>content</code> array is assumed to be valid and is used
  141        * directly in the <code>writeTo</code> method.  This flag is
  142        * set to true when an empty message is created or when the
  143        * <code>saveChanges</code> method is called.
  144        *
  145        * @since	JavaMail 1.2
  146        */
  147       protected boolean modified = false;
  148   
  149       /**
  150        * Does the <code>saveChanges</code> method need to be called on
  151        * this message?  This flag is set to false by the public constructor
  152        * and set to true by the <code>saveChanges</code> method.  The
  153        * <code>writeTo</code> method checks this flag and calls the
  154        * <code>saveChanges</code> method as necessary.  This avoids the
  155        * common mistake of forgetting to call the <code>saveChanges</code>
  156        * method on a newly constructed message.
  157        *
  158        * @since	JavaMail 1.2
  159        */
  160       protected boolean saved = false;
  161   
  162       /**
  163        * If our content is a Multipart of Message object, we save it
  164        * the first time it's created by parsing a stream so that changes
  165        * to the contained objects will not be lost.
  166        *
  167        * XXX - must have package access for MimeBodyPart.updateHeaders
  168        */
  169       Object cachedContent;
  170   
  171       // Used to parse dates
  172       private static MailDateFormat mailDateFormat = new MailDateFormat();
  173   
  174       // Should addresses in headers be parsed in "strict" mode?
  175       private boolean strict = true;
  176   
  177       /**
  178        * Default constructor. An empty message object is created.
  179        * The <code>headers</code> field is set to an empty InternetHeaders
  180        * object. The <code>flags</code> field is set to an empty Flags
  181        * object. The <code>modified</code> flag is set to true.
  182        */
  183       public MimeMessage(Session session) {
  184   	super(session);
  185   	modified = true;
  186   	headers = new InternetHeaders();
  187   	flags = new Flags();	// empty flags object
  188   	initStrict();
  189       }
  190   
  191       /**
  192        * Constructs a MimeMessage by reading and parsing the data from the
  193        * specified MIME InputStream. The InputStream will be left positioned
  194        * at the end of the data for the message. Note that the input stream
  195        * parse is done within this constructor itself. <p>
  196        *
  197        * The input stream contains an entire MIME formatted message with
  198        * headers and data.
  199        *
  200        * @param session	Session object for this message
  201        * @param is	the message input stream
  202        * @exception	MessagingException
  203        */
  204       public MimeMessage(Session session, InputStream is) 
  205   			throws MessagingException {
  206   	super(session);
  207   	flags = new Flags(); // empty Flags object
  208   	initStrict();
  209   	parse(is);
  210   	saved = true;
  211       }
  212   
  213       /**
  214        * Constructs a new MimeMessage with content initialized from the
  215        * <code>source</code> MimeMessage.  The new message is independent
  216        * of the original. <p>
  217        *
  218        * Note: The current implementation is rather inefficient, copying
  219        * the data more times than strictly necessary.
  220        *
  221        * @param	source	the message to copy content from
  222        * @exception	MessagingException
  223        * @since		JavaMail 1.2
  224        */
  225       public MimeMessage(MimeMessage source) throws MessagingException {
  226   	super(source.session);
  227   	flags = source.getFlags();
  228   	ByteArrayOutputStream bos;
  229   	int size = source.getSize();
  230   	if (size > 0)
  231   	    bos = new ByteArrayOutputStream(size);
  232   	else
  233   	    bos = new ByteArrayOutputStream();
  234   	try {
  235   	    strict = source.strict;
  236   	    source.writeTo(bos);
  237   	    bos.close();
  238   	    SharedByteArrayInputStream bis =
  239   			    new SharedByteArrayInputStream(bos.toByteArray());
  240   	    parse(bis);
  241   	    bis.close();
  242   	    saved = true;
  243   	} catch (IOException ex) {
  244   	    // should never happen, but just in case...
  245   	    throw new MessagingException("IOException while copying message",
  246   					    ex);
  247   	}
  248       }
  249   
  250       /**
  251        * Constructs an empty MimeMessage object with the given Folder
  252        * and message number. <p>
  253        *
  254        * This method is for providers subclassing <code>MimeMessage</code>.
  255        */
  256       protected MimeMessage(Folder folder, int msgnum) {
  257   	super(folder, msgnum);
  258   	flags = new Flags();  // empty Flags object
  259   	saved = true;
  260   	initStrict();
  261       }
  262   
  263       /**
  264        * Constructs a MimeMessage by reading and parsing the data from the
  265        * specified MIME InputStream. The InputStream will be left positioned
  266        * at the end of the data for the message. Note that the input stream
  267        * parse is done within this constructor itself. <p>
  268        *
  269        * This method is for providers subclassing <code>MimeMessage</code>.
  270        *
  271        * @param folder	The containing folder.
  272        * @param is	the message input stream
  273        * @param msgnum	Message number of this message within its folder
  274        * @exception	MessagingException
  275        */
  276       protected MimeMessage(Folder folder, InputStream is, int msgnum)
  277   		throws MessagingException {
  278   	this(folder, msgnum);
  279   	initStrict();
  280   	parse(is);
  281       }
  282   
  283       /**
  284        * Constructs a MimeMessage from the given InternetHeaders object
  285        * and content.
  286        *
  287        * This method is for providers subclassing <code>MimeMessage</code>.
  288        *
  289        * @param folder	The containing folder.
  290        * @param headers	The headers
  291        * @param content	The message content
  292        * @param msgnum	Message number of this message within its folder
  293        * @exception	MessagingException
  294        */
  295       protected MimeMessage(Folder folder, InternetHeaders headers,
  296   		byte[] content, int msgnum) throws MessagingException {
  297   	this(folder, msgnum);
  298   	this.headers = headers;
  299   	this.content = content;
  300   	initStrict();
  301       }
  302   
  303       /**
  304        * Set the strict flag based on property.
  305        */
  306       private void initStrict() {
  307   	if (session != null) {
  308   	    String s = session.getProperty("mail.mime.address.strict");
  309   	    strict = s == null || !s.equalsIgnoreCase("false");
  310   	}
  311       }
  312   
  313       /**
  314        * Parse the InputStream setting the <code>headers</code> and
  315        * <code>content</code> fields appropriately.  Also resets the
  316        * <code>modified</code> flag. <p>
  317        *
  318        * This method is intended for use by subclasses that need to
  319        * control when the InputStream is parsed.
  320        *
  321        * @param is	The message input stream
  322        * @exception	MessagingException
  323        */
  324       protected void parse(InputStream is) throws MessagingException {
  325   
  326   	if (!(is instanceof ByteArrayInputStream) &&
  327   	    !(is instanceof BufferedInputStream) &&
  328   	    !(is instanceof SharedInputStream))
  329   	    is = new BufferedInputStream(is);
  330   	
  331   	headers = createInternetHeaders(is);
  332   
  333   	if (is instanceof SharedInputStream) {
  334   	    SharedInputStream sis = (SharedInputStream)is;
  335   	    contentStream = sis.newStream(sis.getPosition(), -1);
  336   	} else {
  337   	    try {
  338   		content = ASCIIUtility.getBytes(is);
  339   	    } catch (IOException ioex) {
  340   		throw new MessagingException("IOException", ioex);
  341   	    }
  342   	}
  343   
  344   	modified = false;
  345       }
  346   
  347       /** 
  348        * Returns the value of the RFC 822 "From" header fields. If this 
  349        * header field is absent, the "Sender" header field is used. 
  350        * If the "Sender" header field is also absent, <code>null</code>
  351        * is returned.<p>
  352        *
  353        * This implementation uses the <code>getHeader</code> method
  354        * to obtain the requisite header field.
  355        *
  356        * @return		Address object
  357        * @exception	MessagingException
  358        * @see	#headers
  359        */
  360       public Address[] getFrom() throws MessagingException {
  361   	Address[] a = getAddressHeader("From");
  362   	if (a == null)
  363   	    a = getAddressHeader("Sender");
  364   	
  365   	return a;
  366       }
  367   
  368       /**
  369        * Set the RFC 822 "From" header field. Any existing values are 
  370        * replaced with the given address. If address is <code>null</code>,
  371        * this header is removed.
  372        *
  373        * @param address	the sender of this message
  374        * @exception	IllegalWriteException if the underlying
  375        *			implementation does not support modification
  376        *			of existing values
  377        * @exception	IllegalStateException if this message is
  378        *			obtained from a READ_ONLY folder.
  379        * @exception	MessagingException
  380        */
  381       public void setFrom(Address address) throws MessagingException {
  382   	if (address == null)
  383   	    removeHeader("From");
  384   	else
  385   	    setHeader("From", address.toString());
  386       }
  387   
  388       /**
  389        * Set the RFC 822 "From" header field using the value of the
  390        * <code>InternetAddress.getLocalAddress</code> method.
  391        *
  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
  398        */
  399       public void setFrom() throws MessagingException {
  400   	InternetAddress me = InternetAddress.getLocalAddress(session);
  401   	if (me != null)
  402   	    setFrom(me);
  403   	else
  404   	    throw new MessagingException("No From address");
  405       }
  406   
  407       /**
  408        * Add the specified addresses to the existing "From" field. If
  409        * the "From" field does not already exist, it is created.
  410        *
  411        * @param addresses	the senders of this message
  412        * @exception	IllegalWriteException if the underlying
  413        *			implementation does not support modification
  414        *			of existing values
  415        * @exception	IllegalStateException if this message is
  416        *			obtained from a READ_ONLY folder.
  417        * @exception	MessagingException
  418        */
  419       public void addFrom(Address[] addresses) throws MessagingException {
  420   	addAddressHeader("From", addresses);
  421       }
  422   
  423       /** 
  424        * Returns the value of the RFC 822 "Sender" header field.
  425        * If the "Sender" header field is absent, <code>null</code>
  426        * is returned.<p>
  427        *
  428        * This implementation uses the <code>getHeader</code> method
  429        * to obtain the requisite header field.
  430        *
  431        * @return		Address object
  432        * @exception	MessagingException
  433        * @see		#headers
  434        * @since		JavaMail 1.3
  435        */
  436       public Address getSender() throws MessagingException {
  437   	Address[] a = getAddressHeader("Sender");
  438   	if (a == null || a.length == 0)
  439   	    return null;
  440   	return a[0];	// there can be only one
  441       }
  442   
  443       /**
  444        * Set the RFC 822 "Sender" header field. Any existing values are 
  445        * replaced with the given address. If address is <code>null</code>,
  446        * this header is removed.
  447        *
  448        * @param address	the sender of this message
  449        * @exception	IllegalWriteException if the underlying
  450        *			implementation does not support modification
  451        *			of existing values
  452        * @exception	IllegalStateException if this message is
  453        *			obtained from a READ_ONLY folder.
  454        * @exception	MessagingException
  455        * @since		JavaMail 1.3
  456        */
  457       public void setSender(Address address) throws MessagingException {
  458   	if (address == null)
  459   	    removeHeader("Sender");
  460   	else
  461   	    setHeader("Sender", address.toString());
  462       }
  463   
  464       /**
  465        * This inner class extends the javax.mail.Message.RecipientType
  466        * class to add additional RecipientTypes. The one additional
  467        * RecipientType currently defined here is NEWSGROUPS.
  468        *
  469        * @see javax.mail.Message.RecipientType
  470        */
  471       public static class RecipientType extends Message.RecipientType {
  472   
  473   	private static final long serialVersionUID = -5468290701714395543L;
  474   
  475   	/**
  476   	 * The "Newsgroup" (Usenet news) recipients.
  477   	 */
  478   	public static final RecipientType NEWSGROUPS =
  479   					new RecipientType("Newsgroups");
  480   	protected RecipientType(String type) {
  481   	    super(type);
  482   	}
  483   
  484   	protected Object readResolve() throws ObjectStreamException {
  485   	    if (type.equals("Newsgroups"))
  486   		return NEWSGROUPS;
  487   	    else
  488   		return super.readResolve();
  489   	}
  490       }
  491   
  492       /**
  493        * Returns the recepients specified by the type. The mapping
  494        * between the type and the corresponding RFC 822 header is
  495        * as follows:
  496        * <pre>
  497        *		Message.RecipientType.TO		"To"
  498        *		Message.RecipientType.CC		"Cc"
  499        *		Message.RecipientType.BCC		"Bcc"
  500        *		MimeMessage.RecipientType.NEWSGROUPS	"Newsgroups"
  501        * </pre><br>
  502        *
  503        * Returns null if the header specified by the type is not found
  504        * or if its value is empty. <p>
  505        *
  506        * This implementation uses the <code>getHeader</code> method
  507        * to obtain the requisite header field.
  508        *
  509        * @param           type	Type of recepient
  510        * @return          array of Address objects
  511        * @exception       MessagingException if header could not
  512        *                  be retrieved
  513        * @exception       AddressException if the header is misformatted
  514        * @see		#headers
  515        * @see		javax.mail.Message.RecipientType#TO
  516        * @see		javax.mail.Message.RecipientType#CC
  517        * @see		javax.mail.Message.RecipientType#BCC
  518        * @see		javax.mail.internet.MimeMessage.RecipientType#NEWSGROUPS
  519        */
  520       public Address[] getRecipients(Message.RecipientType type)
  521   				throws MessagingException {
  522   	if (type == RecipientType.NEWSGROUPS) {
  523   	    String s = getHeader("Newsgroups", ",");
  524   	    return (s == null) ? null : NewsAddress.parse(s);
  525   	} else
  526   	    return getAddressHeader(getHeaderName(type));
  527       }
  528   
  529       /**
  530        * Get all the recipient addresses for the message.
  531        * Extracts the TO, CC, BCC, and NEWSGROUPS recipients.
  532        *
  533        * @return          array of Address objects
  534        * @exception       MessagingException
  535        * @see		javax.mail.Message.RecipientType#TO
  536        * @see		javax.mail.Message.RecipientType#CC
  537        * @see		javax.mail.Message.RecipientType#BCC
  538        * @see		javax.mail.internet.MimeMessage.RecipientType#NEWSGROUPS
  539        */
  540       public Address[] getAllRecipients() throws MessagingException {
  541   	Address[] all = super.getAllRecipients();
  542   	Address[] ng = getRecipients(RecipientType.NEWSGROUPS);
  543   
  544   	if (ng == null)
  545   	    return all;		// the common case
  546   	if (all == null)
  547   	    return ng;		// a rare case
  548   
  549   	Address[] addresses = new Address[all.length + ng.length];
  550   	System.arraycopy(all, 0, addresses, 0, all.length);
  551   	System.arraycopy(ng, 0, addresses, all.length, ng.length);
  552   	return addresses;
  553       }
  554   	
  555       /**
  556        * Set the specified recipient type to the given addresses.
  557        * If the address parameter is <code>null</code>, the corresponding
  558        * recipient field is removed.
  559        *
  560        * @param type	Recipient type
  561        * @param addresses	Addresses
  562        * @exception	IllegalWriteException if the underlying
  563        *			implementation does not support modification
  564        *			of existing values
  565        * @exception	IllegalStateException if this message is
  566        *			obtained from a READ_ONLY folder.
  567        * @exception	MessagingException
  568        * @see		#getRecipients
  569        */
  570       public void setRecipients(Message.RecipientType type, Address[] addresses)
  571                                   throws MessagingException {
  572   	if (type == RecipientType.NEWSGROUPS) {
  573   	    if (addresses == null || addresses.length == 0)
  574   		removeHeader("Newsgroups");
  575   	    else
  576   		setHeader("Newsgroups", NewsAddress.toString(addresses));
  577   	} else
  578   	    setAddressHeader(getHeaderName(type), addresses);
  579       }
  580   
  581       /**
  582        * Set the specified recipient type to the given addresses.
  583        * If the address parameter is <code>null</code>, the corresponding
  584        * recipient field is removed.
  585        *   
  586        * @param type      Recipient type
  587        * @param addresses Addresses
  588        * @exception       AddressException if the attempt to parse the
  589        *                  addresses String fails
  590        * @exception       IllegalWriteException if the underlying
  591        *                  implementation does not support modification
  592        *                  of existing values
  593        * @exception       IllegalStateException if this message is
  594        *                  obtained from a READ_ONLY folder.
  595        * @exception       MessagingException
  596        * @see             #getRecipients
  597        * @since           JavaMail 1.2
  598        */
  599       public void setRecipients(Message.RecipientType type, String addresses)
  600                                   throws MessagingException {
  601           if (type == RecipientType.NEWSGROUPS) {
  602               if (addresses == null || addresses.length() == 0)
  603                   removeHeader("Newsgroups");
  604               else
  605                   setHeader("Newsgroups", addresses);
  606           } else
  607               setAddressHeader(getHeaderName(type), InternetAddress.parse(addresses));
  608       }
  609   
  610       /**
  611        * Add the given addresses to the specified recipient type.
  612        *
  613        * @param type	Recipient type
  614        * @param addresses	Addresses
  615        * @exception	IllegalWriteException if the underlying
  616        *			implementation does not support modification
  617        *			of existing values
  618        * @exception	IllegalStateException if this message is
  619        *			obtained from a READ_ONLY folder.
  620        * @exception	MessagingException
  621        */
  622       public void addRecipients(Message.RecipientType type, Address[] addresses)
  623                                   throws MessagingException {
  624   	if (type == RecipientType.NEWSGROUPS) {
  625   	    String s = NewsAddress.toString(addresses);
  626   	    if (s != null)
  627   		addHeader("Newsgroups", s);
  628   	} else
  629   	    addAddressHeader(getHeaderName(type), addresses);
  630       }
  631   
  632       /**
  633        * Add the given addresses to the specified recipient type.
  634        * 
  635        * @param type      Recipient type
  636        * @param addresses Addresses
  637        * @exception       AddressException if the attempt to parse the
  638        *                  addresses String fails
  639        * @exception       IllegalWriteException if the underlying
  640        *                  implementation does not support modification
  641        *                  of existing values
  642        * @exception       IllegalStateException if this message is
  643        *                  obtained from a READ_ONLY folder.
  644        * @exception       MessagingException
  645        * @since           JavaMail 1.2
  646        */
  647       public void addRecipients(Message.RecipientType type, String addresses)
  648                                   throws MessagingException {
  649           if (type == RecipientType.NEWSGROUPS) {
  650               if (addresses != null && addresses.length() != 0)
  651                   addHeader("Newsgroups", addresses);
  652           } else
  653               addAddressHeader(getHeaderName(type), InternetAddress.parse(addresses));
  654       }
  655    
  656       /**
  657        * Return the value of the RFC 822 "Reply-To" header field. If
  658        * this header is unavailable or its value is absent, then
  659        * the <code>getFrom</code> method is called and its value is returned.
  660        *
  661        * This implementation uses the <code>getHeader</code> method
  662        * to obtain the requisite header field.
  663        *
  664        * @exception	MessagingException
  665        * @see		#headers
  666        */
  667       public Address[] getReplyTo() throws MessagingException {
  668   	Address[] a = getAddressHeader("Reply-To");
  669   	if (a == null)
  670   	    a = getFrom();
  671   	return a;
  672       }
  673   
  674       /**
  675        * Set the RFC 822 "Reply-To" header field. If the address 
  676        * parameter is <code>null</code>, this header is removed.
  677        *
  678        * @exception	IllegalWriteException if the underlying
  679        *			implementation does not support modification
  680        *			of existing values
  681        * @exception	IllegalStateException if this message is
  682        *			obtained from a READ_ONLY folder.
  683        * @exception	MessagingException
  684        */
  685       public void setReplyTo(Address[] addresses) throws MessagingException {
  686   	setAddressHeader("Reply-To", addresses);
  687       }
  688   
  689       // Convenience method to get addresses
  690       private Address[] getAddressHeader(String name) 
  691   			throws MessagingException {
  692   	String s = getHeader(name, ",");
  693   	return (s == null) ? null : InternetAddress.parseHeader(s, strict);
  694       }
  695   
  696       // Convenience method to set addresses
  697       private void setAddressHeader(String name, Address[] addresses)
  698   			throws MessagingException {
  699   	String s = InternetAddress.toString(addresses);
  700   	if (s == null)
  701   	    removeHeader(name);
  702   	else
  703   	    setHeader(name, s);
  704       }
  705   
  706       private void addAddressHeader(String name, Address[] addresses)
  707   			throws MessagingException {
  708   	String s = InternetAddress.toString(addresses);
  709   	if (s == null)
  710   	    return;
  711   	addHeader(name, s);
  712       }
  713   
  714       /**
  715        * Returns the value of the "Subject" header field. Returns null 
  716        * if the subject field is unavailable or its value is absent. <p>
  717        *
  718        * If the subject is encoded as per RFC 2047, it is decoded and
  719        * converted into Unicode. If the decoding or conversion fails, the
  720        * raw data is returned as is. <p>
  721        *
  722        * This implementation uses the <code>getHeader</code> method
  723        * to obtain the requisite header field.
  724        *
  725        * @return          Subject
  726        * @exception	MessagingException
  727        * @see		#headers
  728        */
  729       public String getSubject() throws MessagingException {
  730   	String rawvalue = getHeader("Subject", null);
  731   
  732   	if (rawvalue == null)
  733   	    return null;
  734   
  735   	try {
  736   	    return MimeUtility.decodeText(MimeUtility.unfold(rawvalue));
  737   	} catch (UnsupportedEncodingException ex) {
  738   	    return rawvalue;
  739   	}
  740       }
  741   
  742       /**
  743        * Set the "Subject" header field. If the subject contains 
  744        * non US-ASCII characters, it will be encoded using the 
  745        * platform's default charset. If the subject contains only 
  746        * US-ASCII characters, no encoding is done and it is used 
  747        * as-is. If the subject is null, the existing "Subject" field
  748        * is removed. <p>
  749        *
  750        * The application must ensure that the subject does not contain
  751        * any line breaks. <p>
  752        *
  753        * Note that if the charset encoding process fails, a
  754        * MessagingException is thrown, and an UnsupportedEncodingException
  755        * is included in the chain of nested exceptions within the
  756        * MessagingException.
  757        *
  758        * @param 	subject		The subject
  759        * @exception	IllegalWriteException if the underlying
  760        *			implementation does not support modification
  761        *			of existing values
  762        * @exception	IllegalStateException if this message is
  763        *			obtained from a READ_ONLY folder.
  764        * @exception	MessagingException. An
  765        * 			UnsupportedEncodingException may be included
  766        *			in the exception chain if the charset
  767        *			conversion fails.
  768        */
  769       public void setSubject(String subject) throws MessagingException {
  770   	setSubject(subject, null);
  771       }
  772   
  773       /**
  774        * Set the "Subject" header field. If the subject contains non 
  775        * US-ASCII characters, it will be encoded using the specified
  776        * charset. If the subject contains only US-ASCII characters, no 
  777        * encoding is done and it is used as-is. If the subject is null, 
  778        * the existing "Subject" header field is removed. <p>
  779        *
  780        * The application must ensure that the subject does not contain
  781        * any line breaks. <p>
  782        *
  783        * Note that if the charset encoding process fails, a
  784        * MessagingException is thrown, and an UnsupportedEncodingException
  785        * is included in the chain of nested exceptions within the
  786        * MessagingException.
  787        *
  788        * @param	subject		The subject
  789        * @param	charset		The charset 
  790        * @exception		IllegalWriteException if the underlying
  791        *				implementation does not support modification
  792        *				of existing values
  793        * @exception		IllegalStateException if this message is
  794        *				obtained from a READ_ONLY folder.
  795        * @exception		MessagingException. An
  796        * 				UnsupportedEncodingException may be included
  797        *				in the exception chain if the charset
  798        *				conversion fails.
  799        */
  800       public void setSubject(String subject, String charset)
  801   			throws MessagingException {
  802   	if (subject == null) {
  803   	    removeHeader("Subject");
  804   	} else {
  805   	    try {
  806   		setHeader("Subject", MimeUtility.fold(9,
  807   		    MimeUtility.encodeText(subject, charset, null)));
  808   	    } catch (UnsupportedEncodingException uex) {
  809   		throw new MessagingException("Encoding error", uex);
  810   	    }
  811   	}
  812       }
  813   
  814       /**
  815        * Returns the value of the RFC 822 "Date" field. This is the date 
  816        * on which this message was sent. Returns null if this field is 
  817        * unavailable or its value is absent. <p>
  818        * 
  819        * This implementation uses the <code>getHeader</code> method
  820        * to obtain the requisite header field.
  821        *
  822        * @return          The sent Date
  823        * @exception	MessagingException
  824        */
  825       public Date getSentDate() throws MessagingException {
  826   	String s = getHeader("Date", null);
  827   	if (s != null) {
  828   	    try {
  829   		synchronized (mailDateFormat) {
  830   		    return mailDateFormat.parse(s);
  831   		}
  832   	    } catch (ParseException pex) {
  833   		return null;
  834   	    }
  835   	}
  836   	
  837   	return null;
  838       }
  839   
  840       /**
  841        * Set the RFC 822 "Date" header field. This is the date on which the
  842        * creator of the message indicates that the message is complete
  843        * and ready for delivery. If the date parameter is 
  844        * <code>null</code>, the existing "Date" field is removed.
  845        *
  846        * @exception	IllegalWriteException if the underlying
  847        *			implementation does not support modification
  848        * @exception	IllegalStateException if this message is
  849        *			obtained from a READ_ONLY folder.
  850        * @exception	MessagingException
  851        */
  852       public void setSentDate(Date d) throws MessagingException {
  853   	if (d == null)
  854   	    removeHeader("Date");
  855   	else {
  856   	    synchronized (mailDateFormat) {
  857   		setHeader("Date", mailDateFormat.format(d));
  858   	    }
  859   	}
  860       }
  861   
  862       /**
  863        * Returns the Date on this message was received. Returns 
  864        * <code>null</code> if this date cannot be obtained. <p>
  865        *
  866        * Note that RFC 822 does not define a field for the received
  867        * date. Hence only implementations that can provide this date
  868        * need return a valid value. <p>
  869        *
  870        * This implementation returns <code>null</code>.
  871        *
  872        * @return          the date this message was received
  873        * @exception	MessagingException
  874        */
  875       public Date getReceivedDate() throws MessagingException {
  876   	return null;	
  877       }
  878   
  879       /**
  880        * Return the size of the content of this message in bytes. 
  881        * Return -1 if the size cannot be determined. <p>
  882        *
  883        * Note that this number may not be an exact measure of the
  884        * content size and may or may not account for any transfer
  885        * encoding of the content. <p>
  886        *
  887        * This implementation returns the size of the <code>content</code>
  888        * array (if not null), or, if <code>contentStream</code> is not
  889        * null, and the <code>available</code> method returns a positive
  890        * number, it returns that number as the size.  Otherwise, it returns
  891        * -1.
  892        *
  893        * @return          size of content in bytes
  894        * @exception	MessagingException
  895        */  
  896       public int getSize() throws MessagingException {
  897   	if (content != null)
  898   	    return content.length;
  899   	if (contentStream != null) {
  900   	    try {
  901   		int size = contentStream.available();
  902   		// only believe the size if it's greater than zero, since zero
  903   		// is the default returned by the InputStream class itself
  904   		if (size > 0)
  905   		    return size;
  906   	    } catch (IOException ex) {
  907   		// ignore it
  908   	    }
  909   	}
  910   	return -1;
  911       }
  912   
  913       /**
  914        * Return the number of lines for the content of this message.
  915        * Return -1 if this number cannot be determined. <p>
  916        *
  917        * Note that this number may not be an exact measure of the 
  918        * content length and may or may not account for any transfer 
  919        * encoding of the content. <p>
  920        *
  921        * This implementation returns -1.
  922        *
  923        * @return          number of lines in the content.
  924        * @exception	MessagingException
  925        */  
  926        public int getLineCount() throws MessagingException {
  927   	return -1;
  928        }
  929   
  930       /**
  931        * Returns the value of the RFC 822 "Content-Type" header field. 
  932        * This represents the content-type of the content of this 
  933        * message. This value must not be null. If this field is 
  934        * unavailable, "text/plain" should be returned. <p>
  935        *
  936        * This implementation uses the <code>getHeader</code> method
  937        * to obtain the requisite header field.
  938        *
  939        * @return          The ContentType of this part
  940        * @exception	MessagingException
  941        * @see             javax.activation.DataHandler
  942        */
  943       public String getContentType() throws MessagingException {
  944   	String s = getHeader("Content-Type", null);
  945   	if (s == null)
  946   	    return "text/plain";
  947   	return s;
  948       }
  949   
  950       /**
  951        * Is this Part of the specified MIME type?  This method
  952        * compares <strong>only the <code>primaryType</code> and 
  953        * <code>subType</code></strong>.
  954        * The parameters of the content types are ignored. <p>
  955        *
  956        * For example, this method will return <code>true</code> when
  957        * comparing a Part of content type <strong>"text/plain"</strong>
  958        * with <strong>"text/plain; charset=foobar"</strong>. <p>
  959        *
  960        * If the <code>subType</code> of <code>mimeType</code> is the
  961        * special character '*', then the subtype is ignored during the
  962        * comparison.
  963        */
  964       public boolean isMimeType(String mimeType) throws MessagingException {
  965   	return MimeBodyPart.isMimeType(this, mimeType);
  966       }
  967   
  968       /**
  969        * Returns the value of the "Content-Disposition" header field.
  970        * This represents the disposition of this part. The disposition
  971        * describes how the part should be presented to the user. <p>
  972        *
  973        * If the Content-Disposition field is unavailable, 
  974        * <code>null</code> is returned. <p>
  975        *
  976        * This implementation uses the <code>getHeader</code> method
  977        * to obtain the requisite header field.
  978        *
  979        * @return          disposition of this part, or null if unknown
  980        * @exception	MessagingException
  981        */
  982       public String getDisposition() throws MessagingException {
  983   	return MimeBodyPart.getDisposition(this);
  984       }
  985   
  986       /**
  987        * Set the "Content-Disposition" header field of this Message.
  988        * If <code>disposition</code> is null, any existing "Content-Disposition"
  989        * header field is removed.
  990        *
  991        * @exception	IllegalWriteException if the underlying
  992        *			implementation does not support modification
  993        * @exception	IllegalStateException if this message is
  994        *			obtained from a READ_ONLY folder.
  995        * @exception	MessagingException
  996        */
  997       public void setDisposition(String disposition) throws MessagingException {
  998   	MimeBodyPart.setDisposition(this, disposition);
  999       }
 1000   
 1001       /**
 1002        * Returns the content transfer encoding from the
 1003        * "Content-Transfer-Encoding" header
 1004        * field. Returns <code>null</code> if the header is unavailable
 1005        * or its value is absent. <p>
 1006        *
 1007        * This implementation uses the <code>getHeader</code> method
 1008        * to obtain the requisite header field.
 1009        *
 1010        * @return          content-transfer-encoding
 1011        * @exception	MessagingException
 1012        */
 1013       public String getEncoding() throws MessagingException {
 1014   	return MimeBodyPart.getEncoding(this);
 1015       }
 1016   
 1017       /**
 1018        * Returns the value of the "Content-ID" header field. Returns
 1019        * <code>null</code> if the field is unavailable or its value is 
 1020        * absent. <p>
 1021        *
 1022        * This implementation uses the <code>getHeader</code> method
 1023        * to obtain the requisite header field.
 1024        *
 1025        * @return          content-ID
 1026        * @exception	MessagingException
 1027        */
 1028       public String getContentID() throws MessagingException {
 1029   	return getHeader("Content-Id", null);
 1030       }
 1031   
 1032       /**
 1033        * Set the "Content-ID" header field of this Message.
 1034        * If the <code>cid</code> parameter is null, any existing 
 1035        * "Content-ID" is removed.
 1036        *
 1037        * @exception	IllegalWriteException if the underlying
 1038        *			implementation does not support modification
 1039        * @exception	IllegalStateException if this message is
 1040        *			obtained from a READ_ONLY folder.
 1041        * @exception	MessagingException
 1042        */
 1043       public void setContentID(String cid) throws MessagingException {
 1044   	if (cid == null)
 1045   	    removeHeader("Content-ID");
 1046   	else
 1047   	    setHeader("Content-ID", cid);
 1048       }
 1049   
 1050       /**
 1051        * Return the value of the "Content-MD5" header field. Returns 
 1052        * <code>null</code> if this field is unavailable or its value
 1053        * is absent. <p>
 1054        *
 1055        * This implementation uses the <code>getHeader</code> method
 1056        * to obtain the requisite header field.
 1057        *
 1058        * @return          content-MD5
 1059        * @exception	MessagingException
 1060        */
 1061       public String getContentMD5() throws MessagingException {
 1062   	return getHeader("Content-MD5", null);
 1063       }
 1064   
 1065       /**
 1066        * Set the "Content-MD5" header field of this Message.
 1067        *
 1068        * @exception	IllegalWriteException if the underlying
 1069        *			implementation does not support modification
 1070        * @exception	IllegalStateException if this message is
 1071        *			obtained from a READ_ONLY folder.
 1072        * @exception	MessagingException
 1073        */
 1074       public void setContentMD5(String md5) throws MessagingException {
 1075   	setHeader("Content-MD5", md5);
 1076       }
 1077   
 1078       /**
 1079        * Returns the "Content-Description" header field of this Message.
 1080        * This typically associates some descriptive information with 
 1081        * this part. Returns null if this field is unavailable or its
 1082        * value is absent. <p>
 1083        *
 1084        * If the Content-Description field is encoded as per RFC 2047,
 1085        * it is decoded and converted into Unicode. If the decoding or 
 1086        * conversion fails, the raw data is returned as-is <p>
 1087        *
 1088        * This implementation uses the <code>getHeader</code> method
 1089        * to obtain the requisite header field.
 1090        * 
 1091        * @return	content-description
 1092        * @exception	MessagingException
 1093        */
 1094       public String getDescription() throws MessagingException {
 1095   	return MimeBodyPart.getDescription(this);
 1096       }
 1097   
 1098       /**
 1099        * Set the "Content-Description" header field for this Message.
 1100        * If the description parameter is <code>null</code>, then any 
 1101        * existing "Content-Description" fields are removed. <p>
 1102        *
 1103        * If the description contains non US-ASCII characters, it will 
 1104        * be encoded using the platform's default charset. If the 
 1105        * description contains only US-ASCII characters, no encoding 
 1106        * is done and it is used as-is. <p>
 1107        *
 1108        * Note that if the charset encoding process fails, a
 1109        * MessagingException is thrown, and an UnsupportedEncodingException
 1110        * is included in the chain of nested exceptions within the
 1111        * MessagingException.
 1112        * 
 1113        * @param description content-description
 1114        * @exception	IllegalWriteException if the underlying
 1115        *			implementation does not support modification
 1116        * @exception	IllegalStateException if this message is
 1117        *			obtained from a READ_ONLY folder.
 1118        * @exception	MessagingException. An
 1119        * 			UnsupportedEncodingException may be included
 1120        *			in the exception chain if the charset
 1121        *			conversion fails.
 1122        */
 1123       public void setDescription(String description) throws MessagingException {
 1124   	setDescription(description, null);
 1125       }
 1126   
 1127       /**
 1128        * Set the "Content-Description" header field for this Message.
 1129        * If the description parameter is <code>null</code>, then any 
 1130        * existing "Content-Description" fields are removed. <p>
 1131        *
 1132        * If the description contains non US-ASCII characters, it will 
 1133        * be encoded using the specified charset. If the description 
 1134        * contains only US-ASCII characters, no encoding  is done and 
 1135        * it is used as-is. <p>
 1136        *
 1137        * Note that if the charset encoding process fails, a
 1138        * MessagingException is thrown, and an UnsupportedEncodingException
 1139        * is included in the chain of nested exceptions within the
 1140        * MessagingException.
 1141        * 
 1142        * @param	description	Description
 1143        * @param	charset		Charset for encoding
 1144        * @exception		IllegalWriteException if the underlying
 1145        *				implementation does not support modification
 1146        * @exception		IllegalStateException if this message is
 1147        *				obtained from a READ_ONLY folder.
 1148        * @exception		MessagingException. An
 1149        * 				UnsupportedEncodingException may be included
 1150        *				in the exception chain if the charset
 1151        *				conversion fails.
 1152        */
 1153       public void setDescription(String description, String charset) 
 1154   		throws MessagingException {
 1155   	MimeBodyPart.setDescription(this, description, charset);
 1156       }
 1157   
 1158       /**
 1159        * Get the languages specified in the "Content-Language" header
 1160        * field of this message. The Content-Language header is defined by
 1161        * RFC 1766. Returns <code>null</code> if this field is unavailable
 1162        * or its value is absent. <p>
 1163        *
 1164        * This implementation uses the <code>getHeader</code> method
 1165        * to obtain the requisite header field.
 1166        *
 1167        * @return			value of content-language header.
 1168        * @exception		MessagingException
 1169        */
 1170       public String[] getContentLanguage() throws MessagingException {
 1171   	return MimeBodyPart.getContentLanguage(this);
 1172       }
 1173   
 1174       /**
 1175        * Set the "Content-Language" header of this MimePart. The
 1176        * Content-Language header is defined by RFC 1766.
 1177        *
 1178        * @param languages 	array of language tags
 1179        * @exception		IllegalWriteException if the underlying
 1180        *				implementation does not support modification
 1181        * @exception		IllegalStateException if this message is
 1182        *				obtained from a READ_ONLY folder.
 1183        * @exception		MessagingException
 1184        */
 1185       public void setContentLanguage(String[] languages)
 1186   			throws MessagingException {
 1187   	MimeBodyPart.setContentLanguage(this, languages);
 1188       }
 1189   
 1190       /**
 1191        * Returns the value of the "Message-ID" header field. Returns
 1192        * null if this field is unavailable or its value is absent. <p>
 1193        *
 1194        * The default implementation provided here uses the
 1195        * <code>getHeader</code> method to return the value of the
 1196        * "Message-ID" field.
 1197        *
 1198        * @return     Message-ID
 1199        * @exception  MessagingException if the retrieval of this field
 1200        *			causes any exception.
 1201        * @see        javax.mail.search.MessageIDTerm
 1202        * @since 	   JavaMail 1.1
 1203        */
 1204       public String getMessageID() throws MessagingException {
 1205   	return getHeader("Message-ID", null);
 1206       }
 1207   
 1208       /**
 1209        * Get the filename associated with this Message. <p>
 1210        *
 1211        * Returns the value of the "filename" parameter from the
 1212        * "Content-Disposition" header field of this message. If it's
 1213        * not available, returns the value of the "name" parameter from
 1214        * the "Content-Type" header field of this BodyPart.
 1215        * Returns <code>null</code> if both are absent. <p>
 1216        *
 1217        * If the <code>mail.mime.encodefilename</code> System property
 1218        * is set to true, the {@link MimeUtility#decodeText
 1219        * MimeUtility.decodeText} method will be used to decode the
 1220        * filename.  While such encoding is not supported by the MIME
 1221        * spec, many mailers use this technique to support non-ASCII
 1222        * characters in filenames.  The default value of this property
 1223        * is false.
 1224        *
 1225        * @return	filename
 1226        * @exception		MessagingException
 1227        */
 1228       public String getFileName() throws MessagingException {
 1229   	return MimeBodyPart.getFileName(this);
 1230       }
 1231   
 1232       /**
 1233        * Set the filename associated with this part, if possible. <p>
 1234        *
 1235        * Sets the "filename" parameter of the "Content-Disposition"
 1236        * header field of this message. <p>
 1237        *
 1238        * If the <code>mail.mime.encodefilename</code> System property
 1239        * is set to true, the {@link MimeUtility#encodeText
 1240        * MimeUtility.encodeText} method will be used to encode the
 1241        * filename.  While such encoding is not supported by the MIME
 1242        * spec, many mailers use this technique to support non-ASCII
 1243        * characters in filenames.  The default value of this property
 1244        * is false.
 1245        *
 1246        * @exception		IllegalWriteException if the underlying
 1247        *				implementation does not support modification
 1248        * @exception		IllegalStateException if this message is
 1249        *				obtained from a READ_ONLY folder.
 1250        * @exception		MessagingException
 1251        */
 1252       public void setFileName(String filename) throws MessagingException {
 1253   	MimeBodyPart.setFileName(this, filename);	
 1254       }
 1255   
 1256       private String getHeaderName(Message.RecipientType type)
 1257   				throws MessagingException {
 1258   	String headerName;
 1259   
 1260   	if (type == Message.RecipientType.TO)
 1261   	    headerName = "To";
 1262   	else if (type == Message.RecipientType.CC)
 1263   	    headerName = "Cc";
 1264   	else if (type == Message.RecipientType.BCC)
 1265   	    headerName = "Bcc";
 1266   	else if (type == MimeMessage.RecipientType.NEWSGROUPS)
 1267   	    headerName = "Newsgroups";
 1268   	else
 1269   	    throw new MessagingException("Invalid Recipient Type");
 1270   	return headerName;
 1271       }
 1272   
 1273   
 1274       /**
 1275        * Return a decoded input stream for this Message's "content". <p>
 1276        *
 1277        * This implementation obtains the input stream from the DataHandler,
 1278        * that is, it invokes <code>getDataHandler().getInputStream()</code>.
 1279        *
 1280        * @return 		an InputStream
 1281        * @exception	MessagingException
 1282        * @exception       IOException this is typically thrown by the
 1283        *			DataHandler. Refer to the documentation for
 1284        *			javax.activation.DataHandler for more details.
 1285        *
 1286        * @see	#getContentStream
 1287        * @see 	javax.activation.DataHandler#getInputStream
 1288        */
 1289       public InputStream getInputStream() 
 1290   		throws IOException, MessagingException {
 1291   	return getDataHandler().getInputStream();
 1292       }
 1293   
 1294       /**
 1295        * Produce the raw bytes of the content. This method is used during
 1296        * parsing, to create a DataHandler object for the content. Subclasses
 1297        * that can provide a separate input stream for just the message 
 1298        * content might want to override this method. <p>
 1299        *
 1300        * This implementation returns a SharedInputStream, if
 1301        * <code>contentStream</code> is not null.  Otherwise, it
 1302        * returns a ByteArrayInputStream constructed
 1303        * out of the <code>content</code> byte array.
 1304        *
 1305        * @see #content
 1306        */
 1307       protected InputStream getContentStream() throws MessagingException {
 1308   	if (contentStream != null)
 1309   	    return ((SharedInputStream)contentStream).newStream(0, -1);
 1310   	if (content != null)
 1311   	    return new SharedByteArrayInputStream(content);
 1312   
 1313   	throw new MessagingException("No content");
 1314       }
 1315   
 1316       /**
 1317        * Return an InputStream to the raw data with any Content-Transfer-Encoding
 1318        * intact.  This method is useful if the "Content-Transfer-Encoding"
 1319        * header is incorrect or corrupt, which would prevent the
 1320        * <code>getInputStream</code> method or <code>getContent</code> method
 1321        * from returning the correct data.  In such a case the application may
 1322        * use this method and attempt to decode the raw data itself. <p>
 1323        *
 1324        * This implementation simply calls the <code>getContentStream</code>
 1325        * method.
 1326        *
 1327        * @see	#getInputStream
 1328        * @see	#getContentStream
 1329        * @since	JavaMail 1.2
 1330        */
 1331       public InputStream getRawInputStream() throws MessagingException {
 1332   	return getContentStream();
 1333       }
 1334   
 1335       /**                                                            
 1336        * Return a DataHandler for this Message's content. <p>
 1337        *
 1338        * The implementation provided here works as follows. Note the use of 
 1339        * the <code>getContentStream</code> method to 
 1340        * generate the byte stream for the content. Also note that
 1341        * any transfer-decoding is done automatically within this method.<p>
 1342        *
 1343        * <blockquote><pre>
 1344        *  getDataHandler() {
 1345        *      if (dh == null) {
 1346        *          dh = new DataHandler(new MimePartDataSource(this));
 1347        *      }
 1348        *      return dh;
 1349        *  }
 1350        *  <p>
 1351        *  class MimePartDataSource implements DataSource {
 1352        *      public getInputStream() {
 1353        *          return MimeUtility.decode(
 1354        *		     getContentStream(), getEncoding());
 1355        *      }
 1356        *	
 1357        *		.... <other DataSource methods>
 1358        *  }
 1359        * </pre></blockquote><p>
 1360        *
 1361        * @exception	MessagingException
 1362        */
 1363       public synchronized DataHandler getDataHandler() 
 1364   		throws MessagingException {
 1365   	if (dh == null)
 1366   	    dh = new DataHandler(new MimePartDataSource(this));
 1367   	return dh;
 1368       }
 1369   
 1370       /**
 1371        * Return the content as a Java object. The type of this
 1372        * object is dependent on the content itself. For 
 1373        * example, the native format of a "text/plain" content
 1374        * is usually a String object. The native format for a "multipart"
 1375        * message is always a Multipart subclass. For content types that are
 1376        * unknown to the DataHandler system, an input stream is returned
 1377        * as the content. <p>
 1378        *
 1379        * This implementation obtains the content from the DataHandler,
 1380        * that is, it invokes <code>getDataHandler().getContent()</code>.
 1381        * If the content is a Multipart or Message object and was created by
 1382        * parsing a stream, the object is cached and returned in subsequent
 1383        * calls so that modifications to the content will not be lost.
 1384        *
 1385        * @return          Object
 1386        * @see		javax.mail.Part
 1387        * @see 		javax.activation.DataHandler#getContent
 1388        * @exception       MessagingException
 1389        * @exception       IOException this is typically thrown by the
 1390        *			DataHandler. Refer to the documentation for
 1391        *			javax.activation.DataHandler for more details.
 1392        */
 1393       public Object getContent() throws IOException, MessagingException {
 1394   	if (cachedContent != null)
 1395   	    return cachedContent;
 1396   	Object c;
 1397   	try {
 1398   	    c = getDataHandler().getContent();
 1399   	} catch (FolderClosedIOException fex) {
 1400   	    throw new FolderClosedException(fex.getFolder(), fex.getMessage());
 1401   	} catch (MessageRemovedIOException mex) {
 1402   	    throw new MessageRemovedException(mex.getMessage());
 1403   	}
 1404   	if (MimeBodyPart.cacheMultipart &&
 1405   		(c instanceof Multipart || c instanceof Message) &&
 1406   		(content != null || contentStream != null)) {
 1407   	    cachedContent = c;
 1408   	}
 1409   	return c;
 1410       }
 1411   
 1412       /**
 1413        * This method provides the mechanism to set this part's content.
 1414        * The given DataHandler object should wrap the actual content.
 1415        *
 1416        * @param   dh      The DataHandler for the content.
 1417        * @exception	IllegalWriteException if the underlying
 1418        *			implementation does not support modification
 1419        * @exception	IllegalStateException if this message is
 1420        *			obtained from a READ_ONLY folder.
 1421        * @exception       MessagingException
 1422        */
 1423       public synchronized void setDataHandler(DataHandler dh) 
 1424   		throws MessagingException {
 1425   	this.dh = dh;
 1426   	cachedContent = null;
 1427   	MimeBodyPart.invalidateContentHeaders(this);
 1428       }
 1429   
 1430       /**
 1431        * A convenience method for setting this Message's content. <p>
 1432        *
 1433        * The content is wrapped in a DataHandler object. Note that a
 1434        * DataContentHandler class for the specified type should be
 1435        * available to the JavaMail implementation for this to work right.
 1436        * i.e., to do <code>setContent(foobar, "application/x-foobar")</code>,
 1437        * a DataContentHandler for "application/x-foobar" should be installed.
 1438        * Refer to the Java Activation Framework for more information.
 1439        *
 1440        * @param	o	the content object
 1441        * @param	type	Mime type of the object
 1442        * @exception       IllegalWriteException if the underlying
 1443        *			implementation does not support modification of
 1444        *			existing values
 1445        * @exception	IllegalStateException if this message is
 1446        *			obtained from a READ_ONLY folder.
 1447        * @exception       MessagingException
 1448        */
 1449       public void setContent(Object o, String type) 
 1450   			throws MessagingException {
 1451   	if (o instanceof Multipart)
 1452   	    setContent((Multipart)o);
 1453   	else
 1454   	    setDataHandler(new DataHandler(o, type));
 1455       }
 1456   
 1457       /**
 1458        * Convenience method that sets the given String as this
 1459        * part's content, with a MIME type of "text/plain". If the
 1460        * string contains non US-ASCII characters. it will be encoded
 1461        * using the platform's default charset. The charset is also
 1462        * used to set the "charset" parameter.<p>
 1463        *
 1464        * Note that there may be a performance penalty if
 1465        * <code>text</code> is large, since this method may have
 1466        * to scan all the characters to determine what charset to
 1467        * use. <p>
 1468        *
 1469        * If the charset is already known, use the
 1470        * <code>setText</code> method that takes the charset parameter.
 1471        *
 1472        * @param	text	the text content to set
 1473        * @exception	MessagingException	if an error occurs
 1474        * @see	#setText(String text, String charset)
 1475        */
 1476       public void setText(String text) throws MessagingException {
 1477   	setText(text, null);
 1478       }
 1479   
 1480       /**
 1481        * Convenience method that sets the given String as this part's
 1482        * content, with a MIME type of "text/plain" and the specified
 1483        * charset. The given Unicode string will be charset-encoded
 1484        * using the specified charset. The charset is also used to set
 1485        * the "charset" parameter.
 1486        *
 1487        * @param	text	the text content to set
 1488        * @param	charset	the charset to use for the text
 1489        * @exception	MessagingException	if an error occurs
 1490        */
 1491       public void setText(String text, String charset)
 1492   			throws MessagingException {
 1493   	MimeBodyPart.setText(this, text, charset, "plain");
 1494       }
 1495   
 1496       /**
 1497        * Convenience method that sets the given String as this part's
 1498        * content, with a primary MIME type of "text" and the specified
 1499        * MIME subtype.  The given Unicode string will be charset-encoded
 1500        * using the specified charset. The charset is also used to set
 1501        * the "charset" parameter.
 1502        *
 1503        * @param	text	the text content to set
 1504        * @param	charset	the charset to use for the text
 1505        * @param	subtype	the MIME subtype to use (e.g., "html")
 1506        * @exception	MessagingException	if an error occurs
 1507        * @since	JavaMail 1.4
 1508        */
 1509       public void setText(String text, String charset, String subtype)
 1510                           throws MessagingException {
 1511   	MimeBodyPart.setText(this, text, charset, subtype);
 1512       }
 1513   
 1514       /**
 1515        * This method sets the Message's content to a Multipart object.
 1516        *
 1517        * @param  mp      The multipart object that is the Message's content
 1518        * @exception       IllegalWriteException if the underlying
 1519        *			implementation does not support modification of
 1520        *			existing values
 1521        * @exception	IllegalStateException if this message is
 1522        *			obtained from a READ_ONLY folder.
 1523        * @exception       MessagingException
 1524        */
 1525       public void setContent(Multipart mp) throws MessagingException {
 1526   	setDataHandler(new DataHandler(mp, mp.getContentType()));
 1527   	mp.setParent(this);
 1528       }
 1529   
 1530       /**
 1531        * Get a new Message suitable for a reply to this message.
 1532        * The new Message will have its attributes and headers 
 1533        * set up appropriately.  Note that this new message object
 1534        * will be empty, i.e., it will <strong>not</strong> have a "content".
 1535        * These will have to be suitably filled in by the client. <p>
 1536        *
 1537        * If <code>replyToAll</code> is set, the new Message will be addressed
 1538        * to all recipients of this message.  Otherwise, the reply will be
 1539        * addressed to only the sender of this message (using the value
 1540        * of the <code>getReplyTo</code> method).  <p>
 1541        *
 1542        * The "Subject" field is filled in with the original subject
 1543        * prefixed with "Re:" (unless it already starts with "Re:").
 1544        * The "In-Reply-To" header is set in the new message if this
 1545        * message has a "Message-Id" header.  The <code>ANSWERED</code>
 1546        * flag is set in this message.
 1547        *
 1548        * The current implementation also sets the "References" header
 1549        * in the new message to include the contents of the "References"
 1550        * header (or, if missing, the "In-Reply-To" header) in this message,
 1551        * plus the contents of the "Message-Id" header of this message,
 1552        * as described in RFC 2822.
 1553        *
 1554        * @param	replyToAll	reply should be sent to all recipients
 1555        *				of this message
 1556        * @return		the reply Message
 1557        * @exception	MessagingException
 1558        */
 1559       public Message reply(boolean replyToAll) throws MessagingException {
 1560   	MimeMessage reply = createMimeMessage(session);
 1561   	/*
 1562   	 * Have to manipulate the raw Subject header so that we don't lose
 1563   	 * any encoding information.  This is safe because "Re:" isn't
 1564   	 * internationalized and (generally) isn't encoded.  If the entire
 1565   	 * Subject header is encoded, prefixing it with "Re: " still leaves
 1566   	 * a valid and correct encoded header.
 1567   	 */
 1568   	String subject = getHeader("Subject", null);
 1569   	if (subject != null) {
 1570   	    if (!subject.regionMatches(true, 0, "Re: ", 0, 4))
 1571   		subject = "Re: " + subject;
 1572   	    reply.setHeader("Subject", subject);
 1573   	}
 1574   	Address a[] = getReplyTo();
 1575   	reply.setRecipients(Message.RecipientType.TO, a);
 1576   	if (replyToAll) {
 1577   	    Vector v = new Vector();
 1578   	    // add my own address to list
 1579   	    InternetAddress me = InternetAddress.getLocalAddress(session);
 1580   	    if (me != null)
 1581   		v.addElement(me);
 1582   	    // add any alternate names I'm known by
 1583   	    String alternates = null;
 1584   	    if (session != null)
 1585   		alternates = session.getProperty("mail.alternates");
 1586   	    if (alternates != null)
 1587   		eliminateDuplicates(v,
 1588   				InternetAddress.parse(alternates, false));
 1589   	    // should we Cc all other original recipients?
 1590   	    String replyallccStr = null;
 1591   	    if (session != null)
 1592   		replyallccStr = session.getProperty("mail.replyallcc");
 1593   	    boolean replyallcc =
 1594   		replyallccStr != null && replyallccStr.equalsIgnoreCase("true");
 1595   	    // add the recipients from the To field so far
 1596   	    eliminateDuplicates(v, a);
 1597   	    a = getRecipients(Message.RecipientType.TO);
 1598   	    a = eliminateDuplicates(v, a);
 1599   	    if (a != null && a.length > 0) {
 1600   		if (replyallcc)
 1601   		    reply.addRecipients(Message.RecipientType.CC, a);
 1602   		else
 1603   		    reply.addRecipients(Message.RecipientType.TO, a);
 1604   	    }
 1605   	    a = getRecipients(Message.RecipientType.CC);
 1606   	    a = eliminateDuplicates(v, a);
 1607   	    if (a != null && a.length > 0)
 1608   		reply.addRecipients(Message.RecipientType.CC, a);
 1609   	    // don't eliminate duplicate newsgroups
 1610   	    a = getRecipients(RecipientType.NEWSGROUPS);
 1611   	    if (a != null && a.length > 0)
 1612   		reply.setRecipients(RecipientType.NEWSGROUPS, a);
 1613   	}
 1614   
 1615   	String msgId = getHeader("Message-Id", null);
 1616   	if (msgId != null)
 1617   	    reply.setHeader("In-Reply-To", msgId);
 1618   
 1619   	/*
 1620   	 * Set the References header as described in RFC 2822:
 1621   	 *
 1622   	 * The "References:" field will contain the contents of the parent's
 1623   	 * "References:" field (if any) followed by the contents of the parent's
 1624   	 * "Message-ID:" field (if any).  If the parent message does not contain
 1625   	 * a "References:" field but does have an "In-Reply-To:" field
 1626   	 * containing a single message identifier, then the "References:" field
 1627   	 * will contain the contents of the parent's "In-Reply-To:" field
 1628   	 * followed by the contents of the parent's "Message-ID:" field (if
 1629   	 * any).  If the parent has none of the "References:", "In-Reply-To:",
 1630   	 * or "Message-ID:" fields, then the new message will have no
 1631   	 * "References:" field.
 1632   	 */
 1633   	String refs = getHeader("References", " ");
 1634   	if (refs == null) {
 1635   	    // XXX - should only use if it contains a single message identifier
 1636   	    refs = getHeader("In-Reply-To", " ");
 1637   	}
 1638   	if (msgId != null) {
 1639   	    if (refs != null)
 1640   		refs = MimeUtility.unfold(refs) + " " + msgId;
 1641   	    else
 1642   		refs = msgId;
 1643   	}
 1644   	if (refs != null)
 1645   	    reply.setHeader("References", MimeUtility.fold(12, refs));
 1646   
 1647   	try {
 1648   	    setFlags(answeredFlag, true);
 1649   	} catch (MessagingException mex) {
 1650   	    // ignore it
 1651   	}
 1652   	return reply;
 1653       }
 1654   
 1655       // used above in reply()
 1656       private static final Flags answeredFlag = new Flags(Flags.Flag.ANSWERED);
 1657   
 1658       /**
 1659        * Check addrs for any duplicates that may already be in v.
 1660        * Return a new array without the duplicates.  Add any new
 1661        * addresses to v.  Note that the input array may be modified.
 1662        */
 1663       private Address[] eliminateDuplicates(Vector v, Address[] addrs) {
 1664   	if (addrs == null)
 1665   	    return null;
 1666   	int gone = 0;
 1667   	for (int i = 0; i < addrs.length; i++) {
 1668   	    boolean found = false;
 1669   	    // search the vector for this address
 1670   	    for (int j = 0; j < v.size(); j++) {
 1671   		if (((InternetAddress)v.elementAt(j)).equals(addrs[i])) {
 1672   		    // found it; count it and remove it from the input array
 1673   		    found = true;
 1674   		    gone++;
 1675   		    addrs[i] = null;
 1676   		    break;
 1677   		}
 1678   	    }
 1679   	    if (!found)
 1680   		v.addElement(addrs[i]);	// add new address to vector
 1681   	}
 1682   	// if we found any duplicates, squish the array
 1683   	if (gone != 0) {
 1684   	    Address[] a;
 1685   	    // new array should be same type as original array
 1686   	    // XXX - there must be a better way, perhaps reflection?
 1687   	    if (addrs instanceof InternetAddress[])
 1688   		a = new InternetAddress[addrs.length - gone];
 1689   	    else
 1690   		a = new Address[addrs.length - gone];
 1691   	    for (int i = 0, j = 0; i < addrs.length; i++)
 1692   		if (addrs[i] != null)
 1693   		    a[j++] = addrs[i];
 1694   	    addrs = a;
 1695   	}
 1696   	return addrs;
 1697       }
 1698   
 1699       /**
 1700        * Output the message as an RFC 822 format stream. <p>
 1701        *
 1702        * Note that, depending on how the messag was constructed, it may
 1703        * use a variety of line termination conventions.  Generally the
 1704        * output should be sent through an appropriate FilterOutputStream
 1705        * that converts the line terminators to the desired form, either
 1706        * CRLF for MIME compatibility and for use in Internet protocols,
 1707        * or the local platform's line terminator for storage in a local
 1708        * text file. <p>
 1709        *
 1710        * This implementation calls the <code>writeTo(OutputStream,
 1711        * String[])</code> method with a null ignore list.
 1712        *
 1713        * @exception IOException	if an error occurs writing to the stream
 1714        *				or if an error is generated by the
 1715        *				javax.activation layer.
 1716        * @exception MessagingException
 1717        * @see javax.activation.DataHandler#writeTo
 1718        */
 1719       public void writeTo(OutputStream os)
 1720   				throws IOException, MessagingException {
 1721   	writeTo(os, null);
 1722       }
 1723   
 1724       /**
 1725        * Output the message as an RFC 822 format stream, without
 1726        * specified headers.  If the <code>saved</code> flag is not set,
 1727        * the <code>saveChanges</code> method is called.
 1728        * If the <code>modified</code> flag is not
 1729        * set and the <code>content</code> array is not null, the
 1730        * <code>content</code> array is written directly, after
 1731        * writing the appropriate message headers.
 1732        *
 1733        * @exception javax.mail.MessagingException
 1734        * @exception IOException	if an error occurs writing to the stream
 1735        *				or if an error is generated by the
 1736        *				javax.activation layer.
 1737        * @see javax.activation.DataHandler#writeTo
 1738        */
 1739       public void writeTo(OutputStream os, String[] ignoreList)
 1740   				throws IOException, MessagingException {
 1741   	if (!saved)
 1742   	    saveChanges();
 1743   
 1744   	if (modified) {
 1745   	    MimeBodyPart.writeTo(this, os, ignoreList);
 1746   	    return;
 1747   	}
 1748   
 1749   	// Else, the content is untouched, so we can just output it
 1750   	// First, write out the header
 1751   	Enumeration hdrLines = getNonMatchingHeaderLines(ignoreList);
 1752   	LineOutputStream los = new LineOutputStream(os);
 1753   	while (hdrLines.hasMoreElements())
 1754   	    los.writeln((String)hdrLines.nextElement());
 1755   
 1756   	// The CRLF separator between header and content
 1757   	los.writeln();
 1758   
 1759   	// Finally, the content. 
 1760   	if (content == null) {
 1761   	    // call getContentStream to give subclass a chance to
 1762   	    // provide the data on demand
 1763   	    InputStream is = getContentStream();
 1764   	    // now copy the data to the output stream
 1765   	    byte[] buf = new byte[8192];
 1766   	    int len;
 1767   	    while ((len = is.read(buf)) > 0)
 1768   		os.write(buf, 0, len);
 1769   	    is.close();
 1770   	    buf = null;
 1771   	} else {
 1772   	    os.write(content);
 1773   	}
 1774   	os.flush();
 1775       }
 1776   
 1777       /**
 1778        * Get all the headers for this header_name. Note that certain
 1779        * headers may be encoded as per RFC 2047 if they contain 
 1780        * non US-ASCII characters and these should be decoded. <p>
 1781        *
 1782        * This implementation obtains the headers from the 
 1783        * <code>headers</code> InternetHeaders object.
 1784        *
 1785        * @param	name	name of header
 1786        * @return	array of headers
 1787        * @exception       MessagingException
 1788        * @see 	javax.mail.internet.MimeUtility
 1789        */
 1790       public String[] getHeader(String name)
 1791   			throws MessagingException {
 1792   	return headers.getHeader(name);
 1793       }
 1794   
 1795       /**
 1796        * Get all the headers for this header name, returned as a single
 1797        * String, with headers separated by the delimiter. If the
 1798        * delimiter is <code>null</code>, only the first header is 
 1799        * returned.
 1800        *
 1801        * @param name		the name of this header
 1802        * @param delimiter		separator between values
 1803        * @return                  the value fields for all headers with 
 1804        *				this name
 1805        * @exception       	MessagingException
 1806        */
 1807       public String getHeader(String name, String delimiter)
 1808   				throws MessagingException {
 1809   	return headers.getHeader(name, delimiter);
 1810       }
 1811   
 1812       /**
 1813        * Set the value for this header_name. Replaces all existing
 1814        * header values with this new value. Note that RFC 822 headers
 1815        * must contain only US-ASCII characters, so a header that
 1816        * contains non US-ASCII characters must have been encoded by the
 1817        * caller as per the rules of RFC 2047.
 1818        *
 1819        * @param	name 	header name
 1820        * @param	value	header value
 1821        * @see 	javax.mail.internet.MimeUtility
 1822        * @exception	IllegalWriteException if the underlying
 1823        *			implementation does not support modification
 1824        * @exception	IllegalStateException if this message is
 1825        *			obtained from a READ_ONLY folder.
 1826        * @exception       MessagingException
 1827        */
 1828       public void setHeader(String name, String value)
 1829                                   throws MessagingException {
 1830   	headers.setHeader(name, value);	
 1831       }
 1832   
 1833       /**
 1834        * Add this value to the existing values for this header_name.
 1835        * Note that RFC 822 headers must contain only US-ASCII 
 1836        * characters, so a header that contains non US-ASCII characters 
 1837        * must have been encoded as per the rules of RFC 2047.
 1838        *
 1839        * @param	name 	header name
 1840        * @param	value	header value
 1841        * @see 	javax.mail.internet.MimeUtility
 1842        * @exception	IllegalWriteException if the underlying
 1843        *			implementation does not support modification
 1844        * @exception	IllegalStateException if this message is
 1845        *			obtained from a READ_ONLY folder.
 1846        * @exception       MessagingException
 1847        */
 1848       public void addHeader(String name, String value)
 1849                                   throws MessagingException {
 1850   	headers.addHeader(name, value);
 1851       }
 1852   
 1853       /**
 1854        * Remove all headers with this name.
 1855        * @exception	IllegalWriteException if the underlying
 1856        *			implementation does not support modification
 1857        * @exception	IllegalStateException if this message is
 1858        *			obtained from a READ_ONLY folder.
 1859        * @exception       MessagingException
 1860        */
 1861       public void removeHeader(String name)
 1862                                   throws MessagingException {
 1863   	headers.removeHeader(name);
 1864       }
 1865   
 1866       /**
 1867        * Return all the headers from this Message as an enumeration
 1868        * of Header objects. <p>
 1869        *
 1870        * Note that certain headers may be encoded as per RFC 2047 
 1871        * if they contain non US-ASCII characters and these should 
 1872        * be decoded. <p>
 1873        *
 1874        * This implementation obtains the headers from the 
 1875        * <code>headers</code> InternetHeaders object.
 1876        *
 1877        * @return	array of header objects
 1878        * @exception  MessagingException
 1879        * @see 	javax.mail.internet.MimeUtility
 1880        */
 1881       public Enumeration getAllHeaders() throws MessagingException {
 1882   	return headers.getAllHeaders();	
 1883       }
 1884   
 1885       /**
 1886        * Return matching headers from this Message as an Enumeration of
 1887        * Header objects. This implementation obtains the headers from
 1888        * the <code>headers</code> InternetHeaders object.
 1889        *
 1890        * @exception  MessagingException
 1891        */
 1892       public Enumeration getMatchingHeaders(String[] names)
 1893   			throws MessagingException {
 1894   	return headers.getMatchingHeaders(names);
 1895       }
 1896   
 1897       /**
 1898        * Return non-matching headers from this Message as an
 1899        * Enumeration of Header objects. This implementation 
 1900        * obtains the header from the <code>headers</code> InternetHeaders object.
 1901        *
 1902        * @exception  MessagingException
 1903        */
 1904       public Enumeration getNonMatchingHeaders(String[] names)
 1905   			throws MessagingException {
 1906   	return headers.getNonMatchingHeaders(names);
 1907       }
 1908   
 1909       /**
 1910        * Add a raw RFC 822 header-line. 
 1911        *
 1912        * @exception	IllegalWriteException if the underlying
 1913        *			implementation does not support modification
 1914        * @exception	IllegalStateException if this message is
 1915        *			obtained from a READ_ONLY folder.
 1916        * @exception  	MessagingException
 1917        */
 1918       public void addHeaderLine(String line) throws MessagingException {
 1919   	headers.addHeaderLine(line);
 1920       }
 1921   
 1922       /**
 1923        * Get all header lines as an Enumeration of Strings. A Header
 1924        * line is a raw RFC 822 header-line, containing both the "name" 
 1925        * and "value" field. 
 1926        *
 1927        * @exception  	MessagingException
 1928        */
 1929       public Enumeration getAllHeaderLines() throws MessagingException {
 1930   	return headers.getAllHeaderLines();
 1931       }
 1932   
 1933       /**
 1934        * Get matching header lines as an Enumeration of Strings. 
 1935        * A Header line is a raw RFC 822 header-line, containing both 
 1936        * the "name" and "value" field.
 1937        *
 1938        * @exception  	MessagingException
 1939        */
 1940       public Enumeration getMatchingHeaderLines(String[] names)
 1941                                           throws MessagingException {
 1942   	return headers.getMatchingHeaderLines(names);
 1943       }
 1944   
 1945       /**
 1946        * Get non-matching header lines as an Enumeration of Strings. 
 1947        * A Header line is a raw RFC 822 header-line, containing both 
 1948        * the "name" and "value" field.
 1949        *
 1950        * @exception  	MessagingException
 1951        */
 1952       public Enumeration getNonMatchingHeaderLines(String[] names)
 1953                                           throws MessagingException {
 1954   	return headers.getNonMatchingHeaderLines(names);
 1955       }
 1956   
 1957       /**
 1958        * Return a <code>Flags</code> object containing the flags for 
 1959        * this message. <p>
 1960        *
 1961        * Note that a clone of the internal Flags object is returned, so
 1962        * modifying the returned Flags object will not affect the flags
 1963        * of this message.
 1964        *
 1965        * @return          Flags object containing the flags for this message
 1966        * @exception  	MessagingException
 1967        * @see 		javax.mail.Flags
 1968        */
 1969       public synchronized Flags getFlags() throws MessagingException {
 1970   	return (Flags)flags.clone();
 1971       }
 1972   
 1973       /**
 1974        * Check whether the flag specified in the <code>flag</code>
 1975        * argument is set in this message. <p>
 1976        *
 1977        * This implementation checks this message's internal 
 1978        * <code>flags</code> object.
 1979        *
 1980        * @param flag	the flag
 1981        * @return		value of the specified flag for this message
 1982        * @see 		javax.mail.Flags.Flag
 1983        * @see		javax.mail.Flags.Flag#ANSWERED
 1984        * @see		javax.mail.Flags.Flag#DELETED
 1985        * @see		javax.mail.Flags.Flag#DRAFT
 1986        * @see		javax.mail.Flags.Flag#FLAGGED
 1987        * @see		javax.mail.Flags.Flag#RECENT
 1988        * @see		javax.mail.Flags.Flag#SEEN
 1989        * @exception       MessagingException
 1990        */
 1991       public synchronized boolean isSet(Flags.Flag flag)
 1992   				throws MessagingException {
 1993   	return (flags.contains(flag));
 1994       }
 1995   
 1996       /**
 1997        * Set the flags for this message. <p>
 1998        *
 1999        * This implementation modifies the <code>flags</code> field.
 2000        *
 2001        * @exception	IllegalWriteException if the underlying
 2002        *			implementation does not support modification
 2003        * @exception	IllegalStateException if this message is
 2004        *			obtained from a READ_ONLY folder.
 2005        * @exception  	MessagingException
 2006        */
 2007       public synchronized void setFlags(Flags flag, boolean set)
 2008   			throws MessagingException {
 2009   	if (set)
 2010   	    flags.add(flag);
 2011   	else
 2012   	    flags.remove(flag);
 2013       }
 2014   
 2015       /**
 2016        * Updates the appropriate header fields of this message to be
 2017        * consistent with the message's contents. If this message is
 2018        * contained in a Folder, any changes made to this message are
 2019        * committed to the containing folder. <p>
 2020        *
 2021        * If any part of a message's headers or contents are changed,
 2022        * <code>saveChanges</code> must be called to ensure that those
 2023        * changes are permanent. Otherwise, any such modifications may or 
 2024        * may not be saved, depending on the folder implementation. <p>
 2025        *
 2026        * Messages obtained from folders opened READ_ONLY should not be
 2027        * modified and saveChanges should not be called on such messages. <p>
 2028        *
 2029        * This method sets the <code>modified</code> flag to true, the
 2030        * <code>save</code> flag to true, and then calls the
 2031        * <code>updateHeaders<code> method.
 2032        *
 2033        * @exception	IllegalWriteException if the underlying
 2034        *			implementation does not support modification
 2035        * @exception	IllegalStateException if this message is
 2036        *			obtained from a READ_ONLY folder.
 2037        * @exception  	MessagingException
 2038        */
 2039       public void saveChanges() throws MessagingException {
 2040   	modified = true;
 2041   	saved = true;
 2042   	updateHeaders();
 2043       }
 2044   
 2045       /**
 2046        * Update the Message-ID header.  This method is called
 2047        * by the <code>updateHeaders</code> and allows a subclass
 2048        * to override only the algorithm for choosing a Message-ID.
 2049        *
 2050        * @since		JavaMail 1.4
 2051        */
 2052       protected void updateMessageID() throws MessagingException {
 2053   	setHeader("Message-ID", 
 2054   		  "<" + UniqueValue.getUniqueMessageIDValue(session) + ">");
 2055             
 2056       }	
 2057   
 2058       /**
 2059        * Called by the <code>saveChanges</code> method to actually
 2060        * update the MIME headers.  The implementation here sets the
 2061        * <code>Content-Transfer-Encoding</code> header (if needed
 2062        * and not already set), the <code>MIME-Version</code> header
 2063        * and the <code>Message-ID</code> header. Also, if the content
 2064        * of this message is a <code>MimeMultipart</code>, it's 
 2065        * <code>updateHeaders</code> method is called.
 2066        *
 2067        * @exception	IllegalWriteException if the underlying
 2068        *			implementation does not support modification
 2069        * @exception	IllegalStateException if this message is
 2070        *			obtained from a READ_ONLY folder.
 2071        * @exception  	MessagingException
 2072        */
 2073       protected void updateHeaders() throws MessagingException {
 2074   	MimeBodyPart.updateHeaders(this);	
 2075   	setHeader("MIME-Version", "1.0");
 2076           updateMessageID();
 2077   
 2078   	/*
 2079   	 * If we've cached a Multipart or Message object then
 2080   	 * we're now committed to using this instance of the
 2081   	 * object and we discard any stream data used to create
 2082   	 * this object.
 2083   	 */
 2084   	if (cachedContent != null) {
 2085   	    dh = new DataHandler(cachedContent, getContentType());
 2086   	    cachedContent = null;
 2087   	    content = null;
 2088   	    if (contentStream != null) {
 2089   		try {
 2090   		    contentStream.close();
 2091   		} catch (IOException ioex) { }	// nothing to do
 2092   	    }
 2093   	    contentStream = null;
 2094   	}
 2095       }
 2096   
 2097       /**
 2098        * Create and return an InternetHeaders object that loads the
 2099        * headers from the given InputStream.  Subclasses can override
 2100        * this method to return a subclass of InternetHeaders, if
 2101        * necessary.  This implementation simply constructs and returns
 2102        * an InternetHeaders object.
 2103        *
 2104        * @param	is	the InputStream to read the headers from
 2105        * @exception  	MessagingException
 2106        * @since		JavaMail 1.2
 2107        */
 2108       protected InternetHeaders createInternetHeaders(InputStream is)
 2109   				throws MessagingException {
 2110   	return new InternetHeaders(is);
 2111       }
 2112   
 2113       /**
 2114        * Create and return a MimeMessage object.  The reply method
 2115        * uses this method to create the MimeMessage object that it
 2116        * will return.  Subclasses can override this method to return
 2117        * a subclass of MimeMessage.  This implementation simply constructs
 2118        * and returns a MimeMessage object using the supplied Session.
 2119        *
 2120        * @param	session	the Session to use for the new message
 2121        * @return		the new MimeMessage object
 2122        * @since		JavaMail 1.4
 2123        */
 2124       protected MimeMessage createMimeMessage(Session session)
 2125   				throws MessagingException {
 2126   	return new MimeMessage(session);
 2127       }
 2128   }

Save This Page
Home » glassfish-v2ur2-b04-src » javax » mail » internet » [javadoc | source]