Example #1
0
        /// <summary>
        /// Constructs ENVELOPE address structure.
        /// </summary>
        /// <param name="address">Mailbox address.</param>
        /// <returns></returns>
        private static string ConstructAddress(MailboxAddress address)
        {
            /* An address structure is a parenthesized list that describes an
             *             electronic mail address.  The fields of an address structure
             *             are in the following order: personal name, [SMTP]
             *             at-domain-list (source route), mailbox name, and host name.
             */

            // NOTE: all header fields and parameters must in ENCODED form !!!

            StringBuilder retVal = new StringBuilder();

            retVal.Append("(");

            // personal name
            retVal.Append(TextUtils.QuoteString(MimeUtils.EncodeHeaderField(address.DisplayName)));

            // source route, always NIL (not used nowdays)
            retVal.Append(" NIL");

            // mailbox name
            retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(address.LocalPart)));

            // host name
            retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(address.Domain)));

            retVal.Append(")");

            return(retVal.ToString());
        }
Example #2
0
        /// <summary>
        /// Construct secified mime entity ENVELOPE string.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <returns></returns>
        public static string ConstructEnvelope(MimeEntity entity)
        {
            /* RFC 3501 7.4.2
             *                  ENVELOPE
             *                          A parenthesized list that describes the envelope structure of a
             *                          message.  This is computed by the server by parsing the
             *                          [RFC-2822] header into the component parts, defaulting various
             *                          fields as necessary.
             *
             *                          The fields of the envelope structure are in the following
             *                          order: date, subject, from, sender, reply-to, to, cc, bcc,
             *                          in-reply-to, and message-id.  The date, subject, in-reply-to,
             *                          and message-id fields are strings.  The from, sender, reply-to,
             *                          to, cc, and bcc fields are parenthesized lists of address
             *                          structures.
             *
             *                          An address structure is a parenthesized list that describes an
             *                          electronic mail address.  The fields of an address structure
             *                          are in the following order: personal name, [SMTP]
             *                          at-domain-list (source route), mailbox name, and host name.
             *
             *                          [RFC-2822] group syntax is indicated by a special form of
             *                          address structure in which the host name field is NIL.  If the
             *                          mailbox name field is also NIL, this is an end of group marker
             *                          (semi-colon in RFC 822 syntax).  If the mailbox name field is
             *                          non-NIL, this is a start of group marker, and the mailbox name
             *                          field holds the group name phrase.
             *
             *                          If the Date, Subject, In-Reply-To, and Message-ID header lines
             *                          are absent in the [RFC-2822] header, the corresponding member
             *                          of the envelope is NIL; if these header lines are present but
             *                          empty the corresponding member of the envelope is the empty
             *                          string.
             *
             *                                  Note: some servers may return a NIL envelope member in the
             *                                  "present but empty" case.  Clients SHOULD treat NIL and
             *                                  empty string as identical.
             *
             *                                  Note: [RFC-2822] requires that all messages have a valid
             *                                  Date header.  Therefore, the date member in the envelope can
             *                                  not be NIL or the empty string.
             *
             *                                  Note: [RFC-2822] requires that the In-Reply-To and
             *                                  Message-ID headers, if present, have non-empty content.
             *                                  Therefore, the in-reply-to and message-id members in the
             *                                  envelope can not be the empty string.
             *
             *                          If the From, To, cc, and bcc header lines are absent in the
             *                          [RFC-2822] header, or are present but empty, the corresponding
             *                          member of the envelope is NIL.
             *
             *                          If the Sender or Reply-To lines are absent in the [RFC-2822]
             *                          header, or are present but empty, the server sets the
             *                          corresponding member of the envelope to be the same value as
             *                          the from member (the client is not expected to know to do
             *                          this).
             *
             *                                  Note: [RFC-2822] requires that all messages have a valid
             *                                  From header.  Therefore, the from, sender, and reply-to
             *                                  members in the envelope can not be NIL.
             *
             *                          ENVELOPE ("date" "subject" from sender reply-to to cc bcc "in-reply-to" "messageID")
             */

            // NOTE: all header fields and parameters must in ENCODED form !!!

            StringBuilder retVal = new StringBuilder();

            retVal.Append("(");

            // date
            if (entity.Header.Contains("Date:"))
            {
                retVal.Append(TextUtils.QuoteString(MimeUtils.DateTimeToRfc2822(entity.Date)));
            }
            else
            {
                retVal.Append("NIL");
            }

            // subject
            if (entity.Subject != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.Subject)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // from
            if (entity.From != null && entity.From.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // sender
            //	NOTE: There is confusing part, according rfc 2822 Sender: is MailboxAddress and not AddressList.
            if (entity.Sender != null)
            {
                retVal.Append(" (");

                retVal.Append(ConstructAddress(entity.Sender));

                retVal.Append(")");
            }
            else if (entity.From != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // reply-to
            if (entity.ReplyTo != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.ReplyTo));
            }
            else if (entity.From != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // to
            if (entity.To != null && entity.To.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.To));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // cc
            if (entity.Cc != null && entity.Cc.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.Cc));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // bcc
            if (entity.Bcc != null && entity.Bcc.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.Bcc));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // in-reply-to
            if (entity.InReplyTo != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.InReplyTo)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // message-id
            if (entity.MessageID != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.MessageID)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            retVal.Append(")");

            return(retVal.ToString());
        }
        /// <summary>
        /// Constructs specified entity and it's childentities bodystructure string.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <param name="bodystructure">Specifies if to construct BODY or BODYSTRUCTURE.</param>
        /// <returns></returns>
        private static string ConstructParts(MimeEntity entity, bool bodystructure)
        {
            /* RFC 3501 7.4.2 BODYSTRUCTURE
             *                                            BODY A form of BODYSTRUCTURE without extension data.
             *
             *                  A parenthesized list that describes the [MIME-IMB] body
             *                  structure of a message.  This is computed by the server by
             *                  parsing the [MIME-IMB] header fields, defaulting various fields
             *                  as necessary.
             *
             *                  For example, a simple text message of 48 lines and 2279 octets
             *                  can have a body structure of: ("TEXT" "PLAIN" ("CHARSET"
             *                  "US-ASCII") NIL NIL "7BIT" 2279 48)
             *
             *                  Multiple parts are indicated by parenthesis nesting.  Instead
             *                  of a body type as the first element of the parenthesized list,
             *                  there is a sequence of one or more nested body structures.  The
             *                  second element of the parenthesized list is the multipart
             *                  subtype (mixed, digest, parallel, alternative, etc.).
             *
             *                  For example, a two part message consisting of a text and a
             *                  BASE64-encoded text attachment can have a body structure of:
             *                  (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
             *                  23)("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
             *                  "<*****@*****.**>" "Compiler diff"
             *                  "BASE64" 4554 73) "MIXED")
             *
             *                  Extension data follows the multipart subtype.  Extension data
             *                  is never returned with the BODY fetch, but can be returned with
             *                  a BODYSTRUCTURE fetch.  Extension data, if present, MUST be in
             *                  the defined order.  The extension data of a multipart body part
             *                  are in the following order:
             *
             *                  body parameter parenthesized list
             *                          A parenthesized list of attribute/value pairs [e.g., ("foo"
             *                          "bar" "baz" "rag") where "bar" is the value of "foo", and
             *                          "rag" is the value of "baz"] as defined in [MIME-IMB].
             *
             *                  body disposition
             *                          A parenthesized list, consisting of a disposition type
             *                          string, followed by a parenthesized list of disposition
             *                          attribute/value pairs as defined in [DISPOSITION].
             *
             *                  body language
             *                          A string or parenthesized list giving the body language
             *                          value as defined in [LANGUAGE-TAGS].
             *
             *                  body location
             *                          A string list giving the body content URI as defined in [LOCATION].
             *
             *                  Any following extension data are not yet defined in this
             *                  version of the protocol.  Such extension data can consist of
             *                  zero or more NILs, strings, numbers, or potentially nested
             *                  parenthesized lists of such data.  Client implementations that
             *                  do a BODYSTRUCTURE fetch MUST be prepared to accept such
             *                  extension data.  Server implementations MUST NOT send such
             *                  extension data until it has been defined by a revision of this
             *                  protocol.
             *
             *                  The basic fields of a non-multipart body part are in the
             *                  following order:
             *
             *                  body type
             *                          A string giving the content media type name as defined in [MIME-IMB].
             *
             *                  body subtype
             *                           A string giving the content subtype name as defined in [MIME-IMB].
             *
             *                  body parameter parenthesized list
             *                          A parenthesized list of attribute/value pairs [e.g., ("foo"
             *                          "bar" "baz" "rag") where "bar" is the value of "foo" and
             *                          "rag" is the value of "baz"] as defined in [MIME-IMB].
             *
             *                  body id
             *                          A string giving the content id as defined in [MIME-IMB].
             *
             *                  body description
             *                          A string giving the content description as defined in [MIME-IMB].
             *
             *                  body encoding
             *                          A string giving the content transfer encoding as defined in	[MIME-IMB].
             *
             *                  body size
             *                          A number giving the size of the body in octets.  Note that
             *                          this size is the size in its transfer encoding and not the
             *                          resulting size after any decoding.
             *
             *                  A body type of type MESSAGE and subtype RFC822 contains,
             *                  immediately after the basic fields, the envelope structure,
             *                  body structure, and size in text lines of the encapsulated
             *                  message.
             *
             *                  A body type of type TEXT contains, immediately after the basic
             *                  fields, the size of the body in text lines.  Note that this
             *                  size is the size in its content transfer encoding and not the
             *                  resulting size after any decoding.
             *
             *                  Extension data follows the basic fields and the type-specific
             *                  fields listed above.  Extension data is never returned with the
             *                  BODY fetch, but can be returned with a BODYSTRUCTURE fetch.
             *                  Extension data, if present, MUST be in the defined order.
             *
             *                  The extension data of a non-multipart body part are in the
             *                  following order:
             *
             *                  body MD5
             *                          A string giving the body MD5 value as defined in [MD5].
             *
             *                  body disposition
             *                          A parenthesized list with the same content and function as
             *                          the body disposition for a multipart body part.
             *
             *                  body language
             *                          A string or parenthesized list giving the body language
             *                          value as defined in [LANGUAGE-TAGS].
             *
             *                  body location
             *                          A string list giving the body content URI as defined in [LOCATION].
             *
             *                  Any following extension data are not yet defined in this
             *                  version of the protocol, and would be as described above under
             *                  multipart extension data.
             *
             *
             *                  // We don't construct extention fields like rfc says:
             *                          Server implementations MUST NOT send such
             *                          extension data until it has been defined by a revision of this
             *                          protocol.
             *
             *
             *                  contentTypeMainMediaType - Example: 'TEXT'
             *                  contentTypeSubMediaType  - Example: 'PLAIN'
             *                  conentTypeParameters     - Example: '("CHARSET" "iso-8859-1" ...)'
             *                  contentID                - Content-ID: header field value.
             *                  contentDescription       - Content-Description: header field value.
             *                  contentEncoding          - Content-Transfer-Encoding: header field value.
             *                  contentSize              - mimeEntity ENCODED data size
             *                  [envelope]               - NOTE: included only if contentType = "message" !!!
             *                  [contentLines]           - number of ENCODED data lines. NOTE: included only if contentType = "text" !!!
             *
             *                  // Basic fields for multipart
             *                  (nestedMimeEntries) contentTypeSubMediaType
             *
             *                  // Basic fields for non-multipart
             *                  contentTypeMainMediaType contentTypeSubMediaType (conentTypeParameters) contentID contentDescription contentEncoding contentSize [envelope] [contentLine]
             *
             */

            StringBuilder retVal = new StringBuilder();

            // Multipart message
            if ((entity.ContentType & MediaType_enum.Multipart) != 0)
            {
                retVal.Append("(");

                // Construct child entities.
                foreach (MimeEntity childEntity in entity.ChildEntities)
                {
                    // Construct child entity. This can be multipart or non multipart.
                    retVal.Append(ConstructParts(childEntity, bodystructure));
                }

                // Add contentTypeSubMediaType
                string contentType = entity.ContentTypeString.Split(';')[0];
                if (contentType.Split('/').Length == 2)
                {
                    retVal.Append(" \"" + contentType.Split('/')[1].Replace(";", "") + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                retVal.Append(")");
            }
            // Single part message
            else
            {
                retVal.Append("(");

                // NOTE: all header fields and parameters must in ENCODED form !!!

                // Add contentTypeMainMediaType
                if (entity.ContentTypeString != null)
                {
                    string contentType = entity.ContentTypeString.Split(';')[0];
                    if (contentType.Split('/').Length == 2)
                    {
                        retVal.Append("\"" + entity.ContentTypeString.Split('/')[0] + "\"");
                    }
                    else
                    {
                        retVal.Append("NIL");
                    }
                }
                else
                {
                    retVal.Append("NIL");
                }

                // contentTypeSubMediaType
                if (entity.ContentTypeString != null)
                {
                    string contentType = entity.ContentTypeString.Split(';')[0];
                    if (contentType.Split('/').Length == 2)
                    {
                        retVal.Append(" \"" + contentType.Split('/')[1].Replace(";", "") + "\"");
                    }
                    else
                    {
                        retVal.Append(" NIL");
                    }
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // conentTypeParameters - Syntax: {("name" SP "value" *(SP "name" SP "value"))}
                if (entity.ContentTypeString != null)
                {
                    ParametizedHeaderField contentTypeParameters =
                        new ParametizedHeaderField(entity.Header.GetFirst("Content-Type:"));
                    if (contentTypeParameters.Parameters.Count > 0)
                    {
                        retVal.Append(" (");

                        bool first = true;
                        foreach (HeaderFieldParameter param in contentTypeParameters.Parameters)
                        {
                            // For first item, don't add SP
                            if (!first)
                            {
                                retVal.Append(" ");
                            }
                            else
                            {
                                // Clear first flag
                                first = false;
                            }

                            retVal.Append("\"" + param.Name + "\" \"" +
                                          MimeUtils.EncodeHeaderField(param.Value) + "\"");
                        }

                        retVal.Append(")");
                    }
                    else
                    {
                        retVal.Append(" NIL");
                    }
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentID
                string contentID = entity.ContentID;
                if (contentID != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentID) + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentDescription
                string contentDescription = entity.ContentDescription;
                if (contentDescription != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentDescription) + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentEncoding
                HeaderField contentEncoding = entity.Header.GetFirst("Content-Transfer-Encoding:");
                if (contentEncoding != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentEncoding.Value) + "\"");
                }
                else
                {
                    // If not specified, then must be 7bit.
                    retVal.Append(" \"7bit\"");
                }

                // contentSize
                if (entity.DataEncoded != null)
                {
                    retVal.Append(" " + entity.DataEncoded.Length);
                }
                else
                {
                    retVal.Append(" 0");
                }

                // envelope ---> FOR ContentType: message/rfc822 ONLY ###
                if ((entity.ContentType & MediaType_enum.Message_rfc822) != 0)
                {
                    retVal.Append(" " + IMAP_Envelope.ConstructEnvelope(entity));

                    // TODO: BODYSTRUCTURE,LINES
                }

                // contentLines ---> FOR ContentType: text/xxx ONLY ###
                if ((entity.ContentType & MediaType_enum.Text) != 0)
                {
                    if (entity.DataEncoded != null)
                    {
                        long             lineCount = 0;
                        StreamLineReader r         = new StreamLineReader(new MemoryStream(entity.DataEncoded));
                        byte[]           line      = r.ReadLine();
                        while (line != null)
                        {
                            lineCount++;

                            line = r.ReadLine();
                        }

                        retVal.Append(" " + lineCount);
                    }
                    else
                    {
                        retVal.Append(" 0");
                    }
                }

                retVal.Append(")");
            }

            return(retVal.ToString());
        }