src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 /*
aoqi@0 27 * @(#)MimeMultipart.java 1.31 03/01/29
aoqi@0 28 */
aoqi@0 29
aoqi@0 30
aoqi@0 31
aoqi@0 32 package com.sun.xml.internal.messaging.saaj.packaging.mime.internet;
aoqi@0 33
aoqi@0 34 import java.io.*;
aoqi@0 35
aoqi@0 36 import javax.activation.DataSource;
aoqi@0 37
aoqi@0 38 import com.sun.xml.internal.messaging.saaj.packaging.mime.*;
aoqi@0 39 import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*;
aoqi@0 40 import com.sun.xml.internal.messaging.saaj.util.FinalArrayList;
aoqi@0 41 import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
aoqi@0 42 import com.sun.xml.internal.messaging.saaj.util.SAAJUtil;
aoqi@0 43
aoqi@0 44 /**
aoqi@0 45 * The MimeMultipart class is an implementation
aoqi@0 46 * that uses MIME conventions for the multipart data. <p>
aoqi@0 47 *
aoqi@0 48 * A MimeMultipart is obtained from a MimeBodyPart whose primary type
aoqi@0 49 * is "multipart" (by invoking the part's <code>getContent()</code> method)
aoqi@0 50 * or it can be created by a client as part of creating a new MimeMessage. <p>
aoqi@0 51 *
aoqi@0 52 * The default multipart subtype is "mixed". The other multipart
aoqi@0 53 * subtypes, such as "alternative", "related", and so on, can be
aoqi@0 54 * implemented as subclasses of MimeMultipart with additional methods
aoqi@0 55 * to implement the additional semantics of that type of multipart
aoqi@0 56 * content. The intent is that service providers, mail JavaBean writers
aoqi@0 57 * and mail clients will write many such subclasses and their Command
aoqi@0 58 * Beans, and will install them into the JavaBeans Activation
aoqi@0 59 * Framework, so that any JavaMail implementation and its clients can
aoqi@0 60 * transparently find and use these classes. Thus, a MIME multipart
aoqi@0 61 * handler is treated just like any other type handler, thereby
aoqi@0 62 * decoupling the process of providing multipart handlers from the
aoqi@0 63 * JavaMail API. Lacking these additional MimeMultipart subclasses,
aoqi@0 64 * all subtypes of MIME multipart data appear as MimeMultipart objects. <p>
aoqi@0 65 *
aoqi@0 66 * An application can directly construct a MIME multipart object of any
aoqi@0 67 * subtype by using the <code>MimeMultipart(String subtype)</code>
aoqi@0 68 * constructor. For example, to create a "multipart/alternative" object,
aoqi@0 69 * use <code>new MimeMultipart("alternative")</code>.
aoqi@0 70 *
aoqi@0 71 * @version 1.31, 03/01/29
aoqi@0 72 * @author John Mani
aoqi@0 73 * @author Bill Shannon
aoqi@0 74 * @author Max Spivak
aoqi@0 75 */
aoqi@0 76
aoqi@0 77 //BM MimeMultipart can extend this
aoqi@0 78 public class MimeMultipart {
aoqi@0 79
aoqi@0 80 /**
aoqi@0 81 * The DataSource supplying our InputStream.
aoqi@0 82 */
aoqi@0 83 protected DataSource ds = null;
aoqi@0 84
aoqi@0 85 /**
aoqi@0 86 * Have we parsed the data from our InputStream yet?
aoqi@0 87 * Defaults to true; set to false when our constructor is
aoqi@0 88 * given a DataSource with an InputStream that we need to
aoqi@0 89 * parse.
aoqi@0 90 */
aoqi@0 91 protected boolean parsed = true;
aoqi@0 92
aoqi@0 93 /**
aoqi@0 94 * Vector of MimeBodyPart objects.
aoqi@0 95 */
aoqi@0 96 protected FinalArrayList parts = new FinalArrayList(); // Holds BodyParts
aoqi@0 97
aoqi@0 98 /**
aoqi@0 99 * This field specifies the content-type of this multipart
aoqi@0 100 * object. It defaults to "multipart/mixed".
aoqi@0 101 */
aoqi@0 102 protected ContentType contentType;
aoqi@0 103
aoqi@0 104 /**
aoqi@0 105 * The <code>MimeBodyPart</code> containing this <code>MimeMultipart</code>,
aoqi@0 106 * if known.
aoqi@0 107 * @since JavaMail 1.1
aoqi@0 108 */
aoqi@0 109 protected MimeBodyPart parent;
aoqi@0 110
aoqi@0 111 protected static final boolean ignoreMissingEndBoundary;
aoqi@0 112 static {
aoqi@0 113 ignoreMissingEndBoundary = SAAJUtil.getSystemBoolean("saaj.mime.multipart.ignoremissingendboundary");
aoqi@0 114 }
aoqi@0 115
aoqi@0 116 /**
aoqi@0 117 * Default constructor. An empty MimeMultipart object
aoqi@0 118 * is created. Its content type is set to "multipart/mixed".
aoqi@0 119 * A unique boundary string is generated and this string is
aoqi@0 120 * setup as the "boundary" parameter for the
aoqi@0 121 * <code>contentType</code> field. <p>
aoqi@0 122 *
aoqi@0 123 * MimeBodyParts may be added later.
aoqi@0 124 */
aoqi@0 125 public MimeMultipart() {
aoqi@0 126 this("mixed");
aoqi@0 127 }
aoqi@0 128
aoqi@0 129 /**
aoqi@0 130 * Construct a MimeMultipart object of the given subtype.
aoqi@0 131 * A unique boundary string is generated and this string is
aoqi@0 132 * setup as the "boundary" parameter for the
aoqi@0 133 * <code>contentType</code> field. <p>
aoqi@0 134 *
aoqi@0 135 * MimeBodyParts may be added later.
aoqi@0 136 */
aoqi@0 137 public MimeMultipart(String subtype) {
aoqi@0 138 //super();
aoqi@0 139 /*
aoqi@0 140 * Compute a boundary string.
aoqi@0 141 */
aoqi@0 142 String boundary = UniqueValue.getUniqueBoundaryValue();
aoqi@0 143 contentType = new ContentType("multipart", subtype, null);
aoqi@0 144 contentType.setParameter("boundary", boundary);
aoqi@0 145 }
aoqi@0 146
aoqi@0 147 /**
aoqi@0 148 * Constructs a MimeMultipart object and its bodyparts from the
aoqi@0 149 * given DataSource. <p>
aoqi@0 150 *
aoqi@0 151 * This constructor handles as a special case the situation where the
aoqi@0 152 * given DataSource is a MultipartDataSource object.
aoqi@0 153 *
aoqi@0 154 * Otherwise, the DataSource is assumed to provide a MIME multipart
aoqi@0 155 * byte stream. The <code>parsed</code> flag is set to false. When
aoqi@0 156 * the data for the body parts are needed, the parser extracts the
aoqi@0 157 * "boundary" parameter from the content type of this DataSource,
aoqi@0 158 * skips the 'preamble' and reads bytes till the terminating
aoqi@0 159 * boundary and creates MimeBodyParts for each part of the stream.
aoqi@0 160 *
aoqi@0 161 * @param ds DataSource, can be a MultipartDataSource
aoqi@0 162 * @param ct
aoqi@0 163 * This must be the same information as {@link DataSource#getContentType()}.
aoqi@0 164 * All the callers of this method seem to have this object handy, so
aoqi@0 165 * for performance reason this method accepts it. Can be null.
aoqi@0 166 */
aoqi@0 167 public MimeMultipart(DataSource ds, ContentType ct) throws MessagingException {
aoqi@0 168 // 'ds' was not a MultipartDataSource, we have
aoqi@0 169 // to parse this ourself.
aoqi@0 170 parsed = false;
aoqi@0 171 this.ds = ds;
aoqi@0 172 if (ct==null)
aoqi@0 173 contentType = new ContentType(ds.getContentType());
aoqi@0 174 else
aoqi@0 175 contentType = ct;
aoqi@0 176 }
aoqi@0 177
aoqi@0 178 /**
aoqi@0 179 * Set the subtype. This method should be invoked only on a new
aoqi@0 180 * MimeMultipart object created by the client. The default subtype
aoqi@0 181 * of such a multipart object is "mixed". <p>
aoqi@0 182 *
aoqi@0 183 * @param subtype Subtype
aoqi@0 184 */
aoqi@0 185 public void setSubType(String subtype) {
aoqi@0 186 contentType.setSubType(subtype);
aoqi@0 187 }
aoqi@0 188
aoqi@0 189 /**
aoqi@0 190 * Return the number of enclosed MimeBodyPart objects.
aoqi@0 191 *
aoqi@0 192 * @return number of parts
aoqi@0 193 */
aoqi@0 194 public int getCount() throws MessagingException {
aoqi@0 195 parse();
aoqi@0 196 if (parts == null)
aoqi@0 197 return 0;
aoqi@0 198
aoqi@0 199 return parts.size();
aoqi@0 200 }
aoqi@0 201
aoqi@0 202 /**
aoqi@0 203 * Get the specified MimeBodyPart. BodyParts are numbered starting at 0.
aoqi@0 204 *
aoqi@0 205 * @param index the index of the desired MimeBodyPart
aoqi@0 206 * @return the MimeBodyPart
aoqi@0 207 * @exception MessagingException if no such MimeBodyPart exists
aoqi@0 208 */
aoqi@0 209 public MimeBodyPart getBodyPart(int index)
aoqi@0 210 throws MessagingException {
aoqi@0 211 parse();
aoqi@0 212 if (parts == null)
aoqi@0 213 throw new IndexOutOfBoundsException("No such BodyPart");
aoqi@0 214
aoqi@0 215 return (MimeBodyPart)parts.get(index);
aoqi@0 216 }
aoqi@0 217
aoqi@0 218 /**
aoqi@0 219 * Get the MimeBodyPart referred to by the given ContentID (CID).
aoqi@0 220 * Returns null if the part is not found.
aoqi@0 221 *
aoqi@0 222 * @param CID the ContentID of the desired part
aoqi@0 223 * @return the MimeBodyPart
aoqi@0 224 */
aoqi@0 225 public MimeBodyPart getBodyPart(String CID)
aoqi@0 226 throws MessagingException {
aoqi@0 227 parse();
aoqi@0 228
aoqi@0 229 int count = getCount();
aoqi@0 230 for (int i = 0; i < count; i++) {
aoqi@0 231 MimeBodyPart part = getBodyPart(i);
aoqi@0 232 String s = part.getContentID();
aoqi@0 233 // Old versions of AXIS2 put angle brackets around the content
aoqi@0 234 // id but not the start param
aoqi@0 235 String sNoAngle = (s!= null) ? s.replaceFirst("^<", "").replaceFirst(">$", "")
aoqi@0 236 :null;
aoqi@0 237 if (s != null && (s.equals(CID) || CID.equals(sNoAngle)))
aoqi@0 238 return part;
aoqi@0 239 }
aoqi@0 240 return null;
aoqi@0 241 }
aoqi@0 242
aoqi@0 243 /**
aoqi@0 244 * Update headers. The default implementation here just
aoqi@0 245 * calls the <code>updateHeaders</code> method on each of its
aoqi@0 246 * children BodyParts. <p>
aoqi@0 247 *
aoqi@0 248 * Note that the boundary parameter is already set up when
aoqi@0 249 * a new and empty MimeMultipart object is created. <p>
aoqi@0 250 *
aoqi@0 251 * This method is called when the <code>saveChanges</code>
aoqi@0 252 * method is invoked on the Message object containing this
aoqi@0 253 * MimeMultipart. This is typically done as part of the Message
aoqi@0 254 * send process, however note that a client is free to call
aoqi@0 255 * it any number of times. So if the header updating process is
aoqi@0 256 * expensive for a specific MimeMultipart subclass, then it
aoqi@0 257 * might itself want to track whether its internal state actually
aoqi@0 258 * did change, and do the header updating only if necessary.
aoqi@0 259 */
aoqi@0 260 protected void updateHeaders() throws MessagingException {
aoqi@0 261 for (int i = 0; i < parts.size(); i++)
aoqi@0 262 ((MimeBodyPart)parts.get(i)).updateHeaders();
aoqi@0 263 }
aoqi@0 264
aoqi@0 265 /**
aoqi@0 266 * Iterates through all the parts and outputs each Mime part
aoqi@0 267 * separated by a boundary.
aoqi@0 268 */
aoqi@0 269 public void writeTo(OutputStream os)
aoqi@0 270 throws IOException, MessagingException {
aoqi@0 271 parse();
aoqi@0 272
aoqi@0 273 String boundary = "--" + contentType.getParameter("boundary");
aoqi@0 274
aoqi@0 275 for (int i = 0; i < parts.size(); i++) {
aoqi@0 276 OutputUtil.writeln(boundary, os); // put out boundary
aoqi@0 277 getBodyPart(i).writeTo(os);
aoqi@0 278 OutputUtil.writeln(os); // put out empty line
aoqi@0 279 }
aoqi@0 280
aoqi@0 281 // put out last boundary
aoqi@0 282 OutputUtil.writeAsAscii(boundary, os);
aoqi@0 283 OutputUtil.writeAsAscii("--", os);
aoqi@0 284 os.flush();
aoqi@0 285 }
aoqi@0 286
aoqi@0 287 /**
aoqi@0 288 * Parse the InputStream from our DataSource, constructing the
aoqi@0 289 * appropriate MimeBodyParts. The <code>parsed</code> flag is
aoqi@0 290 * set to true, and if true on entry nothing is done. This
aoqi@0 291 * method is called by all other methods that need data for
aoqi@0 292 * the body parts, to make sure the data has been parsed.
aoqi@0 293 *
aoqi@0 294 * @since JavaMail 1.2
aoqi@0 295 */
aoqi@0 296 protected void parse() throws MessagingException {
aoqi@0 297 if (parsed)
aoqi@0 298 return;
aoqi@0 299
aoqi@0 300 InputStream in;
aoqi@0 301 SharedInputStream sin = null;
aoqi@0 302 long start = 0, end = 0;
aoqi@0 303 boolean foundClosingBoundary = false;
aoqi@0 304
aoqi@0 305 try {
aoqi@0 306 in = ds.getInputStream();
aoqi@0 307 if (!(in instanceof ByteArrayInputStream) &&
aoqi@0 308 !(in instanceof BufferedInputStream) &&
aoqi@0 309 !(in instanceof SharedInputStream))
aoqi@0 310 in = new BufferedInputStream(in);
aoqi@0 311 } catch (Exception ex) {
aoqi@0 312 throw new MessagingException("No inputstream from datasource");
aoqi@0 313 }
aoqi@0 314 if (in instanceof SharedInputStream)
aoqi@0 315 sin = (SharedInputStream)in;
aoqi@0 316
aoqi@0 317 String boundary = "--" + contentType.getParameter("boundary");
aoqi@0 318 byte[] bndbytes = ASCIIUtility.getBytes(boundary);
aoqi@0 319 int bl = bndbytes.length;
aoqi@0 320
aoqi@0 321 try {
aoqi@0 322 // Skip the preamble
aoqi@0 323 LineInputStream lin = new LineInputStream(in);
aoqi@0 324 String line;
aoqi@0 325 while ((line = lin.readLine()) != null) {
aoqi@0 326 /*
aoqi@0 327 * Strip trailing whitespace. Can't use trim method
aoqi@0 328 * because it's too aggressive. Some bogus MIME
aoqi@0 329 * messages will include control characters in the
aoqi@0 330 * boundary string.
aoqi@0 331 */
aoqi@0 332 int i;
aoqi@0 333 for (i = line.length() - 1; i >= 0; i--) {
aoqi@0 334 char c = line.charAt(i);
aoqi@0 335 if (!(c == ' ' || c == '\t'))
aoqi@0 336 break;
aoqi@0 337 }
aoqi@0 338 line = line.substring(0, i + 1);
aoqi@0 339 if (line.equals(boundary))
aoqi@0 340 break;
aoqi@0 341 }
aoqi@0 342 if (line == null)
aoqi@0 343 throw new MessagingException("Missing start boundary");
aoqi@0 344
aoqi@0 345 /*
aoqi@0 346 * Read and process body parts until we see the
aoqi@0 347 * terminating boundary line (or EOF).
aoqi@0 348 */
aoqi@0 349 boolean done = false;
aoqi@0 350 getparts:
aoqi@0 351 while (!done) {
aoqi@0 352 InternetHeaders headers = null;
aoqi@0 353 if (sin != null) {
aoqi@0 354 start = sin.getPosition();
aoqi@0 355 // skip headers
aoqi@0 356 while ((line = lin.readLine()) != null && line.length() > 0)
aoqi@0 357 ;
aoqi@0 358 if (line == null) {
aoqi@0 359 if (!ignoreMissingEndBoundary) {
aoqi@0 360 throw new MessagingException("Missing End Boundary for Mime Package : EOF while skipping headers");
aoqi@0 361 }
aoqi@0 362 // assume there's just a missing end boundary
aoqi@0 363 break getparts;
aoqi@0 364 }
aoqi@0 365 } else {
aoqi@0 366 // collect the headers for this body part
aoqi@0 367 headers = createInternetHeaders(in);
aoqi@0 368 }
aoqi@0 369
aoqi@0 370 if (!in.markSupported())
aoqi@0 371 throw new MessagingException("Stream doesn't support mark");
aoqi@0 372
aoqi@0 373 ByteOutputStream buf = null;
aoqi@0 374 // if we don't have a shared input stream, we copy the data
aoqi@0 375 if (sin == null)
aoqi@0 376 buf = new ByteOutputStream();
aoqi@0 377 int b;
aoqi@0 378 boolean bol = true; // beginning of line flag
aoqi@0 379 // the two possible end of line characters
aoqi@0 380 int eol1 = -1, eol2 = -1;
aoqi@0 381
aoqi@0 382 /*
aoqi@0 383 * Read and save the content bytes in buf.
aoqi@0 384 */
aoqi@0 385 for (;;) {
aoqi@0 386 if (bol) {
aoqi@0 387 /*
aoqi@0 388 * At the beginning of a line, check whether the
aoqi@0 389 * next line is a boundary.
aoqi@0 390 */
aoqi@0 391 int i;
aoqi@0 392 in.mark(bl + 4 + 1000); // bnd + "--\r\n" + lots of LWSP
aoqi@0 393 // read bytes, matching against the boundary
aoqi@0 394 for (i = 0; i < bl; i++)
aoqi@0 395 if (in.read() != bndbytes[i])
aoqi@0 396 break;
aoqi@0 397 if (i == bl) {
aoqi@0 398 // matched the boundary, check for last boundary
aoqi@0 399 int b2 = in.read();
aoqi@0 400 if (b2 == '-') {
aoqi@0 401 if (in.read() == '-') {
aoqi@0 402 done = true;
aoqi@0 403 foundClosingBoundary = true;
aoqi@0 404 break; // ignore trailing text
aoqi@0 405 }
aoqi@0 406 }
aoqi@0 407 // skip linear whitespace
aoqi@0 408 while (b2 == ' ' || b2 == '\t')
aoqi@0 409 b2 = in.read();
aoqi@0 410 // check for end of line
aoqi@0 411 if (b2 == '\n')
aoqi@0 412 break; // got it! break out of the loop
aoqi@0 413 if (b2 == '\r') {
aoqi@0 414 in.mark(1);
aoqi@0 415 if (in.read() != '\n')
aoqi@0 416 in.reset();
aoqi@0 417 break; // got it! break out of the loop
aoqi@0 418 }
aoqi@0 419 }
aoqi@0 420 // failed to match, reset and proceed normally
aoqi@0 421 in.reset();
aoqi@0 422
aoqi@0 423 // if this is not the first line, write out the
aoqi@0 424 // end of line characters from the previous line
aoqi@0 425 if (buf != null && eol1 != -1) {
aoqi@0 426 buf.write(eol1);
aoqi@0 427 if (eol2 != -1)
aoqi@0 428 buf.write(eol2);
aoqi@0 429 eol1 = eol2 = -1;
aoqi@0 430 }
aoqi@0 431 }
aoqi@0 432
aoqi@0 433 // read the next byte
aoqi@0 434 if ((b = in.read()) < 0) {
aoqi@0 435 done = true;
aoqi@0 436 break;
aoqi@0 437 }
aoqi@0 438
aoqi@0 439 /*
aoqi@0 440 * If we're at the end of the line, save the eol characters
aoqi@0 441 * to be written out before the beginning of the next line.
aoqi@0 442 */
aoqi@0 443 if (b == '\r' || b == '\n') {
aoqi@0 444 bol = true;
aoqi@0 445 if (sin != null)
aoqi@0 446 end = sin.getPosition() - 1;
aoqi@0 447 eol1 = b;
aoqi@0 448 if (b == '\r') {
aoqi@0 449 in.mark(1);
aoqi@0 450 if ((b = in.read()) == '\n')
aoqi@0 451 eol2 = b;
aoqi@0 452 else
aoqi@0 453 in.reset();
aoqi@0 454 }
aoqi@0 455 } else {
aoqi@0 456 bol = false;
aoqi@0 457 if (buf != null)
aoqi@0 458 buf.write(b);
aoqi@0 459 }
aoqi@0 460 }
aoqi@0 461
aoqi@0 462 /*
aoqi@0 463 * Create a MimeBody element to represent this body part.
aoqi@0 464 */
aoqi@0 465 MimeBodyPart part;
aoqi@0 466 if (sin != null)
aoqi@0 467 part = createMimeBodyPart(sin.newStream(start, end));
aoqi@0 468 else
aoqi@0 469 part = createMimeBodyPart(headers, buf.getBytes(), buf.getCount());
aoqi@0 470 addBodyPart(part);
aoqi@0 471 }
aoqi@0 472 } catch (IOException ioex) {
aoqi@0 473 throw new MessagingException("IO Error", ioex);
aoqi@0 474 }
aoqi@0 475
aoqi@0 476 if (!ignoreMissingEndBoundary && !foundClosingBoundary && sin== null) {
aoqi@0 477 throw new MessagingException("Missing End Boundary for Mime Package : EOF while skipping headers");
aoqi@0 478 }
aoqi@0 479 parsed = true;
aoqi@0 480 }
aoqi@0 481
aoqi@0 482 /**
aoqi@0 483 * Create and return an InternetHeaders object that loads the
aoqi@0 484 * headers from the given InputStream. Subclasses can override
aoqi@0 485 * this method to return a subclass of InternetHeaders, if
aoqi@0 486 * necessary. This implementation simply constructs and returns
aoqi@0 487 * an InternetHeaders object.
aoqi@0 488 *
aoqi@0 489 * @param is the InputStream to read the headers from
aoqi@0 490 * @exception MessagingException
aoqi@0 491 * @since JavaMail 1.2
aoqi@0 492 */
aoqi@0 493 protected InternetHeaders createInternetHeaders(InputStream is)
aoqi@0 494 throws MessagingException {
aoqi@0 495 return new InternetHeaders(is);
aoqi@0 496 }
aoqi@0 497
aoqi@0 498 /**
aoqi@0 499 * Create and return a MimeBodyPart object to represent a
aoqi@0 500 * body part parsed from the InputStream. Subclasses can override
aoqi@0 501 * this method to return a subclass of MimeBodyPart, if
aoqi@0 502 * necessary. This implementation simply constructs and returns
aoqi@0 503 * a MimeBodyPart object.
aoqi@0 504 *
aoqi@0 505 * @param headers the headers for the body part
aoqi@0 506 * @param content the content of the body part
aoqi@0 507 * @since JavaMail 1.2
aoqi@0 508 */
aoqi@0 509 protected MimeBodyPart createMimeBodyPart(InternetHeaders headers, byte[] content, int len) {
aoqi@0 510 return new MimeBodyPart(headers, content,len);
aoqi@0 511 }
aoqi@0 512
aoqi@0 513 /**
aoqi@0 514 * Create and return a MimeBodyPart object to represent a
aoqi@0 515 * body part parsed from the InputStream. Subclasses can override
aoqi@0 516 * this method to return a subclass of MimeBodyPart, if
aoqi@0 517 * necessary. This implementation simply constructs and returns
aoqi@0 518 * a MimeBodyPart object.
aoqi@0 519 *
aoqi@0 520 * @param is InputStream containing the body part
aoqi@0 521 * @exception MessagingException
aoqi@0 522 * @since JavaMail 1.2
aoqi@0 523 */
aoqi@0 524 protected MimeBodyPart createMimeBodyPart(InputStream is) throws MessagingException {
aoqi@0 525 return new MimeBodyPart(is);
aoqi@0 526 }
aoqi@0 527
aoqi@0 528 /**
aoqi@0 529 * Setup this MimeMultipart object from the given MultipartDataSource. <p>
aoqi@0 530 *
aoqi@0 531 * The method adds the MultipartDataSource's MimeBodyPart
aoqi@0 532 * objects into this MimeMultipart. This MimeMultipart's contentType is
aoqi@0 533 * set to that of the MultipartDataSource. <p>
aoqi@0 534 *
aoqi@0 535 * This method is typically used in those cases where one
aoqi@0 536 * has a multipart data source that has already been pre-parsed into
aoqi@0 537 * the individual body parts (for example, an IMAP datasource), but
aoqi@0 538 * needs to create an appropriate MimeMultipart subclass that represents
aoqi@0 539 * a specific multipart subtype.
aoqi@0 540 *
aoqi@0 541 * @param mp MimeMultipart datasource
aoqi@0 542 */
aoqi@0 543
aoqi@0 544 protected void setMultipartDataSource(MultipartDataSource mp)
aoqi@0 545 throws MessagingException {
aoqi@0 546 contentType = new ContentType(mp.getContentType());
aoqi@0 547
aoqi@0 548 int count = mp.getCount();
aoqi@0 549 for (int i = 0; i < count; i++)
aoqi@0 550 addBodyPart(mp.getBodyPart(i));
aoqi@0 551 }
aoqi@0 552
aoqi@0 553 /**
aoqi@0 554 * Return the content-type of this MimeMultipart. <p>
aoqi@0 555 *
aoqi@0 556 * This implementation just returns the value of the
aoqi@0 557 * <code>contentType</code> field.
aoqi@0 558 *
aoqi@0 559 * @return content-type
aoqi@0 560 * @see #contentType
aoqi@0 561 */
aoqi@0 562 public ContentType getContentType() {
aoqi@0 563 return contentType;
aoqi@0 564 }
aoqi@0 565
aoqi@0 566 /**
aoqi@0 567 * Remove the specified part from the multipart message.
aoqi@0 568 * Shifts all the parts after the removed part down one.
aoqi@0 569 *
aoqi@0 570 * @param part The part to remove
aoqi@0 571 * @return true if part removed, false otherwise
aoqi@0 572 * @exception MessagingException if no such MimeBodyPart exists
aoqi@0 573 */
aoqi@0 574 public boolean removeBodyPart(MimeBodyPart part) throws MessagingException {
aoqi@0 575 if (parts == null)
aoqi@0 576 throw new MessagingException("No such body part");
aoqi@0 577
aoqi@0 578 boolean ret = parts.remove(part);
aoqi@0 579 part.setParent(null);
aoqi@0 580 return ret;
aoqi@0 581 }
aoqi@0 582
aoqi@0 583 /**
aoqi@0 584 * Remove the part at specified location (starting from 0).
aoqi@0 585 * Shifts all the parts after the removed part down one.
aoqi@0 586 *
aoqi@0 587 * @param index Index of the part to remove
aoqi@0 588 * @exception IndexOutOfBoundsException if the given index
aoqi@0 589 * is out of range.
aoqi@0 590 */
aoqi@0 591 public void removeBodyPart(int index) {
aoqi@0 592 if (parts == null)
aoqi@0 593 throw new IndexOutOfBoundsException("No such BodyPart");
aoqi@0 594
aoqi@0 595 MimeBodyPart part = (MimeBodyPart)parts.get(index);
aoqi@0 596 parts.remove(index);
aoqi@0 597 part.setParent(null);
aoqi@0 598 }
aoqi@0 599
aoqi@0 600 /**
aoqi@0 601 * Adds a MimeBodyPart to the multipart. The MimeBodyPart is appended to
aoqi@0 602 * the list of existing Parts.
aoqi@0 603 *
aoqi@0 604 * @param part The MimeBodyPart to be appended
aoqi@0 605 */
aoqi@0 606 public synchronized void addBodyPart(MimeBodyPart part) {
aoqi@0 607 if (parts == null)
aoqi@0 608 parts = new FinalArrayList();
aoqi@0 609
aoqi@0 610 parts.add(part);
aoqi@0 611 part.setParent(this);
aoqi@0 612 }
aoqi@0 613
aoqi@0 614 /**
aoqi@0 615 * Adds a MimeBodyPart at position <code>index</code>.
aoqi@0 616 * If <code>index</code> is not the last one in the list,
aoqi@0 617 * the subsequent parts are shifted up. If <code>index</code>
aoqi@0 618 * is larger than the number of parts present, the
aoqi@0 619 * MimeBodyPart is appended to the end.
aoqi@0 620 *
aoqi@0 621 * @param part The MimeBodyPart to be inserted
aoqi@0 622 * @param index Location where to insert the part
aoqi@0 623 */
aoqi@0 624 public synchronized void addBodyPart(MimeBodyPart part, int index) {
aoqi@0 625 if (parts == null)
aoqi@0 626 parts = new FinalArrayList();
aoqi@0 627
aoqi@0 628 parts.add(index,part);
aoqi@0 629 part.setParent(this);
aoqi@0 630 }
aoqi@0 631
aoqi@0 632 /**
aoqi@0 633 * Return the <code>MimeBodyPart</code> that contains this <code>MimeMultipart</code>
aoqi@0 634 * object, or <code>null</code> if not known.
aoqi@0 635 * @since JavaMail 1.1
aoqi@0 636 */
aoqi@0 637 MimeBodyPart getParent() {
aoqi@0 638 return parent;
aoqi@0 639 }
aoqi@0 640
aoqi@0 641 /**
aoqi@0 642 * Set the parent of this <code>MimeMultipart</code> to be the specified
aoqi@0 643 * <code>MimeBodyPart</code>. Normally called by the <code>Message</code>
aoqi@0 644 * or <code>MimeBodyPart</code> <code>setContent(MimeMultipart)</code> method.
aoqi@0 645 * <code>parent</code> may be <code>null</code> if the
aoqi@0 646 * <code>MimeMultipart</code> is being removed from its containing
aoqi@0 647 * <code>MimeBodyPart</code>.
aoqi@0 648 * @since JavaMail 1.1
aoqi@0 649 */
aoqi@0 650 void setParent(MimeBodyPart parent) {
aoqi@0 651 this.parent = parent;
aoqi@0 652 }
aoqi@0 653 }

mercurial