/*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
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);
}
}