| /* |
| * 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 Distribution License v. 1.0, which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| import java.io.*; |
| import javax.mail.*; |
| import javax.mail.internet.*; |
| import javax.activation.*; |
| |
| /** |
| * This class models a UUEncoded Message sent from MS Outlook etc. <p> |
| * |
| * The message structure looks like this := |
| * [text body] [uuencoded attachment]* |
| * <p> |
| * i.e., an optional text/plain main-body, followed by zero or more |
| * UUENCODE-ed attachments. |
| * |
| * @author John Mani |
| * @author Bill Shannon |
| * @see javax.mail.internet.MimeMessage |
| */ |
| |
| public class MSMessage extends MimeMessage { |
| private String type; |
| |
| /** |
| * Constructor that converts a MimeMessage object into a MSMessage. |
| * |
| * @exception MessagingException if the given MimeMessage |
| * is not a non-MIME MS message, or if an |
| * IOException occurs when accessing the given |
| * MimeMessage object |
| */ |
| public MSMessage(Session session, MimeMessage msg) |
| throws MessagingException { |
| super(session); |
| |
| if (!isMSMessage(msg)) // sanity check |
| throw new MessagingException("Not an MS message"); |
| |
| class FastByteArrayOutputStream extends ByteArrayOutputStream { |
| ByteArrayInputStream toByteArrayInputStream() { |
| return new ByteArrayInputStream(buf, 0, count); |
| } |
| } |
| |
| // extract the bytes of the given message |
| // ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| FastByteArrayOutputStream bos = new FastByteArrayOutputStream(); |
| try { |
| msg.writeTo(bos); |
| } catch (IOException ioex) { |
| throw new MessagingException("IOException", ioex); |
| } catch (Exception ex) { |
| throw new MessagingException("Exception", ex); |
| } |
| //parse(new ByteArrayInputStream(bos.toByteArray())); |
| parse(bos.toByteArrayInputStream()); |
| } |
| |
| /** |
| * Constructor to create a MSMessage from the given InputStream. |
| */ |
| public MSMessage(Session session, InputStream is) |
| throws MessagingException { |
| super(session); // setup headerstore etc |
| parse(is); |
| } |
| |
| // parse input stream |
| protected void parse(InputStream is) throws MessagingException { |
| // Create a buffered input stream for efficiency |
| if (!(is instanceof ByteArrayInputStream) && |
| !(is instanceof BufferedInputStream)) |
| is = new BufferedInputStream(is); |
| |
| // Load headerstore |
| headers.load(is); |
| |
| /* |
| * Load the content into a byte[]. |
| * This byte[] is shared among the bodyparts. |
| */ |
| try { |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| int b; |
| // XXX - room for performance improvement |
| while ((b = is.read()) != -1) |
| bos.write(b); |
| content = bos.toByteArray(); |
| } catch (IOException ioex) { |
| throw new MessagingException("IOException", ioex); |
| } |
| |
| /* |
| * Check whether this is multipart. |
| */ |
| boolean isMulti = false; |
| // check for presence of X-MS-Attachment header |
| String[] att = getHeader("X-MS-Attachment"); |
| if (att != null && att.length > 0) |
| isMulti = true; |
| else { |
| /* |
| * Fall back to scanning the content. |
| * We scan the content until we find a sequence that looks |
| * like the start of a uuencoded block, i.e., "<newline>begin". |
| * If found, we claim that this is a multipart message. |
| */ |
| for (int i = 0; i < content.length; i++) { |
| int b = content[i] & 0xff; // mask higher byte |
| if (b == '\r' || b == '\n') { |
| // start of a new line |
| if ((i + 5) < content.length) { |
| // can there be a "begin" now? |
| String s = toString(content, i+1, i+6); |
| if (s.equalsIgnoreCase("begin")) { |
| isMulti= true; |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| if (isMulti) { |
| type = "multipart/mixed"; |
| dh = new DataHandler(new MSMultipartDataSource(this, content)); |
| } else { |
| type = "text/plain"; // charset = ? |
| dh = new DataHandler(new MimePartDataSource(this)); |
| } |
| |
| modified = false; |
| } |
| |
| /** |
| * Return content-type |
| */ |
| public String getContentType() throws MessagingException { |
| return type; |
| } |
| |
| /** |
| * Return content-disposition |
| */ |
| public String getDisposition() throws MessagingException { |
| return "inline"; |
| } |
| |
| /** |
| * Return content-transfer-encoding |
| */ |
| public String getEncoding() throws MessagingException { |
| return "7bit"; |
| } |
| |
| /** |
| * Check whether the given MimeMessage object represents a |
| * non-MIME message sent by Outlook. Such a message will |
| * have no MIME-Version header, may have an X-Mailer header |
| * that includes the word "Microsoft", and will have at least |
| * one X-MS-Attachment header. |
| */ |
| public static boolean isMSMessage(MimeMessage msg) |
| throws MessagingException { |
| // Check whether the MIME header is present |
| if (msg.getHeader("MIME-Version") != null) |
| // MIME-Version header present, should be a MIME message |
| return false; |
| |
| /* |
| * XXX - disabled X-Mailer check because many sample messages |
| * I saw didn't have an X-Mailer header at all. |
| */ |
| if (false) { |
| // Check X-Mailer |
| String mailer = msg.getHeader("X-mailer", null); |
| if (mailer == null) // No X-mailer ? |
| return false; // Oh well ! |
| if (mailer.indexOf("Microsoft") == -1) // Not MS stuff ? |
| return false; |
| } |
| |
| // Check X-MS-Attachment header |
| // XXX - not all such messages have this header |
| String[] att = msg.getHeader("X-MS-Attachment"); |
| if (att == null || att.length == 0) |
| return false; |
| |
| return true; |
| } |
| |
| // convert given byte array of ASCII characters to string |
| static String toString(byte[] b, int start, int end) { |
| int size = end - start; |
| char[] theChars = new char[size]; |
| |
| for (int i = 0, j = start; i < size; ) |
| theChars[i++] = (char)b[j++]; |
| return new String(theChars); |
| } |
| } |