/* * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at * http://www.eclipse.org/legal/epl-2.0. * * This Source Code may also be made available under the following Secondary * Licenses when the conditions for such availability set forth in the * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, * version 2 with the GNU Classpath Exception, which is available at * https://www.gnu.org/software/classpath/license.html. * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ package com.sun.mail.mbox; import javax.mail.*; import javax.mail.internet.*; import javax.activation.*; import java.util.*; import java.io.*; import java.nio.charset.StandardCharsets; import com.sun.mail.util.LineInputStream; /** * The SunV3Multipart class is an implementation of the abstract Multipart * class that uses SunV3 conventions for the multipart data.

* * @author Bill Shannon */ public class SunV3Multipart extends MimeMultipart { private boolean parsing; /** * Constructs a SunV3Multipart object and its bodyparts from the * given DataSource.

* * @param ds DataSource, can be a MultipartDataSource */ public SunV3Multipart(DataSource ds) throws MessagingException { super(ds); } /** * Set the subtype. Throws MethodNotSupportedException. * * @param subtype Subtype */ public void setSubType(String subtype) throws MessagingException { throw new MethodNotSupportedException( "can't change SunV3Multipart subtype"); } /** * Get the BodyPart referred to by the given ContentID (CID). * Throws MethodNotSupportException. */ public synchronized BodyPart getBodyPart(String CID) throws MessagingException { throw new MethodNotSupportedException( "SunV3Multipart doesn't support Content-ID"); } /** * Update headers. Throws MethodNotSupportException. */ protected void updateHeaders() throws MessagingException { throw new MethodNotSupportedException("SunV3Multipart not writable"); } /** * Iterates through all the parts and outputs each SunV3 part * separated by a boundary. */ public void writeTo(OutputStream os) throws IOException, MessagingException { throw new MethodNotSupportedException( "SunV3Multipart writeTo not supported"); } private static final String boundary = "----------"; /* * Parse the contents of this multipart message and create the * child body parts. */ protected synchronized void parse() throws MessagingException { /* * If the data has already been parsed, or we're in the middle of * parsing it, there's nothing to do. The latter will occur when * we call addBodyPart, which will call parse again. We really * want to be able to call super.super.addBodyPart. */ if (parsed || parsing) return; InputStream in = null; try { in = ds.getInputStream(); if (!(in instanceof ByteArrayInputStream) && !(in instanceof BufferedInputStream)) in = new BufferedInputStream(in); } catch (IOException ex) { throw new MessagingException("No inputstream from datasource"); } catch (RuntimeException ex) { throw new MessagingException("No inputstream from datasource"); } byte[] bndbytes = boundary.getBytes(StandardCharsets.ISO_8859_1); int bl = bndbytes.length; String line; parsing = true; try { /* * Skip any kind of junk until we get to the first * boundary line. */ LineInputStream lin = new LineInputStream(in); while ((line = lin.readLine()) != null) { if (line.trim().equals(boundary)) break; } if (line == null) throw new MessagingException("Missing start boundary"); /* * Read and process body parts until we see the * terminating boundary line (or EOF). */ for (;;) { /* * Collect the headers for this body part. */ InternetHeaders headers = new InternetHeaders(in); if (!in.markSupported()) throw new MessagingException("Stream doesn't support mark"); ByteArrayOutputStream buf = new ByteArrayOutputStream(); int b; /* * Read and save the content bytes in buf. */ while ((b = in.read()) >= 0) { if (b == '\r' || b == '\n') { /* * Found the end of a line, check whether the * next line is a boundary. */ int i; in.mark(bl + 4 + 1); // "4" for possible "--\r\n" if (b == '\r' && in.read() != '\n') { in.reset(); in.mark(bl + 4); } // read bytes, matching against the boundary for (i = 0; i < bl; i++) if (in.read() != bndbytes[i]) break; if (i == bl) { int b2 = in.read(); // check for end of line if (b2 == '\n') break; // got it! break out of the while loop if (b2 == '\r') { in.mark(1); if (in.read() != '\n') in.reset(); break; // got it! break out of the while loop } } // failed to match, reset and proceed normally in.reset(); } buf.write(b); } /* * Create a SunV3BodyPart to represent this body part. */ SunV3BodyPart body = new SunV3BodyPart(headers, buf.toByteArray()); addBodyPart(body); if (b < 0) break; } } catch (IOException e) { throw new MessagingException("IO Error"); // XXX } finally { parsing = false; } parsed = true; } }