示例#1
0
        public bool ProcessEmbedded(ref RxMailMessage Message)
        {
            //raw email tracing
            if (isGetRawEmail)
            {
                isTraceRawEmail = true;
                if (RawEmailSB == null)
                {
                    RawEmailSB = new StringBuilder(100000);
                }
                else
                {
                    RawEmailSB.Length = 0;
                }
            }

            //convert received email into RxMailMessage
            MimeEntityReturnCode MessageMimeReturnCode = ProcessMimeEntity(Message, "");

            if (isGetRawEmail)
            {
                //add raw email version to message
                Message.RawContent = RawEmailSB.ToString();
                isTraceRawEmail    = false;
            }

            if (MessageMimeReturnCode == MimeEntityReturnCode.bodyComplete || MessageMimeReturnCode == MimeEntityReturnCode.parentBoundaryEndFound)
            {
                TraceFrom("email with {0} body chars received", Message.Body.Length);
                return(true);
            }
            return(false);
        }
示例#2
0
        public List <string> UnknowHeaderlines; //


        // Constructors
        // ------------
        /// <summary>
        /// default constructor
        /// </summary>
        public RxMailMessage()
        {
            //for the moment, we assume to be at the top
            //should this entity become a child, TopParent will be overwritten
            TopParent         = this;
            Entities          = new List <RxMailMessage>();
            UnknowHeaderlines = new List <string>();
        }
示例#3
0
        /// <summary>
        /// Creates an empty child MIME entity from the parent MIME entity.
        ///
        /// An email can consist of several MIME entities. A entity has the same structure
        /// like an email, that is header and body. The child inherits few properties
        /// from the parent as default value.
        /// </summary>
        public RxMailMessage CreateChildEntity()
        {
            RxMailMessage child = new RxMailMessage();

            child.Parent    = this;
            child.TopParent = this.TopParent;
            child.ContentTransferEncoding = this.ContentTransferEncoding;
            return(child);
        }
示例#4
0
        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;

            // 01/20/2008 Paul.  We don't want to dramatically change the logic, so only return EOF if this is a memory stream.
            while (!IsEmbeddedEOF() && readMultiLine(out response))
            {
                if (hasParentBoundary && parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, out boundaryMimeReturnCode))
                {
                    return(boundaryMimeReturnCode);
                }
            }

            return(MimeEntityReturnCode.bodyComplete);
        }
示例#5
0
        private void decodeEntity(RxMailMessage entity)
        {
            AppendLine("From  : {0}", entity.From);
            AppendLine("Sender: {0}", entity.Sender);
            AppendLine("To    : {0}", entity.To);
            AppendLine("CC    : {0}", entity.CC);
            AppendLine("ReplyT: {0}", entity.ReplyTo);
            AppendLine("Sub   : {0}", entity.Subject);
            AppendLine("S-Enco: {0}", entity.SubjectEncoding);
            if (entity.DeliveryDate > DateTime.MinValue)
            {
                AppendLine("Date  : {0}", entity.DeliveryDate);
            }
            if (entity.Priority != MailPriority.Normal)
            {
                AppendLine("Priori: {0}", entity.Priority);
            }
            if (entity.Body.Length > 0)
            {
                AppendLine("Body  : {0} byte(s)", entity.Body.Length);
                AppendLine("B-Enco: {0}", entity.BodyEncoding);
            }
            else
            {
                if (entity.BodyEncoding != Encoding.ASCII)
                {
                    AppendLine("B-Enco: {0}", entity.BodyEncoding);
                }
            }
            AppendLine("T-Type: {0}", entity.TransferType);
            AppendLine("C-Type: {0}", entity.ContentType);
            AppendLine("C-Desc: {0}", entity.ContentDescription);
            AppendLine("C-Disp: {0}", entity.ContentDisposition);
            AppendLine("C-Id  : {0}", entity.ContentId);
            AppendLine("M-ID  : {0}", entity.MessageId);
            AppendLine("Mime  : Version {0}", entity.MimeVersion);
            if (entity.ContentStream != null)
            {
                AppendLine("Stream: Length {0}", entity.ContentStream.Length);
            }

            //decode all shild MIME entities
            foreach (RxMailMessage child in entity.Entities)
            {
                mailStructure.AppendLine("------------------------------------");
                decodeEntity(child);
            }

            if (entity.ContentType != null && entity.ContentType.MediaType != null && entity.ContentType.MediaType.StartsWith("multipart"))
            {
                AppendLine("End {0}", entity.ContentType.ToString());
            }
        }
        /// <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>
        /// Gets 1 email from POP3 server and processes it.
        /// </summary>
        /// <param name="MessageNo">Email Id to be fetched from POP3 server</param>
        /// <param name="Message">decoded email</param>
        /// <returns>false: no email received or email not properly formatted</returns>
        public bool GetEmail(int MessageNo, out RxMailMessage Message)
        {
            Message = null;

            //request email, send RETRieve command to POP3 server
            if (!SendRetrCommand(MessageNo))
            {
                return(false);
            }

            //prepare message, set defaults as specified in RFC 2046
            //although they get normally overwritten, we have to make sure there are at least defaults
            Message = new RxMailMessage();
            Message.ContentTransferEncoding = TransferEncoding.SevenBit;
            Message.TransferType            = "7bit";
            this.messageNo = MessageNo;

            //raw email tracing
            if (isGetRawEmail)
            {
                isTraceRawEmail = true;
                if (RawEmailSB == null)
                {
                    RawEmailSB = new StringBuilder(100000);
                }
                else
                {
                    RawEmailSB.Length = 0;
                }
            }

            //convert received email into RxMailMessage
            MimeEntityReturnCode MessageMimeReturnCode = ProcessMimeEntity(Message, "");

            if (isGetRawEmail)
            {
                //add raw email version to message
                Message.RawContent = RawEmailSB.ToString();
                isTraceRawEmail    = false;
            }

            if (MessageMimeReturnCode == MimeEntityReturnCode.bodyComplete ||
                MessageMimeReturnCode == MimeEntityReturnCode.parentBoundaryEndFound)
            {
                TraceFrom("email with {0} body chars received", Message.Body.Length);
                return(true);
            }
            return(false);
        }
        /// <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 &&
                child.Parent.ContentType != null && child.Parent.ContentType.MediaType.ToLowerInvariant() == "multipart/alternative")
            {
                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);
                }
            }
        }
示例#10
0
 /// <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;
 }
示例#11
0
        /// <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);
              }
        }
示例#12
0
        /// <summary>
        /// Process a MIME entity
        /// 
        /// A MIME entity consists of header and body.
        /// Separator lines in the body might mark children MIME entities
        /// </summary>
        private MimeEntityReturnCode ProcessMimeEntity(RxMailMessage message, string parentBoundaryStart)
        {
            bool hasParentBoundary = parentBoundaryStart.Length>0;
              string parentBoundaryEnd = parentBoundaryStart + "--";
              MimeEntityReturnCode boundaryMimeReturnCode;

              //some format fields are inherited from parent, only the default for
              //ContentType needs to be set here, otherwise the boundary parameter would be
              //inherited too !
              message.SetContentTypeFields("text/plain; charset=us-ascii");

              //get header
              //----------
              string completeHeaderField = null;     //consists of one start line and possibly several continuation lines
              string response;

              // read header lines until empty line is found (end of header)
              while (true) {
            if (!readMultiLine(out response)) {
              //POP3 server has not send any more lines
              callGetEmailWarning("incomplete MIME entity header received");
              //empty this message
              while (readMultiLine(out response)) { }
              System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
              return MimeEntityReturnCode.problem;
            }

            if (response.Length<1) {
              //empty line found => end of header
              if (completeHeaderField!=null) {
            ProcessHeaderField(message, completeHeaderField);
              }else{
            //there was only an empty header.
              }
              break;
            }

            //check if there is a parent boundary in the header (wrong format!)
            if (hasParentBoundary && parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, out boundaryMimeReturnCode)){
              callGetEmailWarning("MIME entity header  prematurely ended by parent boundary");
              //empty this message
              while (readMultiLine(out response)) { }
              System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
              return boundaryMimeReturnCode;
            }
            //read header field
            //one header field can extend over one start line and multiple continuation lines
            //a continuation line starts with at least 1 blank (' ') or tab
            if (response[0]==' ' || response[0]=='\t') {
              //continuation line found.
              if (completeHeaderField==null){
            callGetEmailWarning("Email header starts with continuation line");
            //empty this message
            while (readMultiLine(out response)) { }
            System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
            return MimeEntityReturnCode.problem;
              }else {
            // append space, if needed, and continuation line
            if (completeHeaderField[completeHeaderField.Length-1]!=' ') {
              //previous line did not end with a whitespace
              //need to replace CRLF with a ' '
              completeHeaderField += ' ' + response.TrimStart(WhiteSpaceChars);
            } else {
              //previous line did end with a whitespace
              completeHeaderField += response.TrimStart(WhiteSpaceChars);
            }
              }

            } else {
              //a new header field line found
              if (completeHeaderField==null) {
            //very first field, just copy it and then check for continuation lines
            completeHeaderField = response;
              } else {
            //new header line found
            ProcessHeaderField(message, completeHeaderField);

            //save the beginning of the next line
            completeHeaderField = response;
              }
            }
              }//end while read header lines

              //process body
              //------------

              MimeEntitySB.Length=0;  //empty StringBuilder. For speed reasons, reuse StringBuilder defined as member of class
              string BoundaryDelimiterLineStart = null;
              bool isBoundaryDefined = false;
              if (message.ContentType.Boundary!=null) {
            isBoundaryDefined = true;
            BoundaryDelimiterLineStart = "--" + message.ContentType.Boundary;
              }
              //prepare return code for the case there is no boundary in the body
              boundaryMimeReturnCode = MimeEntityReturnCode.bodyComplete;

              //read body lines
              while (readMultiLine(out response)) {
            //check if there is a boundary line from this entity itself in the body
            if (isBoundaryDefined && response.TrimEnd()==BoundaryDelimiterLineStart) {
              //boundary line found.
              //stop the processing here and start a delimited body processing
              return ProcessDelimitedBody(message, BoundaryDelimiterLineStart, parentBoundaryStart, parentBoundaryEnd);
            }

            //check if there is a parent boundary in the body
            if (hasParentBoundary &&
              parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, out boundaryMimeReturnCode)) {
              //a parent boundary is found. Decode the content of the body received so far, then end this MIME entity
              //note that boundaryMimeReturnCode is set here, but used in the return statement
              break;
            }

            //process next line
            MimeEntitySB.Append(response + CRLF);
              }

              //a complete MIME body read
              //convert received US ASCII characters to .NET string (Unicode)
              string TransferEncodedMessage = MimeEntitySB.ToString();
              bool isAttachmentSaved = false;
              switch (message.ContentTransferEncoding) {
              case TransferEncoding.SevenBit:
            //nothing to do
            saveMessageBody(message, TransferEncodedMessage);
            break;

              case TransferEncoding.Base64:
            //convert base 64 -> byte[]
            byte[] bodyBytes = System.Convert.FromBase64String(TransferEncodedMessage);
            message.ContentStream = new MemoryStream(bodyBytes, false);

            if (message.MediaMainType=="text") {
              //convert byte[] -> string
              message.Body = DecodeByteArryToString(bodyBytes, message.BodyEncoding);

            } else if (message.MediaMainType=="image" || message.MediaMainType=="application") {
              SaveAttachment(message);
              isAttachmentSaved = true;
            }
            break;

              case TransferEncoding.QuotedPrintable:
            saveMessageBody(message, QuotedPrintable.Decode(TransferEncodedMessage));
            break;

              default:
            saveMessageBody(message, TransferEncodedMessage);
            //no need to raise a warning here, the warning was done when analising the header
            break;
              }

              if (message.ContentDisposition!=null && message.ContentDisposition.DispositionType.ToLowerInvariant()=="attachment" && !isAttachmentSaved) {
            SaveAttachment(message);
            isAttachmentSaved = true;
              }
              return boundaryMimeReturnCode;
        }
示例#13
0
        /// <summary>
        /// Convert one MIME header field and update message accordingly
        /// </summary>
        private void ProcessHeaderField(RxMailMessage message, string headerField)
        {
            string headerLineType;
              string headerLineContent;
              int separatorPosition = headerField.IndexOf(':');
              if (separatorPosition<1) {
            // header field type not found, skip this line
            callGetEmailWarning("character ':' missing in header format field: '{0}'", headerField);
              } else {

            //process header field type
            headerLineType = headerField.Substring(0, separatorPosition).ToLowerInvariant();
            headerLineContent = headerField.Substring(separatorPosition+1).Trim(WhiteSpaceChars);
            if (headerLineType==""|| headerLineContent=="") {
              //1 of the 2 parts missing, drop the line
              return;
            }
            // add header line to headers
            message.Headers.Add(headerLineType, headerLineContent);

            //interpret if possible
            switch (headerLineType) {
              case "bcc":
            AddMailAddresses(headerLineContent, message.Bcc);
            break;
              case "cc":
            AddMailAddresses(headerLineContent, message.CC);
            break;
              case "content-description":
            message.ContentDescription = headerLineContent;
            break;
              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;
            }
              }
        }
示例#14
0
        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;
        }
示例#15
0
        /// <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 &&
            child.Parent.ContentType!=null && child.Parent.ContentType.MediaType.ToLowerInvariant()=="multipart/alternative")
              {
            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);
            }
              }
        }
示例#16
0
        /// <summary>
        /// Gets 1 email from POP3 server and processes it.
        /// </summary>
        /// <param name="MessageNo">Email Id to be fetched from POP3 server</param>
        /// <param name="Message">decoded email</param>
        /// <returns>false: no email received or email not properly formatted</returns>
        public bool GetEmail(int MessageNo, out RxMailMessage Message)
        {
            Message = null;

              //request email, send RETRieve command to POP3 server
              if (!SendRetrCommand(MessageNo)) {
            return false;
              }

              //prepare message, set defaults as specified in RFC 2046
              //although they get normally overwritten, we have to make sure there are at least defaults
              Message = new RxMailMessage();
              Message.ContentTransferEncoding = TransferEncoding.SevenBit;
              Message.TransferType = "7bit";
              this.messageNo = MessageNo;

              //raw email tracing
              if (isGetRawEmail) {
            isTraceRawEmail = true;
            if (RawEmailSB==null){
              RawEmailSB = new StringBuilder(100000);
            }else{
              RawEmailSB.Length = 0;
            }
              }

              //convert received email into RxMailMessage
              MimeEntityReturnCode MessageMimeReturnCode = ProcessMimeEntity(Message, "");
              if (isGetRawEmail) {
            //add raw email version to message
            Message.RawContent = RawEmailSB.ToString();
            isTraceRawEmail = false;
              }

              if (MessageMimeReturnCode==MimeEntityReturnCode.bodyComplete ||
            MessageMimeReturnCode==MimeEntityReturnCode.parentBoundaryEndFound) {
            TraceFrom("email with {0} body chars received", Message.Body.Length);
            return true;
              }
              return false;
        }
示例#17
0
        public bool ProcessEmbedded(ref RxMailMessage Message)
        {
            //raw email tracing
            if ( isGetRawEmail )
            {
            isTraceRawEmail = true;
            if ( RawEmailSB == null )
            {
                RawEmailSB = new StringBuilder(100000);
            }
            else
            {
                RawEmailSB.Length = 0;
            }
            }

            //convert received email into RxMailMessage
            MimeEntityReturnCode MessageMimeReturnCode = ProcessMimeEntity(Message, "");
            if ( isGetRawEmail )
            {
            //add raw email version to message
            Message.RawContent = RawEmailSB.ToString();
            isTraceRawEmail = false;
            }

            if ( MessageMimeReturnCode == MimeEntityReturnCode.bodyComplete || MessageMimeReturnCode == MimeEntityReturnCode.parentBoundaryEndFound )
            {
            TraceFrom("email with {0} body chars received", Message.Body.Length);
            return true;
            }
            return false;
        }
示例#18
0
        /// <summary>
        /// Process a MIME entity
        ///
        /// A MIME entity consists of header and body.
        /// Separator lines in the body might mark children MIME entities
        /// </summary>
        private MimeEntityReturnCode ProcessMimeEntity(RxMailMessage message, string parentBoundaryStart)
        {
            bool   hasParentBoundary = parentBoundaryStart.Length > 0;
            string parentBoundaryEnd = parentBoundaryStart + "--";
            MimeEntityReturnCode boundaryMimeReturnCode;

            //some format fields are inherited from parent, only the default for
            //ContentType needs to be set here, otherwise the boundary parameter would be
            //inherited too !
            message.SetContentTypeFields("text/plain; charset=us-ascii");

            //get header
            //----------
            string completeHeaderField = null; //consists of one start line and possibly several continuation lines
            string response;

            // read header lines until empty line is found (end of header)
            while (true)
            {
                if (!readMultiLine(out response))
                {
                    //POP3 server has not send any more lines
                    callGetEmailWarning("incomplete MIME entity header received");
                    //empty this message
                    while (readMultiLine(out response))
                    {
                    }
                    System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
                    return(MimeEntityReturnCode.problem);
                }

                if (response.Length < 1)
                {
                    //empty line found => end of header
                    if (completeHeaderField != null)
                    {
                        ProcessHeaderField(message, completeHeaderField);
                    }
                    else
                    {
                        //there was only an empty header.
                    }
                    break;
                }

                //check if there is a parent boundary in the header (wrong format!)
                if (hasParentBoundary && parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, out boundaryMimeReturnCode))
                {
                    callGetEmailWarning("MIME entity header  prematurely ended by parent boundary");
                    //empty this message
                    while (readMultiLine(out response))
                    {
                    }
                    System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
                    return(boundaryMimeReturnCode);
                }
                //read header field
                //one header field can extend over one start line and multiple continuation lines
                //a continuation line starts with at least 1 blank (' ') or tab
                if (response[0] == ' ' || response[0] == '\t')
                {
                    //continuation line found.
                    if (completeHeaderField == null)
                    {
                        callGetEmailWarning("Email header starts with continuation line");
                        //empty this message
                        while (readMultiLine(out response))
                        {
                        }
                        System.Diagnostics.Debugger.Break(); //didn't have a sample email to test this
                        return(MimeEntityReturnCode.problem);
                    }
                    else
                    {
                        // append space, if needed, and continuation line
                        if (completeHeaderField[completeHeaderField.Length - 1] != ' ')
                        {
                            //previous line did not end with a whitespace
                            //need to replace CRLF with a ' '
                            completeHeaderField += ' ' + response.TrimStart(WhiteSpaceChars);
                        }
                        else
                        {
                            //previous line did end with a whitespace
                            completeHeaderField += response.TrimStart(WhiteSpaceChars);
                        }
                    }
                }
                else
                {
                    //a new header field line found
                    if (completeHeaderField == null)
                    {
                        //very first field, just copy it and then check for continuation lines
                        completeHeaderField = response;
                    }
                    else
                    {
                        //new header line found
                        ProcessHeaderField(message, completeHeaderField);

                        //save the beginning of the next line
                        completeHeaderField = response;
                    }
                }
            }//end while read header lines


            //process body
            //------------

            MimeEntitySB.Length = 0; //empty StringBuilder. For speed reasons, reuse StringBuilder defined as member of class
            string BoundaryDelimiterLineStart = null;
            bool   isBoundaryDefined          = false;

            if (message.ContentType.Boundary != null)
            {
                isBoundaryDefined          = true;
                BoundaryDelimiterLineStart = "--" + message.ContentType.Boundary;
            }
            //prepare return code for the case there is no boundary in the body
            boundaryMimeReturnCode = MimeEntityReturnCode.bodyComplete;

            //read body lines
            while (readMultiLine(out response))
            {
                //check if there is a boundary line from this entity itself in the body
                if (isBoundaryDefined && response.TrimEnd() == BoundaryDelimiterLineStart)
                {
                    //boundary line found.
                    //stop the processing here and start a delimited body processing
                    return(ProcessDelimitedBody(message, BoundaryDelimiterLineStart, parentBoundaryStart, parentBoundaryEnd));
                }

                //check if there is a parent boundary in the body
                if (hasParentBoundary &&
                    parentBoundaryFound(response, parentBoundaryStart, parentBoundaryEnd, out boundaryMimeReturnCode))
                {
                    //a parent boundary is found. Decode the content of the body received so far, then end this MIME entity
                    //note that boundaryMimeReturnCode is set here, but used in the return statement
                    break;
                }

                //process next line
                MimeEntitySB.Append(response + CRLF);
            }

            //a complete MIME body read
            //convert received US ASCII characters to .NET string (Unicode)
            string TransferEncodedMessage = MimeEntitySB.ToString();
            bool   isAttachmentSaved      = false;

            switch (message.ContentTransferEncoding)
            {
            case TransferEncoding.SevenBit:
                //nothing to do
                saveMessageBody(message, TransferEncodedMessage);
                break;

            case TransferEncoding.Base64:
                //convert base 64 -> byte[]
                byte[] bodyBytes = System.Convert.FromBase64String(TransferEncodedMessage);
                message.ContentStream = new MemoryStream(bodyBytes, false);

                if (message.MediaMainType == "text")
                {
                    //convert byte[] -> string
                    message.Body = DecodeByteArryToString(bodyBytes, message.BodyEncoding);
                }
                else if (message.MediaMainType == "image" || message.MediaMainType == "application")
                {
                    SaveAttachment(message);
                    isAttachmentSaved = true;
                }
                break;

            case TransferEncoding.QuotedPrintable:
                saveMessageBody(message, QuotedPrintable.Decode(TransferEncodedMessage));
                break;

            default:
                saveMessageBody(message, TransferEncodedMessage);
                //no need to raise a warning here, the warning was done when analising the header
                break;
            }

            if (message.ContentDisposition != null && message.ContentDisposition.DispositionType.ToLowerInvariant() == "attachment" && !isAttachmentSaved)
            {
                SaveAttachment(message);
                isAttachmentSaved = true;
            }
            return(boundaryMimeReturnCode);
        }
示例#19
0
        /// <summary>
        /// Convert one MIME header field and update message accordingly
        /// </summary>
        private void ProcessHeaderField(RxMailMessage message, string headerField)
        {
            string headerLineType;
            string headerLineContent;
            int    separatorPosition = headerField.IndexOf(':');

            if (separatorPosition < 1)
            {
                // header field type not found, skip this line
                callGetEmailWarning("character ':' missing in header format field: '{0}'", headerField);
            }
            else
            {
                //process header field type
                headerLineType    = headerField.Substring(0, separatorPosition).ToLowerInvariant();
                headerLineContent = headerField.Substring(separatorPosition + 1).Trim(WhiteSpaceChars);
                if (headerLineType == "" || headerLineContent == "")
                {
                    //1 of the 2 parts missing, drop the line
                    return;
                }
                // add header line to headers
                message.Headers.Add(headerLineType, headerLineContent);

                //interpret if possible
                switch (headerLineType)
                {
                case "bcc":
                    AddMailAddresses(headerLineContent, message.Bcc);
                    break;

                case "cc":
                    AddMailAddresses(headerLineContent, message.CC);
                    break;

                case "content-description":
                    message.ContentDescription = headerLineContent;
                    break;

                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;
                }
            }
        }