gt: 	    if (!subject.regionMatches(true, 0, "Re: ", 0, 4))
context: /*
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   *
   * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
   *
   * The contents of this file are subject to the terms of either the GNU
   * General Public License Version 2 only ("GPL") or the Common Development
   * and Distribution License("CDDL") (collectively, the "License").  You
   * may not use this file except in compliance with the License. You can obtain
   * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
   * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
   * language governing permissions and limitations under the License.
   *
   * When distributing the software, include this License Header Notice in each
   * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
   * Sun designates this particular file as subject to the "Classpath" exception
   * as provided by Sun in the GPL Version 2 section of the License file that
   * accompanied this code.  If applicable, add the following below the License
   * Header, with the fields enclosed by brackets [] replaced by your own
   * identifying information: "Portions Copyrighted [year]
   * [name of copyright owner]"
   *
   * Contributor(s):
   *
   * If you wish your version of this file to be governed by only the CDDL or
   * only the GPL Version 2, indicate your decision by adding "[Contributor]
   * elects to include this software in this distribution under the [CDDL or GPL
   * Version 2] license."  If you don't indicate a single choice of license, a
   * recipient has the option to distribute your version of this file under
   * either the CDDL, the GPL Version 2 or to extend the choice of license to
   * its licensees as provided above.  However, if you add GPL Version 2 code
   * and therefore, elected the GPL Version 2 license, then the option applies
   * only if the new code is made subject to such option by the copyright
   * holder.
   */
  
  /*
   * @(#)MimeMessage.java	1.95 07/05/14
   */
  
  package javax.mail.internet;
  
  import javax.mail.*;
  import javax.activation.*;
  import java.lang.*;
  import java.io.*;
  import java.util.*;
  import java.text.ParseException;
  import com.sun.mail.util.*;
  import javax.mail.util.SharedByteArrayInputStream;
  
  /**
   * This class represents a MIME style email message. It implements
   * the <code>Message</code> abstract class and the <code>MimePart</code>
   * interface. <p>
   *
   * Clients wanting to create new MIME style messages will instantiate
   * an empty MimeMessage object and then fill it with appropriate 
   * attributes and content. <p>
   * 
   * Service providers that implement MIME compliant backend stores may
   * want to subclass MimeMessage and override certain methods to provide
   * specific implementations. The simplest case is probably a provider
   * that generates a MIME style input stream and leaves the parsing of
   * the stream to this class. <p>
   *
   * MimeMessage uses the <code>InternetHeaders</code> class to parse and
   * store the top level RFC 822 headers of a message. <p>
   *
   * The <code>mail.mime.address.strict</code> session property controls
   * the parsing of address headers.  By default, strict parsing of address
   * headers is done.  If this property is set to <code>"false"</code>,
   * strict parsing is not done and many illegal addresses that sometimes
   * occur in real messages are allowed.  See the <code>InternetAddress</code>
   * class for details. <p>
   *
   * <hr><strong>A note on RFC 822 and MIME headers</strong><p>
   *
   * RFC 822 header fields <strong>must</strong> contain only 
   * US-ASCII characters. MIME allows non ASCII characters to be present
   * in certain portions of certain headers, by encoding those characters.
   * RFC 2047 specifies the rules for doing this. The MimeUtility
   * class provided in this package can be used to to achieve this.
   * Callers of the <code>setHeader</code>, <code>addHeader</code>, and
   * <code>addHeaderLine</code> methods are responsible for enforcing
   * the MIME requirements for the specified headers.  In addition, these
   * header fields must be folded (wrapped) before being sent if they
   * exceed the line length limitation for the transport (1000 bytes for
   * SMTP).  Received headers may have been folded.  The application is
   * responsible for folding and unfolding headers as appropriate. <p>
   *
   * @author John Mani
   * @author Bill Shannon
   * @author Max Spivak
   * @author Kanwar Oberoi
   * @see	javax.mail.internet.MimeUtility
   * @see	javax.mail.Part
   * @see	javax.mail.Message
   * @see	javax.mail.internet.MimePart
   * @see	javax.mail.internet.InternetAddress
   */
  
  public class MimeMessage extends Message implements MimePart {
  
      /**
       * The DataHandler object representing this Message's content.
       */
      protected DataHandler dh;
  
      /**
       * Byte array that holds the bytes of this Message's content.
       */
      protected byte[] content;
  
      /**
       * If the data for this message was supplied by an
       * InputStream that implements the SharedInputStream interface,
       * <code>contentStream</code> is another such stream representing
       * the content of this message.  In this case, <code>content</code>
       * will be null.
       *
       * @since	JavaMail 1.2
       */
      protected InputStream contentStream;
  
      /**
       * The InternetHeaders object that stores the header
       * of this message.
       */
      protected InternetHeaders headers;
  
      /**
       * The Flags for this message. 
       */
      protected Flags flags;
  
      /**
       * A flag indicating whether the message has been modified.
       * If the message has not been modified, any data in the
       * <code>content</code> array is assumed to be valid and is used
       * directly in the <code>writeTo</code> method.  This flag is
       * set to true when an empty message is created or when the
       * <code>saveChanges</code> method is called.
       *
       * @since	JavaMail 1.2
       */
      protected boolean modified = false;
  
      /**
       * Does the <code>saveChanges</code> method need to be called on
       * this message?  This flag is set to false by the public constructor
       * and set to true by the <code>saveChanges</code> method.  The
       * <code>writeTo</code> method checks this flag and calls the
       * <code>saveChanges</code> method as necessary.  This avoids the
       * common mistake of forgetting to call the <code>saveChanges</code>
       * method on a newly constructed message.
       *
       * @since	JavaMail 1.2
       */
      protected boolean saved = false;
  
      /**
       * If our content is a Multipart of Message object, we save it
       * the first time it's created by parsing a stream so that changes
       * to the contained objects will not be lost.
       *
       * XXX - must have package access for MimeBodyPart.updateHeaders
       */
      Object cachedContent;
  
      // Used to parse dates
      private static MailDateFormat mailDateFormat = new MailDateFormat();
  
      // Should addresses in headers be parsed in "strict" mode?
      private boolean strict = true;
  
      /**
       * Default constructor. An empty message object is created.
       * The <code>headers</code> field is set to an empty InternetHeaders
       * object. The <code>flags</code> field is set to an empty Flags
       * object. The <code>modified</code> flag is set to true.
       */
      public MimeMessage(Session session) {
  	super(session);
  	modified = true;
  	headers = new InternetHeaders();
  	flags = new Flags();	// empty flags object
  	initStrict();
      }
  
      /**
       * Constructs a MimeMessage by reading and parsing the data from the
       * specified MIME InputStream. The InputStream will be left positioned
       * at the end of the data for the message. Note that the input stream
       * parse is done within this constructor itself. <p>
       *
       * The input stream contains an entire MIME formatted message with
       * headers and data.
       *
       * @param session	Session object for this message
       * @param is	the message input stream
       * @exception	MessagingException
       */
      public MimeMessage(Session session, InputStream is) 
  			throws MessagingException {
  	super(session);
  	flags = new Flags(); // empty Flags object
  	initStrict();
  	parse(is);
  	saved = true;
      }
  
      /**
       * Constructs a new MimeMessage with content initialized from the
       * <code>source</code> MimeMessage.  The new message is independent
       * of the original. <p>
       *
       * Note: The current implementation is rather inefficient, copying
       * the data more times than strictly necessary.
       *
       * @param	source	the message to copy content from
       * @exception	MessagingException
       * @since		JavaMail 1.2
       */
      public MimeMessage(MimeMessage source) throws MessagingException {
  	super(source.session);
  	flags = source.getFlags();
  	ByteArrayOutputStream bos;
  	int size = source.getSize();
  	if (size > 0)
  	    bos = new ByteArrayOutputStream(size);
  	else
  	    bos = new ByteArrayOutputStream();
  	try {
  	    strict = source.strict;
  	    source.writeTo(bos);
  	    bos.close();
  	    SharedByteArrayInputStream bis =
  			    new SharedByteArrayInputStream(bos.toByteArray());
  	    parse(bis);
  	    bis.close();
  	    saved = true;
  	} catch (IOException ex) {
  	    // should never happen, but just in case...
  	    throw new MessagingException("IOException while copying message",
  					    ex);
  	}
      }
  
      /**
       * Constructs an empty MimeMessage object with the given Folder
       * and message number. <p>
       *
       * This method is for providers subclassing <code>MimeMessage</code>.
       */
      protected MimeMessage(Folder folder, int msgnum) {
  	super(folder, msgnum);
  	flags = new Flags();  // empty Flags object
  	saved = true;
  	initStrict();
      }
  
      /**
       * Constructs a MimeMessage by reading and parsing the data from the
       * specified MIME InputStream. The InputStream will be left positioned
       * at the end of the data for the message. Note that the input stream
       * parse is done within this constructor itself. <p>
       *
       * This method is for providers subclassing <code>MimeMessage</code>.
       *
       * @param folder	The containing folder.
       * @param is	the message input stream
       * @param msgnum	Message number of this message within its folder
       * @exception	MessagingException
       */
      protected MimeMessage(Folder folder, InputStream is, int msgnum)
  		throws MessagingException {
  	this(folder, msgnum);
  	initStrict();
  	parse(is);
      }
  
      /**
       * Constructs a MimeMessage from the given InternetHeaders object
       * and content.
       *
       * This method is for providers subclassing <code>MimeMessage</code>.
       *
       * @param folder	The containing folder.
       * @param headers	The headers
       * @param content	The message content
       * @param msgnum	Message number of this message within its folder
       * @exception	MessagingException
       */
      protected MimeMessage(Folder folder, InternetHeaders headers,
  		byte[] content, int msgnum) throws MessagingException {
  	this(folder, msgnum);
  	this.headers = headers;
  	this.content = content;
  	initStrict();
      }
  
      /**
       * Set the strict flag based on property.
       */
      private void initStrict() {
  	if (session != null) {
  	    String s = session.getProperty("mail.mime.address.strict");
  	    strict = s == null || !s.equalsIgnoreCase("false");
  	}
      }
  
      /**
       * Parse the InputStream setting the <code>headers</code> and
       * <code>content</code> fields appropriately.  Also resets the
       * <code>modified</code> flag. <p>
       *
       * This method is intended for use by subclasses that need to
       * control when the InputStream is parsed.
       *
       * @param is	The message input stream
       * @exception	MessagingException
       */
      protected void parse(InputStream is) throws MessagingException {
  
  	if (!(is instanceof ByteArrayInputStream) &&
  	    !(is instanceof BufferedInputStream) &&
  	    !(is instanceof SharedInputStream))
  	    is = new BufferedInputStream(is);
  	
  	headers = createInternetHeaders(is);
  
  	if (is instanceof SharedInputStream) {
  	    SharedInputStream sis = (SharedInputStream)is;
  	    contentStream = sis.newStream(sis.getPosition(), -1);
  	} else {
  	    try {
  		content = ASCIIUtility.getBytes(is);
  	    } catch (IOException ioex) {
  		throw new MessagingException("IOException", ioex);
  	    }
  	}
  
  	modified = false;
      }
  
      /** 
       * Returns the value of the RFC 822 "From" header fields. If this 
       * header field is absent, the "Sender" header field is used. 
       * If the "Sender" header field is also absent, <code>null</code>
       * is returned.<p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return		Address object
       * @exception	MessagingException
       * @see	#headers
       */
      public Address[] getFrom() throws MessagingException {
  	Address[] a = getAddressHeader("From");
  	if (a == null)
  	    a = getAddressHeader("Sender");
  	
  	return a;
      }
  
      /**
       * Set the RFC 822 "From" header field. Any existing values are 
       * replaced with the given address. If address is <code>null</code>,
       * this header is removed.
       *
       * @param address	the sender of this message
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       *			of existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void setFrom(Address address) throws MessagingException {
  	if (address == null)
  	    removeHeader("From");
  	else
  	    setHeader("From", address.toString());
      }
  
      /**
       * Set the RFC 822 "From" header field using the value of the
       * <code>InternetAddress.getLocalAddress</code> method.
       *
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       *			of existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void setFrom() throws MessagingException {
  	InternetAddress me = InternetAddress.getLocalAddress(session);
  	if (me != null)
  	    setFrom(me);
  	else
  	    throw new MessagingException("No From address");
      }
  
      /**
       * Add the specified addresses to the existing "From" field. If
       * the "From" field does not already exist, it is created.
       *
       * @param addresses	the senders of this message
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       *			of existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void addFrom(Address[] addresses) throws MessagingException {
  	addAddressHeader("From", addresses);
      }
  
      /** 
       * Returns the value of the RFC 822 "Sender" header field.
       * If the "Sender" header field is absent, <code>null</code>
       * is returned.<p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return		Address object
       * @exception	MessagingException
       * @see		#headers
       * @since		JavaMail 1.3
       */
      public Address getSender() throws MessagingException {
  	Address[] a = getAddressHeader("Sender");
  	if (a == null || a.length == 0)
  	    return null;
  	return a[0];	// there can be only one
      }
  
      /**
       * Set the RFC 822 "Sender" header field. Any existing values are 
       * replaced with the given address. If address is <code>null</code>,
       * this header is removed.
       *
       * @param address	the sender of this message
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       *			of existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       * @since		JavaMail 1.3
       */
      public void setSender(Address address) throws MessagingException {
  	if (address == null)
  	    removeHeader("Sender");
  	else
  	    setHeader("Sender", address.toString());
      }
  
      /**
       * This inner class extends the javax.mail.Message.RecipientType
       * class to add additional RecipientTypes. The one additional
       * RecipientType currently defined here is NEWSGROUPS.
       *
       * @see javax.mail.Message.RecipientType
       */
      public static class RecipientType extends Message.RecipientType {
  
  	private static final long serialVersionUID = -5468290701714395543L;
  
  	/**
  	 * The "Newsgroup" (Usenet news) recipients.
  	 */
  	public static final RecipientType NEWSGROUPS =
  					new RecipientType("Newsgroups");
  	protected RecipientType(String type) {
  	    super(type);
  	}
  
  	protected Object readResolve() throws ObjectStreamException {
  	    if (type.equals("Newsgroups"))
  		return NEWSGROUPS;
  	    else
  		return super.readResolve();
  	}
      }
  
      /**
       * Returns the recepients specified by the type. The mapping
       * between the type and the corresponding RFC 822 header is
       * as follows:
       * <pre>
       *		Message.RecipientType.TO		"To"
       *		Message.RecipientType.CC		"Cc"
       *		Message.RecipientType.BCC		"Bcc"
       *		MimeMessage.RecipientType.NEWSGROUPS	"Newsgroups"
       * </pre><br>
       *
       * Returns null if the header specified by the type is not found
       * or if its value is empty. <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @param           type	Type of recepient
       * @return          array of Address objects
       * @exception       MessagingException if header could not
       *                  be retrieved
       * @exception       AddressException if the header is misformatted
       * @see		#headers
       * @see		javax.mail.Message.RecipientType#TO
       * @see		javax.mail.Message.RecipientType#CC
       * @see		javax.mail.Message.RecipientType#BCC
       * @see		javax.mail.internet.MimeMessage.RecipientType#NEWSGROUPS
       */
      public Address[] getRecipients(Message.RecipientType type)
  				throws MessagingException {
  	if (type == RecipientType.NEWSGROUPS) {
  	    String s = getHeader("Newsgroups", ",");
  	    return (s == null) ? null : NewsAddress.parse(s);
  	} else
  	    return getAddressHeader(getHeaderName(type));
      }
  
      /**
       * Get all the recipient addresses for the message.
       * Extracts the TO, CC, BCC, and NEWSGROUPS recipients.
       *
       * @return          array of Address objects
       * @exception       MessagingException
       * @see		javax.mail.Message.RecipientType#TO
       * @see		javax.mail.Message.RecipientType#CC
       * @see		javax.mail.Message.RecipientType#BCC
       * @see		javax.mail.internet.MimeMessage.RecipientType#NEWSGROUPS
       */
      public Address[] getAllRecipients() throws MessagingException {
  	Address[] all = super.getAllRecipients();
  	Address[] ng = getRecipients(RecipientType.NEWSGROUPS);
  
  	if (ng == null)
  	    return all;		// the common case
  	if (all == null)
  	    return ng;		// a rare case
  
  	Address[] addresses = new Address[all.length + ng.length];
  	System.arraycopy(all, 0, addresses, 0, all.length);
  	System.arraycopy(ng, 0, addresses, all.length, ng.length);
  	return addresses;
      }
  	
      /**
       * Set the specified recipient type to the given addresses.
       * If the address parameter is <code>null</code>, the corresponding
       * recipient field is removed.
       *
       * @param type	Recipient type
       * @param addresses	Addresses
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       *			of existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       * @see		#getRecipients
       */
      public void setRecipients(Message.RecipientType type, Address[] addresses)
                                  throws MessagingException {
  	if (type == RecipientType.NEWSGROUPS) {
  	    if (addresses == null || addresses.length == 0)
  		removeHeader("Newsgroups");
  	    else
  		setHeader("Newsgroups", NewsAddress.toString(addresses));
  	} else
  	    setAddressHeader(getHeaderName(type), addresses);
      }
  
      /**
       * Set the specified recipient type to the given addresses.
       * If the address parameter is <code>null</code>, the corresponding
       * recipient field is removed.
       *   
       * @param type      Recipient type
       * @param addresses Addresses
       * @exception       AddressException if the attempt to parse the
       *                  addresses String fails
       * @exception       IllegalWriteException if the underlying
       *                  implementation does not support modification
       *                  of existing values
       * @exception       IllegalStateException if this message is
       *                  obtained from a READ_ONLY folder.
       * @exception       MessagingException
       * @see             #getRecipients
       * @since           JavaMail 1.2
       */
      public void setRecipients(Message.RecipientType type, String addresses)
                                  throws MessagingException {
          if (type == RecipientType.NEWSGROUPS) {
              if (addresses == null || addresses.length() == 0)
                  removeHeader("Newsgroups");
              else
                  setHeader("Newsgroups", addresses);
          } else
              setAddressHeader(getHeaderName(type), InternetAddress.parse(addresses));
      }
  
      /**
       * Add the given addresses to the specified recipient type.
       *
       * @param type	Recipient type
       * @param addresses	Addresses
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       *			of existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void addRecipients(Message.RecipientType type, Address[] addresses)
                                  throws MessagingException {
  	if (type == RecipientType.NEWSGROUPS) {
  	    String s = NewsAddress.toString(addresses);
  	    if (s != null)
  		addHeader("Newsgroups", s);
  	} else
  	    addAddressHeader(getHeaderName(type), addresses);
      }
  
      /**
       * Add the given addresses to the specified recipient type.
       * 
       * @param type      Recipient type
       * @param addresses Addresses
       * @exception       AddressException if the attempt to parse the
       *                  addresses String fails
       * @exception       IllegalWriteException if the underlying
       *                  implementation does not support modification
       *                  of existing values
       * @exception       IllegalStateException if this message is
       *                  obtained from a READ_ONLY folder.
       * @exception       MessagingException
       * @since           JavaMail 1.2
       */
      public void addRecipients(Message.RecipientType type, String addresses)
                                  throws MessagingException {
          if (type == RecipientType.NEWSGROUPS) {
              if (addresses != null && addresses.length() != 0)
                  addHeader("Newsgroups", addresses);
          } else
              addAddressHeader(getHeaderName(type), InternetAddress.parse(addresses));
      }
   
      /**
       * Return the value of the RFC 822 "Reply-To" header field. If
       * this header is unavailable or its value is absent, then
       * the <code>getFrom</code> method is called and its value is returned.
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @exception	MessagingException
       * @see		#headers
       */
      public Address[] getReplyTo() throws MessagingException {
  	Address[] a = getAddressHeader("Reply-To");
  	if (a == null)
  	    a = getFrom();
  	return a;
      }
  
      /**
       * Set the RFC 822 "Reply-To" header field. If the address 
       * parameter is <code>null</code>, this header is removed.
       *
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       *			of existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void setReplyTo(Address[] addresses) throws MessagingException {
  	setAddressHeader("Reply-To", addresses);
      }
  
      // Convenience method to get addresses
      private Address[] getAddressHeader(String name) 
  			throws MessagingException {
  	String s = getHeader(name, ",");
  	return (s == null) ? null : InternetAddress.parseHeader(s, strict);
      }
  
      // Convenience method to set addresses
      private void setAddressHeader(String name, Address[] addresses)
  			throws MessagingException {
  	String s = InternetAddress.toString(addresses);
  	if (s == null)
  	    removeHeader(name);
  	else
  	    setHeader(name, s);
      }
  
      private void addAddressHeader(String name, Address[] addresses)
  			throws MessagingException {
  	String s = InternetAddress.toString(addresses);
  	if (s == null)
  	    return;
  	addHeader(name, s);
      }
  
      /**
       * Returns the value of the "Subject" header field. Returns null 
       * if the subject field is unavailable or its value is absent. <p>
       *
       * If the subject is encoded as per RFC 2047, it is decoded and
       * converted into Unicode. If the decoding or conversion fails, the
       * raw data is returned as is. <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return          Subject
       * @exception	MessagingException
       * @see		#headers
       */
      public String getSubject() throws MessagingException {
  	String rawvalue = getHeader("Subject", null);
  
  	if (rawvalue == null)
  	    return null;
  
  	try {
  	    return MimeUtility.decodeText(MimeUtility.unfold(rawvalue));
  	} catch (UnsupportedEncodingException ex) {
  	    return rawvalue;
  	}
      }
  
      /**
       * Set the "Subject" header field. If the subject contains 
       * non US-ASCII characters, it will be encoded using the 
       * platform's default charset. If the subject contains only 
       * US-ASCII characters, no encoding is done and it is used 
       * as-is. If the subject is null, the existing "Subject" field
       * is removed. <p>
       *
       * The application must ensure that the subject does not contain
       * any line breaks. <p>
       *
       * Note that if the charset encoding process fails, a
       * MessagingException is thrown, and an UnsupportedEncodingException
       * is included in the chain of nested exceptions within the
       * MessagingException.
       *
       * @param 	subject		The subject
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       *			of existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException. An
       * 			UnsupportedEncodingException may be included
       *			in the exception chain if the charset
       *			conversion fails.
       */
      public void setSubject(String subject) throws MessagingException {
  	setSubject(subject, null);
      }
  
      /**
       * Set the "Subject" header field. If the subject contains non 
       * US-ASCII characters, it will be encoded using the specified
       * charset. If the subject contains only US-ASCII characters, no 
       * encoding is done and it is used as-is. If the subject is null, 
       * the existing "Subject" header field is removed. <p>
       *
       * The application must ensure that the subject does not contain
       * any line breaks. <p>
       *
       * Note that if the charset encoding process fails, a
       * MessagingException is thrown, and an UnsupportedEncodingException
       * is included in the chain of nested exceptions within the
       * MessagingException.
       *
       * @param	subject		The subject
       * @param	charset		The charset 
       * @exception		IllegalWriteException if the underlying
       *				implementation does not support modification
       *				of existing values
       * @exception		IllegalStateException if this message is
       *				obtained from a READ_ONLY folder.
       * @exception		MessagingException. An
       * 				UnsupportedEncodingException may be included
       *				in the exception chain if the charset
       *				conversion fails.
       */
      public void setSubject(String subject, String charset)
  			throws MessagingException {
  	if (subject == null) {
  	    removeHeader("Subject");
  	} else {
  	    try {
  		setHeader("Subject", MimeUtility.fold(9,
  		    MimeUtility.encodeText(subject, charset, null)));
  	    } catch (UnsupportedEncodingException uex) {
  		throw new MessagingException("Encoding error", uex);
  	    }
  	}
      }
  
      /**
       * Returns the value of the RFC 822 "Date" field. This is the date 
       * on which this message was sent. Returns null if this field is 
       * unavailable or its value is absent. <p>
       * 
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return          The sent Date
       * @exception	MessagingException
       */
      public Date getSentDate() throws MessagingException {
  	String s = getHeader("Date", null);
  	if (s != null) {
  	    try {
  		synchronized (mailDateFormat) {
  		    return mailDateFormat.parse(s);
  		}
  	    } catch (ParseException pex) {
  		return null;
  	    }
  	}
  	
  	return null;
      }
  
      /**
       * Set the RFC 822 "Date" header field. This is the date on which the
       * creator of the message indicates that the message is complete
       * and ready for delivery. If the date parameter is 
       * <code>null</code>, the existing "Date" field is removed.
       *
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void setSentDate(Date d) throws MessagingException {
  	if (d == null)
  	    removeHeader("Date");
  	else {
  	    synchronized (mailDateFormat) {
  		setHeader("Date", mailDateFormat.format(d));
  	    }
  	}
      }
  
      /**
       * Returns the Date on this message was received. Returns 
       * <code>null</code> if this date cannot be obtained. <p>
       *
       * Note that RFC 822 does not define a field for the received
       * date. Hence only implementations that can provide this date
       * need return a valid value. <p>
       *
       * This implementation returns <code>null</code>.
       *
       * @return          the date this message was received
       * @exception	MessagingException
       */
      public Date getReceivedDate() throws MessagingException {
  	return null;	
      }
  
      /**
       * Return the size of the content of this message in bytes. 
       * Return -1 if the size cannot be determined. <p>
       *
       * Note that this number may not be an exact measure of the
       * content size and may or may not account for any transfer
       * encoding of the content. <p>
       *
       * This implementation returns the size of the <code>content</code>
       * array (if not null), or, if <code>contentStream</code> is not
       * null, and the <code>available</code> method returns a positive
       * number, it returns that number as the size.  Otherwise, it returns
       * -1.
       *
       * @return          size of content in bytes
       * @exception	MessagingException
       */  
      public int getSize() throws MessagingException {
  	if (content != null)
  	    return content.length;
  	if (contentStream != null) {
  	    try {
  		int size = contentStream.available();
  		// only believe the size if it's greater than zero, since zero
  		// is the default returned by the InputStream class itself
  		if (size > 0)
  		    return size;
  	    } catch (IOException ex) {
  		// ignore it
  	    }
  	}
  	return -1;
      }
  
      /**
       * Return the number of lines for the content of this message.
       * Return -1 if this number cannot be determined. <p>
       *
       * Note that this number may not be an exact measure of the 
       * content length and may or may not account for any transfer 
       * encoding of the content. <p>
       *
       * This implementation returns -1.
       *
       * @return          number of lines in the content.
       * @exception	MessagingException
       */  
       public int getLineCount() throws MessagingException {
  	return -1;
       }
  
      /**
       * Returns the value of the RFC 822 "Content-Type" header field. 
       * This represents the content-type of the content of this 
       * message. This value must not be null. If this field is 
       * unavailable, "text/plain" should be returned. <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return          The ContentType of this part
       * @exception	MessagingException
       * @see             javax.activation.DataHandler
       */
      public String getContentType() throws MessagingException {
  	String s = getHeader("Content-Type", null);
  	if (s == null)
  	    return "text/plain";
  	return s;
      }
  
      /**
       * Is this Part of the specified MIME type?  This method
       * compares <strong>only the <code>primaryType</code> and 
       * <code>subType</code></strong>.
       * The parameters of the content types are ignored. <p>
       *
       * For example, this method will return <code>true</code> when
       * comparing a Part of content type <strong>"text/plain"</strong>
       * with <strong>"text/plain; charset=foobar"</strong>. <p>
       *
       * If the <code>subType</code> of <code>mimeType</code> is the
       * special character '*', then the subtype is ignored during the
       * comparison.
       */
      public boolean isMimeType(String mimeType) throws MessagingException {
  	return MimeBodyPart.isMimeType(this, mimeType);
      }
  
      /**
       * Returns the value of the "Content-Disposition" header field.
       * This represents the disposition of this part. The disposition
       * describes how the part should be presented to the user. <p>
       *
       * If the Content-Disposition field is unavailable, 
       * <code>null</code> is returned. <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return          disposition of this part, or null if unknown
       * @exception	MessagingException
       */
      public String getDisposition() throws MessagingException {
  	return MimeBodyPart.getDisposition(this);
      }
  
      /**
       * Set the "Content-Disposition" header field of this Message.
       * If <code>disposition</code> is null, any existing "Content-Disposition"
       * header field is removed.
       *
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void setDisposition(String disposition) throws MessagingException {
  	MimeBodyPart.setDisposition(this, disposition);
      }
  
      /**
       * Returns the content transfer encoding from the
       * "Content-Transfer-Encoding" header
       * field. Returns <code>null</code> if the header is unavailable
       * or its value is absent. <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return          content-transfer-encoding
       * @exception	MessagingException
       */
      public String getEncoding() throws MessagingException {
  	return MimeBodyPart.getEncoding(this);
      }
  
      /**
       * Returns the value of the "Content-ID" header field. Returns
       * <code>null</code> if the field is unavailable or its value is 
       * absent. <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return          content-ID
       * @exception	MessagingException
       */
      public String getContentID() throws MessagingException {
  	return getHeader("Content-Id", null);
      }
  
      /**
       * Set the "Content-ID" header field of this Message.
       * If the <code>cid</code> parameter is null, any existing 
       * "Content-ID" is removed.
       *
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void setContentID(String cid) throws MessagingException {
  	if (cid == null)
  	    removeHeader("Content-ID");
  	else
  	    setHeader("Content-ID", cid);
      }
  
      /**
       * Return the value of the "Content-MD5" header field. Returns 
       * <code>null</code> if this field is unavailable or its value
       * is absent. <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return          content-MD5
       * @exception	MessagingException
       */
      public String getContentMD5() throws MessagingException {
  	return getHeader("Content-MD5", null);
      }
  
      /**
       * Set the "Content-MD5" header field of this Message.
       *
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException
       */
      public void setContentMD5(String md5) throws MessagingException {
  	setHeader("Content-MD5", md5);
      }
  
      /**
       * Returns the "Content-Description" header field of this Message.
       * This typically associates some descriptive information with 
       * this part. Returns null if this field is unavailable or its
       * value is absent. <p>
       *
       * If the Content-Description field is encoded as per RFC 2047,
       * it is decoded and converted into Unicode. If the decoding or 
       * conversion fails, the raw data is returned as-is <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       * 
       * @return	content-description
       * @exception	MessagingException
       */
      public String getDescription() throws MessagingException {
  	return MimeBodyPart.getDescription(this);
      }
  
      /**
       * Set the "Content-Description" header field for this Message.
       * If the description parameter is <code>null</code>, then any 
       * existing "Content-Description" fields are removed. <p>
       *
       * If the description contains non US-ASCII characters, it will 
       * be encoded using the platform's default charset. If the 
       * description contains only US-ASCII characters, no encoding 
       * is done and it is used as-is. <p>
       *
       * Note that if the charset encoding process fails, a
       * MessagingException is thrown, and an UnsupportedEncodingException
       * is included in the chain of nested exceptions within the
       * MessagingException.
       * 
       * @param description content-description
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception	MessagingException. An
       * 			UnsupportedEncodingException may be included
       *			in the exception chain if the charset
       *			conversion fails.
       */
      public void setDescription(String description) throws MessagingException {
  	setDescription(description, null);
      }
  
      /**
       * Set the "Content-Description" header field for this Message.
       * If the description parameter is <code>null</code>, then any 
       * existing "Content-Description" fields are removed. <p>
       *
       * If the description contains non US-ASCII characters, it will 
       * be encoded using the specified charset. If the description 
       * contains only US-ASCII characters, no encoding  is done and 
       * it is used as-is. <p>
       *
       * Note that if the charset encoding process fails, a
       * MessagingException is thrown, and an UnsupportedEncodingException
       * is included in the chain of nested exceptions within the
       * MessagingException.
       * 
       * @param	description	Description
       * @param	charset		Charset for encoding
       * @exception		IllegalWriteException if the underlying
       *				implementation does not support modification
       * @exception		IllegalStateException if this message is
       *				obtained from a READ_ONLY folder.
       * @exception		MessagingException. An
       * 				UnsupportedEncodingException may be included
       *				in the exception chain if the charset
       *				conversion fails.
       */
      public void setDescription(String description, String charset) 
  		throws MessagingException {
  	MimeBodyPart.setDescription(this, description, charset);
      }
  
      /**
       * Get the languages specified in the "Content-Language" header
       * field of this message. The Content-Language header is defined by
       * RFC 1766. Returns <code>null</code> if this field is unavailable
       * or its value is absent. <p>
       *
       * This implementation uses the <code>getHeader</code> method
       * to obtain the requisite header field.
       *
       * @return			value of content-language header.
       * @exception		MessagingException
       */
      public String[] getContentLanguage() throws MessagingException {
  	return MimeBodyPart.getContentLanguage(this);
      }
  
      /**
       * Set the "Content-Language" header of this MimePart. The
       * Content-Language header is defined by RFC 1766.
       *
       * @param languages 	array of language tags
       * @exception		IllegalWriteException if the underlying
       *				implementation does not support modification
       * @exception		IllegalStateException if this message is
       *				obtained from a READ_ONLY folder.
       * @exception		MessagingException
       */
      public void setContentLanguage(String[] languages)
  			throws MessagingException {
  	MimeBodyPart.setContentLanguage(this, languages);
      }
  
      /**
       * Returns the value of the "Message-ID" header field. Returns
       * null if this field is unavailable or its value is absent. <p>
       *
       * The default implementation provided here uses the
       * <code>getHeader</code> method to return the value of the
       * "Message-ID" field.
       *
       * @return     Message-ID
       * @exception  MessagingException if the retrieval of this field
       *			causes any exception.
       * @see        javax.mail.search.MessageIDTerm
       * @since 	   JavaMail 1.1
       */
      public String getMessageID() throws MessagingException {
  	return getHeader("Message-ID", null);
      }
  
      /**
       * Get the filename associated with this Message. <p>
       *
       * Returns the value of the "filename" parameter from the
       * "Content-Disposition" header field of this message. If it's
       * not available, returns the value of the "name" parameter from
       * the "Content-Type" header field of this BodyPart.
       * Returns <code>null</code> if both are absent. <p>
       *
       * If the <code>mail.mime.encodefilename</code> System property
       * is set to true, the {@link MimeUtility#decodeText
       * MimeUtility.decodeText} method will be used to decode the
       * filename.  While such encoding is not supported by the MIME
       * spec, many mailers use this technique to support non-ASCII
       * characters in filenames.  The default value of this property
       * is false.
       *
       * @return	filename
       * @exception		MessagingException
       */
      public String getFileName() throws MessagingException {
  	return MimeBodyPart.getFileName(this);
      }
  
      /**
       * Set the filename associated with this part, if possible. <p>
       *
       * Sets the "filename" parameter of the "Content-Disposition"
       * header field of this message. <p>
       *
       * If the <code>mail.mime.encodefilename</code> System property
       * is set to true, the {@link MimeUtility#encodeText
       * MimeUtility.encodeText} method will be used to encode the
       * filename.  While such encoding is not supported by the MIME
       * spec, many mailers use this technique to support non-ASCII
       * characters in filenames.  The default value of this property
       * is false.
       *
       * @exception		IllegalWriteException if the underlying
       *				implementation does not support modification
       * @exception		IllegalStateException if this message is
       *				obtained from a READ_ONLY folder.
       * @exception		MessagingException
       */
      public void setFileName(String filename) throws MessagingException {
  	MimeBodyPart.setFileName(this, filename);	
      }
  
      private String getHeaderName(Message.RecipientType type)
  				throws MessagingException {
  	String headerName;
  
  	if (type == Message.RecipientType.TO)
  	    headerName = "To";
  	else if (type == Message.RecipientType.CC)
  	    headerName = "Cc";
  	else if (type == Message.RecipientType.BCC)
  	    headerName = "Bcc";
  	else if (type == MimeMessage.RecipientType.NEWSGROUPS)
  	    headerName = "Newsgroups";
  	else
  	    throw new MessagingException("Invalid Recipient Type");
  	return headerName;
      }
  
  
      /**
       * Return a decoded input stream for this Message's "content". <p>
       *
       * This implementation obtains the input stream from the DataHandler,
       * that is, it invokes <code>getDataHandler().getInputStream()</code>.
       *
       * @return 		an InputStream
       * @exception	MessagingException
       * @exception       IOException this is typically thrown by the
       *			DataHandler. Refer to the documentation for
       *			javax.activation.DataHandler for more details.
       *
       * @see	#getContentStream
       * @see 	javax.activation.DataHandler#getInputStream
       */
      public InputStream getInputStream() 
  		throws IOException, MessagingException {
  	return getDataHandler().getInputStream();
      }
  
      /**
       * Produce the raw bytes of the content. This method is used during
       * parsing, to create a DataHandler object for the content. Subclasses
       * that can provide a separate input stream for just the message 
       * content might want to override this method. <p>
       *
       * This implementation returns a SharedInputStream, if
       * <code>contentStream</code> is not null.  Otherwise, it
       * returns a ByteArrayInputStream constructed
       * out of the <code>content</code> byte array.
       *
       * @see #content
       */
      protected InputStream getContentStream() throws MessagingException {
  	if (contentStream != null)
  	    return ((SharedInputStream)contentStream).newStream(0, -1);
  	if (content != null)
  	    return new SharedByteArrayInputStream(content);
  
  	throw new MessagingException("No content");
      }
  
      /**
       * Return an InputStream to the raw data with any Content-Transfer-Encoding
       * intact.  This method is useful if the "Content-Transfer-Encoding"
       * header is incorrect or corrupt, which would prevent the
       * <code>getInputStream</code> method or <code>getContent</code> method
       * from returning the correct data.  In such a case the application may
       * use this method and attempt to decode the raw data itself. <p>
       *
       * This implementation simply calls the <code>getContentStream</code>
       * method.
       *
       * @see	#getInputStream
       * @see	#getContentStream
       * @since	JavaMail 1.2
       */
      public InputStream getRawInputStream() throws MessagingException {
  	return getContentStream();
      }
  
      /**                                                            
       * Return a DataHandler for this Message's content. <p>
       *
       * The implementation provided here works as follows. Note the use of 
       * the <code>getContentStream</code> method to 
       * generate the byte stream for the content. Also note that
       * any transfer-decoding is done automatically within this method.<p>
       *
       * <blockquote><pre>
       *  getDataHandler() {
       *      if (dh == null) {
       *          dh = new DataHandler(new MimePartDataSource(this));
       *      }
       *      return dh;
       *  }
       *  <p>
       *  class MimePartDataSource implements DataSource {
       *      public getInputStream() {
       *          return MimeUtility.decode(
       *		     getContentStream(), getEncoding());
       *      }
       *	
       *		.... <other DataSource methods>
       *  }
       * </pre></blockquote><p>
       *
       * @exception	MessagingException
       */
      public synchronized DataHandler getDataHandler() 
  		throws MessagingException {
  	if (dh == null)
  	    dh = new DataHandler(new MimePartDataSource(this));
  	return dh;
      }
  
      /**
       * Return the content as a Java object. The type of this
       * object is dependent on the content itself. For 
       * example, the native format of a "text/plain" content
       * is usually a String object. The native format for a "multipart"
       * message is always a Multipart subclass. For content types that are
       * unknown to the DataHandler system, an input stream is returned
       * as the content. <p>
       *
       * This implementation obtains the content from the DataHandler,
       * that is, it invokes <code>getDataHandler().getContent()</code>.
       * If the content is a Multipart or Message object and was created by
       * parsing a stream, the object is cached and returned in subsequent
       * calls so that modifications to the content will not be lost.
       *
       * @return          Object
       * @see		javax.mail.Part
       * @see 		javax.activation.DataHandler#getContent
       * @exception       MessagingException
       * @exception       IOException this is typically thrown by the
       *			DataHandler. Refer to the documentation for
       *			javax.activation.DataHandler for more details.
       */
      public Object getContent() throws IOException, MessagingException {
  	if (cachedContent != null)
  	    return cachedContent;
  	Object c;
  	try {
  	    c = getDataHandler().getContent();
  	} catch (FolderClosedIOException fex) {
  	    throw new FolderClosedException(fex.getFolder(), fex.getMessage());
  	} catch (MessageRemovedIOException mex) {
  	    throw new MessageRemovedException(mex.getMessage());
  	}
  	if (MimeBodyPart.cacheMultipart &&
  		(c instanceof Multipart || c instanceof Message) &&
  		(content != null || contentStream != null)) {
  	    cachedContent = c;
  	}
  	return c;
      }
  
      /**
       * This method provides the mechanism to set this part's content.
       * The given DataHandler object should wrap the actual content.
       *
       * @param   dh      The DataHandler for the content.
       * @exception	IllegalWriteException if the underlying
       *			implementation does not support modification
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception       MessagingException
       */
      public synchronized void setDataHandler(DataHandler dh) 
  		throws MessagingException {
  	this.dh = dh;
  	cachedContent = null;
  	MimeBodyPart.invalidateContentHeaders(this);
      }
  
      /**
       * A convenience method for setting this Message's content. <p>
       *
       * The content is wrapped in a DataHandler object. Note that a
       * DataContentHandler class for the specified type should be
       * available to the JavaMail implementation for this to work right.
       * i.e., to do <code>setContent(foobar, "application/x-foobar")</code>,
       * a DataContentHandler for "application/x-foobar" should be installed.
       * Refer to the Java Activation Framework for more information.
       *
       * @param	o	the content object
       * @param	type	Mime type of the object
       * @exception       IllegalWriteException if the underlying
       *			implementation does not support modification of
       *			existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception       MessagingException
       */
      public void setContent(Object o, String type) 
  			throws MessagingException {
  	if (o instanceof Multipart)
  	    setContent((Multipart)o);
  	else
  	    setDataHandler(new DataHandler(o, type));
      }
  
      /**
       * Convenience method that sets the given String as this
       * part's content, with a MIME type of "text/plain". If the
       * string contains non US-ASCII characters. it will be encoded
       * using the platform's default charset. The charset is also
       * used to set the "charset" parameter.<p>
       *
       * Note that there may be a performance penalty if
       * <code>text</code> is large, since this method may have
       * to scan all the characters to determine what charset to
       * use. <p>
       *
       * If the charset is already known, use the
       * <code>setText</code> method that takes the charset parameter.
       *
       * @param	text	the text content to set
       * @exception	MessagingException	if an error occurs
       * @see	#setText(String text, String charset)
       */
      public void setText(String text) throws MessagingException {
  	setText(text, null);
      }
  
      /**
       * Convenience method that sets the given String as this part's
       * content, with a MIME type of "text/plain" and the specified
       * charset. The given Unicode string will be charset-encoded
       * using the specified charset. The charset is also used to set
       * the "charset" parameter.
       *
       * @param	text	the text content to set
       * @param	charset	the charset to use for the text
       * @exception	MessagingException	if an error occurs
       */
      public void setText(String text, String charset)
  			throws MessagingException {
  	MimeBodyPart.setText(this, text, charset, "plain");
      }
  
      /**
       * Convenience method that sets the given String as this part's
       * content, with a primary MIME type of "text" and the specified
       * MIME subtype.  The given Unicode string will be charset-encoded
       * using the specified charset. The charset is also used to set
       * the "charset" parameter.
       *
       * @param	text	the text content to set
       * @param	charset	the charset to use for the text
       * @param	subtype	the MIME subtype to use (e.g., "html")
       * @exception	MessagingException	if an error occurs
       * @since	JavaMail 1.4
       */
      public void setText(String text, String charset, String subtype)
                          throws MessagingException {
  	MimeBodyPart.setText(this, text, charset, subtype);
      }
  
      /**
       * This method sets the Message's content to a Multipart object.
       *
       * @param  mp      The multipart object that is the Message's content
       * @exception       IllegalWriteException if the underlying
       *			implementation does not support modification of
       *			existing values
       * @exception	IllegalStateException if this message is
       *			obtained from a READ_ONLY folder.
       * @exception       MessagingException
       */
      public void setContent(Multipart mp) throws MessagingException {
  	setDataHandler(new DataHandler(mp, mp.getContentType()));
  	mp.setParent(this);
      }
  
      /**
       * Get a new Message suitable for a reply to this message.
       * The new Message will have its attributes and headers 
       * set up appropriately.  Note that this new message object
       * will be empty, i.e., it will <strong>not</strong> have a "content".
       * These will have to be suitably filled in by the client. <p>
       *
       * If <code>replyToAll</code> is set, the new Message will be addressed
       * to all recipients of this message.  Otherwise, the reply will be
       * addressed to only the sender of this message (using the value
       * of the <code>getReplyTo</code> method).  <p>
       *
       * The "Subject" field is filled in with the original subject
       * prefixed with "Re:" (unless it already starts with "Re:").
       * The "In-Reply-To" header is set in the new message if this
       * message has a "Message-Id" header.  The <code>ANSWERED</code>
       * flag is set in this message.
       *
       * The current implementation also sets the "References" header
       * in the new message to include the contents of the "References"
       * header (or, if missing, the "In-Reply-To" header) in this message,
       * plus the contents of the "Message-Id" header of this message,
       * as described in RFC 2822.
       *
       * @param	replyToAll	reply should be sent to all recipients
       *				of this message
       * @return		the reply Message
       * @exception	MessagingException
       */
      public Message reply(boolean replyToAll) throws MessagingException {
  	MimeMessage reply = createMimeMessage(session);
  	/*
  	 * Have to manipulate the raw Subject header so that we don't lose
  	 * any encoding information.  This is safe because "Re:" isn't
  	 * internationalized and (generally) isn't encoded.  If the entire
  	 * Subject header is encoded, prefixing it with "Re: " still leaves
  	 * a valid and correct encoded header.
  	 */
  	String subject = getHeader("Subject", null);
  	if (subject != null) {
  