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    * @(#)MimeBodyPart.java	1.67 07/05/04
   39    */
   40   
   41   package javax.mail.internet;
   42   
   43   import javax.mail;
   44   import javax.activation;
   45   import java.io;
   46   import java.util;
   47   import com.sun.mail.util;
   48   
   49   /**
   50    * This class represents a MIME body part. It implements the 
   51    * <code>BodyPart</code> abstract class and the <code>MimePart</code>
   52    * interface. MimeBodyParts are contained in <code>MimeMultipart</code>
   53    * objects. <p>
   54    *
   55    * MimeBodyPart uses the <code>InternetHeaders</code> class to parse
   56    * and store the headers of that body part. <p>
   57    *
   58    * <hr><strong>A note on RFC 822 and MIME headers</strong><p>
   59    *
   60    * RFC 822 header fields <strong>must</strong> contain only
   61    * US-ASCII characters. MIME allows non ASCII characters to be present
   62    * in certain portions of certain headers, by encoding those characters.
   63    * RFC 2047 specifies the rules for doing this. The MimeUtility
   64    * class provided in this package can be used to to achieve this.
   65    * Callers of the <code>setHeader</code>, <code>addHeader</code>, and
   66    * <code>addHeaderLine</code> methods are responsible for enforcing
   67    * the MIME requirements for the specified headers.  In addition, these
   68    * header fields must be folded (wrapped) before being sent if they
   69    * exceed the line length limitation for the transport (1000 bytes for
   70    * SMTP).  Received headers may have been folded.  The application is
   71    * responsible for folding and unfolding headers as appropriate. <p>
   72    *
   73    * @author John Mani
   74    * @author Bill Shannon
   75    * @author Kanwar Oberoi
   76    * @see javax.mail.Part
   77    * @see javax.mail.internet.MimePart
   78    * @see javax.mail.internet.MimeUtility
   79    */
   80   
   81   public class MimeBodyPart extends BodyPart implements MimePart {
   82   
   83       // Paranoia:
   84       // allow this last minute change to be disabled if it causes problems
   85       private static boolean setDefaultTextCharset = true;
   86   
   87       private static boolean setContentTypeFileName = true;
   88   
   89       private static boolean encodeFileName = false;
   90       private static boolean decodeFileName = false;
   91   
   92       // Paranoia:
   93       // allow this last minute change to be disabled if it causes problems
   94       static boolean cacheMultipart = true;	// accessed by MimeMessage
   95   
   96       static {
   97   	try {
   98   	    String s = System.getProperty("mail.mime.setdefaulttextcharset");
   99   	    // default to true
  100   	    setDefaultTextCharset = s == null || !s.equalsIgnoreCase("false");
  101   
  102   	    s = System.getProperty("mail.mime.setcontenttypefilename");
  103   	    // default to true
  104   	    setContentTypeFileName = s == null || !s.equalsIgnoreCase("false");
  105   
  106   	    s = System.getProperty("mail.mime.encodefilename");
  107   	    // default to false
  108   	    encodeFileName = s != null && !s.equalsIgnoreCase("false");
  109   
  110   	    s = System.getProperty("mail.mime.decodefilename");
  111   	    // default to false
  112   	    decodeFileName = s != null && !s.equalsIgnoreCase("false");
  113   
  114   	    s = System.getProperty("mail.mime.cachemultipart");
  115   	    // default to true
  116   	    cacheMultipart = s == null || !s.equalsIgnoreCase("false");
  117   	} catch (SecurityException sex) {
  118   	    // ignore it
  119   	}
  120       }
  121      
  122       /**
  123        * The DataHandler object representing this Part's content.
  124        */
  125       protected DataHandler dh;
  126   
  127       /**
  128        * Byte array that holds the bytes of the content of this Part.
  129        */
  130       protected byte[] content;
  131   
  132       /**
  133        * If the data for this body part was supplied by an
  134        * InputStream that implements the SharedInputStream interface,
  135        * <code>contentStream</code> is another such stream representing
  136        * the content of this body part.  In this case, <code>content</code>
  137        * will be null.
  138        *
  139        * @since	JavaMail 1.2
  140        */
  141       protected InputStream contentStream;
  142   
  143       /**
  144        * The InternetHeaders object that stores all the headers
  145        * of this body part.
  146        */
  147       protected InternetHeaders headers;
  148   
  149       /**
  150        * If our content is a Multipart of Message object, we save it
  151        * the first time it's created by parsing a stream so that changes
  152        * to the contained objects will not be lost.
  153        */
  154       private Object cachedContent;
  155   
  156       /**
  157        * An empty MimeBodyPart object is created.
  158        * This body part maybe filled in by a client constructing a multipart
  159        * message.
  160        */
  161       public MimeBodyPart() {
  162   	super();
  163   	headers = new InternetHeaders();
  164       }
  165   
  166       /**
  167        * Constructs a MimeBodyPart by reading and parsing the data from
  168        * the specified input stream. The parser consumes data till the end
  169        * of the given input stream.  The input stream must start at the
  170        * beginning of a valid MIME body part and must terminate at the end
  171        * of that body part. <p>
  172        *
  173        * Note that the "boundary" string that delimits body parts must 
  174        * <strong>not</strong> be included in the input stream. The intention 
  175        * is that the MimeMultipart parser will extract each body part's bytes
  176        * from a multipart stream and feed them into this constructor, without 
  177        * the delimiter strings.
  178        *
  179        * @param	is	the body part Input Stream
  180        */
  181       public MimeBodyPart(InputStream is) throws MessagingException {
  182   	if (!(is instanceof ByteArrayInputStream) &&
  183   	    !(is instanceof BufferedInputStream) &&
  184   	    !(is instanceof SharedInputStream))
  185   	    is = new BufferedInputStream(is);
  186   	
  187   	headers = new InternetHeaders(is);
  188   
  189   	if (is instanceof SharedInputStream) {
  190   	    SharedInputStream sis = (SharedInputStream)is;
  191   	    contentStream = sis.newStream(sis.getPosition(), -1);
  192   	} else {
  193   	    try {
  194   		content = ASCIIUtility.getBytes(is);
  195   	    } catch (IOException ioex) {
  196   		throw new MessagingException("Error reading input stream", ioex);
  197   	    }
  198   	}
  199   
  200       }
  201   
  202       /**
  203        * Constructs a MimeBodyPart using the given header and
  204        * content bytes. <p>
  205        *
  206        * Used by providers.
  207        *
  208        * @param	headers	The header of this part
  209        * @param	content	bytes representing the body of this part.
  210        */
  211       public MimeBodyPart(InternetHeaders headers, byte[] content) 
  212   			throws MessagingException {
  213   	super();
  214   	this.headers = headers;
  215   	this.content = content;
  216       }
  217   
  218       /**
  219        * Return the size of the content of this body part in bytes.
  220        * Return -1 if the size cannot be determined. <p>
  221        *
  222        * Note that this number may not be an exact measure of the
  223        * content size and may or may not account for any transfer
  224        * encoding of the content. <p>
  225        *
  226        * This implementation returns the size of the <code>content</code>
  227        * array (if not null), or, if <code>contentStream</code> is not
  228        * null, and the <code>available</code> method returns a positive
  229        * number, it returns that number as the size.  Otherwise, it returns
  230        * -1.
  231        *
  232        * @return size in bytes, or -1 if not known
  233        */
  234       public int getSize() throws MessagingException {
  235   	if (content != null)
  236   	    return content.length;
  237   	if (contentStream != null) {
  238   	    try {
  239   		int size = contentStream.available();
  240   		// only believe the size if it's greate than zero, since zero
  241   		// is the default returned by the InputStream class itself
  242   		if (size > 0)
  243   		    return size;
  244   	    } catch (IOException ex) {
  245   		// ignore it
  246   	    }
  247   	}
  248   	return -1;
  249       }
  250   
  251       /**
  252        * Return the number of lines for the content of this Part.
  253        * Return -1 if this number cannot be determined. <p>
  254        *
  255        * Note that this number may not be an exact measure of the 
  256        * content length and may or may not account for any transfer 
  257        * encoding of the content. <p>
  258        *
  259        * This implementation returns -1.
  260        *
  261        * @return number of lines, or -1 if not known
  262        */  
  263        public int getLineCount() throws MessagingException {
  264   	return -1;
  265        }
  266   
  267       /**
  268        * Returns the value of the RFC 822 "Content-Type" header field.
  269        * This represents the content type of the content of this
  270        * body part. This value must not be null. If this field is
  271        * unavailable, "text/plain" should be returned. <p>
  272        *
  273        * This implementation uses <code>getHeader(name)</code>
  274        * to obtain the requisite header field.
  275        *
  276        * @return	Content-Type of this body part
  277        */
  278       public String getContentType() throws MessagingException {
  279   	String s = getHeader("Content-Type", null);
  280   	if (s == null)
  281   	    s = "text/plain";
  282   	
  283   	return s;
  284       }
  285   
  286       /**
  287        * Is this Part of the specified MIME type?  This method
  288        * compares <strong>only the <code>primaryType</code> and 
  289        * <code>subType</code></strong>.
  290        * The parameters of the content types are ignored. <p>
  291        *
  292        * For example, this method will return <code>true</code> when
  293        * comparing a Part of content type <strong>"text/plain"</strong>
  294        * with <strong>"text/plain; charset=foobar"</strong>. <p>
  295        *
  296        * If the <code>subType</code> of <code>mimeType</code> is the
  297        * special character '*', then the subtype is ignored during the
  298        * comparison.
  299        */
  300       public boolean isMimeType(String mimeType) throws MessagingException {
  301   	return isMimeType(this, mimeType);
  302       }
  303   
  304       /**
  305        * Returns the value of the "Content-Disposition" header field.
  306        * This represents the disposition of this part. The disposition
  307        * describes how the part should be presented to the user. <p>
  308        *
  309        * If the Content-Disposition field is unavailable,
  310        * null is returned. <p>
  311        *
  312        * This implementation uses <code>getHeader(name)</code>
  313        * to obtain the requisite header field.
  314        *
  315        * @see #headers
  316        */
  317       public String getDisposition() throws MessagingException {
  318   	return getDisposition(this);
  319       }
  320   
  321       /**
  322        * Set the "Content-Disposition" header field of this body part.
  323        * If the disposition is null, any existing "Content-Disposition"
  324        * header field is removed.
  325        *
  326        * @exception	IllegalWriteException if the underlying
  327        *			implementation does not support modification
  328        * @exception	IllegalStateException if this body part is
  329        *			obtained from a READ_ONLY folder.
  330        */
  331       public void setDisposition(String disposition) throws MessagingException {
  332   	setDisposition(this, disposition);
  333       }
  334   
  335       /**
  336        * Returns the content transfer encoding from the
  337        * "Content-Transfer-Encoding" header
  338        * field. Returns <code>null</code> if the header is unavailable
  339        * or its value is absent. <p>
  340        *
  341        * This implementation uses <code>getHeader(name)</code>
  342        * to obtain the requisite header field.
  343        *
  344        * @see #headers
  345        */
  346       public String getEncoding() throws MessagingException {
  347   	return getEncoding(this);
  348       }
  349   
  350       /**
  351        * Returns the value of the "Content-ID" header field. Returns
  352        * <code>null</code> if the field is unavailable or its value is 
  353        * absent. <p>
  354        *
  355        * This implementation uses <code>getHeader(name)</code>
  356        * to obtain the requisite header field.
  357        */
  358       public String getContentID() throws MessagingException {
  359   	return getHeader("Content-Id", null);
  360       }
  361   
  362       /**
  363        * Set the "Content-ID" header field of this body part.
  364        * If the <code>cid</code> parameter is null, any existing 
  365        * "Content-ID" is removed.
  366        *
  367        * @exception	IllegalWriteException if the underlying
  368        *			implementation does not support modification
  369        * @exception	IllegalStateException if this body part is
  370        *			obtained from a READ_ONLY folder.
  371        * @exception	MessagingException
  372        * @since		JavaMail 1.3
  373        */
  374       public void setContentID(String cid) throws MessagingException {
  375   	if (cid == null)
  376   	    removeHeader("Content-ID");
  377   	else
  378   	    setHeader("Content-ID", cid);
  379       }
  380   
  381       /**
  382        * Return the value of the "Content-MD5" header field. Returns 
  383        * <code>null</code> if this field is unavailable or its value
  384        * is absent. <p>
  385        *
  386        * This implementation uses <code>getHeader(name)</code>
  387        * to obtain the requisite header field.
  388        */
  389       public String getContentMD5() throws MessagingException {
  390   	return getHeader("Content-MD5", null);
  391       }
  392   
  393       /**
  394        * Set the "Content-MD5" header field of this body part.
  395        *
  396        * @exception	IllegalWriteException if the underlying
  397        *			implementation does not support modification
  398        * @exception	IllegalStateException if this body part is
  399        *			obtained from a READ_ONLY folder.
  400        */
  401       public void setContentMD5(String md5) throws MessagingException {
  402   	setHeader("Content-MD5", md5);
  403       }
  404   
  405       /**
  406        * Get the languages specified in the Content-Language header
  407        * of this MimePart. The Content-Language header is defined by
  408        * RFC 1766. Returns <code>null</code> if this header is not
  409        * available or its value is absent. <p>
  410        *
  411        * This implementation uses <code>getHeader(name)</code>
  412        * to obtain the requisite header field.
  413        */
  414       public String[] getContentLanguage() throws MessagingException {
  415   	return getContentLanguage(this);
  416       }
  417   
  418       /**
  419        * Set the Content-Language header of this MimePart. The
  420        * Content-Language header is defined by RFC 1766.
  421        *
  422        * @param languages 	array of language tags
  423        */
  424       public void setContentLanguage(String[] languages)
  425   			throws MessagingException {
  426   	setContentLanguage(this, languages);
  427       }
  428   
  429       /**
  430        * Returns the "Content-Description" header field of this body part.
  431        * This typically associates some descriptive information with 
  432        * this part. Returns null if this field is unavailable or its
  433        * value is absent. <p>
  434        *
  435        * If the Content-Description field is encoded as per RFC 2047,
  436        * it is decoded and converted into Unicode. If the decoding or 
  437        * conversion fails, the raw data is returned as is. <p>
  438        *
  439        * This implementation uses <code>getHeader(name)</code>
  440        * to obtain the requisite header field.
  441        * 
  442        * @return	content description
  443        */
  444       public String getDescription() throws MessagingException {
  445   	return getDescription(this);
  446       }
  447   
  448       /**
  449        * Set the "Content-Description" header field for this body part.
  450        * If the description parameter is <code>null</code>, then any 
  451        * existing "Content-Description" fields are removed. <p>
  452        *
  453        * If the description contains non US-ASCII characters, it will 
  454        * be encoded using the platform's default charset. If the 
  455        * description contains only US-ASCII characters, no encoding 
  456        * is done and it is used as is. <p>
  457        *
  458        * Note that if the charset encoding process fails, a
  459        * MessagingException is thrown, and an UnsupportedEncodingException
  460        * is included in the chain of nested exceptions within the
  461        * MessagingException.
  462        * 
  463        * @param description content description
  464        * @exception	IllegalWriteException if the underlying
  465        *			implementation does not support modification
  466        * @exception	IllegalStateException if this body part is
  467        *			obtained from a READ_ONLY folder.
  468        * @exception       MessagingException otherwise; an
  469        *                  UnsupportedEncodingException may be included
  470        *                  in the exception chain if the charset
  471        *                  conversion fails.
  472        */
  473       public void setDescription(String description) throws MessagingException {
  474   	setDescription(description, null);
  475       }
  476   
  477       /**
  478        * Set the "Content-Description" header field for this body part.
  479        * If the description parameter is <code>null</code>, then any 
  480        * existing "Content-Description" fields are removed. <p>
  481        *
  482        * If the description contains non US-ASCII characters, it will 
  483        * be encoded using the specified charset. If the description 
  484        * contains only US-ASCII characters, no encoding  is done and 
  485        * it is used as is. <p>
  486        *
  487        * Note that if the charset encoding process fails, a
  488        * MessagingException is thrown, and an UnsupportedEncodingException
  489        * is included in the chain of nested exceptions within the
  490        * MessagingException.
  491        *
  492        * @param	description	Description
  493        * @param	charset		Charset for encoding
  494        * @exception	IllegalWriteException if the underlying
  495        *			implementation does not support modification
  496        * @exception	IllegalStateException if this body part is
  497        *			obtained from a READ_ONLY folder.
  498        * @exception       MessagingException otherwise; an
  499        *                  UnsupportedEncodingException may be included
  500        *                  in the exception chain if the charset
  501        *                  conversion fails.
  502        */
  503       public void setDescription(String description, String charset) 
  504   		throws MessagingException {
  505   	setDescription(this, description, charset);
  506       }
  507   
  508       /**
  509        * Get the filename associated with this body part. <p>
  510        *
  511        * Returns the value of the "filename" parameter from the
  512        * "Content-Disposition" header field of this body part. If its
  513        * not available, returns the value of the "name" parameter from
  514        * the "Content-Type" header field of this body part.
  515        * Returns <code>null</code> if both are absent. <p>
  516        *
  517        * If the <code>mail.mime.encodefilename</code> System property
  518        * is set to true, the {@link MimeUtility#decodeText
  519        * MimeUtility.decodeText} method will be used to decode the
  520        * filename.  While such encoding is not supported by the MIME
  521        * spec, many mailers use this technique to support non-ASCII
  522        * characters in filenames.  The default value of this property
  523        * is false.
  524        *
  525        * @return	filename
  526        */
  527       public String getFileName() throws MessagingException {
  528   	return getFileName(this);
  529       }
  530   
  531       /**
  532        * Set the filename associated with this body part, if possible. <p>
  533        *
  534        * Sets the "filename" parameter of the "Content-Disposition"
  535        * header field of this body part.  For compatibility with older
  536        * mailers, the "name" parameter of the "Content-Type" header is
  537        * also set. <p>
  538        *
  539        * If the <code>mail.mime.encodefilename</code> System property
  540        * is set to true, the {@link MimeUtility#encodeText
  541        * MimeUtility.encodeText} method will be used to encode the
  542        * filename.  While such encoding is not supported by the MIME
  543        * spec, many mailers use this technique to support non-ASCII
  544        * characters in filenames.  The default value of this property
  545        * is false.
  546        *
  547        * @exception	IllegalWriteException if the underlying
  548        *			implementation does not support modification
  549        * @exception	IllegalStateException if this body part is
  550        *			obtained from a READ_ONLY folder.
  551        */
  552       public void setFileName(String filename) throws MessagingException {
  553   	setFileName(this, filename);
  554       }
  555   
  556       /**
  557        * Return a decoded input stream for this body part's "content". <p>
  558        *
  559        * This implementation obtains the input stream from the DataHandler.
  560        * That is, it invokes getDataHandler().getInputStream();
  561        *
  562        * @return 		an InputStream
  563        * @exception	MessagingException
  564        * @exception       IOException this is typically thrown by the
  565        *			DataHandler. Refer to the documentation for
  566        *			javax.activation.DataHandler for more details.
  567        *
  568        * @see	#getContentStream
  569        * @see 	javax.activation.DataHandler#getInputStream
  570        */
  571       public InputStream getInputStream() 
  572   		throws IOException, MessagingException {
  573   	return getDataHandler().getInputStream();
  574       }
  575   
  576      /**
  577        * Produce the raw bytes of the content. This method is used
  578        * when creating a DataHandler object for the content. Subclasses
  579        * that can provide a separate input stream for just the Part
  580        * content might want to override this method. <p>
  581        * 
  582        * @see #content
  583        * @see MimeMessage#getContentStream
  584        */
  585       protected InputStream getContentStream() throws MessagingException {
  586   	if (contentStream != null)
  587   	    return ((SharedInputStream)contentStream).newStream(0, -1);
  588   	if (content != null)
  589   	    return new ByteArrayInputStream(content);
  590   	
  591   	throw new MessagingException("No content");
  592       }
  593   
  594       /**
  595        * Return an InputStream to the raw data with any Content-Transfer-Encoding
  596        * intact.  This method is useful if the "Content-Transfer-Encoding"
  597        * header is incorrect or corrupt, which would prevent the
  598        * <code>getInputStream</code> method or <code>getContent</code> method
  599        * from returning the correct data.  In such a case the application may
  600        * use this method and attempt to decode the raw data itself. <p>
  601        *
  602        * This implementation simply calls the <code>getContentStream</code>
  603        * method.
  604        *
  605        * @see	#getInputStream
  606        * @see	#getContentStream
  607        * @since	JavaMail 1.2
  608        */
  609       public InputStream getRawInputStream() throws MessagingException {
  610   	return getContentStream();
  611       }
  612   
  613       /**
  614        * Return a DataHandler for this body part's content. <p>
  615        *
  616        * The implementation provided here works just like the
  617        * the implementation in MimeMessage.
  618        * @see	MimeMessage#getDataHandler
  619        */  
  620       public DataHandler getDataHandler() throws MessagingException {
  621   	if (dh == null)
  622   	    dh = new DataHandler(new MimePartDataSource(this));
  623   	return dh;
  624       }
  625   
  626       /**
  627        * Return the content as a Java object. The type of the object
  628        * returned is of course dependent on the content itself. For 
  629        * example, the native format of a text/plain content is usually
  630        * a String object. The native format for a "multipart"
  631        * content is always a Multipart subclass. For content types that are
  632        * unknown to the DataHandler system, an input stream is returned
  633        * as the content. <p>
  634        *
  635        * This implementation obtains the content from the DataHandler.
  636        * That is, it invokes getDataHandler().getContent();
  637        * If the content is a Multipart or Message object and was created by
  638        * parsing a stream, the object is cached and returned in subsequent
  639        * calls so that modifications to the content will not be lost.
  640        *
  641        * @return          Object
  642        * @exception       MessagingException
  643        * @exception       IOException this is typically thrown by the
  644        *			DataHandler. Refer to the documentation for
  645        *			javax.activation.DataHandler for more details.
  646        */  
  647       public Object getContent() throws IOException, MessagingException {
  648   	if (cachedContent != null)
  649   	    return cachedContent;
  650   	Object c;
  651   	try {
  652   	    c = getDataHandler().getContent();
  653   	} catch (FolderClosedIOException fex) {
  654   	    throw new FolderClosedException(fex.getFolder(), fex.getMessage());
  655   	} catch (MessageRemovedIOException mex) {
  656   	    throw new MessageRemovedException(mex.getMessage());
  657   	}
  658   	if (cacheMultipart &&
  659   		(c instanceof Multipart || c instanceof Message) &&
  660   		(content != null || contentStream != null)) {
  661   	    cachedContent = c;
  662   	}
  663   	return c;
  664       }
  665   
  666       /**
  667        * This method provides the mechanism to set this body part's content.
  668        * The given DataHandler object should wrap the actual content.
  669        * 
  670        * @param   dh      The DataHandler for the content
  671        * @exception       IllegalWriteException if the underlying
  672        * 			implementation does not support modification
  673        * @exception	IllegalStateException if this body part is
  674        *			obtained from a READ_ONLY folder.
  675        */                 
  676       public void setDataHandler(DataHandler dh) 
  677   		throws MessagingException {
  678   	this.dh = dh;
  679   	cachedContent = null;
  680   	MimeBodyPart.invalidateContentHeaders(this);
  681       }
  682   
  683       /**
  684        * A convenience method for setting this body part's content. <p>
  685        *
  686        * The content is wrapped in a DataHandler object. Note that a
  687        * DataContentHandler class for the specified type should be
  688        * available to the JavaMail implementation for this to work right.
  689        * That is, to do <code>setContent(foobar, "application/x-foobar")</code>,
  690        * a DataContentHandler for "application/x-foobar" should be installed.
  691        * Refer to the Java Activation Framework for more information.
  692        *
  693        * @param	o	the content object
  694        * @param	type	Mime type of the object
  695        * @exception       IllegalWriteException if the underlying
  696        *			implementation does not support modification of
  697        *			existing values
  698        * @exception	IllegalStateException if this body part is
  699        *			obtained from a READ_ONLY folder.
  700        */
  701       public void setContent(Object o, String type) 
  702   		throws MessagingException {
  703   	if (o instanceof Multipart) {
  704   	    setContent((Multipart)o);
  705   	} else {
  706   	    setDataHandler(new DataHandler(o, type));
  707   	}
  708       }
  709   
  710       /**
  711        * Convenience method that sets the given String as this
  712        * part's content, with a MIME type of "text/plain". If the
  713        * string contains non US-ASCII characters, it will be encoded
  714        * using the platform's default charset. The charset is also
  715        * used to set the "charset" parameter. <p>
  716        *
  717        * Note that there may be a performance penalty if
  718        * <code>text</code> is large, since this method may have
  719        * to scan all the characters to determine what charset to
  720        * use. <p>
  721        *
  722        * If the charset is already known, use the
  723        * <code>setText</code> method that takes the charset parameter.
  724        *
  725        * @param	text	the text content to set
  726        * @exception	MessagingException	if an error occurs
  727        * @see	#setText(String text, String charset)
  728        */
  729       public void setText(String text) throws MessagingException {
  730   	setText(text, null);
  731       }
  732   
  733       /**
  734        * Convenience method that sets the given String as this part's
  735        * content, with a MIME type of "text/plain" and the specified
  736        * charset. The given Unicode string will be charset-encoded
  737        * using the specified charset. The charset is also used to set
  738        * the "charset" parameter.
  739        *
  740        * @param	text	the text content to set
  741        * @param	charset	the charset to use for the text
  742        * @exception	MessagingException	if an error occurs
  743        */
  744       public void setText(String text, String charset)
  745   			throws MessagingException {
  746   	setText(this, text, charset, "plain");
  747       }
  748   
  749       /**
  750        * Convenience method that sets the given String as this part's
  751        * content, with a primary MIME type of "text" and the specified
  752        * MIME subtype.  The given Unicode string will be charset-encoded
  753        * using the specified charset. The charset is also used to set
  754        * the "charset" parameter.
  755        *
  756        * @param	text	the text content to set
  757        * @param	charset	the charset to use for the text
  758        * @param	subtype	the MIME subtype to use (e.g., "html")
  759        * @exception	MessagingException	if an error occurs
  760        * @since	JavaMail 1.4
  761        */
  762       public void setText(String text, String charset, String subtype)
  763                           throws MessagingException {
  764   	setText(this, text, charset, subtype);
  765       }
  766    
  767       /**
  768        * This method sets the body part's content to a Multipart object.
  769        *
  770        * @param  mp      	The multipart object that is the Message's content
  771        * @exception       IllegalWriteException if the underlying
  772        *			implementation does not support modification of
  773        *			existing values.
  774        * @exception	IllegalStateException if this body part is
  775        *			obtained from a READ_ONLY folder.
  776        */
  777       public void setContent(Multipart mp) throws MessagingException {
  778   	setDataHandler(new DataHandler(mp, mp.getContentType()));
  779   	mp.setParent(this);
  780       }
  781   
  782       /**
  783        * Use the specified file to provide the data for this part.
  784        * The simple file name is used as the file name for this
  785        * part and the data in the file is used as the data for this
  786        * part.  The encoding will be chosen appropriately for the
  787        * file data.
  788        *
  789        * @param		file		the File object to attach
  790        * @exception	IOException	errors related to accessing the file
  791        * @exception	MessagingException	message related errors
  792        * @since		JavaMail 1.4
  793        */
  794       public void attachFile(File file) throws IOException, MessagingException {
  795       	FileDataSource fds = new FileDataSource(file);   	
  796           this.setDataHandler(new DataHandler(fds));
  797           this.setFileName(fds.getName());
  798       }
  799   
  800       /**
  801        * Use the specified file to provide the data for this part.
  802        * The simple file name is used as the file name for this
  803        * part and the data in the file is used as the data for this
  804        * part.  The encoding will be chosen appropriately for the
  805        * file data.
  806        *
  807        * @param		file		the name of the file to attach
  808        * @exception	IOException	errors related to accessing the file
  809        * @exception	MessagingException	message related errors
  810        * @since		JavaMail 1.4
  811        */
  812       public void attachFile(String file) throws IOException, MessagingException {
  813       	File f = new File(file);
  814       	attachFile(f);
  815       }
  816   
  817       /**
  818        * Save the contents of this part in the specified file.  The content
  819        * is decoded and saved, without any of the MIME headers.
  820        *
  821        * @param		file		the File object to write to
  822        * @exception	IOException	errors related to accessing the file
  823        * @exception	MessagingException	message related errors
  824        * @since		JavaMail 1.4
  825        */
  826       public void saveFile(File file) throws IOException, MessagingException {
  827       	OutputStream out = null;
  828           InputStream in = null;
  829           try {
  830   	    out = new BufferedOutputStream(new FileOutputStream(file));
  831   	    in = this.getInputStream();
  832   	    byte[] buf = new byte[8192];
  833   	    int len;
  834   	    while ((len = in.read(buf)) > 0)
  835   		out.write(buf, 0, len); 
  836           } finally {
  837   	    // close streams, but don't mask original exception, if any
  838   	    try {
  839   		if (in != null)
  840   		    in.close();
  841   	    } catch (IOException ex) { }
  842   	    try {
  843   		if (out != null)
  844   		    out.close();
  845   	    } catch (IOException ex) { }
  846           }
  847       }
  848   
  849       /**
  850        * Save the contents of this part in the specified file.  The content
  851        * is decoded and saved, without any of the MIME headers.
  852        *
  853        * @param		file		the name of the file to write to
  854        * @exception	IOException	errors related to accessing the file
  855        * @exception	MessagingException	message related errors
  856        * @since		JavaMail 1.4
  857        */
  858       public void saveFile(String file) throws IOException, MessagingException {
  859       	File f = new File(file);
  860       	saveFile(f);
  861       }
  862   
  863       /**
  864        * Output the body part as an RFC 822 format stream.
  865        *
  866        * @exception MessagingException
  867        * @exception IOException	if an error occurs writing to the
  868        *				stream or if an error is generated
  869        *				by the javax.activation layer.
  870        * @see javax.activation.DataHandler#writeTo
  871        */
  872       public void writeTo(OutputStream os)
  873   				throws IOException, MessagingException {
  874   	writeTo(this, os, null);
  875       }
  876   
  877       /**
  878        * Get all the headers for this header_name. Note that certain
  879        * headers may be encoded as per RFC 2047 if they contain
  880        * non US-ASCII characters and these should be decoded.
  881        *
  882        * @param   name    name of header
  883        * @return  array of headers
  884        * @see     javax.mail.internet.MimeUtility
  885        */  
  886       public String[] getHeader(String name) throws MessagingException {
  887   	return headers.getHeader(name);
  888       }
  889   
  890       /**
  891        * Get all the headers for this header name, returned as a single
  892        * String, with headers separated by the delimiter. If the
  893        * delimiter is <code>null</code>, only the first header is 
  894        * returned.
  895        *
  896        * @param name		the name of this header
  897        * @param delimiter		delimiter between fields in returned string
  898        * @return			the value fields for all headers with 
  899        *				this name
  900        * @exception       	MessagingException
  901        */
  902       public String getHeader(String name, String delimiter)
  903   				throws MessagingException {
  904   	return headers.getHeader(name, delimiter);
  905       }
  906   
  907       /**
  908        * Set the value for this header_name. Replaces all existing
  909        * header values with this new value. Note that RFC 822 headers
  910        * must contain only US-ASCII characters, so a header that
  911        * contains non US-ASCII characters must be encoded as per the
  912        * rules of RFC 2047.
  913        *
  914        * @param   name    header name
  915        * @param   value   header value
  916        * @see     javax.mail.internet.MimeUtility
  917        */
  918       public void setHeader(String name, String value)
  919                                   throws MessagingException {
  920   	headers.setHeader(name, value);
  921       }
  922    
  923       /**
  924        * Add this value to the existing values for this header_name.
  925        * Note that RFC 822 headers must contain only US-ASCII
  926        * characters, so a header that contains non US-ASCII characters
  927        * must be encoded as per the rules of RFC 2047.
  928        *
  929        * @param   name    header name
  930        * @param   value   header value
  931        * @see     javax.mail.internet.MimeUtility
  932        */
  933       public void addHeader(String name, String value)
  934                                   throws MessagingException {
  935   	headers.addHeader(name, value);    
  936       }
  937   
  938       /**
  939        * Remove all headers with this name.
  940        */
  941       public void removeHeader(String name) throws MessagingException {
  942   	headers.removeHeader(name);
  943       }
  944    
  945       /**
  946        * Return all the headers from this Message as an Enumeration of
  947        * Header objects.
  948        */
  949       public Enumeration getAllHeaders() throws MessagingException {
  950   	return headers.getAllHeaders();
  951       }
  952      
  953       /**
  954        * Return matching headers from this Message as an Enumeration of
  955        * Header objects. <p>
  956        */
  957       public Enumeration getMatchingHeaders(String[] names)
  958                           throws MessagingException {
  959   	return headers.getMatchingHeaders(names);
  960       }
  961    
  962       /**
  963        * Return non-matching headers from this Message as an
  964        * Enumeration of Header objects.
  965        */
  966       public Enumeration getNonMatchingHeaders(String[] names)
  967                           throws MessagingException {
  968   	return headers.getNonMatchingHeaders(names);
  969       }
  970         
  971       /**
  972        * Add a header line to this body part
  973        */
  974       public void addHeaderLine(String line) throws MessagingException {
  975   	headers.addHeaderLine(line);
  976       }
  977        
  978       /**
  979        * Get all header lines as an Enumeration of Strings. A Header
  980        * line is a raw RFC 822 header line, containing both the "name"
  981        * and "value" field.
  982        */
  983       public Enumeration getAllHeaderLines() throws MessagingException {
  984     	return headers.getAllHeaderLines(); 
  985       }
  986    
  987       /**
  988        * Get matching header lines as an Enumeration of Strings.
  989        * A Header line is a raw RFC 822 header line, containing both
  990        * the "name" and "value" field.
  991        */
  992       public Enumeration getMatchingHeaderLines(String[] names)
  993                                       throws MessagingException {
  994   	return headers.getMatchingHeaderLines(names);
  995       }
  996    
  997       /**
  998        * Get non-matching header lines as an Enumeration of Strings.
  999        * A Header line is a raw RFC 822 header line, containing both
 1000        * the "name"  and "value" field.
 1001        */
 1002       public Enumeration getNonMatchingHeaderLines(String[] names)  
 1003                                           throws MessagingException {
 1004   	return headers.getNonMatchingHeaderLines(names);
 1005       }
 1006   
 1007       /**
 1008        * Examine the content of this body part and update the appropriate
 1009        * MIME headers.  Typical headers that get set here are
 1010        * <code>Content-Type</code> and <code>Content-Transfer-Encoding</code>.
 1011        * Headers might need to be updated in two cases:
 1012        *
 1013        * <br>
 1014        * - A message being crafted by a mail application will certainly
 1015        * need to activate this method at some point to fill up its internal
 1016        * headers.
 1017        *
 1018        * <br>
 1019        * - A message read in from a Store will have obtained
 1020        * all its headers from the store, and so doesn't need this.
 1021        * However, if this message is editable and if any edits have
 1022        * been made to either the content or message structure, we might
 1023        * need to resync our headers.
 1024        *
 1025        * <br>
 1026        * In both cases this method is typically called by the
 1027        * <code>Message.saveChanges</code> method.
 1028        */
 1029       protected void updateHeaders() throws MessagingException {
 1030   	updateHeaders(this);
 1031   	/*
 1032   	 * If we've cached a Multipart or Message object then
 1033   	 * we're now committed to using this instance of the
 1034   	 * object and we discard any stream data used to create
 1035   	 * this object.
 1036   	 */
 1037   	if (cachedContent != null) {
 1038   	    dh = new DataHandler(cachedContent, getContentType());
 1039   	    cachedContent = null;
 1040   	    content = null;
 1041   	    if (contentStream != null) {
 1042   		try {
 1043   		    contentStream.close();
 1044   		} catch (IOException ioex) { }	// nothing to do
 1045   	    }
 1046   	    contentStream = null;
 1047   	}
 1048       }
 1049   
 1050       /////////////////////////////////////////////////////////////
 1051       // Package private convenience methods to share code among //
 1052       // MimeMessage and MimeBodyPart                            //
 1053       /////////////////////////////////////////////////////////////
 1054   
 1055       static boolean isMimeType(MimePart part, String mimeType)
 1056   				throws MessagingException {
 1057   	// XXX - lots of room for optimization here!
 1058   	try {
 1059   	    ContentType ct = new ContentType(part.getContentType());
 1060   	    return ct.match(mimeType);
 1061   	} catch (ParseException ex) {
 1062   	    return part.getContentType().equalsIgnoreCase(mimeType);
 1063   	}
 1064       }
 1065   
 1066       static void setText(MimePart part, String text, String charset,
 1067   			String subtype) throws MessagingException {
 1068   	if (charset == null) {
 1069   	    if (MimeUtility.checkAscii(text) != MimeUtility.ALL_ASCII)
 1070   		charset = MimeUtility.getDefaultMIMECharset();
 1071   	    else
 1072   		charset = "us-ascii";
 1073   	}
 1074   	// XXX - should at least ensure that subtype is an atom
 1075   	part.setContent(text, "text/" + subtype + "; charset=" +
 1076   			MimeUtility.quote(charset, HeaderTokenizer.MIME));
 1077       }
 1078   
 1079       static String getDisposition(MimePart part) throws MessagingException {
 1080   	String s = part.getHeader("Content-Disposition", null);
 1081   
 1082   	if (s == null)
 1083   	    return null;
 1084   
 1085   	ContentDisposition cd = new ContentDisposition(s);
 1086   	return cd.getDisposition();
 1087       }
 1088   
 1089       static void setDisposition(MimePart part, String disposition)
 1090   			throws MessagingException {
 1091   	if (disposition == null)
 1092   	    part.removeHeader("Content-Disposition");
 1093   	else {
 1094   	    String s = part.getHeader("Content-Disposition", null);
 1095   	    if (s != null) { 
 1096   		/* A Content-Disposition header already exists ..
 1097   		 *
 1098   		 * Override disposition, but attempt to retain 
 1099   		 * existing disposition parameters
 1100   		 */
 1101   		ContentDisposition cd = new ContentDisposition(s);
 1102   		cd.setDisposition(disposition);
 1103   		disposition = cd.toString();
 1104   	    }
 1105   	    part.setHeader("Content-Disposition", disposition);
 1106   	}
 1107       }
 1108   
 1109       static String getDescription(MimePart part) 
 1110   			throws MessagingException {
 1111   	String rawvalue = part.getHeader("Content-Description", null);
 1112   
 1113   	if (rawvalue == null)
 1114   	    return null;
 1115   
 1116   	try {
 1117   	    return MimeUtility.decodeText(MimeUtility.unfold(rawvalue));
 1118   	} catch (UnsupportedEncodingException ex) {
 1119   	    return rawvalue;
 1120   	}
 1121       }
 1122   
 1123       static void 
 1124       setDescription(MimePart part, String description, String charset) 
 1125   			throws MessagingException {
 1126   	if (description == null) {
 1127   	    part.removeHeader("Content-Description");
 1128   	    return;
 1129   	}
 1130   	
 1131   	try {
 1132   	    part.setHeader("Content-Description", MimeUtility.fold(21,
 1133   		MimeUtility.encodeText(description, charset, null)));
 1134   	} catch (UnsupportedEncodingException uex) {
 1135   	    throw new MessagingException("Encoding error", uex);
 1136   	}
 1137       }
 1138   
 1139       static String getFileName(MimePart part) throws MessagingException {
 1140   	String filename = null;
 1141   	String s = part.getHeader("Content-Disposition", null);
 1142   
 1143   	if (s != null) {
 1144   	    // Parse the header ..
 1145   	    ContentDisposition cd = new ContentDisposition(s);
 1146   	    filename = cd.getParameter("filename");
 1147   	}
 1148   	if (filename == null) {
 1149   	    // Still no filename ? Try the "name" ContentType parameter
 1150   	    s = part.getHeader("Content-Type", null);
 1151   	    if (s != null) {
 1152   		try {
 1153   		    ContentType ct = new ContentType(s);
 1154   		    filename = ct.getParameter("name");
 1155   		} catch (ParseException pex) { }	// ignore it
 1156   	    }
 1157   	}
 1158   	if (decodeFileName && filename != null) {
 1159   	    try {
 1160   		filename = MimeUtility.decodeText(filename);
 1161   	    } catch (UnsupportedEncodingException ex) {
 1162   		throw new MessagingException("Can't decode filename", ex);
 1163   	    }
 1164   	}
 1165   	return filename;
 1166       }
 1167   
 1168       static void setFileName(MimePart part, String name) 
 1169   		throws MessagingException {
 1170   	if (encodeFileName && name != null) {
 1171   	    try {
 1172   		name = MimeUtility.encodeText(name);
 1173   	    } catch (UnsupportedEncodingException ex) {
 1174   		throw new MessagingException("Can't encode filename", ex);
 1175   	    }
 1176   	}
 1177   
 1178   	// Set the Content-Disposition "filename" parameter
 1179   	String s = part.getHeader("Content-Disposition", null);
 1180   	ContentDisposition cd = 
 1181   		new ContentDisposition(s == null ? Part.ATTACHMENT : s);
 1182   	cd.setParameter("filename", name);
 1183   	part.setHeader("Content-Disposition", cd.toString());
 1184   
 1185   	/*
 1186   	 * Also attempt to set the Content-Type "name" parameter,
 1187   	 * to satisfy ancient MUAs.  XXX - This is not RFC compliant.
 1188   	 */
 1189   	if (setContentTypeFileName) {
 1190   	    s = part.getHeader("Content-Type", null);
 1191   	    if (s != null) {
 1192   		try {
 1193   		    ContentType cType = new ContentType(s);
 1194   		    cType.setParameter("name", name);
 1195   		    part.setHeader("Content-Type", cType.toString());
 1196   		} catch (ParseException pex) { }	// ignore it
 1197   	    }
 1198   	}
 1199       }
 1200   
 1201       static String[] getContentLanguage(MimePart part) 
 1202   		throws MessagingException {
 1203   	String s = part.getHeader("Content-Language", null);
 1204   
 1205   	if (s == null)
 1206   	    return null;
 1207   
 1208   	// Tokenize the header to obtain the Language-tags (skip comments)
 1209   	HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
 1210   	Vector v = new Vector();
 1211   
 1212   	HeaderTokenizer.Token tk;
 1213   	int tkType;
 1214   
 1215   	while (true) {
 1216   	    tk = h.next(); // get a language-tag
 1217   	    tkType = tk.getType();
 1218   	    if (tkType == HeaderTokenizer.Token.EOF)
 1219   		break; // done
 1220   	    else if (tkType == HeaderTokenizer.Token.ATOM)
 1221   		v.addElement(tk.getValue());
 1222   	    else // invalid token, skip it.
 1223   		continue;
 1224   	}
 1225   
 1226   	if (v.size() == 0)
 1227   	    return null;
 1228   
 1229   	String[] language = new String[v.size()];
 1230   	v.copyInto(language);
 1231   	return language;	
 1232       }
 1233   
 1234       static void setContentLanguage(MimePart part, String[] languages)
 1235   			throws MessagingException {
 1236   	StringBuffer sb = new StringBuffer(languages[0]);
 1237   	for (int i = 1; i < languages.length; i++)
 1238   	    sb.append(',').append(languages[i]);
 1239   	part.setHeader("Content-Language", sb.toString());
 1240       }
 1241   
 1242       static String getEncoding(MimePart part) throws MessagingException {
 1243   	String s = part.getHeader("Content-Transfer-Encoding", null);
 1244   
 1245   	if (s == null)
 1246   	    return null;
 1247   
 1248   	s = s.trim();	// get rid of trailing spaces
 1249   	// quick check for known values to avoid unnecessary use
 1250   	// of tokenizer.
 1251   	if (s.equalsIgnoreCase("7bit") || s.equalsIgnoreCase("8bit") ||
 1252   		s.equalsIgnoreCase("quoted-printable") ||
 1253   		s.equalsIgnoreCase("binary") ||
 1254   		s.equalsIgnoreCase("base64"))
 1255   	    return s;
 1256   
 1257   	// Tokenize the header to obtain the encoding (skip comments)
 1258   	HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
 1259   
 1260   	HeaderTokenizer.Token tk;
 1261   	int tkType;
 1262   
 1263   	for (;;) {
 1264   	    tk = h.next(); // get a token
 1265   	    tkType = tk.getType();
 1266   	    if (tkType == HeaderTokenizer.Token.EOF)
 1267   		break; // done
 1268   	    else if (tkType == HeaderTokenizer.Token.ATOM)
 1269   		return tk.getValue();
 1270   	    else // invalid token, skip it.
 1271   		continue;
 1272   	}
 1273   	return s;
 1274       }
 1275   
 1276       static void setEncoding(MimePart part, String encoding)
 1277   				throws MessagingException {
 1278   	part.setHeader("Content-Transfer-Encoding", encoding);
 1279       }
 1280   
 1281       static void updateHeaders(MimePart part) throws MessagingException {
 1282   	DataHandler dh = part.getDataHandler();
 1283   	if (dh == null) // Huh ?
 1284   	    return;
 1285   
 1286   	try {
 1287   	    String type = dh.getContentType();
 1288   	    boolean composite = false;
 1289   	    boolean needCTHeader = part.getHeader("Content-Type") == null;
 1290   
 1291   	    ContentType cType = new ContentType(type);
 1292   	    if (cType.match("multipart/*")) {
 1293   		// If multipart, recurse
 1294   		composite = true;
 1295   		Object o;
 1296   		if (part instanceof MimeBodyPart) {
 1297   		    MimeBodyPart mbp = (MimeBodyPart)part;
 1298   		    o = mbp.cachedContent != null ?
 1299   				mbp.cachedContent : dh.getContent();
 1300   		} else if (part instanceof MimeMessage) {
 1301   		    MimeMessage msg = (MimeMessage)part;
 1302   		    o = msg.cachedContent != null ?
 1303   				msg.cachedContent : dh.getContent();
 1304   		} else
 1305   		    o = dh.getContent();
 1306   		if (o instanceof MimeMultipart)
 1307   		    ((MimeMultipart)o).updateHeaders();
 1308   		else
 1309   		    throw new MessagingException("MIME part of type \"" +
 1310   			type + "\" contains object of type " +
 1311   			o.getClass().getName() + " instead of MimeMultipart");
 1312   	    } else if (cType.match("message/rfc822")) {
 1313   		composite = true;
 1314   		// XXX - call MimeMessage.updateHeaders()?
 1315   	    }
 1316   
 1317   	    // Content-Transfer-Encoding, but only if we don't
 1318   	    // already have one
 1319   	    if (!composite) {	// not allowed on composite parts
 1320   		if (part.getHeader("Content-Transfer-Encoding") == null)
 1321   		    setEncoding(part, MimeUtility.getEncoding(dh));
 1322   
 1323   		if (needCTHeader && setDefaultTextCharset &&
 1324   			cType.match("text/*") &&
 1325   			cType.getParameter("charset") == null) {
 1326   		    /*
 1327   		     * Set a default charset for text parts.
 1328   		     * We really should examine the data to determine
 1329   		     * whether or not it's all ASCII, but that's too
 1330   		     * expensive so we make an assumption:  If we
 1331   		     * chose 7bit encoding for this data, it's probably
 1332   		     * ASCII.  (MimeUtility.getEncoding will choose
 1333   		     * 7bit only in this case, but someone might've
 1334   		     * set the Content-Transfer-Encoding header manually.)
 1335   		     */
 1336   		    String charset;
 1337   		    String enc = part.getEncoding();
 1338   		    if (enc != null && enc.equalsIgnoreCase("7bit"))
 1339   			charset = "us-ascii";
 1340   		    else
 1341   			charset = MimeUtility.getDefaultMIMECharset();
 1342   		    cType.setParameter("charset", charset);
 1343   		    type = cType.toString();
 1344   		}
 1345   	    }
 1346   
 1347   	    // Now, let's update our own headers ...
 1348   
 1349   	    // Content-type, but only if we don't already have one
 1350   	    if (needCTHeader) {
 1351   		/*
 1352   		 * Pull out "filename" from Content-Disposition, and
 1353   		 * use that to set the "name" parameter. This is to
 1354   		 * satisfy older MUAs (DtMail, Roam and probably
 1355   		 * a bunch of others).
 1356   		 */
 1357   		String s = part.getHeader("Content-Disposition", null);
 1358   		if (s != null) {
 1359   		    // Parse the header ..
 1360   		    ContentDisposition cd = new ContentDisposition(s);
 1361   		    String filename = cd.getParameter("filename");
 1362   		    if (filename != null) {
 1363   			cType.setParameter("name", filename);
 1364   			type = cType.toString();
 1365   		    }
 1366   		}
 1367   		
 1368   		part.setHeader("Content-Type", type);
 1369   	    }
 1370   	} catch (IOException ex) {
 1371   	    throw new MessagingException("IOException updating headers", ex);
 1372   	}
 1373       }
 1374   
 1375       static void invalidateContentHeaders(MimePart part)
 1376   					throws MessagingException {
 1377   	part.removeHeader("Content-Type");
 1378   	part.removeHeader("Content-Transfer-Encoding");
 1379       }
 1380       
 1381       static void writeTo(MimePart part, OutputStream os, String[] ignoreList)
 1382   			throws IOException, MessagingException {
 1383   
 1384   	// see if we already have a LOS
 1385   	LineOutputStream los = null;
 1386   	if (os instanceof LineOutputStream) {
 1387   	    los = (LineOutputStream) os;
 1388   	} else {
 1389   	    los = new LineOutputStream(os);
 1390   	}
 1391   
 1392   	// First, write out the header
 1393   	Enumeration hdrLines = part.getNonMatchingHeaderLines(ignoreList);
 1394   	while (hdrLines.hasMoreElements())
 1395   	    los.writeln((String)hdrLines.nextElement());
 1396   
 1397   	// The CRLF separator between header and content
 1398   	los.writeln();
 1399   
 1400   	// Finally, the content. Encode if required.
 1401   	// XXX: May need to account for ESMTP ?
 1402   	os = MimeUtility.encode(os, part.getEncoding());
 1403   	part.getDataHandler().writeTo(os);
 1404   	os.flush(); // Needed to complete encoding
 1405       }
 1406   }

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