/*
* Created on 07.11.2004
*
* This file is part of susimail project, see http://susi.i2p/
*
* Copyright (C) 2004-2005 <susi23@mail.i2p>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.4 $
*/
package i2p.susi.webmail;
import i2p.susi.debug.Debug;
import i2p.susi.util.ReadBuffer;
import i2p.susi.webmail.encoding.DecodingException;
import i2p.susi.webmail.encoding.Encoding;
import i2p.susi.webmail.encoding.EncodingFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import net.i2p.data.DataHelper;
/**
* @author susi23
*/
class MailPart {
public final String[] headerLines;
public final String type, encoding, name,
description, disposition, charset, version;
private final int beginBody, begin, end;
/** fixme never set */
public final String filename = null;
public final List<MailPart> parts;
public final boolean multipart, message;
public final ReadBuffer buffer;
public MailPart( ReadBuffer readBuffer ) throws DecodingException
{
this(readBuffer, readBuffer.offset, readBuffer.length);
}
public MailPart( ReadBuffer readBuffer, int offset, int length ) throws DecodingException
{
begin = offset;
end = offset + length;
buffer = readBuffer;
parts = new ArrayList<MailPart>();
/*
* parse header lines
*/
int bb = end;
for( int i = begin; i < end - 4; i++ ) {
if( buffer.content[i] == '\r' &&
buffer.content[i+1] == '\n' &&
buffer.content[i+2] == '\r' &&
buffer.content[i+3] == '\n' ) {
bb = i + 2;
break;
}
}
beginBody = bb;
ReadBuffer decodedHeaders = EncodingFactory.getEncoding( "HEADERLINE" ).decode( buffer.content, begin, beginBody - begin );
headerLines = DataHelper.split(new String(decodedHeaders.content, decodedHeaders.offset, decodedHeaders.length), "\r\n");
String boundary = null;
String x_encoding = null;
String x_disposition = null;
String x_type = null;
boolean x_multipart = false;
boolean x_message = false;
String x_name = null;
String x_charset = null;
String x_description = null;
String x_version = null;
for( int i = 0; i < headerLines.length; i++ )
{
if( headerLines[i].toLowerCase(Locale.US).startsWith( "content-transfer-encoding: " ) ) {
x_encoding = getFirstAttribute( headerLines[i] ).toLowerCase(Locale.US);
}
else if( headerLines[i].toLowerCase(Locale.US).startsWith( "content-disposition: " ) ) {
x_disposition = getFirstAttribute( headerLines[i] ).toLowerCase(Locale.US);
String str;
str = getHeaderLineAttribute( headerLines[i], "filename" );
if( str != null )
x_name = str;
}
else if( headerLines[i].toLowerCase(Locale.US).startsWith( "content-type: " ) ) {
x_type = getFirstAttribute( headerLines[i] ).toLowerCase(Locale.US);
/*
* extract boundary, name and charset from content type
*/
String str;
str = getHeaderLineAttribute( headerLines[i], "boundary" );
if( str != null )
boundary = str;
if (x_type.startsWith( "multipart" ) && boundary != null )
x_multipart = true;
if (x_type.startsWith( "message" ) )
x_message = true;
str = getHeaderLineAttribute( headerLines[i], "name" );
if( str != null )
x_name = str;
str = getHeaderLineAttribute( headerLines[i], "charset" );
if( str != null )
x_charset = str.toUpperCase(Locale.US);
}
else if( headerLines[i].toLowerCase(Locale.US).startsWith( "content-description: " ) ) {
x_description = getFirstAttribute( headerLines[i] );
}
else if( headerLines[i].toLowerCase(Locale.US).startsWith( "mime-version: " ) ) {
x_version = getFirstAttribute( headerLines[i] );
}
}
encoding = x_encoding;
disposition = x_disposition;
type = x_type;
multipart = x_multipart;
message = x_message;
name = x_name;
charset = x_charset;
description = x_description;
version = x_version;
/*
* parse body
*/
int beginLastPart = -1;
if( multipart ) {
byte boundaryArray[] = DataHelper.getUTF8(boundary);
for( int i = beginBody; i < end - 4; i++ ) {
if( buffer.content[i] == '\r' &&
buffer.content[i+1] == '\n' &&
buffer.content[i+2] == '-' &&
buffer.content[i+3] == '-' ) {
/*
* begin of possible boundary line
*/
int j = 0;
for( ; j < boundaryArray.length && i + 4 + j < end; j++ )
if( buffer.content[ i + 4 + j ] != boundaryArray[j] )
break;
if( j == boundaryArray.length ) {
int k = i + 4 + j;
if( k < end - 2 &&
buffer.content[k] == '-' &&
buffer.content[k+1] == '-' )
k += 2;
if( k < end - 2 &&
buffer.content[k] == '\r' &&
buffer.content[k+1] == '\n' ) {
k += 2;
if( beginLastPart != -1 ) {
int endLastPart = Math.min(i + 2, end);
MailPart newPart = new MailPart( buffer, beginLastPart, endLastPart - beginLastPart );
parts.add( newPart );
}
beginLastPart = k;
}
i = k;
}
}
}
}
else if( message ) {
MailPart newPart = new MailPart(buffer, beginBody, end - beginBody);
parts.add( newPart );
}
}
/**
* @param offset 2 for sendAttachment, 0 otherwise, don't know why
* @since 0.9.13
*/
public ReadBuffer decode(int offset) throws DecodingException {
String encg = encoding;
if (encg == null) {
//throw new DecodingException("No encoding specified");
Debug.debug(Debug.DEBUG, "Warning: no transfer encoding found, fallback to 7bit.");
encg = "7bit";
}
Encoding enc = EncodingFactory.getEncoding(encg);
if(enc == null)
throw new DecodingException(_t("No encoder found for encoding \\''{0}\\''.", WebMail.quoteHTML(encg)));
return enc.decode(buffer.content, beginBody + offset, end - beginBody - offset);
}
private static String getFirstAttribute( String line )
{
String result = null;
int i = line.indexOf( ": " );
if( i != - 1 ) {
int j = line.indexOf(';', i + 2 );
if( j == -1 )
result = line.substring( i + 2 );
else
result = line.substring( i + 2, j );
result = result.trim();
}
return result;
}
private static String getHeaderLineAttribute( String line, String attributeName )
{
String result = null;
int h = 0;
int l = attributeName.length();
while( true ) {
int i = line.indexOf( attributeName, h );
// System.err.println( "i=" + i );
if( i == -1 )
break;
h = i + l;
int j = line.indexOf('=', i + l );
// System.err.println( "j=" + j );
if( j != -1 ) {
int k = line.indexOf('"', j + 1 );
int m = line.indexOf(';', j + 1 );
// System.err.println( "k=" + k );
if( k != -1 && ( m == -1 || k < m ) ) {
/*
* we found a " before a possible ;
*
* now we look for the 2nd (not quoted) "
*/
m = -1;
int k2 = k + 1;
while( true ) {
m = line.indexOf('"', k2 );
// System.err.println( "m=" + m + " '" + line.substring( m ) + "'" );
if( m == -1 ) {
break;
}
else {
/*
* found one
*/
if( line.charAt( m - 1 ) != '\\' ) {
/*
* its not quoted, so it is the one we look for
*/
result = line.substring( k + 1, m );
break;
}
else {
/*
* this is quoted, so we extract the quote and continue the search
*/
line = line.substring( 0, m - 1 ) + line.substring( m );
// System.err.println( "quoting found, line='" + line + "'" );
k2 = m;
}
}
}
}
else if( m != -1 ) {
/*
* no " found, but a ;
*/
result = line.substring( j + 1, m ).trim();
}
else {
/*
* no " found and no ;
*/
result = line.substring( j + 1 );
}
}
}
return result;
}
/** translate */
private static String _t(String s, Object o) {
return Messages.getString(s, o);
}
}