www.pudn.com > NETINFO.rar > EmailAnalyse.cpp


#include "EmailAnalyse.h" 
#include "tools.h" 
#include "EmailDecode.h" 
 
 
//BNF grammer 
#define LWSP " \t" 
#define TSPECIALS "()<>@,;:\\\"/[]?=" 
 
//parameter names 
#define CHARSET "charset" 
#define BOUNDARY "boundary" 
#define FILENAME "filename" 
#define CONTENT_NAME "name" 
 
//encoding types 
#define ENCODE_7BIT "7bit" 
#define ENCODE_8BIT "8bit" 
#define ENCODE_BINARY "binary" 
#define ENCODE_QUOTED_PRINTABLE "quoted-printable" 
#define ENCODE_BASE64	"base64" 
 
//media type 
#define TYPE_TEXT "text" 
#define TYPE_IMAGE "image" 
#define TYPE_AUDIO "audio" 
#define TYPE_VIDEO "video" 
#define TYPE_APPLICATION "application" 
#define TYPE_MESSAGE "message" 
#define TYPE_MODEL "model" 
#define TYPE_MULTIPART "multipart" 
 
 
//media subtype 
 
//text category 
#define SUBTYPE_PLAIN "plain" 
#define SUBTYPE_RTF "rtf" 
#define SUBTYPE_HTML "html" 
#define SUBTYPE_XML "xml" 
 
//image category 
#define SUBTYPE_GIF "gif" 
#define SUBTYPE_JPEG "jpg" 
#define SUBTYPE_PNG "png" 
#define SUBTYPE_TIFF "tif" 
 
//audio category 
 
//video category 
#define SUBTYPE_MEPG "mpg" 
 
//application 
#define SUBTYPE_OCTET_STREAM "octet-stream" 
#define SUBTYPE_PDF "pdf" 
 
//message subtypes 
#define SUBTYPE_RFC822 "rfc822" 
 
 
//header filed names 
#define FROM "From" 
#define TO "To" 
#define SUBJECT "Subject" 
#define	MIME_VERSION "Mime-Version" 
#define CONTENT_TYPE "Content-Type" 
#define CONTENT_TRANSFER_ENCODING "Content-Transfer-Encoding" 
#define CONTENT_DISPOSITION "Content-Disposition" 
#define CONTENT_ID "Content-ID" 
#define CONTENT_LANGUAGE "Content-Language" 
 
void AnalyseParameter(const char parameters[], int n, const char* names[], char* values[]) 
{ 
	int start = 0, i = 0, len = strlen(parameters); 
	if( i>=len ) return; //no parameter, so return 
	while( i < len ) //get attribute=value pair 
	{ 
		char attribute[MAX_EMAIL_LINE], value[MAX_EMAIL_LINE]; 
 
		//exract attribute token ( ascii except LWSP, CTRLS, TSPECIALS ) 
		for(; i=pStart && isspace(*pEnd); pEnd--)NULL; //skip end space 
	if(pEnd>=pStart && pEnd - pStart + 2 < MAX_EMAIL_LINE ) 
	{ 
		memcpy(name, pStart, pEnd-pStart+1); 
		name[pEnd-pStart+1] = 0; 
	} 
	else 
		strcpy(name, ""); 
 
	//extract value 
	const char* pZero = pColon + strlen(pColon); 
	for(pStart = pColon+1; pStart=pStart && isspace(*pEnd); pEnd--)NULL; //skip end space 
	if(pEnd>=pStart && pEnd - pStart + 2 < MAX_EMAIL_LINE ) 
	{ 
		memcpy(value, pStart, pEnd-pStart+1); 
		value[pEnd-pStart+1] = 0; 
	} 
	else 
		strcpy(value, ""); 
	return TRUE; 
} 
 
void AnalyseHeader(const char header[MAX_EMAIL_LINE], struct MESSAGE_HEADERS *pHeaders) 
{ 
	char name[MAX_EMAIL_LINE], value[MAX_EMAIL_LINE]; 
	if( !SplitMessageHeader(header, name, value) )return; 
 
	//extract from 
	if( stricmp(name, FROM)==0 ) 
		strcpy(pHeaders->from, value); 
	//extract to 
	else if( stricmp(name, TO)==0 ) 
		strcpy(pHeaders->to, value); 
	//extract subject 
	else if( stricmp(name, SUBJECT)==0 ) 
		strcpy(pHeaders->subject, value); 
	//extract mime-version 
	else if( stricmp(name, MIME_VERSION)==0 ) 
		strcpy(pHeaders->mime_Version, value); 
	//extract content-type 
	else if( stricmp(name, CONTENT_TYPE)==0 ) 
	{ 
		int i, len = strlen(header); 
		for(i=0; icontent_Type, header+start, i - start); 
			pHeaders->content_Type[ i - start ] = 0; 
		} 
 
		for(; icontent_Subtype, header+start, i - start); 
			pHeaders->content_Subtype[ i - start ] = 0; 
		} 
 
		for(; i=len ) return; //no parameter, so return 
		const static char* names[3] ={CHARSET, BOUNDARY, CONTENT_NAME}; 
		char* values[3] = {pHeaders->charset, pHeaders->boundary, pHeaders->name}; 
		AnalyseParameter(header+i, 3,  names, values); 
	} 
	else if( stricmp(name, CONTENT_TRANSFER_ENCODING) == 0 ) 
		strcpy(pHeaders->content_Transfer_Encoding, value); 
	else if( stricmp(name, CONTENT_DISPOSITION) == 0 ) 
	{ 
		int i, len = strlen(header); 
		for(i=0; icontent_Disposition, header+start, i - start); 
			pHeaders->content_Disposition[ i - start ] = 0; 
		} 
 
		for(; i=len ) return; //no parameter, so return 
 
		const static char* names[1] ={FILENAME}; 
		char* values[1] = {pHeaders->filename}; 
		AnalyseParameter(header+i, 1,  names, values); 
	} 
} 
 
 
 
CMessageDecoder::CMessageDecoder(void*pUserData, const MESSAGE_DECODE_CALLBACKS *pFuncs) 
:m_funcs(*pFuncs) 
{ 
	strcpy(m_szHeader, ""); 
	memset(&m_headers, 0, sizeof(m_headers)); 
	m_status = MESSAGE_BEGIN; 
	memset(&m_dataAccepter, 0, sizeof(m_dataAccepter)); 
	m_messageType = MESSAGE_TYPE_DATA; 
	m_pUserData = pUserData; 
}; 
 
CMessageDecoder::~CMessageDecoder() 
{ 
	if( m_status != MESSAGE_END ) 
		FindEnd(); 
} 
 
void CMessageDecoder::GetLine(const char inputLine[], int inputStrlen) 
{ 
	if( m_status == MESSAGE_BEGIN || m_status == MESSAGE_HEADER ) 
	{ 
		m_status = MESSAGE_HEADER; 
 
		//get rid of ending "\r\n"	of line  
		char line[MAX_EMAIL_LINE]; 
		memcpy(line, inputLine, inputStrlen-2); 
		line[inputStrlen-2] = 0; 
 
		//end of header erea 
		if( strcmp(line, "") == 0 ) 
		{ 
			AnalyseHeader(m_szHeader, &m_headers); 
			PostGetHeader(); 
			m_status = MESSAGE_BODY; 
		} 
 
		//folded header line 
		else if( strchr(LWSP, line[0]) ) 
		{ 
			strcat(m_szHeader, line); 
		} 
 
		//another header  
		else 
		{ 
			AnalyseHeader(m_szHeader, &m_headers); 
			strcpy(m_szHeader, line); 
		} 
	} 
	else if( m_status == MESSAGE_BODY ) 
	{ 
		if( m_messageType == MESSAGE_TYPE_MULTIPART ) 
		{ 
			char delimiter[MAX_EMAIL_LINE]; 
			//delimiter of multipart 
			sprintf(delimiter, "--%s", m_headers.boundary); 
			if( memcmp(inputLine, delimiter, strlen(delimiter)) == 0 ) 
			{ 
				//delete current message decoder 
				if( m_dataAccepter.m_pMessageDecoder ) 
				{ 
					m_dataAccepter.m_pMessageDecoder->FindEnd(); 
					delete m_dataAccepter.m_pMessageDecoder; 
					m_dataAccepter.m_pMessageDecoder = NULL; 
				} 
				//end delimiter of multipart 
				sprintf(delimiter, "--%s--", m_headers.boundary); 
				if( memcmp(inputLine, delimiter, strlen(delimiter)) == 0 ) 
				{ 
					m_status = MESSAGE_END; 
					return; 
				} 
				//not end of message,  new CMessageDecoder to decode new Entity 
				else 
					m_dataAccepter.m_pMessageDecoder = new CMessageDecoder(m_pUserData, &m_funcs); 
			} 
			//normal data line need to be send to current MessageDecoder 
			else 
			{ 
				if( m_dataAccepter.m_pMessageDecoder ) 
					m_dataAccepter.m_pMessageDecoder->GetLine(inputLine, inputStrlen); 
			} 
		} 
		else if( m_messageType == MESSAGE_TYPE_MESSAGE ) 
		{ 
			if( m_dataAccepter.m_pMessageDecoder ) 
				m_dataAccepter.m_pMessageDecoder->GetLine(inputLine, inputStrlen); 
		} 
		else if( m_messageType == MESSAGE_TYPE_DATA ) 
		{ 
			char data[MAX_EMAIL_LINE]; 
			int length; 
			//decode data and send it to callback functions 
			if( !m_dataAccepter.m_pTransferDecoder 
				|| !m_dataAccepter.m_pTransferDecoder->Decode(inputLine, inputStrlen, data, MAX_EMAIL_LINE, &length) )				 
			{ 
				memcpy(data, inputLine, inputStrlen); 
				length = inputStrlen; 
			} 
 
			if( m_funcs.fnOnMessageEntityBody ) 
				m_funcs.fnOnMessageEntityBody(m_pUserData, (const BYTE*)data, length); 
		} 
	} 
} 
 
void CMessageDecoder::PostGetHeader() 
{ 
	//decode header field encoding(include from, to, subject, name, filename) 
	char temp[MAX_EMAIL_LINE]; 
	int outputLength; 
	if( HeaderDecode(m_headers.from, strlen(m_headers.from), temp, sizeof(temp), &outputLength) ) 
		strcpy(m_headers.from, temp); 
	if( HeaderDecode(m_headers.to, strlen(m_headers.to), temp, sizeof(temp), &outputLength) ) 
		strcpy(m_headers.to, temp); 
	if( HeaderDecode(m_headers.subject, strlen(m_headers.subject), temp, sizeof(temp), &outputLength) ) 
		strcpy(m_headers.subject, temp); 
	if( HeaderDecode(m_headers.filename, strlen(m_headers.filename), temp, sizeof(temp), &outputLength) ) 
		strcpy(m_headers.filename, temp); 
	if( HeaderDecode(m_headers.name, strlen(m_headers.name), temp, sizeof(temp), &outputLength) ) 
		strcpy(m_headers.name, temp); 
 
	//send CALLBACKS with message header info such as: from, to, subject 
	if( strcmp(m_headers.from, "")!=0 ) 
	{ 
		if( m_funcs.fnOnMessageHeader ) 
			m_funcs.fnOnMessageHeader(m_pUserData, m_headers.from, m_headers.to, m_headers.subject); 
	} 
 
	//set default values 
	if( stricmp(m_headers.content_Type, "") == 0 ) 
	{ 
		strcpy(m_headers.content_Type, TYPE_TEXT); 
		strcpy(m_headers.content_Subtype, SUBTYPE_PLAIN); 
	} 
	if( stricmp(m_headers.charset, "") == 0 ) 
		strcpy(m_headers.charset, "us-ascii"); 
	if( stricmp(m_headers.content_Transfer_Encoding, "") == 0 ) 
		strcpy(m_headers.content_Transfer_Encoding, ENCODE_7BIT); 
 
	//get filename from name 
	if( strcmp(m_headers.filename, "") == 0 && strcmp(m_headers.name, "") !=0 ) 
	{ 
		strcpy(m_headers.filename, m_headers.name); 
	} 
 
	//get filename from MIME type & subtype, mainly to get proper extension of file name 
	if( strcmp(m_headers.filename, "") == 0 ) 
	{ 
		char extension[MAX_EMAIL_LINE] = ""; 
		GetExtFromMimeType(m_headers.content_Type, m_headers.content_Subtype, extension); 
		sprintf(m_headers.filename, "%d.%s", rand(), extension); 
	} 
	else //get pure file name of filename possiblly include path( indicater is '\\' or '/' ) 
	{ 
		char filePath[MAX_EMAIL_LINE]; 
		strcpy(filePath, m_headers.filename); 
		GetPureFileName(filePath, m_headers.filename); 
	} 
 
	//decode multipart 
	if( stricmp(m_headers.content_Type, TYPE_MULTIPART) == 0 ) 
	{ 
		m_messageType = MESSAGE_TYPE_MULTIPART; 
		m_dataAccepter.m_pMessageDecoder = NULL; 
	} 
	//decode message  
	else if( stricmp(m_headers.content_Type, TYPE_MESSAGE) == 0 
			 && stricmp(m_headers.content_Subtype, SUBTYPE_RFC822) == 0 ) 
	{ 
		m_messageType = MESSAGE_TYPE_MESSAGE; 
		m_dataAccepter.m_pMessageDecoder = new CMessageDecoder(m_pUserData, &m_funcs); 
	} 
	//pure data 
	else 
	{ 
		m_messageType = MESSAGE_TYPE_DATA; 
		if( stricmp(m_headers.content_Transfer_Encoding, ENCODE_7BIT) == 0  
			|| stricmp(m_headers.content_Transfer_Encoding, ENCODE_8BIT) == 0 ) 
			m_dataAccepter.m_pTransferDecoder = new C7bit8bitTranferDecoder(); 
		else if( stricmp(m_headers.content_Transfer_Encoding, ENCODE_QUOTED_PRINTABLE) == 0 ) 
			m_dataAccepter.m_pTransferDecoder = new CQPTranferDecoder(); 
		else if( stricmp(m_headers.content_Transfer_Encoding, ENCODE_BASE64) == 0 ) 
			m_dataAccepter.m_pTransferDecoder = new CBase64TranferDecoder(); 
		else 
			m_dataAccepter.m_pTransferDecoder = NULL; 
 
		if( m_funcs.fnOnMessageEntityHeader ) 
			m_funcs.fnOnMessageEntityHeader(m_pUserData, m_headers.content_Type, m_headers.content_Subtype, m_headers.filename); 
	} 
} 
 
void CMessageDecoder::FindEnd() 
{ 
	if( m_status == MESSAGE_HEADER ) 
	{ 
		PostGetHeader(); 
	} 
	else if( m_status == MESSAGE_BODY ) 
	{ 
		if( m_messageType == MESSAGE_TYPE_MULTIPART  
			|| m_messageType == MESSAGE_TYPE_MESSAGE ) 
		{ 
			if( m_dataAccepter.m_pMessageDecoder ) 
			{ 
				m_dataAccepter.m_pMessageDecoder->FindEnd(); 
				delete m_dataAccepter.m_pMessageDecoder; 
				m_dataAccepter.m_pMessageDecoder = NULL; 
			} 
		} 
		else if( m_messageType == MESSAGE_TYPE_DATA ) 
		{ 
			if( m_dataAccepter.m_pTransferDecoder ) 
			{ 
				delete m_dataAccepter.m_pTransferDecoder; 
				m_dataAccepter.m_pTransferDecoder = NULL; 
			} 
			if( m_funcs.fnOnMessageEntityBodyEnd ) m_funcs.fnOnMessageEntityBodyEnd(m_pUserData); 
		} 
	} 
	m_status = MESSAGE_END; 
}