Open Source Repository

Home /mail/mail-1.4.1 | Repository Home


com/sun/mail/dsn/MultipartReport.java
/*
 * 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.
 */

/*
 * @(#)MultipartReport.java  1.7 07/05/04
 */

package com.sun.mail.dsn;

import java.io.*;
import java.util.Vector;

import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;

/**
 * A multipart/report message content, as defined in
 * <A HREF="http://www.ietf.org/rfc/rfc3462.txt">RFC 3462</A>.
 * A multipart/report content is a container for mail reports
 * of any kind, and is most often used to return a delivery
 * status report.  This class only supports that most common
 * usage. <p>
 *
 * A MultipartReport object is a special type of MimeMultipart
 * object with a restricted set of body parts.  A MultipartReport
 * object contains:
 <ul>
 <li>[Required] A human readable text message describing the
 * reason the report was generated.</li>
 <li>[Required] A {@link DeliveryStatus} object containing the
 * details for why the report was generated.</li>
 <li>[Optional] A returned copy of the entire message, or just
 * its headers, which caused the generation of this report.
 </ul>
 * Many of the normal MimeMultipart operations are restricted to
 * ensure that the MultipartReport object always follows this
 * structure.
 */
public class MultipartReport extends MimeMultipart {
    protected boolean constructed; // true when done with constructor

    /**
     * Construct a multipart/report object with no content.
     */
    public MultipartReport() throws MessagingException {
  super("report");
  // always at least two body parts
  MimeBodyPart mbp = new MimeBodyPart();
  setBodyPart(mbp, 0);
  mbp = new MimeBodyPart();
  setBodyPart(mbp, 1);
  constructed = true;
    }

    /**
     * Construct a multipart/report object with the specified plain
     * text and delivery status to be returned to the user.
     */
    public MultipartReport(String text, DeliveryStatus status)
        throws MessagingException {
  super("report");
  ContentType ct = new ContentType(contentType);
  ct.setParameter("report-type""delivery-status");
  contentType = ct.toString();
  MimeBodyPart mbp = new MimeBodyPart();
  mbp.setText(text);
  setBodyPart(mbp, 0);
  mbp = new MimeBodyPart();
  mbp.setContent(status, "message/delivery-status");
  setBodyPart(mbp, 1);
  constructed = true;
    }

    /**
     * Construct a multipart/report object with the specified plain
     * text, delivery status, and original message to be returned to the user.
     */
    public MultipartReport(String text, DeliveryStatus status,
        MimeMessage msgthrows MessagingException {
  this(text, status);
  if (msg != null) {
      MimeBodyPart mbp = new MimeBodyPart();
      mbp.setContent(msg, "message/rfc822");
      setBodyPart(mbp, 2);
  }
    }

    /**
     * Construct a multipart/report object with the specified plain
     * text, delivery status, and headers from the original message
     * to be returned to the user.
     */
    public MultipartReport(String text, DeliveryStatus status,
        InternetHeaders hdrthrows MessagingException {
  this(text, status);
  if (hdr != null) {
      MimeBodyPart mbp = new MimeBodyPart();
      mbp.setContent(new MessageHeaders(hdr)"text/rfc822-headers");
      setBodyPart(mbp, 2);
  }
    }

    /**
     * Constructs a MultipartReport object and its bodyparts from the 
     * given DataSource. <p>
     *
     @param  ds  DataSource, can be a MultipartDataSource
     */
    public MultipartReport(DataSource dsthrows MessagingException {
  super(ds);
  parse();
  constructed = true;
  /*
   * Can't fail to construct object because some programs just
   * want to treat this as a Multipart and examine the parts.
   *
  if (getCount() < 2 || getCount() > 3)  // XXX allow extra parts
      throw new MessagingException(
    "Wrong number of parts in multipart/report: " + getCount());
   */
    }

    /**
     * Get the plain text to be presented to the user, if there is any.
     * Rarely, the message may contain only HTML text, or no text at
     * all.  If the text body part of this multipart/report object is
     * of type text/plain, or if it is of type multipart/alternative
     * and contains a text/plain part, the text from that part is
     * returned.  Otherwise, null is return and the {@link #getTextBodyPart
     * getTextBodyPart} method may be used to extract the data.
     */
    public synchronized String getText() throws MessagingException {
  try {
      BodyPart bp = getBodyPart(0);
      if (bp.isMimeType("text/plain"))
    return (String)bp.getContent();
      if (bp.isMimeType("multipart/alternative")) {
    Multipart mp = (Multipart)bp.getContent();
    for (int i = 0; i < mp.getCount(); i++) {
        bp = mp.getBodyPart(i);
        if (bp.isMimeType("text/plain"))
      return (String)bp.getContent();
    }
      }
  catch (IOException ex) {
      throw new MessagingException("Exception getting text content", ex);
  }
  return null;
    }

    /**
     * Set the message to be presented to the user as just a text/plain
     * part containing the specified text.
     */
    public synchronized void setText(String textthrows MessagingException {
  MimeBodyPart mbp = new MimeBodyPart();
  mbp.setText(text);
  setBodyPart(mbp, 0);
    }

    /**
     * Return the body part containing the message to be presented to
     * the user, usually just a text/plain part.
     */
    public synchronized MimeBodyPart getTextBodyPart()
        throws MessagingException {
  return (MimeBodyPart)getBodyPart(0);
    }

    /**
     * Set the body part containing the text to be presented to the
     * user.  Usually this a text/plain part, but it might also be
     * a text/html part or a multipart/alternative part containing
     * text/plain and text/html parts.  Any type is allowed here
     * but these types are most common.
     */
    public synchronized void setTextBodyPart(MimeBodyPart mbp)
        throws MessagingException {
  setBodyPart(mbp, 0);
    }

    /**
     * Get the delivery status associated with this multipart/report.
     */
    public synchronized DeliveryStatus getDeliveryStatus()
        throws MessagingException {
  if (getCount() 2)
      return null;
  BodyPart bp = getBodyPart(1);
  if (!bp.isMimeType("message/delivery-status"))
      return null;
  try {
      return (DeliveryStatus)bp.getContent();
  catch (IOException ex) {
      throw new MessagingException("IOException getting DeliveryStatus",
          ex);
  }
    }

    /**
     * Set the delivery status associated with this multipart/report.
     */
    public synchronized void setDeliveryStatus(DeliveryStatus status)
        throws MessagingException {
  MimeBodyPart mbp = new MimeBodyPart();
  mbp.setContent(status, "message/delivery-status");
  setBodyPart(mbp, 2);
  ContentType ct = new ContentType(contentType);
  ct.setParameter("report-type""delivery-status");
  contentType = ct.toString();
    }

    /**
     * Get the original message that is being returned along with this
     * multipart/report.  If no original message is included, null is
     * returned.  In some cases only the headers of the original
     * message will be returned as an object of type MessageHeaders.
     */
    public synchronized MimeMessage getReturnedMessage()
        throws MessagingException {
  if (getCount() 3)
      return null;
  BodyPart bp = getBodyPart(2);
  if (!bp.isMimeType("message/rfc822"&&
    !bp.isMimeType("text/rfc822-headers"))
      return null;
  try {
      return (MimeMessage)bp.getContent();
  catch (IOException ex) {
      throw new MessagingException("IOException getting ReturnedMessage",
          ex);
  }
    }

    /**
     * Set the original message to be returned as part of the
     * multipart/report.  If msg is null, any previously set
     * returned message or headers is removed.
     */
    public synchronized void setReturnedMessage(MimeMessage msg)
        throws MessagingException {
  if (msg == null) {
      BodyPart part = (BodyPart)parts.elementAt(2);
      super.removeBodyPart(2);
      return;
  }
  MimeBodyPart mbp = new MimeBodyPart();
  if (msg instanceof MessageHeaders)
      mbp.setContent(msg, "text/rfc822-headers");
  else
      mbp.setContent(msg, "message/rfc822");
  setBodyPart(mbp, 2);
    }

    private synchronized void setBodyPart(BodyPart part, int index
        throws MessagingException {
  if (parts == null)  // XXX - can never happen?
      parts = new Vector();

  if (index < parts.size())
      super.removeBodyPart(index);
  super.addBodyPart(part, index);
    }


    // Override Multipart methods to preserve integrity of multipart/report.

    /**
     * Set the subtype.  Throws MessagingException.
     *
     @param  subtype    Subtype
     @exception  MessagingException  always; can't change subtype
     */
    public synchronized void setSubType(String subtype
      throws MessagingException {
  throw new MessagingException("Can't change subtype of MultipartReport");
    }

    /**
     * Remove the specified part from the multipart message.
     * Not allowed on a multipart/report object.
     *
     @param   part  The part to remove
     @exception  MessagingException always
     */
    public boolean removeBodyPart(BodyPart partthrows MessagingException {
  throw new MessagingException(
      "Can't remove body parts from multipart/report");
    }

    /**
     * Remove the part at specified location (starting from 0).
     * Not allowed on a multipart/report object.
     *
     @param   index  Index of the part to remove
     @exception  MessagingException  always
     */
    public void removeBodyPart(int indexthrows MessagingException {
  throw new MessagingException(
      "Can't remove body parts from multipart/report");
    }

    /**
     * Adds a Part to the multipart.
     * Not allowed on a multipart/report object.
     *
     @param  part  The Part to be appended
     @exception       MessagingException  always
     */
    public synchronized void addBodyPart(BodyPart part
    throws MessagingException {
  // Once constructor is done, don't allow this anymore.
  if (!constructed)
      super.addBodyPart(part);
  else
      throw new MessagingException(
    "Can't add body parts to multipart/report 1");
    }

    /**
     * Adds a BodyPart at position <code>index</code>.
     * Not allowed on a multipart/report object.
     *
     @param  part  The BodyPart to be inserted
     @param  index Location where to insert the part
     @exception       MessagingException  always
     */
    public synchronized void addBodyPart(BodyPart part, int index
        throws MessagingException {
  throw new MessagingException(
      "Can't add body parts to multipart/report 2");
    }
}