timeless%mac.com 21c081c8bc Bugzilla Bug 106386 rid source of these misspellings: persistant persistance priviledge protocal editting editted targetted targetting
r='s from many people. sr=jst


git-svn-id: svn://10.0.0.236/trunk@111049 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-23 23:23:41 +00:00

2836 lines
85 KiB
Java

/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Netscape Messaging Access SDK Version 3.5 code,
* released on or about June 15, 1998. *
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): ______________________________________.
*/
/*
* Copyright (c) 1997 and 1998 Netscape Communications Corporation
* (http://home.netscape.com/misc/trademarks.html)
*/
/**
* The MIMEParser class represents a MIME parser.
* This generic parser takes an email message encoded in
* MIME and decodes it into a set of usable structures.
* @author Carson Lee
* @version 1.0
* Dec 17,1997
*/
package netscape.messaging.mime;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Vector;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.util.Enumeration;
import netscape.messaging.mime.MIMEMessage;
import netscape.messaging.mime.MIMEBasicPart;
import netscape.messaging.mime.MIMEMultiPart;
import netscape.messaging.mime.MIMEMessagePart;
import netscape.messaging.mime.MIMEHelper;
import netscape.messaging.mime.MIMEDataSink;
import netscape.messaging.mime.log;
public final class MIMEParser
{
// used internally by parser to track information
final class mimeInfo
{
int m_type; // content type
byte[] m_name; // header name
byte[] m_value; // header value
Vector m_param; // header param
mimeInfo( int type1, byte[] name1, byte[] value1 )
{
m_type = type1;
m_name = name1;
m_value = value1;
m_param = new Vector();
}
mimeInfo()
{
m_type = 0;
m_name = null;
m_value = null;
m_param = new Vector();
}
mimeInfo( int type1, byte[] name1 )
{
m_type = type1;
m_name = name1;
m_param = new Vector();
}
}
final static int MIME_INFO_CONTENT_TYPE = 1;
final static int MIME_INFO_CONTENT_SUBTYPE = 2;
final static int MIME_INFO_CONTENT_TRANSFER_ENCODING = 3;
final static int MIME_INFO_CONTENT_DISPOSITION = 4;
final static int MIME_INFO_CONTENT_ID = 5;
final static int MIME_INFO_CONTENT_DESCRIPTION = 6;
final static int MIME_INFO_CONTENT_BASE = 7;
final static int MIME_INFO_MIME_VERSION = 8;
final static private int MIME_INFO = 31;
final static private int MIME_HEADER = 32;
final static private int MIME_XHEADER = 33;
final static private int MIME_MESSAGE_DATA = 34;
final static private int MIME_PARAM = 35;
final static private int MIME_BOUNDARY = 36;
final static private int MIME_CRLF = 37;
final static private int MIME_UNINITIALIZED = -88;
final static private int MIME_CONTENT_PARSE_ALL = -99;
final static private int NSMAIL_ERR_INVALIDPARAM = -1;
final static private int NSMAIL_ERR_OUTOFMEMORY = -2;
final static private int NSMAIL_OK = 0;
final static private int NOT_A_BOUNDARY = 21;
final static private int START_BOUNDARY = 22;
final static private int END_BOUNDARY = 23;
final static int BUFFER_SIZE = 2048;
final static int SUBTYPE_RFC822 = 1;
final static int SUBTYPE_EXTERNAL_BODY = 2;
final static byte[] mb_MultiPart = "Multipart".getBytes();
//final static byte[] mb_MessagePart = "Messagepart".getBytes();
final static byte[] mb_MessagePart = "Message".getBytes();
final static byte[] mb_TextPart = "Text".getBytes();
final static byte[] mb_AudioPart = "Audio".getBytes();
final static byte[] mb_VideoPart = "Video".getBytes();
final static byte[] mb_ImagePart = "Image".getBytes();
final static byte[] mb_ApplPart = "Application".getBytes();
private static final byte[] CRLF = "\r\n".getBytes();
private Vector m_messageData; // text buffer
private Vector m_mimeInfo; // message info
private Vector m_msgParts; // message info
private MIMEMessage m_mimeMessage; // entire decoded mime message
private int m_nMessageType; // message type, ie: message, basicpart, etc.
private Object m_currentMessage; // current message being processed
private MIMEBasicPart m_currentBasicPart;
private MIMEMultiPart m_currentMultiPart;
private MIMEMessagePart m_currentMessagePart;
private int m_nCurrentMessageType; // current message type
private boolean m_bStartData; // TRUE if start of data
private int m_emptyLineNo; // TRUE if current line is empty
private MIMEDataSink m_dataSink; // callback datasink
private byte[] m_leftoverBuffer; // leftover buffer
private byte[] m_inputBuffer; // inputbuffer
private int m_leftoverBytes; // left over bytes from previous parse
private int m_out_byte; // state info
private int m_out_bits; // state info
private boolean m_bParseEntireFile; // false if parsing in chunks
private byte[] m_QPLeftoverBuffer; // leftover buffer
private int m_QPLeftoverBytes; // left over bytes from previous parse
private Vector m_currentParent; // current message parent
private MIMEMessage m_currentMimeMessage; // current mime message
private boolean m_bDecodeData = true;
private boolean m_bLocalStorage = true;
private MIMEMessage m_nextMimeMessage;
private int m_lastBoundry;
private Vector m_mimeInfoQueue;
private Vector m_headerQueue;
private boolean m_qp = false;
private boolean m_readCR = false;
private Object m_headerParent;
private Object m_nextHeaderParent;
private String m_previousHeaderName;
private int m_messagePartSubType;
private boolean m_fSeenBoundary = false;
private boolean m_fEndMessageHeader = false;
// exposed routines ------------------------------------------------------------
/**
* Default Constructor. Use with static parsing
* when the entire message to be parsed is available.
* @see #parseEntireMessage
*
*/
public MIMEParser()
{
this( (MIMEMessage) null);
}
/**
* Parses an entire message from an input stream.
* @param input User's input stream; source of message to parse.
* @return New parsed MIMEMessage object.
* @exception MIMEException If any parameter is NULL.
*/
public MIMEMessage parseEntireMessage( InputStream input ) throws MIMEException
{
init( null );
return (MIMEMessage) parseMimeMessage( input, MIME_CONTENT_PARSE_ALL );
}
// internal routines ------------------------------------------------------------
/**
* @param dataSink User's datasink for callbacks. Can not be null.
* @return New MIMEParser object
* @exception none
*/
protected MIMEParser (MIMEDataSink dataSink, boolean decodeData, boolean localStorage) throws MIMEException
{
this( (MIMEMessage) null );
if ( dataSink == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
m_dataSink = dataSink;
m_bParseEntireFile = false;
m_bDecodeData = decodeData;
m_bLocalStorage = localStorage;
}
/**
* Begin parse / reset parser.
* Only used for callbacks
*
* @author Carson Lee
* @version %I%, %G%
*
* @param none
* @return none
* @exception none
*/
protected void beginParse() throws MIMEException
{
m_leftoverBytes = 0;
m_QPLeftoverBytes = 0;
m_out_byte = 0;
m_out_bits = 0;
if ( m_dataSink == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
reInit (null);
//if ( m_bLocalStorage )
// m_mimeMessage.setUserObject( m_dataSink.startMessage( m_mimeMessage ) );
//else
m_mimeMessage.setUserObject( m_dataSink.startMessage() );
}
/**
* Parse incoming data. Only used for callbacks
*
* @author Carson Lee
* @version %I%, %G%
*
* @param input User's inputstream. Data will be read off this inputstream.
* @return none
* @exception MIMEException
*/
protected void parse( InputStream input ) throws MIMEException
{
parseMimeMessage( input, MIME_CONTENT_PARSE_ALL );
}
/**
* End parse. Tell parse there is no more data.
* Used only for callbacks.
*
* @author Carson Lee
* @version %I%, %G%
*
* @param none
* @return none
* @exception MIMEException
*/
protected void endParse() throws MIMEException
{
decodeDataBuffer();
if ( m_dataSink == null )
return;
MIMEBodyPart m = (MIMEBodyPart) m_currentMessage;
// take care of leftover bytes
if ( m_nCurrentMessageType == MIMEMessage.BASICPART )
{
MIMEBasicPart mimeBasicPart = (MIMEBasicPart) m_currentMessage;
/* base64 */
if ( mimeBasicPart.getContentEncoding() == MIMEBodyPart.BASE64 && m_out_bits > 0 )
{
byte[] decodedBuffer = MIMEHelper.decodeBase64LeftOverBytes( m_out_bits, m_out_byte );
saveBodyData( new ByteBuffer( decodedBuffer ), decodedBuffer.length, mimeBasicPart );
}
// will never happen
/*
else if ( mimeBasicPart.getContentEncoding() == MIMEBodyPart.QP && m_QPLeftoverBytes > 0 )
{
int[] param = new int[2];
param[0] = m_QPLeftoverBytes;
byte[] decodedBuffer = MIMEHelper.decodeQPVector( m_messageData,
mimeBasicPart.getStartMessageDataIndex(),
mimeBasicPart.getEndMessageDataIndex(),
param,
m_QPLeftoverBuffer );
if ( decodedBuffer != null )
{
m_QPLeftoverBytes = param[0];
param = null;
saveBodyData( new ByteBuffer( decodedBuffer ), param[1], mimeBasicPart );
}
}
*/
m_dataSink.endBasicPart( m.getUserObject() );
}
else if ( m_nCurrentMessageType == MIMEMessage.MULTIPART )
{
m_dataSink.endMultiPart( m.getUserObject() );
}
else if ( m_nCurrentMessageType == MIMEMessage.MESSAGEPART )
{
m_dataSink.endMessagePart( m.getUserObject() );
m_msgParts.removeElement (m);
}
// systematically invoke end* callback on all pending parts.
int nCurrentParentType = getCurrentParentType();
while (nCurrentParentType != MIME_UNINITIALIZED)
{
switch (nCurrentParentType)
{
case MIMEMessage.MULTIPART:
//MIMEMultiPart mp = (MIMEMultiPart) m_currentParent.lastElement();;
//m_dataSink.endMultiPart (mp.getUserObject());
// ingore. taken care of at END_BOUNDARY!
break;
case MIMEMessage.MESSAGEPART:
MIMEMessagePart msgP = (MIMEMessagePart) m_currentParent.lastElement();
String cst = msgP.getContentSubType();
if (cst.equalsIgnoreCase ("rfc822"))
{
// if it is rfc822. do endMessage() also
MIMEMessage mmm = msgP.getMessage();
m_dataSink.endMessage (mmm.getUserObject());
}
m_dataSink.endMessagePart (msgP.getUserObject());
m_msgParts.removeElement (msgP);
break;
}
m_currentParent.removeElementAt (m_currentParent.size() - 1);
nCurrentParentType = getCurrentParentType();
//System.out.println ("placeyy> currentParentType = " + nCurrentParentType);
}
// now check for any leftover ones still!
int partCount = m_msgParts.size();
while (partCount > 0)
{
MIMEMessagePart msgP = (MIMEMessagePart) m_msgParts.elementAt(partCount-1);
String cst = msgP.getContentSubType();
if (cst.equalsIgnoreCase ("rfc822"))
{
// if it is rfc822. do endMessage() also
MIMEMessage mmm = msgP.getMessage();
m_dataSink.endMessage (mmm.getUserObject());
}
m_dataSink.endMessagePart (msgP.getUserObject());
m_msgParts.removeElement (msgP);
partCount--;
}
m_dataSink.endMessage( m_mimeMessage.getUserObject() );
//checkForEmptyMessages( m_mimeMessage );
}
/**
* General constructor
*
* @author Carson Lee
* @version %I%, %G%
*
* @param m User's MimeMessage object. Will populate data into this object.
* @return none
* @exception none
*/
protected MIMEParser( MIMEMessage m )
{
init( m );
}
/**
* General constructor
*
* @author Carson Lee
* @version %I%, %G%
*
* @param m User's MimeMessage object. Will populate data into this object.
* @return none
* @exception none
*/
protected void init( MIMEMessage m )
{
m_messageData = new Vector();
m_mimeInfo = new Vector();
m_msgParts = new Vector();
m_mimeMessage = m == null ? new MIMEMessage() : m;
m_bStartData = false;
m_mimeMessage.m_parsedPart = 1;
m_nMessageType = MIME_UNINITIALIZED;
m_nCurrentMessageType = MIME_UNINITIALIZED;
m_currentMessage = null;
m_dataSink = null;
m_leftoverBuffer = new byte[2048];
m_inputBuffer = new byte[2048];
m_out_byte = 0;
m_out_bits = 0;
m_currentBasicPart = null;
m_currentMultiPart = null;
m_currentMessagePart = null;
m_bParseEntireFile = true;
m_currentParent = new Vector();
m_currentMimeMessage = m_mimeMessage;
m_currentParent.addElement( m_mimeMessage );
m_nextMimeMessage = null;
m_lastBoundry = START_BOUNDARY;
m_mimeInfoQueue = new Vector();
m_headerQueue = new Vector();
m_QPLeftoverBuffer = new byte[2];
m_qp = false;
m_readCR = false;
m_headerParent = m_mimeMessage;
m_nextHeaderParent = null;
m_previousHeaderName = null;
m_messagePartSubType = SUBTYPE_RFC822;
m_fEndMessageHeader = false;
}
protected void reInit( MIMEMessage m )
{
m_messageData = new Vector();
m_mimeInfo = new Vector();
m_msgParts = new Vector();
m_mimeMessage = m == null ? new MIMEMessage() : m;
m_bStartData = false;
m_mimeMessage.m_parsedPart = 1;
m_nMessageType = MIME_UNINITIALIZED;
m_nCurrentMessageType = MIME_UNINITIALIZED;
m_currentMessage = null;
//m_dataSink = null;
m_leftoverBuffer = new byte[2048];
m_inputBuffer = new byte[2048];
m_out_byte = 0;
m_out_bits = 0;
m_currentBasicPart = null;
m_currentMultiPart = null;
m_currentMessagePart = null;
m_bParseEntireFile = true;
m_currentParent = new Vector();
m_currentMimeMessage = m_mimeMessage;
m_currentParent.addElement( m_mimeMessage );
m_nextMimeMessage = null;
m_lastBoundry = START_BOUNDARY;
m_mimeInfoQueue = new Vector();
m_headerQueue = new Vector();
m_QPLeftoverBuffer = new byte[2];
m_qp = false;
m_readCR = false;
m_headerParent = m_mimeMessage;
m_nextHeaderParent = null;
m_previousHeaderName = null;
m_messagePartSubType = SUBTYPE_RFC822;
m_fEndMessageHeader = false;
}
/**
* Parse user inputstream and return a populated data structure
*
* @author Carson Lee
* @version %I%, %G%
*
* @param input User's inputstream
* @param nMessageType <PRE>
* MIME_CONTENT_PARSE_ALL if you want it to parse the entire message
* MIMEMessage.BASICPART for basicPart
* MIMEMessage.MULTIPART for multiPart
* MIMEMessage.MESSAGEPART for messagePart</PRE>
*
* @return <PRE>MIMEMessage object if nMessageType = MIME_CONTENT_PARSE_ALL
*MIMEBasicPart object if nMessageType = MIMEMessage.BASICPART;
*MIMEMultiPart object if nMessageType = MIMEMessage.MULTIPART;
*MIMEMessagePart object if nMessageType = MIMEMessage.MESSAGEPART; </PRE>
* @exception MIMEException
*/
protected Object parseMimeMessage( InputStream input, int nMessageType ) throws MIMEException
{
byte ch = 0;
String s;
int type, lineLen, messageLen;
Object returnObject = null;
int i = 0, j = 0, ii;
boolean lastLine = false;
byte[] swap;
boolean bMoreData = true;
if ( input == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
type = MIME_HEADER;
try
{
messageLen = input.available();
for ( i = 0, j = m_leftoverBytes; bMoreData; )
{
lineLen = input.read( m_inputBuffer );
if ( lineLen < m_inputBuffer.length )
bMoreData = false;
if ( lineLen < 0 )
break;
i = i + lineLen;
for ( ii = 0; ii < lineLen; ii++ )
{
ch = m_inputBuffer[ii];
if ( ch == -1 )
break;
// eat it
if ( !m_readCR && ch == '\r' )
continue;
else if ( ch == '\n' )
{
// look for continuation
if ( MIMEHelper.bStringEquals( m_leftoverBuffer, "content-" ) )
{
int jj = j > 0 ? j - 1 : 0;
char ch2;
for ( ch2 = (char) m_leftoverBuffer[jj]; jj > 0 && Character.isWhitespace( ch2 ); ch2 = (char) m_leftoverBuffer[--jj] )
;
// implement look ahead logic
if ( ( m_inputBuffer[ii+1] == ' ' || m_inputBuffer[ii+1] == '\t' ) &&
!MIMEHelper.bStringEquals( m_leftoverBuffer, "content-transfer-encoding" ) )
{
// System.out.println("continue = [" + new String( m_leftoverBuffer, 0, j) + "]" );
m_leftoverBuffer[j++] = ch;
continue;
}
}
if ( m_readCR )
m_leftoverBuffer[j++] = ch;
type = parseLine( m_leftoverBuffer, j, type, lastLine );
j = 0;
continue;
}
m_leftoverBuffer[j++] = ch;
}
}
}
catch ( IOException e )
{
// rethrow to a common exception handler
throw new MIMEException( e.getMessage() );
}
// handle lastline
if ( m_dataSink == null && j != 0 )
{
type = parseLine( m_leftoverBuffer, j, type, lastLine );
}
m_leftoverBytes = j;
if ( m_mimeMessage != null && m_dataSink == null )
checkForEmptyMessages( m_mimeMessage );
if ( m_mimeMessage != null && m_dataSink == null )
{
decodeDataBuffer();
if ( nMessageType == MIME_CONTENT_PARSE_ALL )
returnObject = m_mimeMessage;
else if ( nMessageType == MIMEMessage.BASICPART ||
nMessageType == MIMEMessage.MULTIPART ||
nMessageType == MIMEMessage.MESSAGEPART )
returnObject = m_mimeMessage.getBody();
}
// send data out right now using callbacks
else if ( m_dataSink != null && m_bStartData )
{
decodeDataBuffer();
}
return returnObject;
}
/**
* Save decoded data
*
* @author Carson Lee
* @version %I%, %G%
*
* @param byteBuffer data buffer
* @param len number of bytes in the data buffer to save
* @param mimeBasicPart save data to this mimeBasicPart
* @return none
* @exception MIMEException
*/
private void saveBodyData( ByteBuffer byteBuffer, int len, MIMEBasicPart mimeBasicPart ) throws MIMEException
{
if ( byteBuffer == null || mimeBasicPart == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
if ( m_bLocalStorage )
{
if ( m_bParseEntireFile )
{
mimeBasicPart.setBodyData( byteBuffer );
mimeBasicPart.setMessageDataLen( len );
}
else
{
ByteBuffer b = mimeBasicPart.getDataBuf();
if ( b == null )
{
mimeBasicPart.setBodyData( byteBuffer );
mimeBasicPart.setMessageDataLen( len );
}
else
{
b.append( byteBuffer );
mimeBasicPart.setMessageDataLen( mimeBasicPart.getMessageDataLen() + len );
}
}
}
if (m_dataSink != null)
{
if (len>0)
m_dataSink.bodyData (mimeBasicPart.getUserObject(), byteBuffer.getInputStream(), len);
if (mimeBasicPart.m_endData == true)
m_dataSink.endBasicPart (mimeBasicPart.getUserObject());
if (mimeBasicPart.m_parentContainer != null)
{
MIMEMultiPart mp = mimeBasicPart.m_parentContainer;
if (mp.m_endPart == true)
m_dataSink.endMultiPart (mp.getUserObject());
else; // ignore taken care of at end_boundary
}
}
else
mimeBasicPart.setDecodedData( true );
}
/**
* Decode message Data
*
* @author Carson Lee
* @version %I%, %G%
*
* @param none
* @return none
* @exception MIMEException
*/
private void decodeDataBuffer() throws MIMEException
{
int i;
int type2;
int len = 0;
int nIndex;
boolean finished = false;
mimeInfo mi;
MIMEMessagePart mimeMessagePart;
MIMEBasicPart mimeBasicPart;
MIMEMultiPart mimeMultiPart;
ByteBuffer newBuffer = null;
byte decodedBuffer[] = null;
byte line[];
int param[];
boolean bDecoded = false;
int nStart;
int nEnd;
// no decoding
if (m_nCurrentMessageType != MIMEMessage.BASICPART || m_currentMessage == null)
return;
mimeBasicPart = (MIMEBasicPart) m_currentMessage;
nStart = mimeBasicPart.getStartMessageDataIndex();
nEnd = mimeBasicPart.getEndMessageDataIndex();
// already being here
if (mimeBasicPart.getDecodedData())
return;
/* base64 */
if ( mimeBasicPart.getContentEncoding() == MIMEBodyPart.BASE64 && m_bDecodeData )
{
param = new int[3];
param[0] = m_out_byte;
param[1] = m_out_bits;
decodedBuffer = MIMEHelper.decodeBase64Vector( m_messageData,
nStart,
nEnd,
mimeBasicPart.getMessageDataLen(),
param );
if ( decodedBuffer != null )
{
m_out_byte = param[0];
m_out_bits = param[1];
len = param[2];
param = null;
saveBodyData( new ByteBuffer( decodedBuffer, len ), len, mimeBasicPart );
}
bDecoded = true;
}
/* quoted printable */
else if ( mimeBasicPart.getContentEncoding() == MIMEBodyPart.QP && m_bDecodeData )
{
param = new int[2];
param[0] = m_QPLeftoverBytes;
decodedBuffer = MIMEHelper.decodeQPVector( m_messageData,
nStart,
nEnd,
param,
m_QPLeftoverBuffer );
if ( decodedBuffer != null )
{
m_QPLeftoverBytes = param[0];
len = param[1];
param = null;
saveBodyData( new ByteBuffer( decodedBuffer ), len, mimeBasicPart );
}
bDecoded = true;
}
/* base64 without decodeing */
else if ( mimeBasicPart.getContentEncoding() == MIMEBodyPart.BASE64 )
{
if ( nEnd >= nStart && nStart != MIMEBasicPart.UNINITIALIZED )
{
// get message size
for (i = nStart, len = 0; i <= nEnd; i++)
{
line = (byte[]) m_messageData.elementAt( i );
//len = len + line.length;
len = len + line.length + 2; // for CRLF
}
newBuffer = new ByteBuffer( len );
if ( newBuffer != null )
{
for ( i = nStart; i <= nEnd; i++ )
{
line = (byte[]) m_messageData.elementAt( i );
newBuffer.append( line );
newBuffer.append( CRLF );
}
}
saveBodyData( newBuffer, len, mimeBasicPart );
bDecoded = true;
}
}
/* plain buffer creation */
else
{
boolean fQP = false;
if (mimeBasicPart.getContentEncoding() == MIMEBodyPart.QP)
fQP = true;
if ( nEnd >= nStart && nStart != MIMEBasicPart.UNINITIALIZED )
{
// get message size
for ( i = nStart, len = 0; i <= nEnd; i++ )
{
line = (byte[]) m_messageData.elementAt( i );
//len = len + line.length + 1;
len = len + line.length;
if (!fQP)
len = len + 2;
}
newBuffer = new ByteBuffer( len );
byte b = '\n';
byte r = '\r';
if ( newBuffer != null )
{
for ( i = nStart; i <= nEnd; i++ )
{
line = (byte[]) m_messageData.elementAt( i );
newBuffer.append( line );
if (!fQP)
{
newBuffer.append(r);
newBuffer.append(b);
}
}
}
saveBodyData( newBuffer, len, mimeBasicPart );
bDecoded = true;
}
}
if ( bDecoded )
{
if ( m_dataSink == null )
mimeBasicPart.setDecodedData( true );
else
{
// reset
mimeBasicPart.setStartMessageDataIndex( MIMEBasicPart.UNINITIALIZED );
mimeBasicPart.setEndMessageDataIndex( MIMEBasicPart.UNINITIALIZED );
}
}
}
/**
* Parse one line of data
*
* @author Carson Lee
* @version %I%, %G%
*
* @param s input line
* @param len length of line
* @param type line type for the previous line<PRE>
* MIME_HEADER header line
* MIME_INFO mime info line</PRE>
*
* @return line type for current line
* @exception MIMEException
*/
private int parseLine( byte s[], int len, int type, boolean lastLine ) throws MIMEException
{
int i;
int type2;
int nIndex;
boolean finished = false;
mimeInfo mi;
MIMEMessagePart mimeMessagePart;
MIMEBasicPart mimeBasicPart;
MIMEMultiPart mimeMultiPart;
MIMEMessage mimeMessage;
MIMEBodyPart m = (MIMEBodyPart) m_currentMessage;
if ( s == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
// debug
/*
//if ( MIMEHelper.bStringEquals( s, 7, "Subject" ) )
//if ( MIMEHelper.bStringEquals (s, 13, "--mail.sleepy"))
String ss = new String(s,0,len);
System.out.println (ss);
boolean fRightHdr = false;
//if (MIMEHelper.bStringEquals (s, "X-Original-In-reply-to"))
if (MIMEHelper.bStringEquals (s, "Content-Type: message/rfc822"))
{
ss = new String(s,0,len);
fRightHdr = true;
}
else if (MIMEHelper.bStringEquals (s, "Content-type: message/external-body"))
{
ss = new String(s,0,len);
fRightHdr = false;
}
*/
/* ignore additional header info */
if ( ( type == MIME_INFO || type == MIME_HEADER || type == MIME_XHEADER )&& ( len > 0 &&( s[0] == '\t' || s[0] == ' ' ) ) )
{
if (!(m_nCurrentMessageType == MIMEMessage.BASICPART && m_bStartData == true))
{
Header h[];
// continuation headers
if ( m_headerParent instanceof MIMEBasicPart )
{
mimeBasicPart = (MIMEBasicPart) m_currentMessage;
mimeBasicPart.addHeader( m_previousHeaderName, new String ("\r\n" + new String( s, 0, len ) ));
}
else if ( m_headerParent instanceof MIMEMessagePart )
{ // Ignore!!
// mimeMessagePart = (MIMEMessagePart) m_currentMessage;
// h = mimeMessagePart.getAllHeaders();
// mimeMessagePart.addHeader( m_previousHeaderName, new String( s, 0, len ) );
//m_currentMimeMessage.addHeader( m_previousHeaderName, new String( s, 0, len ) );
m_currentMimeMessage.addHeader( m_previousHeaderName, new String ("\r\n" + new String( s, 0, len ) ));
}
else
{
if (m_previousHeaderName == null)
{
appToLastHdrOnQueue (MIMEHelper.byteSubstring( s, 0, len));
}
else
{
m_currentMimeMessage.addHeader( m_previousHeaderName, new String ("\r\n" + new String( s, 0, len ) ));
if (m_dataSink != null)
{
m_dataSink.addHeader (m_currentMimeMessage.getUserObject(),
m_previousHeaderName.getBytes(),
MIMEHelper.byteSubstring(s, 0, len));
}
}
}
/*
if ( h != null && h[ h.length - 1 ] != null )
{
h[ h.length - 1 ].setValue( h[ h.length - 1 ].getValue() + "\n" + new String( s,0,len ) );
}
*/
return type;
}
}
else if (( type == MIME_INFO || type == MIME_HEADER || type == MIME_XHEADER ) && m_dataSink != null)
{
// a new header with same name
m_previousHeaderName = null;
}
if ( len == 0 )
{
m_emptyLineNo++;
/* end of header callback (only on top level MimeMessage) */
if (m_emptyLineNo == 1 && m_fEndMessageHeader == false)
{
m_fEndMessageHeader = true;
if (m_dataSink != null)
m_dataSink.endMessageHeader (m_mimeMessage.getUserObject());
}
}
if ( len == 0 && !m_bStartData )
{
int nCurrentParentType = getCurrentParentType();
if ( m_qp && m_emptyLineNo == 1 )
m_readCR = true;
//if ( m_emptyLineNo == 2 )
if (m_emptyLineNo >= 2 && !(m_nCurrentMessageType == MIMEMessage.MULTIPART && m_fSeenBoundary==false))
{
m_bStartData = true;
}
else if (m_emptyLineNo == 1 && nCurrentParentType == MIMEMessage.MULTIPART && m_fSeenBoundary == true)
{
if (m_nCurrentMessageType == MIME_UNINITIALIZED)
m_bStartData = true;
}
/*else if (m_emptyLineNo == 1 && m_nCurrentMessageType == MIMEMessage.MULTIPART) This broke mime11 */
else if (m_emptyLineNo > 1 && m_nCurrentMessageType == MIMEMessage.MULTIPART)
{
//System.out.println ("m_fSeenBoundary=" + m_fSeenBoundary);
if (m_fSeenBoundary == true)
m_bStartData = true;
else
{
mimeMultiPart = (MIMEMultiPart) m_currentMessage;
s[0] = '\r';
s[1] = '\n';
mimeMultiPart.addPreamble (s, 2);
return MIME_CRLF;
}
}
else if ( m_emptyLineNo == 1 )
{
// change mimeMessage parent
if ( m_nextMimeMessage != null )
{
// change parent only after first blank line
m_currentMimeMessage = m_nextMimeMessage;
m_nextMimeMessage = null;
}
// insert headers from queue
if ( m_nCurrentMessageType != MIME_UNINITIALIZED && m_headerQueue.size() > 0 )
{
if ( m_headerQueue.size() > 0 )
{
for ( i = 0; i < m_headerQueue.size(); i++ )
{
mi = (mimeInfo) m_headerQueue.elementAt(i);
addHeader( mi.m_name, mi.m_value, false );
}
m_headerQueue.removeAllElements();
}
}
// change header parent
if ( m_nextHeaderParent != null && !( m_nextHeaderParent instanceof MIMEMultiPart) )
m_headerParent = m_nextHeaderParent;
}
}
if ( MIMEHelper.bStringEquals( s, len, "content-type" ) )
{
if (m_emptyLineNo > 0 && m_nCurrentMessageType != MIMEMessage.MESSAGEPART)
m_emptyLineNo = 0;
}
/* boundary */
if ( ( type == MIME_INFO || type == MIME_HEADER || type == MIME_XHEADER ) &&
len == 0 && m_nCurrentMessageType != MIME_UNINITIALIZED && m_messagePartSubType != SUBTYPE_EXTERNAL_BODY )
{
if ( m_nCurrentMessageType == MIMEMessage.MESSAGEPART || m_nCurrentMessageType == MIMEMessage.MULTIPART )
{
if ( m_emptyLineNo == 1 || m_emptyLineNo == 2 )
type = MIME_HEADER;
else
{
mi = new mimeInfo();
// content type
mi.m_type = MIME_INFO;
mi.m_name = MIMEHelper.stringToByte( "content-type" );
mi.m_value = MIMEHelper.stringToByte( "text/plain" );
setData( mi );
parseMimeInfo( mi );
m_mimeInfo.addElement( mi );
// content type
//mi.m_type = MIME_INFO;
//mi.m_name = MIMEHelper.stringToByte( "content-transfer-encoding" );
//mi.m_value = MIMEHelper.stringToByte( "7bit" );
//setData( mi );
//parseMimeInfo( mi );
//m_mimeInfo.addElement( mi );
m_bStartData = true;
m_fSeenBoundary = false;
}
}
else if ( m_nCurrentMessageType == MIMEMessage.BASICPART )
{
m_bStartData = true;
m_fSeenBoundary = false;
}
if ( m_emptyLineNo == 1 )
return type;
}
if ( !m_bStartData && len == 0 )
{
// Add to preamble if multi-part
if (m_nCurrentMessageType == MIMEMessage.MULTIPART)
{
m_emptyLineNo = 0;
mimeMultiPart = (MIMEMultiPart) m_currentMessage;
s[0] = '\r';
s[1] = '\n';
mimeMultiPart.addPreamble (s, 2);
}
return MIME_CRLF;
}
/* -------------------------- identify line ----------------------- */
type2 = checkForLineType( s, len, m_bStartData );
if (type2 == START_BOUNDARY)
{
m_fSeenBoundary = true;
m_emptyLineNo = 0;
if (m_nCurrentMessageType == MIMEMessage.MESSAGEPART &&
m_messagePartSubType == SUBTYPE_EXTERNAL_BODY)
m_bStartData = false;
// give the boundary
if (m_nCurrentMessageType == MIMEMessage.MULTIPART && m_dataSink != null)
{
MIMEMultiPart mp = (MIMEMultiPart) m_currentMessage;
m_dataSink.boundary (mp.getUserObject(), (mp.getBoundary()).getBytes());
}
else if (m_dataSink != null)
{
int nCurrentParentType = getCurrentParentType();
if (nCurrentParentType == MIMEMessage.MULTIPART)
{
MIMEMultiPart mp = (MIMEMultiPart) m_currentParent.lastElement();;
m_dataSink.boundary (mp.getUserObject(), (mp.getBoundary()).getBytes());
}
}
}
// start of simple basicpart message
if ( type == MIME_CRLF && m_nCurrentMessageType == MIME_UNINITIALIZED && m_lastBoundry == START_BOUNDARY &&
type2 == MIME_MESSAGE_DATA && ( m_emptyLineNo == 1 || m_emptyLineNo == 2 ) &&
m_messagePartSubType != SUBTYPE_EXTERNAL_BODY )
{
mi = new mimeInfo();
// content type
mi.m_type = MIME_INFO;
mi.m_name = MIMEHelper.stringToByte( "content-type" );
mi.m_value = MIMEHelper.stringToByte( "text/plain" );
setData( mi );
parseMimeInfo( mi );
m_mimeInfo.addElement( mi );
m_bStartData = true;
m_fSeenBoundary = false;
if ( m_emptyLineNo == 1 || m_emptyLineNo == 2 )
{
// insert headers from queue
if ( m_headerQueue.size() > 0 )
// if ( m_nCurrentMessageType != MIME_UNINITIALIZED && m_headerQueue.size() > 0 )
{
if ( m_nextHeaderParent != null )
m_headerParent = m_nextHeaderParent;
for ( i = 0; i < m_headerQueue.size(); i++ )
{
mi = (mimeInfo) m_headerQueue.elementAt(i);
addHeader( mi.m_name, mi.m_value, false );
}
m_headerQueue.removeAllElements();
}
// change header parent
if ( m_nextHeaderParent != null )
m_headerParent = m_nextHeaderParent;
m_emptyLineNo = 0; // reset for headers
}
}
/* start boundary */
if ( !m_bStartData && type2 == START_BOUNDARY )
{
unwindCurrentParent( s, false );
m_out_byte = 0;
m_out_bits = 0;
m_leftoverBytes = 0;
m_QPLeftoverBytes = 0;
m_emptyLineNo = 0;
m_nCurrentMessageType = MIME_UNINITIALIZED;
m_lastBoundry = START_BOUNDARY;
m_fSeenBoundary = true;
m_qp = false;
m_readCR = false;
m_messagePartSubType = SUBTYPE_RFC822;
return MIME_INFO;
}
/* end boundary */
else if ( type2 == END_BOUNDARY || type2 == START_BOUNDARY )
{
if ( m_dataSink != null )
{
switch( m_nCurrentMessageType )
{
case MIMEMessage.BASICPART:
//m_dataSink.endBasicPart( m.getUserObject() ); break;
((MIMEBasicPart)m).m_endData = true; break;
case MIMEMessage.MULTIPART:
if (type2 == END_BOUNDARY)
m_dataSink.endMultiPart (m.getUserObject());
break;
case MIMEMessage.MESSAGEPART:
m_dataSink.endMessagePart (m.getUserObject());
m_msgParts.removeElement (m);
break;
}
if (type2 == END_BOUNDARY)
{
int nCurrentParentType = getCurrentParentType();
if (nCurrentParentType == MIMEMessage.MULTIPART)
{
MIMEMultiPart mp = (MIMEMultiPart) m_currentParent.lastElement();;
if (m_nCurrentMessageType != MIMEMessage.BASICPART)
m_dataSink.endMultiPart (mp.getUserObject());
else
{
mp.m_endPart = true;
((MIMEBasicPart)m).m_parentContainer = mp;
}
}
//else if (m_nCurrentMessageType == MIMEMessage.MULTIPART)
//{
// MIMEMultiPart mp = (MIMEMultiPart) m_currentMessage;
// m_dataSink.endMultiPart (mp.getUserObject());
// System.out.println ("at END_BOUNDARY() nCurrentParentType= " + nCurrentParentType);
// System.out.println ("at END_BOUNDARY() m_nCurrentMessageType= " + m_nCurrentMessageType);
//}
}
}
if ( type2 == END_BOUNDARY )
{
unwindCurrentParent( s, true );
m_lastBoundry = END_BOUNDARY;
m_fSeenBoundary = false;
}
else
m_lastBoundry = START_BOUNDARY;
m_emptyLineNo = 0;
m_bStartData = false;
decodeDataBuffer();
m_nCurrentMessageType = MIME_UNINITIALIZED;
m_qp = false;
m_readCR = false;
m_messagePartSubType = SUBTYPE_RFC822;
return type2;
}
/* message data */
else if ( m_bStartData )
{
// clone
byte sss[] = new byte[len];
System.arraycopy( s, 0, sss, 0, len );
m_messageData.addElement( sss );
nIndex = m_messageData.size() - 1;
if (m_nCurrentMessageType == MIME_UNINITIALIZED)
{
int nCurrentParentType = getCurrentParentType();
//System.out.println ("m_nCurrentMessageType== UNINIT");
//System.out.println ("nCurrentParentType= " + nCurrentParentType);
if (nCurrentParentType == MIMEMessage.MULTIPART)
{
mi = new mimeInfo();
// content type
mi.m_type = MIME_INFO;
mi.m_name = MIMEHelper.stringToByte("content-type");
mi.m_value = MIMEHelper.stringToByte("text/plain");
setData( mi );
parseMimeInfo( mi );
m_mimeInfo.addElement( mi );
}
}
if ( m_nCurrentMessageType == MIMEMessage.BASICPART && m_currentMessage != null )
{
mimeBasicPart = (MIMEBasicPart) m_currentMessage;
if ( mimeBasicPart.getStartMessageDataIndex() == MIMEBasicPart.UNINITIALIZED )
mimeBasicPart.setStartMessageDataIndex( nIndex );
mimeBasicPart.setEndMessageDataIndex( nIndex );
if ( lastLine )
{
decodeDataBuffer();
if ( m_dataSink != null )
{
switch( m_nCurrentMessageType )
{
case MIMEMessage.BASICPART:
m_dataSink.endBasicPart( m.getUserObject() ); break;
case MIMEMessage.MULTIPART: m_dataSink.endMultiPart( m.getUserObject() ); break;
case MIMEMessage.MESSAGEPART:
m_dataSink.endMessagePart( m.getUserObject() );
m_msgParts.removeElement (m);
break;
}
}
}
}
return MIME_MESSAGE_DATA;
}
// add preamble
if (m_emptyLineNo> 0 && m_nCurrentMessageType == MIMEMessage.MULTIPART && ! m_fSeenBoundary)
{
mimeMultiPart = (MIMEMultiPart) m_currentMessage;
s[len] = '\n';
mimeMultiPart.addPreamble(s, len + 1);
return type2;
}
mi = new mimeInfo();
mi.m_type = type2;
boolean startQuote = false;
for ( i = 0; i < len && !finished; i++ )
{
if ( s[i] == '"' )
startQuote = startQuote ? false : true;
if ( s[i] == ':' && !startQuote )
{
mi.m_name = MIMEHelper.byteSubstring( s, 0, i );
/* remove junk spaces */
for ( ++i; i < len && s[i] != 0 && Character.isWhitespace( (char) s[i] ); i++ )
;
mi.m_value = MIMEHelper.byteSubstring( s, i, len - i );
if ( mi.m_type == MIME_INFO )
{
setData( mi );
if ( m_messagePartSubType != SUBTYPE_EXTERNAL_BODY )
{
parseMimeInfo( mi );
m_mimeInfo.addElement( mi );
}
}
else if ( ( mi.m_type == MIME_XHEADER || mi.m_type == MIME_HEADER ) && m_headerParent != null )
{
addHeader( mi.m_name, mi.m_value, true );
m_emptyLineNo = 0;
}
finished = true;
}
}
// add preamble
if ( !finished && m_nCurrentMessageType == MIMEMessage.MULTIPART )
{
m_emptyLineNo = 0;
mimeMultiPart = (MIMEMultiPart) m_currentMessage;
s[len] = '\n';
mimeMultiPart.addPreamble( s, len + 1 );
}
mi = null;
if ( lastLine )
{
decodeDataBuffer();
if ( m_dataSink != null )
{
switch( m_nCurrentMessageType )
{
case MIMEMessage.BASICPART:
m_dataSink.endBasicPart( m.getUserObject() ); break;
case MIMEMessage.MULTIPART: m_dataSink.endMultiPart( m.getUserObject() ); break;
case MIMEMessage.MESSAGEPART:
m_dataSink.endMessagePart( m.getUserObject() );
m_msgParts.removeElement (m);
break;
}
}
}
return type2;
}
private void appToLastHdrOnQueue (byte value[])
{
mimeInfo mi;
int i = m_headerQueue.size();
if (i > 0)
{
mi = (mimeInfo) m_headerQueue.elementAt(i-1);
m_headerQueue.removeElementAt (i-1);
String val = new String (mi.m_value);
val = val.concat ("\r\n");
String s2 = new String (value);
val = val.concat (s2);
//val.concat (new String (value));
mi.m_value = val.getBytes();
m_headerQueue.addElement( mi );
}
}
//add cont * headers to the bodypart. used by MessagePart only at this point.
private void addContHeader (MIMEBodyPart bp, mimeInfo mi)
{
try
{
if (MIMEHelper.bStringEquals (mi.m_name, "content-description"))
{
bp.setContentDescription (new String (mi.m_value));
}
else if (MIMEHelper.bStringEquals (mi.m_name, "content-disposition"))
{
int disp = translateDispType (mi.m_value);
bp.setContentDisposition (disp);
}
else if (MIMEHelper.bStringEquals (mi.m_name, "content-id"))
{
bp.setContentID (new String (mi.m_value));
}
else if (MIMEHelper.bStringEquals (mi.m_name, "content-md5"))
{
if (bp instanceof MIMEBasicPart)
((MIMEBasicPart)bp).setContentMD5 (new String (mi.m_value));
}
else if (MIMEHelper.bStringEquals (mi.m_name, "content-transfer-encoding"))
{
//int encoding = mime_translateMimeEncodingType (mi.m_value);
//bp.setContentEncoding (encoding);
}
}
catch (Exception e)
{
// ignore
}
}
/**
* add header
*
* @author Carson Lee
* @version %I%, %G%
*
* @param mi.name header name
* @param mi.value header value
* @return none
* @exception MIMEException
*/
private void addHeader( byte name[], byte value[], boolean addToQueue ) throws MIMEException
{
MIMEMessagePart mimeMessagePart;
MIMEBasicPart mimeBasicPart;
MIMEMessage mimeMessage;
mimeInfo mi;
if ( name == null || value == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
if (m_nCurrentMessageType == MIME_UNINITIALIZED && m_headerParent == m_mimeMessage)
{
m_mimeMessage.addRHeader( new String( name), new String( value ) );
if (m_dataSink != null)
{
if (m_previousHeaderName != null && m_previousHeaderName.equals (new String (name)))
m_dataSink.addHeader (m_mimeMessage.getUserObject(), name, value );
else
{
m_dataSink.header (m_mimeMessage.getUserObject(), name, value );
}
}
m_previousHeaderName = new String( name );
return;
}
// insert headers from queue, restore header order
if ( m_nCurrentMessageType != MIME_UNINITIALIZED && addToQueue && m_headerQueue.size() > 0 )
{
for ( int i = 0; i < m_headerQueue.size(); i++ )
{
mi = (mimeInfo) m_headerQueue.elementAt(i);
addHeader( mi.m_name, mi.m_value, false );
}
m_headerQueue.removeAllElements();
}
// add to header queue
if ( m_nCurrentMessageType == MIME_UNINITIALIZED && addToQueue )
{
mi = new mimeInfo();
if ( mi != null )
{
mi.m_name = name;
mi.m_value = value;
m_headerQueue.addElement( mi );
}
}
else if ( m_headerParent instanceof MIMEMessage )
{
mimeMessage = (MIMEMessage) m_headerParent;
mimeMessage.addRHeader( new String( name ), new String( value ) );
if (m_dataSink != null)
{
if (m_previousHeaderName != null && m_previousHeaderName.equals (new String(name)))
m_dataSink.addHeader (mimeMessage.getUserObject(), name, value);
else
m_dataSink.header (mimeMessage.getUserObject(), name, value);
}
m_previousHeaderName = new String( name );
}
else if ( m_emptyLineNo > 0 || (m_headerParent instanceof MIMEBasicPart && m_fSeenBoundary))
{
if ( m_headerParent instanceof MIMEBasicPart )
{
mimeBasicPart = (MIMEBasicPart) m_headerParent;
mimeBasicPart.setHeader( new String( name ), new String( value ) );
m_previousHeaderName = new String( name );
if ( m_dataSink != null )
{
m_dataSink.header( mimeBasicPart.getUserObject(), name, value );
}
}
else if ( m_headerParent instanceof MIMEMessagePart || m_headerParent instanceof MIMEMultiPart )
{
mimeMessage = (MIMEMessage) m_currentMimeMessage;
mimeMessage.addRHeader( new String( name), new String( value ) );
if ( m_dataSink != null )
{
if (m_previousHeaderName != null && m_previousHeaderName.equals (new String (name)))
m_dataSink.addHeader (mimeMessage.getUserObject(), name, value);
else
{
m_dataSink.header(mimeMessage.getUserObject(), name, value);
}
}
m_previousHeaderName = new String( name );
}
}
}
/**
* fill in data fields from pMimeinfo
*
* @author Carson Lee
* @version %I%, %G%
*
* @param mi mimeInfo structure
* @return none
* @exception MIMEException
*/
private void setData( mimeInfo mi ) throws MIMEException
{
MIMEMessagePart mimeMessagePart;
MIMEBasicPart mimeBasicPart;
byte[] param[];
int contentDisposition;
MIMEBodyPart m = (MIMEBodyPart) m_currentMessage;
if ( mi == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
param = new byte[1][];
if ( m_messagePartSubType == SUBTYPE_EXTERNAL_BODY && m_nCurrentMessageType == MIMEMessage.MESSAGEPART )
{
// add as external body headers
mimeMessagePart = (MIMEMessagePart) m_currentMessage;
if ( m_emptyLineNo >= 1 )
{
mimeMessagePart.setExtBodyHeader (new String( mi.m_name),
new String( mi.m_value ) );
m_previousHeaderName = new String( mi.m_name );
}
else
{
addContHeader (mimeMessagePart, mi);
//addHeader( mi.m_name, mi.m_value, true );
}
}
//if ( m_messagePartSubType == SUBTYPE_EXTERNAL_BODY && m_nCurrentMessageType == MIMEMessage.MESSAGEPART )
//{
// // add as external body headers
// mimeMessagePart = (MIMEMessagePart) m_currentMessage;
// mimeMessagePart.setExtBodyHeader( new String( mi.m_name), new String( mi.m_value ) );
// m_previousHeaderName = new String( mi.m_name );
//}
/* create message structure */
else if ( MIMEHelper.bStringEquals( mi.m_name, "content-type" ) )
{
newMessageStructure( mi.m_value );
// add from queue
if ( m_mimeInfoQueue.size() > 0 && m_messagePartSubType != SUBTYPE_EXTERNAL_BODY )
{
for ( int i = 0; i < m_mimeInfoQueue.size(); i++ )
{
setData( (mimeInfo) m_mimeInfoQueue.elementAt(i) );
}
m_mimeInfoQueue.removeAllElements();
}
}
// no structure created yet
else if ( m_currentMessage == null )
return;
else if ( MIMEHelper.bStringEquals( mi.m_name, "content-description" ) )
{
if ( m_nCurrentMessageType == MIME_UNINITIALIZED )
m_mimeInfoQueue.addElement( mi );
else
{
m.setContentDescription( new String( mi.m_value ) );
if ( m_dataSink != null )
m_dataSink.contentDescription( m.getUserObject(), mi.m_value );
}
}
else if ( MIMEHelper.bStringEquals( mi.m_name, "content-disposition" ) )
{
if ( m_nCurrentMessageType == MIME_UNINITIALIZED )
m_mimeInfoQueue.addElement( mi );
else
{
contentDisposition = translateDispType( mi.m_value, param );
if ( contentDisposition != NSMAIL_ERR_INVALIDPARAM )
{
m.setContentDisposition( contentDisposition );
if ( m_dataSink != null )
m_dataSink.contentDisposition( m.getUserObject(), contentDisposition );
if ( param[0] != null )
{
m.setContentDispParams( new String( param[0] ) );
if ( m_dataSink != null )
m_dataSink.contentDispParams( m.getUserObject(), param[0] );
}
}
}
}
else if ( MIMEHelper.bStringEquals( mi.m_name, "content-id" ) )
{
if ( m_nCurrentMessageType == MIME_UNINITIALIZED )
m_mimeInfoQueue.addElement( mi );
else
{
m.setContentID( new String( mi.m_value ) );
if ( m_dataSink != null )
m_dataSink.contentID( m.getUserObject(), mi.m_value );
}
}
else if ( MIMEHelper.bStringEquals( mi.m_name, "content-transfer-encoding" ) )
{
if ( m_nCurrentMessageType == MIME_UNINITIALIZED )
m_mimeInfoQueue.addElement( mi );
else
{
if ( m_currentMessage instanceof MIMEBasicPart )
{
mimeBasicPart = (MIMEBasicPart) m_currentMessage;
int encoding;
encoding = mime_translateMimeEncodingType( mi.m_value );
mimeBasicPart.setContentEncoding( encoding );
if ( encoding == MIMEBodyPart.QP )
m_qp = true;
if ( m_dataSink != null )
m_dataSink.contentEncoding( mimeBasicPart.getUserObject(), encoding );
}
else if ( m_currentMessage instanceof MIMEMessagePart )
{
mimeMessagePart = (MIMEMessagePart) m_currentMessage;
int encoding;
encoding = mime_translateMimeEncodingType( mi.m_value );
mimeMessagePart.setContentEncoding( encoding );
if ( m_dataSink != null )
m_dataSink.contentEncoding( mimeMessagePart.getUserObject(), encoding );
}
else if ( m_currentMessage instanceof MIMEMultiPart )
{
MIMEMultiPart mimeMultiPart = (MIMEMultiPart) m_currentMessage;
int encoding = mime_translateMimeEncodingType( mi.m_value );
mimeMultiPart.setContentEncoding( encoding );
}
}
}
else if ( MIMEHelper.bStringEquals( mi.m_name, "content-md5" ) )
{
if ( m_nCurrentMessageType == MIME_UNINITIALIZED )
m_mimeInfoQueue.addElement( mi );
else
{
mimeBasicPart = (MIMEBasicPart) m_currentMessage;
mimeBasicPart.setContentMD5( new String( mi.m_value ) );
if ( m_dataSink != null )
m_dataSink.contentMD5( mimeBasicPart.getUserObject(), mi.m_value );
}
}
else
{
if (m_nCurrentMessageType == MIME_UNINITIALIZED)
m_mimeInfoQueue.addElement (mi);
else
{
// add unknown tags as header
addHeader( mi.m_name, mi.m_value, true );
/*
mimeBasicPart = (MIMEBasicPart) m_currentMessage;
mimeBasicPart.setHeader (new String(mi.m_name), new String (mi.m_value));
if ( m_dataSink != null )
m_dataSink.header (mimeBasicPart.getUserObject(), mi.m_name, mi.m_value);
*/
}
}
}
/**
* Parse a line into name, value, parameters and store it in a mimeInfo structure
*
* @author Carson Lee
* @version %I%, %G%
*
* @param mi mimeInfo structure to be parsed
* @return none
* @exception MIMEException
*/
private void parseMimeInfo( mimeInfo mi ) throws MIMEException
{
byte[] paramName = null;
byte[] value = null;
int offset = 0;
int len = 0;
boolean beginQuote = false;
byte ch;
int i;
mimeInfo mi2;
int nValueLen;
if ( mi == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
nValueLen = mi.m_value.length;
/* go through entire line */
for ( i = 0; i < nValueLen; i++ )
{
ch = mi.m_value[i];
/* handle quotes */
if ( ch == '"' )
beginQuote = beginQuote ? false : true;
if ( beginQuote )
{
len++;
continue;
}
/* parse and fill in fields */
switch ( ch )
{
case ';':
value = MIMEHelper.byteSubstring( mi.m_value, offset, len );
// trim();
offset = i + 1;
mi2 = new mimeInfo( MIME_INFO, paramName, value );
if ( mi2 == null )
throw new MIMEException( MIMEHelper.szERROR_OUT_OF_MEMORY );
mi.m_param.addElement( mi2 );
value = null;
paramName = null;
len = 0;
break;
case '=':
paramName = MIMEHelper.byteSubstring( mi.m_value, offset, len );
// trim();
offset = i + 1;
len = 0;
break;
default:
len++;
}
}
/* add it to internal buffer */
if ( len > 0 )
{
value = MIMEHelper.byteSubstring( mi.m_value, offset, len ); //trim();
mi2 = new mimeInfo( MIME_INFO, paramName, value );
if ( mi2== null )
throw new MIMEException( MIMEHelper.szERROR_OUT_OF_MEMORY );
mi.m_param.addElement( mi2 );
}
}
private byte[] getBytecontType (int nMessageType, int basicPartcontType)
{
switch ( nMessageType )
{
case MIMEMessage.BASICPART:
switch (basicPartcontType)
{
case MIMEBasicPart.TEXT:
return mb_TextPart;
case MIMEBasicPart.AUDIO:
return mb_AudioPart;
case MIMEBasicPart.VIDEO:
return mb_VideoPart;
case MIMEBasicPart.IMAGE:
return mb_ImagePart;
case MIMEBasicPart.APPLICATION:
return mb_ApplPart;
}
case MIMEMessage.MULTIPART:
return mb_MultiPart;
case MIMEMessage.MESSAGEPART:
return mb_MessagePart;
}
return null;
}
/**
* create new message structure based on content type
* the input string will be parsed to determine the content type
*
* @author Carson Lee
* @version %I%, %G%
*
* @param s input line
* @return none
* @exception MIMEException
*/
private void newMessageStructure( byte[] s ) throws MIMEException
{
MIMEMessagePart mimeMessagePart;
MIMEBasicPart mimeBasicPart;
MIMEMultiPart mimeMultiPart;
int nMessageType;
byte[] param[] = new byte[2][];
int contentType[] = new int[1];
nMessageType = nGetMessageType( s, param, contentType );
switch ( nMessageType )
{
case MIMEMessage.BASICPART:
mimeBasicPart = new MIMEBasicPart();
if ( m_dataSink != null )
{
//if ( m_bLocalStorage )
// mimeBasicPart.setUserObject( m_dataSink.startBasicPart( mimeBasicPart ) );
//else
mimeBasicPart.setUserObject( m_dataSink.startBasicPart() );
}
addMessage( mimeBasicPart, MIMEMessage.BASICPART );
break;
case MIMEMessage.MULTIPART:
mimeMultiPart = new MIMEMultiPart();
mimeMultiPart.m_parsedPart=1;
if ( m_dataSink != null )
{
//if ( m_bLocalStorage )
// mimeMultiPart.setUserObject( m_dataSink.startMultiPart( mimeMultiPart ) );
//else
mimeMultiPart.setUserObject( m_dataSink.startMultiPart() );
}
addMessage( mimeMultiPart, MIMEMessage.MULTIPART );
/* save boundary */
mimeMultiPart = (MIMEMultiPart) m_currentMessage;
String boundary = parseForBoundary( new String(s) );
mimeMultiPart.setBoundary( boundary );
// debug
// System.out.println( "boundary = [" + boundary + "]" );
// if ( m_dataSink != null )
// m_dataSink.boundary( mimeMultiPart.getUserObject(), boundary.getBytes() );
break;
case MIMEMessage.MESSAGEPART:
mimeMessagePart = new MIMEMessagePart();
if ( m_dataSink != null )
{
//if ( m_bLocalStorage )
// mimeMessagePart.setUserObject( m_dataSink.startMessagePart( mimeMessagePart ) );
//else
mimeMessagePart.setUserObject( m_dataSink.startMessagePart() );
m_msgParts.addElement (mimeMessagePart);
}
if ( MIMEHelper.bStringEquals( param[0], "external-body" ) )
{
m_messagePartSubType = SUBTYPE_EXTERNAL_BODY;
}
// unsupported partial subtype
else if ( MIMEHelper.bStringEquals( param[0], "partial" ) )
{
throw new MIMEException( MIMEHelper.szERROR_UNSUPPORTED_PARTIAL_SUBTYPE );
}
addMessage( mimeMessagePart, MIMEMessage.MESSAGEPART );
// determine subtype
if ( MIMEHelper.bStringEquals( param[0], "rfc822" ) )
{
m_messagePartSubType = SUBTYPE_RFC822;
MIMEMessage m = new MIMEMessage();
m.m_parsedPart = 1;
mimeMessagePart.setMessage( m, false );
if ( m_dataSink != null )
{
//if (m_bLocalStorage)
// m.setUserObject (m_dataSink.startMessage (m));
//else
m.setUserObject (m_dataSink.startMessage());
}
m_nextHeaderParent = m;
// defered assignment till received first blank line
m_nextMimeMessage = m;
}
break;
}
// initialize structure
if ( m_currentMessage != null )
{
MIMEBodyPart m = (MIMEBodyPart) m_currentMessage;
if ( param[0] != null )
m.setContentSubType( new String( param[0] ) );
if ( param[1] != null && !MIMEHelper.bStringEquals( param[1], "boundary"))
{
String cps = new String (param[1]);
if (! (cps.indexOf ("boundary") > 0))
m.setContentTypeParams( new String( param[1] ) );
}
if ( m_dataSink != null )
{
//m_dataSink.contentType( m.getUserObject(), contentType[0] );
m_dataSink.contentType (m.getUserObject(), getBytecontType (nMessageType, contentType[0]));
if ( param[0] != null )
m_dataSink.contentSubType( m.getUserObject(), param[0] );
if (param[1] != null && param[1].length > 0 &&
!MIMEHelper.bStringEqualsLtrim(param[1], "boundary"))
{
m_dataSink.contentTypeParams( m.getUserObject(), param[1] );
}
}
if ( m_nCurrentMessageType == MIMEMessage.BASICPART )
{
mimeBasicPart = (MIMEBasicPart) m_currentMessage;
mimeBasicPart.setContentType( contentType[0] );
}
}
}
/**
* add a new message ( part ) to a multipart message, mimeMessage of messagePart
*
* @author Carson Lee
* @version %I%, %G%
*
* @param message input message
* @param nMessageType message type
* @return none
* @exception MIMEException
*/
private void addMessage( Object message, int nMessageType ) throws MIMEException
{
MIMEMultiPart multiPart = null;
MIMEBasicPart basicPart = null;
MIMEMessagePart messagePart = null;
int nCurrentParentType = getCurrentParentType();
if ( message == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
// determine current message
if ( nCurrentParentType == MIMEMessage.BASICPART )
{
// can't add messages to a basicpart
return;
}
else if ( nCurrentParentType == MIME_UNINITIALIZED )
{
if ( nMessageType == MIMEMessage.BASICPART )
{
//debug
//System.out.println( "adding basicpart to message" );
m_mimeMessage.setBody( (MIMEBasicPart) message, false );
m_nMessageType = MIMEMessage.BASICPART;
}
else if ( nMessageType == MIMEMessage.MULTIPART )
{
//debug
//System.out.println( "adding multipart to message" );
m_mimeMessage.setBody( (MIMEMultiPart) message, false );
m_nMessageType = MIMEMessage.MULTIPART;
m_currentParent.addElement( (MIMEMultiPart) message );
m_fSeenBoundary = false;
}
else if ( nMessageType == MIMEMessage.MESSAGEPART )
{
//debug
//System.out.println( "adding messagepart to message" );
m_mimeMessage.setBody( (MIMEMessagePart) message, false );
m_nMessageType = MIMEMessage.MESSAGEPART;
m_currentParent.addElement( (MIMEMessagePart) message );
}
setCurrentMessage( message, nMessageType );
}
// add to vector
else if ( nCurrentParentType == MIMEMessage.MULTIPART && m_currentMessage != null )
{
multiPart = (MIMEMultiPart) m_currentParent.lastElement();
if ( nMessageType == MIMEMessage.BASICPART )
{
//debug
//System.out.println( "adding basicpart to multipart" );
multiPart.addBodyPart( (MIMEBasicPart) message, false );
}
else if ( nMessageType == MIMEMessage.MULTIPART )
{
//debug
//System.out.println( "adding multipart to multipart" );
multiPart.addBodyPart( (MIMEMultiPart) message, false );
m_currentParent.addElement( (MIMEMultiPart) message );
}
else if ( nMessageType == MIMEMessage.MESSAGEPART )
{
//debug
//System.out.println( "adding messagepart to multipart" );
multiPart.addBodyPart( (MIMEMessagePart) message, false );
m_currentParent.addElement( (MIMEMessagePart) message );
}
setCurrentMessage( message, nMessageType );
}
else if ( nCurrentParentType == MIMEMessage.MESSAGEPART && m_currentMessage != null )
{
messagePart = (MIMEMessagePart) m_currentParent.lastElement();
if ( nMessageType == MIMEMessage.BASICPART )
{
//debug
//System.out.println( "adding basicpart to messagepart" );
messagePart.getMessage( false ).setBody( (MIMEBasicPart) message, false );
}
else if ( nMessageType == MIMEMessage.MULTIPART )
{
//debug
//System.out.println( "adding multipart to messagepart" );
messagePart.getMessage( false ).setBody( (MIMEMultiPart) message, false );
m_currentParent.addElement( (MIMEMultiPart) message );
}
else if ( nMessageType == MIMEMessage.MESSAGEPART )
{
//debug
//System.out.println( "adding messagepart to messagepart" );
messagePart.getMessage( false ).setBody( (MIMEMessagePart) message, false );
m_currentParent.addElement( (MIMEMessagePart) message );
}
setCurrentMessage( message, nMessageType );
}
}
// helper functions ----------------------------------------
/**
* Set current message
*
* @author Carson Lee
* @version %I%, %G%
*
* @param message input message
* @param nMessageType message type
* @return MIME_OK if successful, an error code otherwise
* @exception none
*/
private int setCurrentMessage( Object message, int nMessageType )
{
if ( message == null )
return NSMAIL_ERR_INVALIDPARAM;
m_currentMessage = message;
m_nCurrentMessageType = nMessageType;
m_nextHeaderParent = message;
if ( nMessageType == MIMEMessage.BASICPART )
{
m_currentBasicPart = (MIMEBasicPart) message;
m_currentMultiPart = null;
m_currentMessagePart = null;
int nCurrentParentType = getCurrentParentType();
if (nCurrentParentType == MIMEMessage.MULTIPART && m_fSeenBoundary)
{
//start following adding headers to this part itself
m_headerParent = message;
m_nextHeaderParent = message;
}
}
else if ( nMessageType == MIMEMessage.MULTIPART )
{
m_currentBasicPart = null;
m_currentMultiPart = (MIMEMultiPart) message;
m_currentMessagePart = null;
}
else if ( nMessageType == MIMEMessage.MESSAGEPART )
{
m_currentBasicPart = null;
m_currentMultiPart = null;
m_currentMessagePart = (MIMEMessagePart) message;
}
return NSMAIL_OK;
}
/**
* Determine if line is a boundary
*
* @author Carson Lee
* @version %I%, %G%
*
* @param s input string
* @param len size of input string
* @return : START_BOUNDARY if it's a start boundary, END_BOUNDARY if it's a end boundary, NOT_A_BOUNDARY if it's not a boundary
* @exception none
*/
private int boundaryCheck( byte s[], int len )
{
String currentBoundary = getCurrentBoundary();
int boundaryLen = 0;
if ( len > 0 && Character.isWhitespace( (char) s[len-1] ) )
len--;
if ( len > 0 && Character.isWhitespace( (char) s[len-1] ) )
len--;
if ( len >= 2 && s != null && currentBoundary != null )
{
boundaryLen = currentBoundary.length();
if ( (len == boundaryLen + 4) && s[0] == '-' && s[1] == '-' &&
s[ boundaryLen + 2 ] == '-' && s[ boundaryLen + 3 ] == '-' &&
MIMEHelper.bStringEquals( 2, s, currentBoundary ) )
{
return END_BOUNDARY;
}
else if ((len == boundaryLen + 2) && s[0] == '-' && s[1] == '-' &&
MIMEHelper.bStringEquals( 2, s, currentBoundary ) )
{
return START_BOUNDARY;
}
}
return NOT_A_BOUNDARY;
}
/**
* check what kind of line this is
*
* @author Carson Lee
* @version %I%, %G%
*
* @param s input string
* @param len size of input string
* @return line type can be MIME_INFO, MIME_XHEADER, MIME_CRLF, MIME_HEADER
* @exception none
*/
private int checkForLineType( byte s[], int len, boolean startData )
{
if ( s == null )
return NSMAIL_ERR_INVALIDPARAM;
if ( startData )
{
int type = boundaryCheck(s, len);
if ( type != NOT_A_BOUNDARY )
return type;
return MIME_HEADER;
}
else if ( MIMEHelper.bStringEquals( s, "content-" ) )
return MIME_INFO;
else if ( MIMEHelper.bStringEquals( s, "x-" ) )
return MIME_XHEADER;
else if ( len == 0 )
return MIME_CRLF;
else
{
int type = boundaryCheck(s, len);
if ( type != NOT_A_BOUNDARY )
return type;
else
{
boolean seenNonSpace = false;
for ( int i = 0; i < len; i++ )
{
if (!Character.isWhitespace ((char) s[i]))
seenNonSpace = true;
else if (seenNonSpace && Character.isWhitespace ((char) s[i])) // its not a header! Its MESSAGE_DATA!
{
break;
}
if ( s[i] == ':' )
return MIME_HEADER;
}
}
}
return MIME_MESSAGE_DATA;
}
/**
* Get message type, subtype, content type parameters and content type
*
* @author Carson Lee
* @version %I%, %G%
*
* @param s input string
* @param param[] (output) returns subtype in param[0], parameters in param[1]
* @param contentType[] (output) returns content type in contentType[0]
* @return message type, returns subtype in param[0], parameters in param[1]
* @exception none
*/
private int nGetMessageType( byte[] s, byte[] param[], int contentType[] ) throws MIMEException
{
int i, nStart, nSubtypeStart;
byte[] MessageType = null;
int nMessageType = MIME_UNINITIALIZED;
byte[] subtype = null;
if ( s == null || param == null )
return NSMAIL_ERR_INVALIDPARAM;
int len = s.length;
/* skip spaces and colons */
for ( i=0; i < len && s[i] != 0 && ( Character.isWhitespace( (char)s[i] ) || s[i] == ':' ); i++ )
;
/* skip to subtype */
for ( nStart = i; i < len && s[i] != 0 && s[i] != '/' && s[i] != ';'; i++ )
;
/* content type */
MessageType = MIMEHelper.byteSubstring( s, nStart, i - nStart );
/* content subtype */
if ( i < len && s[i] == '/' )
{
for ( nSubtypeStart = ++i; i < len && s[i] != 0 && s[i] != ';' && s[i] != ','; i++ )
;
/* content subtype */
subtype = MIMEHelper.byteSubstring( s, nSubtypeStart, i - nSubtypeStart );
}
param[0] = subtype;
/* skip spaces and colons */
if ( i < len )
{
for ( ; i < len && s[i] != 0 && ( s[i] == ' ' || s[i] == ';' || s[i] == ',' ); i++ )
;
}
param[1] = i > (int) s.length ? null : MIMEHelper.byteSubstring( s, i, s.length-i ); // trim
/* determine content type */
if ( MIMEHelper.bStringEquals( MessageType, "text" ) )
{
nMessageType = MIMEMessage.BASICPART;
contentType[0] = MIMEBasicPart.TEXT;
}
else if ( MIMEHelper.bStringEquals( MessageType, "audio" ) )
{
nMessageType = MIMEMessage.BASICPART;
contentType[0] = MIMEBasicPart.AUDIO;
}
else if ( MIMEHelper.bStringEquals( MessageType, "image" ) )
{
nMessageType = MIMEMessage.BASICPART;
contentType[0] = MIMEBasicPart.IMAGE;
}
else if ( MIMEHelper.bStringEquals( MessageType, "video" ) )
{
nMessageType = MIMEMessage.BASICPART;
contentType[0] = MIMEBasicPart.VIDEO;
}
else if ( MIMEHelper.bStringEquals( MessageType, "application" ) )
{
nMessageType = MIMEMessage.BASICPART;
contentType[0] = MIMEBasicPart.APPLICATION;
}
else if ( MIMEHelper.bStringEquals( MessageType, "multipart" ) )
{
nMessageType = MIMEMessage.MULTIPART;
contentType[0] = MIMEBasicPart.TEXT;
}
else if ( MIMEHelper.bStringEquals( MessageType, "message" ) )
{
nMessageType = MIMEMessage.MESSAGEPART;
contentType[0] = MIMEBasicPart.TEXT;
}
else
{
//nMessageType = MIMEBasicPart.TEXT;
//contentType[0] = MIMEBasicPart.TEXT;
throw new MIMEException ("Error: Unknown/Unsupported Content-Type: " + new String (MessageType));
}
return nMessageType;
}
/**
* Parse an input string for boundary
* default to "-----" if none is found
*
* @author Carson Lee
* @version %I%, %G%
*
* @param s input string
* @return boundary string
* @exception none
*/
private String parseForBoundary( String s )
{
String boundary;
int nLen;
int len;
int start;
int pos;
boolean bQuotes = false;
char ch;
if ( s == null )
return null;
pos = s.indexOf( "boundary" );
len = s.length();
if ( pos == -1 )
boundary = "-----";
else
{
/* skip spaces and colons */
for ( pos = pos + 9, ch = s.charAt(pos); pos < len && ( ch == ' ' || ch == '=' ); ch = s.charAt( ++pos >= len ? 0 : pos ) )
;
if ( ch == '"' )
{
bQuotes = true;
pos++;
}
start = pos;
for ( nLen = 0, ch = s.charAt(pos); pos < len && ch != ';'; nLen++, ch = s.charAt( ++pos >= len ? 0 : pos ) )
{
if ( bQuotes && ch == '"' )
break;
}
boundary = s.substring( start, start + nLen );
}
return boundary;
}
/**
* translate encoding type to an integer
*
* @author Carson Lee
* @version %I%, %G%
*
* @param s input string
* @return encoding type
* @exception none
*/
private int mime_translateMimeEncodingType( byte[] s )
{
if ( s == null )
return NSMAIL_ERR_INVALIDPARAM;
if ( MIMEHelper.bStringEquals( s, "base64" ) )
return MIMEBodyPart.BASE64;
else if ( MIMEHelper.bStringEquals( s, "qp" ) || MIMEHelper.bStringEquals( s, "quoted-printable" ) )
return MIMEBodyPart.QP;
else if ( MIMEHelper.bStringEquals( s, "7bit" ) )
return MIMEBodyPart.E7BIT;
else if ( MIMEHelper.bStringEquals( s, "8bit" ) )
return MIMEBodyPart.E8BIT;
else if ( MIMEHelper.bStringEquals( s, "binary" ) )
return MIMEBodyPart.BINARY;
return MIMEBodyPart.E7BIT;
}
/**
* translate disposition type to an integer
*
* @author Carson Lee
* @version %I%, %G%
*
* @param s input string
* @param param[] return content disposition parameters in param[0]
* @return <PRE>
* NSMAIL_ERR_INVALIDPARAM if parameters are invalid
* MIMEBodyPart.INLINE disposition type is inline
* MIMEBodyPart.ATTACHMENT disposition type is an attachment</PRE>
*
* @exception MIMEException
*/
private int translateDispType( byte[] s, byte[] param[] )
{
if ( s == null || param == null )
return NSMAIL_ERR_INVALIDPARAM;
param[0] = null;
if ( MIMEHelper.bStringEquals( s, "inline" ) )
{
if ( s.length >= 8 )
param[0] = MIMEHelper.byteSubstring( s, 0, 7 );
return MIMEBodyPart.INLINE;
}
else if ( MIMEHelper.bStringEquals( s, "attachment" ) )
{
if ( s.length >= 12 )
param[0] = MIMEHelper.byteSubstring( s, 0, 12 );
return MIMEBodyPart.ATTACHMENT;
}
else if ( s.length >= 8 )
param[0] = MIMEHelper.byteSubstring( s, 0, 7 );
return MIMEBodyPart.INLINE;
}
// ----------new one
private int translateDispType (byte[] s)
{
if ( s == null)
return NSMAIL_ERR_INVALIDPARAM;
if (MIMEHelper.bStringEquals (s, "inline"))
return MIMEBodyPart.INLINE;
if (MIMEHelper.bStringEquals (s, "attachment"))
return MIMEBodyPart.ATTACHMENT;
return MIMEBodyPart.INLINE;
}
private int getCurrentParentType()
{
if ( m_currentParent.size() > 0 )
{
Object o = m_currentParent.lastElement();
if ( o != null )
{
if ( o instanceof MIMEBasicPart )
return MIMEMessage.BASICPART;
else if ( o instanceof MIMEMultiPart )
return MIMEMessage.MULTIPART;
else if ( o instanceof MIMEMessagePart )
return MIMEMessage.MESSAGEPART;
}
}
return MIME_UNINITIALIZED;
}
/**
* get the boundary corresponding to the current multiPart message
*
* @author Carson Lee
* @version %I%, %G%
*
* @param none
* @return current boundary string, null if there isn't a current boundary
* @exception none
*/
private String getCurrentBoundary()
{
if ( m_currentParent.size() > 0 )
{
for ( int i = m_currentParent.size(); i > 0; i-- )
{
Object o = m_currentParent.elementAt( i - 1 );
if ( o != null && o instanceof MIMEMultiPart )
return ( (MIMEMultiPart) o ).getBoundary();
}
}
return null;
}
/**
* get the boundary corresponding to the current multiPart message
*
* @author Carson Lee
* @version %I%, %G%
*
* @param none
* @return current boundary string, null if there isn't a current boundary
* @exception none
*/
private void unwindCurrentParent( byte[] s, boolean delete )
{
if ( m_currentParent.size() > 0 )
{
String boundary = new String( s, 2, s.length - 2 );
for ( int i = m_currentParent.size(); i > 0; i-- )
{
Object o = m_currentParent.elementAt( i - 1 );
if ( o != null && o instanceof MIMEMultiPart && boundary.startsWith( ((MIMEMultiPart) o ).getBoundary() ) )
{
if ( delete )
{
m_currentParent.removeElementAt( i - 1 );
// reposition to next multipart
for ( ; m_currentParent.size() > 0; )
{
o = m_currentParent.lastElement();
if ( o instanceof MIMEMultiPart )
return;
m_currentParent.removeElementAt( m_currentParent.size() - 1 );
}
}
return;
}
m_currentParent.removeElementAt( i - 1 );
}
}
}
/**
* check for empty messages in all basicparts
*
* @author Carson Lee
* @version %I%, %G%
*
* @param
*
* o : any mime message structure, usually MIMEMessage
*
* @return none
* @exception MIMEException
*/
void checkForEmptyMessages( Object o ) throws MIMEException
{
if ( o == null )
throw new MIMEException( MIMEHelper.szERROR_BAD_PARAMETER );
if ( o instanceof MIMEMessage )
{
checkForEmptyMessages( ((MIMEMessage) o).getBody() );
}
else if ( o instanceof MIMEBasicPart )
{
if ( ((MIMEBasicPart) o).getMessageDataLen() == 0 )
throw new MIMEException( MIMEHelper.szERROR_EMPTY_MESSAGE );
}
else if ( o instanceof MIMEMultiPart )
{
MIMEMultiPart m = (MIMEMultiPart) o;
int count = m.getBodyPartCount();
for ( int i = 0; i < count; i++ )
{
Object part = m.getBodyPart( i, false );
checkForEmptyMessages( part );
}
}
else if ( o instanceof MIMEMessagePart )
{
String cst = (((MIMEMessagePart)o).getContentSubType()).trim();
if (cst == null || cst.equalsIgnoreCase("rfc822"))
{
MIMEMessage messagePart = ((MIMEMessagePart) o).getMessage();
checkForEmptyMessages( messagePart );
}
else if (cst.equalsIgnoreCase("external-body"))
{
Header[] hdrs = ((MIMEMessagePart)o).getAllHeaders();
//if (hdrs == null)
// throw new MIMEException (MIMEHelper.szERROR_BAD_EXTERNAL_MESSAGE_PART);
}
else if (cst.equalsIgnoreCase("partial"))
{
throw new MIMEException (MIMEHelper.szERROR_UNSUPPORTED_PARTIAL_SUBTYPE);
}
else
throw new MIMEException( MIMEHelper.szERROR_BAD_MIME_MESSAGE);
}
}
}