📄 pop3mimeclient.cs
字号:
case "content-disposition":
message.ContentDisposition = new ContentDisposition(headerLineContent);
break;
case "content-id":
message.ContentId = headerLineContent;
break;
case "content-transfer-encoding":
message.TransferType = headerLineContent;
message.ContentTransferEncoding = ConvertToTransferEncoding(headerLineContent);
break;
case "content-type":
message.SetContentTypeFields(headerLineContent);
break;
case "date":
message.DeliveryDate = ConvertToDateTime(headerLineContent);
break;
case "delivered-to":
message.DeliveredTo = ConvertToMailAddress(headerLineContent);
break;
case "from":
MailAddress address = ConvertToMailAddress(headerLineContent);
if (address!=null) {
message.From = address;
}
break;
case "message-id":
message.MessageId = headerLineContent;
break;
case "mime-version":
message.MimeVersion = headerLineContent;
//message.BodyEncoding = new Encoding();
break;
case "sender":
message.Sender = ConvertToMailAddress(headerLineContent);
break;
case "subject":
message.Subject = headerLineContent;
break;
case "received":
//throw mail routing information away
break;
case "reply-to":
message.ReplyTo = ConvertToMailAddress(headerLineContent);
break;
case "return-path":
message.ReturnPath = ConvertToMailAddress(headerLineContent);
break;
case "to":
AddMailAddresses(headerLineContent, message.To);
break;
default:
message.UnknowHeaderlines.Add(headerField);
if (isCollectUnknowHeaderLines) {
AllUnknowHeaderLines.Add(headerField);
}
break;
}
}
}
/// <summary>
/// find individual addresses in the string and add it to address collection
/// </summary>
/// <param name="Addresses">string with possibly several email addresses</param>
/// <param name="AddressCollection">parsed addresses</param>
private void AddMailAddresses(string Addresses, MailAddressCollection AddressCollection) {
MailAddress adr;
try {
string[] AddressSplit = Addresses.Split(',');
foreach (string adrString in AddressSplit) {
adr = ConvertToMailAddress(adrString);
if (adr!=null) {
AddressCollection.Add(adr);
}
}
} catch {
System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
}
}
/// <summary>
/// Tries to convert a string into an email address
/// </summary>
public MailAddress ConvertToMailAddress(string address) {
address = address.Trim();
if (address=="<>") {
//empty email address, not recognised a such by .NET
return null;
}
try {
return new MailAddress(address);
} catch {
callGetEmailWarning("address format not recognised: '" + address.Trim() + "'");
}
return null;
}
private IFormatProvider culture = new CultureInfo("en-US", true);
/// <summary>
/// Tries to convert string to date, following POP3 rules
/// If there is a run time error, the smallest possible date is returned
/// <example>Wed, 04 Jan 2006 07:58:08 -0800</example>
/// </summary>
public DateTime ConvertToDateTime(string date) {
DateTime ReturnDateTime;
try {
//sample; 'Wed, 04 Jan 2006 07:58:08 -0800 (PST)'
//remove day of the week before ','
//remove date zone in '()', -800 indicates the zone already
//remove day of week
string cleanDateTime = date;
string[] DateSplit = cleanDateTime.Split(CommaChars, 2);
if (DateSplit.Length>1) {
cleanDateTime = DateSplit[1];
}
//remove time zone (PST)
DateSplit = cleanDateTime.Split(BracketChars);
if (DateSplit.Length>1) {
cleanDateTime = DateSplit[0];
}
//convert to DateTime
if (!DateTime.TryParse(
cleanDateTime,
culture,
DateTimeStyles.AdjustToUniversal|DateTimeStyles.AllowWhiteSpaces,
out ReturnDateTime)) {
//try just to convert the date
int DateLength = cleanDateTime.IndexOf(':') - 3;
cleanDateTime = cleanDateTime.Substring(0, DateLength);
if (DateTime.TryParse(
cleanDateTime,
culture,
DateTimeStyles.AdjustToUniversal|DateTimeStyles.AllowWhiteSpaces,
out ReturnDateTime)) {
callGetEmailWarning("got only date, time format not recognised: '" + date + "'");
} else {
callGetEmailWarning("date format not recognised: '" + date + "'");
System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
return DateTime.MinValue;
}
}
} catch {
callGetEmailWarning("date format not recognised: '" + date + "'");
return DateTime.MinValue;
}
return ReturnDateTime;
}
/// <summary>
/// converts TransferEncoding as defined in the RFC into a .NET TransferEncoding
///
/// .NET doesn't know the type "bit8". It is translated here into "bit7", which
/// requires the same kind of processing (none).
/// </summary>
/// <param name="TransferEncodingString"></param>
/// <returns></returns>
private TransferEncoding ConvertToTransferEncoding(string TransferEncodingString) {
// here, "bit8" is marked as "bit7" (i.e. no transfer encoding needed)
// "binary" is illegal in SMTP
// something like "7bit" / "8bit" / "binary" / "quoted-printable" / "base64"
switch (TransferEncodingString.Trim().ToLowerInvariant()) {
case "7bit":
case "8bit":
return TransferEncoding.SevenBit;
case "quoted-printable":
return TransferEncoding.QuotedPrintable;
case "base64":
return TransferEncoding.Base64;
case "binary":
throw new Pop3Exception("SMPT does not support binary transfer encoding");
default:
callGetEmailWarning("not supported content-transfer-encoding: " + TransferEncodingString);
return TransferEncoding.Unknown;
}
}
/// <summary>
/// Copies the content found for the MIME entity to the RxMailMessage body and creates
/// a stream which can be used to create attachements, alternative views, ...
/// </summary>
private void saveMessageBody(RxMailMessage message, string contentString) {
message.Body = contentString;
MemoryStream bodyStream = new MemoryStream();
StreamWriter bodyStreamWriter = new StreamWriter(bodyStream);
bodyStreamWriter.Write(contentString);
int l = contentString.Length;
bodyStreamWriter.Flush();
message.ContentStream = bodyStream;
}
/// <summary>
/// each attachement is stored in its own MIME entity and read into this entity's
/// ContentStream. SaveAttachment creates an attachment out of the ContentStream
/// and attaches it to the parent MIME entity.
/// </summary>
private void SaveAttachment(RxMailMessage message) {
if (message.Parent==null) {
System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
} else {
Attachment thisAttachment = new Attachment(message.ContentStream, message.ContentType);
//no idea why ContentDisposition is read only. on the other hand, it is anyway redundant
if (message.ContentDisposition!=null) {
ContentDisposition messageContentDisposition = message.ContentDisposition;
ContentDisposition AttachmentContentDisposition = thisAttachment.ContentDisposition;
if (messageContentDisposition.CreationDate>DateTime.MinValue) {
AttachmentContentDisposition.CreationDate = messageContentDisposition.CreationDate;
}
AttachmentContentDisposition.DispositionType = messageContentDisposition.DispositionType;
AttachmentContentDisposition.FileName = messageContentDisposition.FileName;
AttachmentContentDisposition.Inline = messageContentDisposition.Inline;
if (messageContentDisposition.ModificationDate>DateTime.MinValue) {
AttachmentContentDisposition.ModificationDate = messageContentDisposition.ModificationDate;
}
AttachmentContentDisposition.Parameters.Clear();
if (messageContentDisposition.ReadDate>DateTime.MinValue) {
AttachmentContentDisposition.ReadDate = messageContentDisposition.ReadDate;
}
if (messageContentDisposition.Size>0) {
AttachmentContentDisposition.Size = messageContentDisposition.Size;
}
foreach (string key in messageContentDisposition.Parameters.Keys) {
AttachmentContentDisposition.Parameters.Add(key, messageContentDisposition.Parameters[key]);
}
}
//get ContentId
string contentIdString = message.ContentId;
if (contentIdString!=null) {
thisAttachment.ContentId = RemoveBrackets(contentIdString);
}
thisAttachment.TransferEncoding = message.ContentTransferEncoding;
message.Parent.Attachments.Add(thisAttachment);
}
}
/// <summary>
/// removes leading '<' and trailing '>' if both exist
/// </summary>
/// <param name="parameterString"></param>
/// <returns></returns>
private string RemoveBrackets(string parameterString) {
if (parameterString==null) {
return null;
}
if (parameterString.Length<1 ||
parameterString[0]!='<' ||
parameterString[parameterString.Length-1]!='>') {
System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
return parameterString;
} else {
return parameterString.Substring(1, parameterString.Length-2);
}
}
private MimeEntityReturnCode ProcessDelimitedBody(
RxMailMessage message,
string BoundaryStart,
string parentBoundaryStart,
string parentBoundaryEnd)
{
string response;
if (BoundaryStart.Trim()==parentBoundaryStart.Trim()) {
//Mime entity boundaries have to be unique
callGetEmailWarning("new boundary same as parent boundary: '{0}'", parentBoundaryStart);
//empty this message
while (readMultiLine(out response)) { }
return MimeEntityReturnCode.problem;
}
//
MimeEntityReturnCode ReturnCode;
do {
//empty StringBuilder
MimeEntitySB.Length=0;
RxMailMessage ChildPart = message.CreateChildEntity();
//recursively call MIME part processing
ReturnCode = ProcessMimeEntity(ChildPart, BoundaryStart);
if (ReturnCode==MimeEntityReturnCode.problem) {
//it seems the received email doesn't follow the MIME specification. Stop here
return MimeEntityReturnCode.problem;
}
//add the newly found child MIME part to the parent
AddChildPartsToParent(ChildPart, message);
} while (ReturnCode!= MimeEntityReturnCode.parentBoundaryEndFound);
//disregard all future lines until parent boundary is found or end of complete message
MimeEntityReturnCode boundaryMimeReturnCode;
bool hasParentBoundary = parentBoundaryStart.Length>0;
while (readMultiLine(out response)) {
if (hasParentBoundary && parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, out boundaryMimeReturnCode)) {
return boundaryMimeReturnCode;
}
}
return MimeEntityReturnCode.bodyComplete;
}
/// <summary>
/// Add all attachments and alternative views from child to the parent
/// </summary>
private void AddChildPartsToParent(RxMailMessage child, RxMailMessage parent) {
//add the child itself to the parent
parent.Entities.Add(child);
//add the alternative views of the child to the parent
if (child.AlternateViews!=null) {
foreach (AlternateView childView in child.AlternateViews) {
parent.AlternateViews.Add(childView);
}
}
//add the body of the child as alternative view to parent
//this should be the last view attached here, because the POP 3 MIME client
//is supposed to display the last alternative view
if (child.MediaMainType=="text" && child.ContentStream!=null) {
AlternateView thisAlternateView = new AlternateView(child.ContentStream);
thisAlternateView.ContentId = RemoveBrackets(child.ContentId);
thisAlternateView.ContentType = child.ContentType;
thisAlternateView.TransferEncoding = child.ContentTransferEncoding;
parent.AlternateViews.Add(thisAlternateView);
}
//add the attachments of the child to the parent
if (child.Attachments!=null) {
foreach (Attachment childAttachment in child.Attachments) {
parent.Attachments.Add(childAttachment);
}
}
}
/// <summary>
/// Converts byte array to string, using decoding as requested
/// </summary>
public string DecodeByteArryToString(byte[] ByteArry, Encoding ByteEncoding) {
if (ByteArry==null) {
//no bytes to convert
return null;
}
Decoder byteArryDecoder;
if (ByteEncoding==null){
//no encoding indicated. Let's try UTF7
System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
byteArryDecoder = Encoding.UTF7.GetDecoder();
}else{
byteArryDecoder = ByteEncoding.GetDecoder();
}
int charCount = byteArryDecoder.GetCharCount(ByteArry, 0, ByteArry.Length);
char[] bodyChars = new Char[charCount];
int charsDecodedCount = byteArryDecoder.GetChars(ByteArry, 0, ByteArry.Length, bodyChars, 0);
//convert char[] to string
return new string(bodyChars);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -