Attachment.cs
上传用户:hncsjykj
上传日期:2022-08-09
资源大小:461k
文件大小:18k
源码类别:

Email客户端

开发平台:

C#

  1. /******************************************************************************
  2. Copyright 2003-2004 Hamid Qureshi and Unruled Boy 
  3. OpenPOP.Net is free software; you can redistribute it and/or modify
  4. it under the terms of the Lesser GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. OpenPOP.Net is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10. Lesser GNU General Public License for more details.
  11. You should have received a copy of the Lesser GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  14. /*******************************************************************************/
  15. /*
  16. *Name: OpenPOP.MIMEParser.Attachment
  17. *Function: Attachment
  18. *Author: Hamid Qureshi
  19. *Created: 2003/8
  20. *Last Modified: 2004/5/28 10:19 GMT+8 by Unruled Boy
  21. *Description:
  22. *Changes:
  23. * 2004/5/28 10:19 GMT+8 by grandepuffo via Unruled Boy
  24. * 1.Fixed a bug in parsing ContentFileName @ https://sourceforge.net/forum/message.php?msg_id=2589759
  25. * 2004/5/17 14:20 GMT+8 by Unruled Boy
  26. * 1.Fixed a bug in parsing FileName
  27. * 2004/5/8 17:00 GMT+8 by Unruled Boy
  28. * 1.Again, hopefully we have handled the NotAttachment property correctly
  29. * 2004/5/1 14:13 GMT+8 by Unruled Boy
  30. * 1.Adding three more constructors
  31. * 2.Adding descriptions to every public functions/property/void
  32. * 2004/4/29 19:05 GMT+8 by Unruled Boy
  33. * 1.Hopefully we have handled the NotAttachment property correctly
  34. * 2004/3/29 10:28 GMT+8 by Unruled Boy
  35. * 1.removing bugs in decoding attachment
  36. * 2004/3/29 17:32 GMT+8 by Unruled Boy
  37. * 1.support for reply message using ms-tnef 
  38. * 2.adding detail description for every function
  39. * 3.cleaning up the codes
  40. */
  41. using System;
  42. using System.IO;
  43. using System.Text;
  44. using System.Text.RegularExpressions;
  45. namespace OpenPOP.MIMEParser
  46. {
  47. /// <summary>
  48. /// Summary description for Attachment.
  49. /// </summary>
  50. public class Attachment : IComparable
  51. {
  52. #region Member Variables
  53. private string _contentType=null;
  54. private string _contentCharset=null;
  55. private string _contentFormat=null;
  56. private string _contentTransferEncoding=null;
  57. private string _contentDescription=null;
  58. private string _contentDisposition=null;
  59. private string _contentFileName="";
  60. private string _defaultFileName="body.htm";
  61. private string _defaultFileName2="body*.htm";
  62. private string _defaultReportFileName="report.htm";
  63. private string _defaultMIMEFileName="body.eml";
  64. private string _defaultMSTNEFFileName="winmail.dat";
  65. private string _contentID=null;
  66. private long _contentLength=0;
  67. private string _rawAttachment=null;
  68. private bool _inBytes=false;
  69. private byte[] _rawBytes=null;
  70. #endregion
  71. #region Properties
  72. /// <summary>
  73. /// raw attachment content bytes
  74. /// </summary>
  75. public byte[] RawBytes
  76. {
  77. get{return _rawBytes;}
  78. set{_rawBytes=value;}
  79. }
  80. /// <summary>
  81. /// whether attachment is in bytes
  82. /// </summary>
  83. public bool InBytes
  84. {
  85. get{return _inBytes;}
  86. set{_inBytes=value;}
  87. }
  88. /// <summary>
  89. /// Content length
  90. /// </summary>
  91. public long ContentLength
  92. {
  93. get{return _contentLength;}
  94. }
  95. /// <summary>
  96. /// verify the attachment whether it is a real attachment or not
  97. /// </summary>
  98. /// <remarks>this is so far not comprehensive and needs more work to finish</remarks>
  99. public bool NotAttachment
  100. {
  101. get
  102. {
  103. /* if (_contentDisposition==null||_contentType==null)
  104. return true;
  105. else
  106. return (_contentDisposition.IndexOf("attachment")==-1 && _contentType.IndexOf("text/plain")!=-1); */
  107. /* if (_contentType==null)
  108. return true;
  109. else
  110. return (_contentFileName!="");*/
  111. if ((_contentType==null||_contentFileName=="") && _contentID==null)//&&_contentType.ToLower().IndexOf("text/")!=-1)
  112. return true;
  113. else
  114. return false;
  115. }
  116. }
  117. /// <summary>
  118. /// Content format
  119. /// </summary>
  120. public string ContentFormat
  121. {
  122. get{return _contentFormat;}
  123. }
  124. /// <summary>
  125. /// Content charset
  126. /// </summary>
  127. public string ContentCharset
  128. {
  129. get{return _contentCharset;}
  130. }
  131. /// <summary>
  132. /// default file name
  133. /// </summary>
  134. public string DefaultFileName
  135. {
  136. get{return _defaultFileName;}
  137. set{_defaultFileName=value;}
  138. }
  139. /// <summary>
  140. /// default file name 2
  141. /// </summary>
  142. public string DefaultFileName2
  143. {
  144. get{return _defaultFileName2;}
  145. set{_defaultFileName2=value;}
  146. }
  147. /// <summary>
  148. /// default report file name
  149. /// </summary>
  150. public string DefaultReportFileName
  151. {
  152. get{return _defaultReportFileName;}
  153. set{_defaultReportFileName=value;}
  154. }
  155. /// <summary>
  156. /// default MIME File Name
  157. /// </summary>
  158. public string DefaultMIMEFileName
  159. {
  160. get{return _defaultMIMEFileName;}
  161. set{_defaultMIMEFileName=value;}
  162. }
  163. /// <summary>
  164. /// Content Type
  165. /// </summary>
  166. public string ContentType
  167. {
  168. get{return _contentType;}
  169. }
  170. /// <summary>
  171. /// Content Transfer Encoding
  172. /// </summary>
  173. public string ContentTransferEncoding
  174. {
  175. get{return _contentTransferEncoding;}
  176. }
  177. /// <summary>
  178. /// Content Description
  179. /// </summary>
  180. public string ContentDescription
  181. {
  182. get{return _contentDescription;}
  183. }
  184. /// <summary>
  185. /// Content File Name
  186. /// </summary>
  187. public string ContentFileName
  188. {
  189. get{return _contentFileName;}
  190. set{_contentFileName=value;}
  191. }
  192. /// <summary>
  193. /// Content Disposition
  194. /// </summary>
  195. public string ContentDisposition
  196. {
  197. get{return _contentDisposition;}
  198. }
  199. /// <summary>
  200. /// Content ID
  201. /// </summary>
  202. public string ContentID
  203. {
  204. get{return _contentID;}
  205. }
  206. /// <summary>
  207. /// Raw Attachment
  208. /// </summary>
  209. public string RawAttachment
  210. {
  211. get{return _rawAttachment;}
  212. }
  213. /// <summary>
  214. /// decoded attachment in bytes
  215. /// </summary>
  216. public byte[] DecodedAttachment
  217. {
  218. get
  219. {
  220. return DecodedAsBytes();
  221. }
  222. }
  223. #endregion
  224. /// <summary>
  225. /// release all objects
  226. /// </summary>
  227. ~Attachment()
  228. {
  229. _rawBytes=null;
  230. _rawAttachment=null;
  231. }
  232. /// <summary>
  233. /// New Attachment
  234. /// </summary>
  235. /// <param name="bytAttachment">attachment bytes content</param>
  236. /// <param name="lngFileLength">file length</param>
  237. /// <param name="strFileName">file name</param>
  238. /// <param name="strContentType">content type</param>
  239. public Attachment(byte[] bytAttachment, long lngFileLength, string strFileName, string strContentType)
  240. {
  241. _inBytes=true;
  242. _rawBytes=bytAttachment;
  243. _contentLength=lngFileLength;
  244. _contentFileName=strFileName;
  245. _contentType=strContentType;
  246. }
  247. /// <summary>
  248. /// New Attachment
  249. /// </summary>
  250. /// <param name="bytAttachment">attachment bytes content</param>
  251. /// <param name="strFileName">file name</param>
  252. /// <param name="strContentType">content type</param>
  253. public Attachment(byte[] bytAttachment, string strFileName, string strContentType)
  254. {
  255. _inBytes=true;
  256. _rawBytes=bytAttachment;
  257. _contentLength=bytAttachment.Length;
  258. _contentFileName=strFileName;
  259. _contentType=strContentType;
  260. }
  261. /// <summary>
  262. /// New Attachment
  263. /// </summary>
  264. /// <param name="strAttachment">attachment content</param>
  265. /// <param name="strContentType">content type</param>
  266. /// <param name="blnParseHeader">whether only parse the header or not</param>
  267. public Attachment(string strAttachment,string strContentType, bool blnParseHeader)
  268. {
  269. if(!blnParseHeader)
  270. {
  271. _contentFileName=_defaultMSTNEFFileName;
  272. _contentType=strContentType;
  273. }
  274. this.NewAttachment(strAttachment,blnParseHeader);
  275. }
  276. /// <summary>
  277. /// New Attachment
  278. /// </summary>
  279. /// <param name="strAttachment">attachment content</param>
  280. public Attachment(string strAttachment)
  281. {
  282. this.NewAttachment(strAttachment,true);
  283. }
  284. /// <summary>
  285. /// create attachment
  286. /// </summary>
  287. /// <param name="strAttachment">raw attachment text</param>
  288. /// <param name="blnParseHeader">parse header</param>
  289.         ///
  290.         private void NewAttachment(string strAttachment, bool blnParseHeader)
  291.         {
  292.             _inBytes = false;
  293.             if (strAttachment == null)
  294.                 throw new ArgumentNullException("strAttachment");
  295.             StringReader srReader = new StringReader(strAttachment);
  296.             
  297.             if (blnParseHeader)
  298.             { 
  299.                 string strLine = srReader.ReadLine();
  300.                 string strRead = "Begin";
  301.                 
  302.                 //if (strLine.Contains("name=") && !strLine.EndsWith("""))
  303.                 if(strLine.ToLower().Contains("content-type")&&!strLine.ToLower().Contains("text/plain"))
  304.                 {
  305.                     while (!strRead.EndsWith("""))
  306.                     {
  307.                         strRead = srReader.ReadLine();
  308.                         strLine = String.Concat(strLine, strRead);
  309.                         strLine=Regex.Replace(strLine, "\?= =\?gbk\?Q\?", "", RegexOptions.IgnoreCase);
  310.                         
  311.                     }
  312.                 }
  313.                 while (Utility.IsNotNullTextEx(strLine))
  314.                 {
  315.                     ParseHeader(srReader, ref strLine);
  316.                     if (Utility.IsOrNullTextEx(strLine))
  317.                         break;
  318.                     else
  319.                     {
  320.                         strLine = srReader.ReadLine();
  321.                         strRead = "Begin";
  322.                         if (Utility.IsOrNullTextEx(strLine))
  323.                             break;
  324.                         if (strLine.Contains("name=") && !strLine.EndsWith("""))
  325.                         {
  326.                             while (!strRead.EndsWith("""))
  327.                             {
  328.                                 strRead = srReader.ReadLine();
  329.                                 strLine = String.Concat(strLine, strRead);
  330.                                 strLine = Regex.Replace(strLine, "\?= =\?gbk\?Q\?", "", RegexOptions.IgnoreCase);
  331.                             }
  332.                         }
  333.                     }
  334.                 }
  335.             }
  336.             this._rawAttachment = srReader.ReadToEnd();
  337.             _contentLength = this._rawAttachment.Length;
  338.         }
  339.         /// <summary>
  340.         /// Parse header fields and set member variables
  341.         /// </summary>
  342.         /// <param name="srReader">string reader</param>
  343.         /// <param name="strLine">header line</param>
  344.         private void ParseHeader(StringReader srReader, ref string strLine)
  345.         {
  346.             string[] array = Utility.GetHeadersValue(strLine);
  347.             string[] values = Regex.Split(array[1], ";");
  348.             string strRet = null;
  349.             switch (array[0].ToUpper())
  350.             {
  351.                 case "CONTENT-TYPE":
  352.                     if (values.Length > 0)
  353.                         _contentType = values[0].Trim();
  354.                     if (values.Length > 1)
  355.                     {
  356.                         _contentCharset = Utility.GetQuotedValue(values[1], "=", "charset");
  357.                     }
  358.                     if (values.Length > 2)
  359.                     {
  360.                         _contentFormat = Utility.GetQuotedValue(values[2], "=", "format");
  361.                     }
  362.                     _contentFileName = Utility.ParseFileName(strLine);
  363.                     if (_contentFileName == "")
  364.                     {
  365.                         strRet = srReader.ReadLine();
  366.                         if (strRet == "")
  367.                         {
  368.                             strLine = "";
  369.                             break;
  370.                         }
  371.                         _contentFileName = Utility.ParseFileName(strLine);
  372.                         if (_contentFileName == "")
  373.                             ParseHeader(srReader, ref strRet);
  374.                     }
  375.                     break;
  376.                 case "CONTENT-TRANSFER-ENCODING":
  377.                     _contentTransferEncoding = Utility.SplitOnSemiColon(array[1])[0].Trim();
  378.                     break;
  379.                 case "CONTENT-DESCRIPTION":
  380.                     _contentDescription = Utility.DecodeText(Utility.SplitOnSemiColon(array[1])[0].Trim());
  381.                     break;
  382.                 case "CONTENT-DISPOSITION":
  383.                     if (values.Length > 0)
  384.                         _contentDisposition = values[0].Trim();
  385.                     ///<bug>reported by grandepuffo @ https://sourceforge.net/forum/message.php?msg_id=2589759
  386.                     //_contentFileName=values[1];
  387.                     if (values.Length > 1)
  388.                     {
  389.                         _contentFileName = values[1];
  390.                     }
  391.                     else
  392.                     {
  393.                         _contentFileName = "";
  394.                     }
  395.                     if (_contentFileName == "")
  396.                     {
  397.                         _contentFileName = srReader.ReadLine();
  398.                         //-------start by shine -----------------------------------//
  399.                         while(!_contentFileName.EndsWith("""))
  400.                         {
  401.                             _contentFileName += srReader.ReadLine();
  402.                         }
  403.                         //---------end by shine -----------------------------------//
  404.                     }
  405.                     _contentFileName = _contentFileName.Replace("t", "");
  406.                     _contentFileName = Utility.GetQuotedValue(_contentFileName, "=", "filename");
  407.                     _contentFileName = Utility.DecodeText(_contentFileName);
  408.                     break;
  409.                 case "CONTENT-ID":
  410.                     _contentID = Utility.SplitOnSemiColon(array[1])[0].Trim('<').Trim('>');
  411.                     break;
  412.             }
  413.         }
  414. /// <summary>
  415. /// verify the encoding
  416. /// </summary>
  417. /// <param name="encoding">encoding to verify</param>
  418. /// <returns>true if encoding</returns>
  419. private bool IsEncoding(string encoding)
  420. {
  421. return _contentTransferEncoding.ToLower().IndexOf(encoding.ToLower())!=-1;
  422. }
  423. /// <summary>
  424. /// Decode the attachment to text
  425. /// </summary>
  426. /// <returns>Decoded attachment text</returns>
  427. public string DecodeAsText()
  428. {
  429. string decodedAttachment=null;
  430. try
  431. {
  432. if(_contentType.ToLower()=="message/rfc822".ToLower())
  433. decodedAttachment=Utility.DecodeText(_rawAttachment);
  434. else if(_contentTransferEncoding!=null)
  435. {
  436. decodedAttachment=_rawAttachment;
  437. if(!IsEncoding("7bit"))
  438. {
  439. if(IsEncoding("8bit")&&_contentCharset!=null&_contentCharset!="")
  440. decodedAttachment=Utility.Change(decodedAttachment,_contentCharset);
  441. if(Utility.IsQuotedPrintable(_contentTransferEncoding))
  442. decodedAttachment=DecodeQP.ConvertHexContent(decodedAttachment);
  443. //else if(IsEncoding("8bit"))
  444. //decodedAttachment=decodedAttachment;
  445. else
  446. decodedAttachment=Utility.deCodeB64s(Utility.RemoveNonB64(decodedAttachment));
  447. }
  448. }
  449. else if(_contentCharset!=null)
  450. decodedAttachment=Utility.Change(_rawAttachment,_contentCharset);//Encoding.Default.GetString(Encoding.GetEncoding(_contentCharset).GetBytes(_rawAttachment));
  451. else
  452. decodedAttachment=_rawAttachment;
  453. }
  454. catch
  455. {
  456. decodedAttachment=_rawAttachment;
  457. }
  458. return decodedAttachment;
  459. }
  460. /// <summary>
  461. /// decode attachment to be a message object
  462. /// </summary>
  463. /// <returns>message</returns>
  464. public Message DecodeAsMessage()
  465. {
  466. bool blnRet=false;
  467. return new Message(ref blnRet,"",false ,_rawAttachment,false);
  468. }
  469. /// <summary>
  470. /// Decode the attachment to bytes
  471. /// </summary>
  472. /// <returns>Decoded attachment bytes</returns>
  473. public byte[] DecodedAsBytes()
  474. {
  475. if(_rawAttachment==null)
  476. return null;
  477. if(_contentFileName!="")
  478. {
  479. byte []decodedBytes=null;
  480. if(_contentType!=null && _contentType.ToLower()=="message/rfc822".ToLower())
  481. decodedBytes=Encoding.Default.GetBytes(Utility.DecodeText(_rawAttachment));
  482. else if(_contentTransferEncoding!=null)
  483. {
  484. string bytContent=_rawAttachment;
  485. if(!IsEncoding("7bit"))
  486. {
  487. if(IsEncoding("8bit")&&_contentCharset!=null&_contentCharset!="")
  488. bytContent=Utility.Change(bytContent,_contentCharset);
  489. if(Utility.IsQuotedPrintable(_contentTransferEncoding))
  490. decodedBytes=Encoding.Default.GetBytes(DecodeQP.ConvertHexContent(bytContent));
  491. else if(IsEncoding("8bit"))
  492. decodedBytes=Encoding.Default.GetBytes(bytContent);
  493. else
  494. decodedBytes=Convert.FromBase64String(Utility.RemoveNonB64(bytContent));
  495. }
  496. else
  497. decodedBytes=Encoding.Default.GetBytes(bytContent);
  498. }
  499. else if(_contentCharset!=null)
  500. decodedBytes=Encoding.Default.GetBytes(Utility.Change(_rawAttachment,_contentCharset));//Encoding.Default.GetString(Encoding.GetEncoding(_contentCharset).GetBytes(_rawAttachment));
  501. else
  502. decodedBytes=Encoding.Default.GetBytes(_rawAttachment);
  503. return decodedBytes;
  504. }
  505. else
  506. {
  507. return null;
  508. }
  509. }
  510. public int CompareTo(object attachment)
  511. {
  512. return (this.RawAttachment.CompareTo(((Attachment)(attachment)).RawAttachment));
  513. }
  514. }
  515. }