// ---------------------- LoadEmail --------------------------- private void LoadEmail(SocketExchange InEx, Int64 InMailDropPosition) { // tell the server we want to read the message. InEx.Send("retr " + InMailDropPosition + PopConstants.CrLf); InEx.ExpectedResponseCodes = new ExpectedResponseCodes(PopConstants.Ok, PopConstants.Error); InEx.SendReceive("retr " + InMailDropPosition + PopConstants.CrLf); InEx.ThrowIfUnexpectedResponse( ); // -ERR response. no such message number. if (InEx.ResponseCode == PopConstants.Error) { } else { // for now, receive SSL link messages in the same thread. if (InEx.ConnectedSecureSocket != null) { StringBuilder mail = null; mail = ReceiveMessage_SameThread(InEx); InEx.LoadResponseMessage(mail.ToString( )); } // receive in a background thread. else { StartReceive(InEx); InEx.LoadResponseMessage(mSockThreadState.sb.ToString( )); } } // parse email ... mParts = MimeCommon.MessagePartSplitter(InEx.ResponseMessage); string[] lines = MimeCommon.MessageLineSplitter(InEx.ResponseMessage); mAttachments = null; MimeAttachment attach = (MimeAttachment)Attachments.FirstAttachment( ).Current; if (attach != null) { attach.SaveAs("c:\\apress\\attachment.txt"); } // if (1 == 2) // DumpHeader(InEx, InMailDropPosition); for (int ix = 0; ix < lines.Length; ++ix) { InEx.Logger.AddMessage(NetworkRole.Server, lines[ix]); } ParseEmail(lines); // remove reading pop3State ... mSockThreadState = null; }
/// <summary> /// Build list of attachments in the mime message. /// </summary> /// <param name="InPartList"></param> /// <returns></returns> public MimeAttachmentList BuildList(MimeMessagePartList InPartList) { // clear the list Clear( ); AcEnumerator it = InPartList.BeginParts( ); for (it = InPartList.FirstPart( ); it.Current != null; it.MoveNext( )) { MimeMessagePart part = (MimeMessagePart)it.Current; PartProperty.ContentDisposition disp = part.Properties.ContentDisposition; if ((disp != null) && (disp.Disposition == "attachment")) { AddNewAttachment(part); } } return(this); }
// -------------------------- MessagePartSplitter ----------------------- // input is an array holding the unfolded lines of the message. // Build and return a list of MimeMessagePart objects. Each part object holds the // lines of a part of the message. // ( a part is either the header part or the boundary string delimited content parts. public static InMail.MimeMessagePartList MessagePartSplitter(string InStream) { InMail.MimeMessagePartList parts = new InMail.MimeMessagePartList( ); bool currentlyBetweenParts = false; StringStack bdryStack = new StringStack( ); int Ex = -1; string line = null; MimeMessagePart.PartInProgress pip = new MimeMessagePart.PartInProgress(MimePartCode.Top); while (true) { // advance in string. int lineBx = Ex + 1; if (lineBx >= InStream.Length) { break; } // the next line in the stream. recognize folds depending on if currently within // a part header or within the message lines of the part ( no folding there ) if (pip.CurrentlyAmoungPropertyLines == true) { IntStringPair rv = ScanEndUnfoldedLine(InStream, lineBx); Ex = rv.a; line = rv.b; } else { IntStringPair rv = ScanEndLine(InStream, lineBx); Ex = rv.a; line = rv.b; } // calc what kind of a line in the mime document we have here. MimeLineCode lc = MimeParser.CalcLineCode(line, bdryStack.GetTop( )); if ((lc == MimeLineCode.Property) && (pip.CurrentlyAmoungMessageLines == true)) { lc = MimeLineCode.Text; } switch (lc) { case MimeLineCode.Property: { StringPair propPair = MimeParser.SplitPropertyLine(line); // the content-type property. Could have an boundary="xxxxx" element. // Boundary strings in a mime document have scope. That is, within one // boundary ( section ) of the document, there can be sub boundaries // ( sub sections ) if (propPair.a.ToLower( ) == "content-type") { PartProperty.ContentType ct = MimeParser.ParseContentType(propPair.b); if ((ct.Boundary != null) && (ct.Boundary != "")) { bdryStack.Push(ct.Boundary); } } pip.AddLine(lineBx, line); break; } // part boundary line. load the lines of the current part and reset the line // counter of this new part. case MimeLineCode.PartBdry: if (pip.HasLines == true) { parts.AddNewPart(InStream, pip); } pip = new MimeMessagePart.PartInProgress(MimePartCode.Content); currentlyBetweenParts = false; break; case MimeLineCode.PartEndBdry: if (pip.HasLines == true) { parts.AddNewPart(InStream, pip); } pip = new MimeMessagePart.PartInProgress(MimePartCode.Content); if (bdryStack.IsNotEmpty) { bdryStack.Pop( ); } currentlyBetweenParts = true; break; // we have a line which is not a property line, not a boundary line. default: { // just starting out. discard the "+OK" response sent by the server immed // before the start of the message. if ((pip.PartCode == MimePartCode.Top) && (pip.PartIsJustStarting == true) && (line.Length >= 3) && (line.Substring(0, 3) == "+OK")) { } // currently handling property lines. else if (pip.CurrentlyAmoungPropertyLines == true) { // a blank line switches from property lines to message lines. if (line.Length == 0) { pip.CurrentlyAmoungPropertyLines = false; pip.CurrentlyAmoungMessageLines = true; } // what is this text line doing amoung the property lines ?? // for now, just ignore it. else { } } else if (currentlyBetweenParts == false) { pip.AddLine(lineBx, line); } break; } } } // load the lines of the final in progress part. if (pip.HasLines == true) { parts.AddNewPart(InStream, pip); } return(parts); }
// -------------------------- MessagePartSplitter ----------------------- // input is an array holding the unfolded lines of the message. // Build and return a list of MimeMessagePart objects. Each part object holds the // lines of a part of the message. // ( a part is either the header part or the boundary string delimited content parts. public static InMail.MimeMessagePartList MessagePartSplitter(string[] InLines) { InMail.MimeMessagePartList parts = new InMail.MimeMessagePartList( ); int curPartBx = -1; int curPartCx = 0; MimePartCode curPartCode = MimePartCode.Top; bool currentlyBetweenParts = false; bool partIsJustStarting = true; StringStack bdryStack = new StringStack( ); for (int Ix = 0; Ix < InLines.Length; ++Ix) { string line = InLines[Ix]; MimeLineCode lc = MimeParser.CalcLineCode(line, bdryStack.GetTop( )); switch (lc) { case MimeLineCode.Property: { StringPair propPair = MimeParser.SplitPropertyLine(line); // the content-type property. Could have an boundary="xxxxx" element. // Boundary strings in a mime document have scope. That is, within one // boundary ( section ) of the document, there can be sub boundaries // ( sub sections ) if (propPair.a.ToLower( ) == "content-type") { PartProperty.ContentType ct = MimeParser.ParseContentType(propPair.b); if ((ct.Boundary != null) && (ct.Boundary != "")) { bdryStack.Push(ct.Boundary); } } break; } // part boundary line. load the lines of the current part and reset the line // counter of this new part. case MimeLineCode.PartBdry: if (curPartBx != -1) { parts.AddNewPart(curPartCode) .LoadLines(InLines, curPartBx, curPartCx); } curPartCx = 0; curPartBx = -1; curPartCode = MimePartCode.Content; currentlyBetweenParts = false; partIsJustStarting = true; break; case MimeLineCode.PartEndBdry: if (curPartBx != -1) { parts.AddNewPart(curPartCode) .LoadLines(InLines, curPartBx, curPartCx); } curPartCx = 0; curPartBx = -1; if (bdryStack.IsNotEmpty) { bdryStack.Pop( ); } currentlyBetweenParts = true; break; default: break; } // add to range of lines in the current part. if ((currentlyBetweenParts == false) && (lc != MimeLineCode.PartBdry)) { if ((partIsJustStarting == true) && (line == "")) { } else { ++curPartCx; if (curPartBx == -1) { curPartBx = Ix; } } partIsJustStarting = false; } } // load the lines of the final in progress part. if (curPartBx != -1) { parts.AddNewPart(curPartCode) .LoadLines(InLines, curPartBx, curPartCx); } return(parts); }
// ---------------------- LoadEmail --------------------------- private void LoadEmail(SocketExchange InEx, System.Int64 InMailDropPosition) { // tell the server we want to read the message. InEx.Send("retr " + InMailDropPosition + PopConstants.CrLf); InEx.ExpectedResponseCodes = new ExpectedResponseCodes(PopConstants.Ok, PopConstants.Error); InEx.SendReceive("retr " + InMailDropPosition + PopConstants.CrLf); InEx.ThrowIfUnexpectedResponse( ); // -ERR response. no such message number. if (InEx.ResponseCode == PopConstants.Error) { } else { // for now, receive SSL link messages in the same thread. if (InEx.ConnectedSecureSocket != null) { StringBuilder mail = null; mail = ReceiveMessage_SameThread(InEx); InEx.LoadResponseMessage(mail.ToString( )); } // receive in a background thread. else { StartReceive(InEx); InEx.LoadResponseMessage(mSockThreadState.sb.ToString( )); } } // parse email ... mParts = MimeCommon.MessagePartSplitter(InEx.ResponseMessage); string[] lines = MimeCommon.MessageLineSplitter(InEx.ResponseMessage); if (1 == 2) { mParts = MimeCommon.MessagePartSplitter(lines); } mAttachments = null; MimeAttachment attach = (MimeAttachment)Attachments.FirstAttachment( ).Current; if (attach != null) { attach.SaveAs("c:\\apress\\attachment.txt"); } if (1 == 2) { // dump the header lines of the top part. InEx.Logger.AddMessage(NetworkRole.Server, "--- start header line dump ---"); MimeTopPart topPart = ( MimeTopPart )mParts.GetTopPart( ); for (int Ix = 0; Ix < topPart.PropertyLines.Length; ++Ix) { InEx.Logger.AddMessage(NetworkRole.Server, topPart.PropertyLines[Ix]); } for (int Ix = 0; Ix < topPart.MessageLines.Length; ++Ix) { InEx.Logger.AddMessage(NetworkRole.Server, topPart.MessageLines[Ix]); } InEx.Logger.AddMessage(NetworkRole.Server, "--- end of header line dump ---"); // dump the lines of each part. foreach (MimeMessagePart part in mParts) { InEx.Logger.AddMessage(NetworkRole.Server, "** message part **"); InEx.Logger.AddMessage(NetworkRole.Server, "** property lines **"); foreach (string line in part.PropertyLines) { InEx.Logger.AddMessage(NetworkRole.Server, line); } InEx.Logger.AddMessage(NetworkRole.Server, "** message lines **"); foreach (string line in part.MessageLines) { InEx.Logger.AddMessage(NetworkRole.Server, line); } } InEx.Logger.AddMessage(NetworkRole.Server, "---- end of parts ----------"); } for (int ix = 0; ix < lines.Length; ++ix) { InEx.Logger.AddMessage(NetworkRole.Server, lines[ix]); } ParseEmail(lines); // remove reading pop3State ... mSockThreadState = null; }