Class that holds all headers for a message
Headers which are unknown the the parser will be held in the UnknownHeaders collection.

This class cannot be instantiated from outside the library.
See RFC 4021 for a large list of headers.
		/// <summary>
		/// Extract the header part and body part of a message.<br/>
		/// The headers are then parsed to a strongly typed <see cref="MessageHeader"/> object.
		/// </summary>
		/// <param name="fullRawMessage">The full message in bytes where header and body needs to be extracted from</param>
		/// <param name="headers">The extracted header parts of the message</param>
		/// <param name="body">The body part of the message</param>
		/// <exception cref="ArgumentNullException">If <paramref name="fullRawMessage"/> is <see langword="null"/></exception>
		public static void ExtractHeadersAndBody(Byte[] fullRawMessage, out MessageHeader headers, out Byte[] body)
		{
			if (fullRawMessage == null)
				throw new ArgumentNullException("fullRawMessage");

			// Find the end location of the headers
			Int32 endOfHeaderLocation = FindHeaderEndPosition(fullRawMessage);

			// The headers are always in ASCII - therefore we can convert the header part into a String
			// using US-ASCII encoding
			String headersString = Encoding.ASCII.GetString(fullRawMessage, 0, endOfHeaderLocation);

			// Now parse the headers to a NameValueCollection
			NameValueCollection headersUnparsedCollection = ExtractHeaders(headersString);

			// Use the NameValueCollection to parse it into a strongly-typed MessageHeader header
			headers = new MessageHeader(headersUnparsedCollection);

			// Since we know where the headers end, we also know where the body is
			// Copy the body part into the body parameter
			body = new Byte[fullRawMessage.Length - endOfHeaderLocation];
			Array.Copy(fullRawMessage, endOfHeaderLocation, body, 0, body.Length);
		}
Example #2
0
        /// <summary>
        /// Used to construct the topmost message part
        /// </summary>
        /// <param name="rawBody">The body that needs to be parsed</param>
        /// <param name="headers">The headers that should be used from the message</param>
        /// <exception cref="ArgumentNullException">If <paramref name="rawBody"/> or <paramref name="headers"/> is <see langword="null"/></exception>
        public MessagePart(Byte[] rawBody, MessageHeader headers)
        {
            if (rawBody == null)
                throw new ArgumentNullException("rawBody");

            if (headers == null)
                throw new ArgumentNullException("headers");

            this.Header = headers;

            if (headers.ContentType != null)
                ContentType = headers.ContentType;
            else
                ContentType = new ContentType("text/plain; charset=us-ascii");
            ContentDescription = headers.ContentDescription;
            ContentTransferEncoding = headers.ContentTransferEncoding;
            ContentId = headers.ContentId;
            ContentDisposition = headers.ContentDisposition;

            FileName = FindFileName(ContentType, ContentDisposition, "(no name)");
            BodyEncoding = ParseBodyEncoding(ContentType.CharSet);

            ParseBody(rawBody);
        }
Example #3
0
        /// <summary>
        /// Parses a single header and sets member variables according to it.
        /// </summary>
        /// <param name="headerName">The name of the header</param>
        /// <param name="headerValue">The value of the header in unfolded state (only one line)</param>
        /// <exception cref="ArgumentNullException">If <paramref name="headerName"/> or <paramref name="headerValue"/> is <see langword="null"/></exception>
        public void ParseHeader(String headerName, String headerValue)
        {
            if (headerName == null)
            {
                throw new ArgumentNullException("headerName");
            }

            if (headerValue == null)
            {
                throw new ArgumentNullException("headerValue");
            }

            HeaderValueChanged(headerName, headerValue);

            switch (headerName.ToUpperInvariant())
            {
            // See http://tools.ietf.org/html/rfc5322#section-3.6.3
            case "TO":
                this.To = MessageHeader.ParseAddresses(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.3
            case "CC":
                this.Cc = MessageHeader.ParseAddresses(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.3
            case "BCC":
                this.Bcc = MessageHeader.ParseAddresses(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.2
            case "FROM":
                // There is only one MailAddress in the from field
                this.From = MessageAddress.ParseAddress(headerValue);
                break;

            // http://tools.ietf.org/html/rfc5322#section-3.6.2
            // The implementation here might be wrong
            case "REPLY-TO":
                // This field may actually be a list of addresses, but no
                // such case has been encountered
                this.ReplyTo = MessageAddress.ParseAddress(headerValue);
                break;

            // http://tools.ietf.org/html/rfc5322#section-3.6.2
            case "SENDER":
                this.Sender = MessageAddress.ParseAddress(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.5
            // RFC 5322:
            // The "Keywords:" field contains a comma-separated list of one or more
            // words or quoted-strings.
            // The field are intended to have only human-readable content
            // with information about the message
            case "KEYWORDS":
                var keywordsTemp = headerValue.Split(",");
                foreach (String keyword in keywordsTemp)
                {
                    // Remove the quotes if there is any
                    Keywords.Add(Utility.RemoveQuotesIfAny(keyword.Trim()));
                }
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.7
            case "RECEIVED":
                // Simply add the value to the list
                Received.Add(headerValue.Trim());
                break;

            case "IMPORTANCE":
                Importance = HeaderFieldParser.ParseImportance(headerValue.Trim());
                break;

            // See http://tools.ietf.org/html/rfc3798#section-2.1
            case "DISPOSITION-NOTIFICATION-TO":
                this.DispositionNotificationTo = MessageHeader.ParseAddresses(headerValue);
                break;

            case "MIME-VERSION":
                MimeVersion = headerValue.Trim();
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.5
            case "SUBJECT":
            case "THREAD-TOPIC":
                Subject = EncodedWord.Decode(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.7
            case "RETURN-PATH":
                // Return-paths does not include a username, but we
                // may still use the address parser
                this.ReturnPath = MessageAddress.ParseAddress(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.4
            // Example Message-ID
            // <*****@*****.**>
            case "MESSAGE-ID":
                MessageId = HeaderFieldParser.ParseId(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.4
            case "IN-REPLY-TO":
                InReplyTo = HeaderFieldParser.ParseMultipleIDs(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.4
            case "REFERENCES":
                References = HeaderFieldParser.ParseMultipleIDs(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc5322#section-3.6.1))
            case "DATE":
                Date     = headerValue.Trim();
                DateSent = Rfc2822DateTime.StringToDate(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc2045#section-6
            // See ContentTransferEncoding class for more details
            case "CONTENT-TRANSFER-ENCODING":
                ContentTransferEncoding = HeaderFieldParser.ParseContentTransferEncoding(headerValue.Trim());
                break;

            // See http://tools.ietf.org/html/rfc2045#section-8
            case "CONTENT-DESCRIPTION":
                // Human description of for example a file. Can be encoded
                ContentDescription = EncodedWord.Decode(headerValue.Trim());
                break;

            // See http://tools.ietf.org/html/rfc2045#section-5.1
            // Example: Content-type: text/plain; charset="us-ascii"
            case "CONTENT-TYPE":
                ContentType = HeaderFieldParser.ParseContentType(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc2183
            case "CONTENT-DISPOSITION":
                ContentDisposition = HeaderFieldParser.ParseContentDisposition(headerValue);
                break;

            // See http://tools.ietf.org/html/rfc2045#section-7
            // Example: <foo4*[email protected]>
            case "CONTENT-ID":
                ContentId = HeaderFieldParser.ParseId(headerValue);
                break;

            case "_REQUEST-LINE_":
                // header could contain request-line that could not be parsed as simple key value pair, so store entire line
                // Example: POST /odata/$batch HTTP/1.1
                RequestLine = headerValue;
                break;

            default:
                // This is an unknown header

                // Custom headers are allowed. That means headers
                // that are not mentionen in the RFC.
                // Such headers start with the letter "X"
                // We do not have any special parsing of such

                // Add it to unknown headers
                UnknownHeaders.Add(headerName, headerValue);
                break;
            }
        }