www.pudn.com > MailAccess.rar > TNEFParser.cs


/****************************************************************************** 
	Copyright 2003-2004 Hamid Qureshi and Unruled Boy  
	OpenPOP.Net is free software; you can redistribute it and/or modify 
	it under the terms of the Lesser GNU General Public License as published by 
	the Free Software Foundation; either version 2 of the License, or 
	(at your option) any later version. 
 
	OpenPOP.Net 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 
	Lesser GNU General Public License for more details. 
 
	You should have received a copy of the Lesser 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 
/*******************************************************************************/ 
 
/********************************************************************* 
* Based on tnef.c from Thomas Boll  
**********************************************************************/ 
 
/* 
*Name:			OpenPOP.MIMEParser.TNEFParser 
*Function:		MS TNEF Parser 
*Author:		Thomas Boll(c version), Unruled Boy(c# version) 
*Created:		2004/3 
*Modified:		2004/5/1 14:13 GMT+8 by Unruled Boy 
*Description: 
*Changes:		 
*				2004/5/1 14:13 GMT+8 by Unruled Boy 
*					1.Adding descriptions to every public functions/property/void 
*/ 
using System; 
using System.IO; 
using System.Text; 
using System.Collections; 
 
namespace OpenPOP.MIMEParser 
{ 
	///  
	/// OpenPOP.MIMEParser.TNEFParser 
	///  
	public class TNEFParser 
	{ 
		#region Member Variables 
		private const int TNEF_SIGNATURE  =0x223e9f78; 
		private const int LVL_MESSAGE     =0x01; 
		private const int LVL_ATTACHMENT  =0x02; 
		private const int _string			=0x00010000; 
		private const int _BYTE			=0x00060000; 
		private const int _WORD			=0x00070000; 
		private const int _DWORD			=0x00080000; 
 
		private const int AVERSION      =(_DWORD|0x9006); 
		private const int AMCLASS       =(_WORD|0x8008); 
		private const int ASUBJECT      =(_DWORD|0x8004); 
		private const int AFILENAME     =(_string|0x8010); 
		private const int ATTACHDATA    =(_BYTE|0x800f); 
 
		private Stream fsTNEF; 
		private Hashtable _attachments=new Hashtable(); 
		private TNEFAttachment _attachment=null; 
 
		private bool _verbose = false; 
		//private string _logFile="OpenPOP.TNEF.log"; 
		private string _basePath=null; 
		private int _skipSignature = 0; 
		private bool _searchSignature = false; 
		private long _offset = 0; 
		private long _fileLength=0; 
		private string _tnefFile=""; 
		private string strSubject; 
		#endregion 
 
		#region Properties 
		//		public string LogFilePath 
		//		{ 
		//			get{return _logFile;} 
		//			set{_logFile=value;} 
		//		} 
 
		public string TNEFFile 
		{ 
			get{return _tnefFile;} 
			set{_tnefFile=value;} 
		} 
 
		public bool Verbose 
		{ 
			get{return _verbose;} 
			set{_verbose=value;} 
		} 
 
		public string BasePath 
		{ 
			get{return _basePath;} 
			set 
			{ 
				try 
				{ 
					if(value.EndsWith("\\")) 
						_basePath=value; 
					else 
						_basePath=value+"\\"; 
				} 
				catch 
				{ 
				} 
			} 
		} 
 
		public int SkipSignature 
		{ 
			get{return _skipSignature;} 
			set{_skipSignature=value;} 
		} 
 
		public bool SearchSignature 
		{ 
			get{return _searchSignature;} 
			set{_searchSignature=value;} 
		} 
 
		public long Offset 
		{ 
			get{return _offset;} 
			set{_offset=value;} 
		} 
		#endregion 
 
 
		private int GETINT32(byte[] p) 
		{ 
			return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); 
		} 
 
		private short GETINT16(byte[] p) 
		{ 
			return (short)(p[0]+(p[1]<<8)); 
		} 
 
		private int geti32 ()  
		{ 
			byte[] buf=new byte[4]; 
 
			if(StreamReadBytes(buf,4)!=1) 
			{ 
				Utility.LogError("geti32():unexpected end of input\n"); 
				return 1; 
			} 
			return GETINT32(buf); 
		} 
 
		private int geti16 ()  
		{ 
			byte[] buf=new byte[2]; 
 
			if(StreamReadBytes(buf,2)!=1) 
			{ 
				Utility.LogError("geti16():unexpected end of input\n"); 
				return 1; 
			} 
			return GETINT16(buf); 
		} 
 
		private int geti8 ()  
		{ 
			byte[] buf=new byte[1]; 
 
			if(StreamReadBytes(buf,1)!=1) 
			{ 
				Utility.LogError("geti8():unexpected end of input\n"); 
				return 1; 
			} 
			return (int)buf[0]; 
		} 
 
		private int StreamReadBytes(byte[] buffer, int size) 
		{ 
			try 
			{ 
				if(fsTNEF.Position+size<=_fileLength)					 
				{ 
					fsTNEF.Read(buffer,0,size); 
					return 1; 
				} 
				else 
					return 0; 
			} 
			catch(Exception e)				 
			{				 
				Utility.LogError("StreamReadBytes():"+e.Message); 
				return 0; 
			} 
		} 
 
		private void CloseTNEFStream() 
		{ 
			try 
			{ 
				fsTNEF.Close(); 
			} 
			catch(Exception e) 
			{ 
				Utility.LogError("CloseTNEFStream():"+e.Message); 
			} 
		} 
 
		///  
		/// Open the MS-TNEF stream from file 
		///  
		/// MS-TNEF file 
		///  
		public bool OpenTNEFStream(string strFile) 
		{ 
			//Utility.LogFilePath=LogFilePath; 
 
			TNEFFile=strFile; 
			try 
			{ 
				fsTNEF=new FileStream(strFile,FileMode.Open,FileAccess.Read); 
				FileInfo fi=new FileInfo(strFile); 
				_fileLength=fi.Length; 
				fi=null; 
				return true; 
			} 
			catch(Exception e) 
			{ 
				Utility.LogError("OpenTNEFStream(File):"+e.Message); 
				return false; 
			} 
		} 
 
		///  
		/// Open the MS-TNEF stream from bytes 
		///  
		/// MS-TNEF bytes 
		///  
		public bool OpenTNEFStream(byte[] bytContents) 
		{ 
			//Utility.LogFilePath=LogFilePath; 
 
			try 
			{ 
				fsTNEF=new MemoryStream(bytContents); 
				_fileLength=bytContents.Length; 
				return true; 
			} 
			catch(Exception e) 
			{ 
				Utility.LogError("OpenTNEFStream(Bytes):"+e.Message); 
				return false; 
			} 
		} 
 
		///  
		/// Find the MS-TNEF signature 
		///  
		/// true if found, vice versa 
		public bool FindSignature() 
		{ 
			bool ret=false; 
			long lpos=0; 
 
			int d; 
 
			try 
			{ 
				for (lpos=0; ; lpos++)  
				{ 
 
					if (fsTNEF.Seek(lpos,SeekOrigin.Begin)==-1) 
					{ 
						PrintResult("No signature found\n"); 
						return false; 
					} 
 
					d = geti32(); 
					if (d == TNEF_SIGNATURE)  
					{ 
						PrintResult("Signature found at {0}\n", lpos); 
						break; 
					} 
				} 
				ret=true; 
			} 
			catch(Exception e) 
			{ 
				Utility.LogError("FindSignature():"+e.Message); 
				ret=false; 
			} 
 
			fsTNEF.Position=lpos; 
 
			return ret; 
		} 
 
		private void decode_attribute (int d)  
		{ 
			byte[] buf=new byte[4000]; 
			int len; 
			int v; 
			int i; 
 
			len = geti32();   /* data length */ 
 
			switch(d&0xffff0000) 
			{ 
				case _BYTE: 
					PrintResult("Attribute {0} =", d&0xffff); 
					for (i=0; i < len; i+=1)  
					{ 
						v = geti8(); 
 
						if (i< 10) PrintResult(" {0}", v); 
						else if (i==10) PrintResult("..."); 
					} 
					PrintResult("\n"); 
					break; 
				case _WORD: 
					PrintResult("Attribute {0} =", d&0xffff); 
					for (i=0; i < len; i+=2)  
					{ 
						v = geti16(); 
 
						if (i < 6) PrintResult(" {0}", v); 
						else if (i==6) PrintResult("..."); 
					} 
					PrintResult("\n"); 
					break; 
				case _DWORD: 
					PrintResult("Attribute {0} =", d&0xffff); 
					for (i=0; i < len; i+=4)  
					{ 
						v = geti32(); 
 
						if (i < 4) PrintResult(" {0}", v); 
						else if (i==4) PrintResult("..."); 
					} 
					PrintResult("\n"); 
					break; 
				case _string: 
					StreamReadBytes(buf, len); 
 
					PrintResult("Attribute {0} = {1}\n", d&0xffff, Encoding.Default.GetString(buf)); 
					break; 
				default: 
					StreamReadBytes(buf, len); 
					PrintResult("Attribute {0}\n", d); 
					break; 
			} 
 
			geti16();     /* checksum */ 
		} 
 
		private void decode_message()  
		{   
			int d; 
 
			d = geti32(); 
 
			decode_attribute(d); 
		} 
 
		private void decode_attachment()  
		{   
			byte[] buf=new byte[4096]; 
			int d; 
			int len; 
			int i,chunk; 
     
			d = geti32(); 
 
			switch (d)  
			{ 
				case ASUBJECT: 
					len = geti32(); 
 
					StreamReadBytes(buf,len); 
 
					byte[] _subjectBuffer=new byte[len-1]; 
 
					Array.Copy(buf,_subjectBuffer,(long)len-1); 
 
					strSubject=Encoding.Default.GetString(_subjectBuffer); 
 
					PrintResult("Found subject: {0}", strSubject); 
 
					geti16();     /* checksum */  
 
					break; 
 
				case AFILENAME: 
					len = geti32(); 
					StreamReadBytes(buf,len); 
					//PrintResult("File-Name: {0}\n", buf); 
					byte[] _fileNameBuffer=new byte[len-1]; 
					Array.Copy(buf,_fileNameBuffer,(long)len-1); 
 
					if (_fileNameBuffer == null) _fileNameBuffer = Encoding.Default.GetBytes("tnef.dat"); 
					string strFileName=Encoding.Default.GetString(_fileNameBuffer); 
 
					PrintResult("{0}: WRITING {1}\n", BasePath, strFileName); 
 
					//new attachment found because attachment data goes before attachment name 
					_attachment.FileName=strFileName; 
					_attachment.Subject=strSubject; 
					_attachments.Add(_attachment.FileName,_attachment); 
 
					geti16();     /* checksum */  
 
					break; 
 
				case ATTACHDATA: 
					len = geti32(); 
					PrintResult("ATTACH-DATA: {0} bytes\n", len); 
 
					_attachment=new TNEFAttachment(); 
					_attachment.FileContent=new byte[len]; 
					_attachment.FileLength=len; 
 
					for (i = 0; i < len; )  
					{ 
						chunk = len-i; 
						if (chunk > buf.Length) chunk = buf.Length; 
 
						StreamReadBytes(buf,chunk); 
 
						Array.Copy(buf,0,_attachment.FileContent,i,chunk); 
 
						i += chunk; 
					} 
 
					geti16();     /* checksum */  
		 
					break; 
		   
				default: 
					decode_attribute(d); 
					break; 
			} 
		} 
 
		///  
		/// decoded attachments 
		///  
		/// attachment array 
		public Hashtable Attachments() 
		{ 
			return _attachments; 
		} 
 
		///  
		/// save all decoded attachments to files 
		///  
		/// true is succeded, vice versa 
		public bool SaveAttachments() 
		{ 
			bool blnRet=false; 
			IDictionaryEnumerator ideAttachments=_attachments.GetEnumerator(); 
 
			while(ideAttachments.MoveNext()) 
			{ 
				blnRet=SaveAttachment((TNEFAttachment)ideAttachments.Value); 
			} 
 
			return blnRet; 
		} 
 
		///  
		/// save a decoded attachment to file 
		///  
		/// decoded attachment 
		/// true is succeded, vice versa 
		public bool SaveAttachment(TNEFAttachment attachment) 
		{ 
			try 
			{ 
				string strOutFile=BasePath+attachment.FileName; 
 
				if(File.Exists(strOutFile)) 
					File.Delete(strOutFile); 
				FileStream fsData=new FileStream(strOutFile,FileMode.CreateNew,FileAccess.Write); 
 
				fsData.Write(attachment.FileContent,0,(int)attachment.FileLength); 
 
				fsData.Close(); 
 
				return true; 
			} 
			catch(Exception e) 
			{ 
				Utility.LogError("SaveAttachment():"+e.Message); 
				return false; 
			} 
		} 
 
		///  
		/// parse MS-TNEF stream 
		///  
		/// true is succeded, vice versa 
		public bool Parse() 
		{ 
			byte[] buf=new byte[4]; 
			int d; 
 
			if(FindSignature()) 
			{ 
				if (SkipSignature < 2)  
				{ 
					d = geti32(); 
					if (SkipSignature < 1)  
					{ 
						if (d != TNEF_SIGNATURE)  
						{ 
							PrintResult("Seems not to be a TNEF file\n"); 
							return false; 
						} 
					} 
				} 
 
				d = geti16(); 
				PrintResult("TNEF Key is: {0}\n", d); 
				for (;;)  
				{ 
					if(StreamReadBytes(buf,1)==0)  
						break; 
 
					d = (int)buf[0]; 
 
					switch (d)  
					{ 
						case LVL_MESSAGE: 
							PrintResult("{0}: Decoding Message Attributes\n",fsTNEF.Position); 
							decode_message(); 
							break; 
						case LVL_ATTACHMENT: 
							PrintResult("Decoding Attachment\n"); 
							decode_attachment(); 
							break; 
						default: 
							PrintResult("Coding Error in TNEF file\n"); 
							return false; 
					} 
				} 
				return true; 
			} 
			else 
				return false; 
		} 
 
		private void PrintResult(string strResult, params object[] strContent) 
		{ 
			string strRet=string.Format(strResult,strContent); 
			if (Verbose)  
				Utility.LogError(strRet); 
		} 
 
		~TNEFParser() 
		{ 
			_attachments=null; 
			CloseTNEFStream(); 
		} 
 
		public TNEFParser() 
		{ 
		} 
 
		///  
		/// open MS-TNEF stream from a file 
		///  
		/// MS-TNEF file 
		public TNEFParser(string strFile) 
		{ 
			OpenTNEFStream(strFile); 
		}	 
 
		///  
		/// open MS-TNEF stream from bytes 
		///  
		/// MS-TNEF bytes 
		public TNEFParser(byte[] bytContents) 
		{ 
			OpenTNEFStream(bytContents); 
		} 
	} 
}