Esempio n. 1
0
 //add a new header and set its value
 internal void InternalAdd(string name, string value)
 {
     if (MailHeaderInfo.IsSingleton(name))
     {
         base.Set(name, value);
     }
     else
     {
         base.Add(name, value);
     }
 }
Esempio n. 2
0
        /// <summary>
        /// Extract headers from the text stream into the Headers collection of the ReceivedMessage object provided.
        /// </summary>
        /// <param name="reader">TextReader providing the data stream to be parsed</param>
        /// <param name="messageHeaders">Collection of message headers.</param>
        /// <param name="rawheaders">Raw text of headers as received from server.</param>
        /// <returns>Returns false if no headers were found. Otherwise returns true.</returns>
        private static bool LoadHeaders(TextReader reader, NameValueCollection messageHeaders, StringBuilder rawheaders)
        {
            Debug.WriteLine("LoadHeaders()");
            string line          = null;
            string lastHeaderKey = null;
            //multiple values with the same header key will be delimited by semi-colon.
            //semi-colon is reserved as a special character for header encoding in RFC 2047, so this should be safe
            Dictionary <string, StringBuilder> headersBuilders = new Dictionary <string, StringBuilder>(StringComparer.InvariantCultureIgnoreCase);
            Dictionary <string, string[]>      headers;

            Debug.WriteLine("Raw:");
            while (null != (line = reader.ReadLine()))
            {
                Debug.WriteLine(line);
                if (rawheaders != null)
                {
                    rawheaders.AppendLine(line);
                }

                //headers end with an empty line
                if (line == string.Empty || line.Trim() == string.Empty)
                {
                    break;
                }

                //some agents malform the key: value expression so that there is no space after the colon.
                //for example this BlackBerry Message-ID header
                //Message-ID:<*****@*****.**>
                Regex regex = new Regex(@"^([^:]+):\s?(.*)$");
                Match match = regex.Match(line);

                //if a line does not contain a colon it is either a continuation of a previous line or an error
                if (match.Success)
                {
                    //split header key from RFC 2047 encoded value

                    string headerkey = match.Groups[1].Value;

                    string value = match.Groups[2].Value;


                    if (!headersBuilders.ContainsKey(headerkey))
                    {
                        headersBuilders.Add(headerkey, new StringBuilder(value));
                    }
                    else
                    {
                        headersBuilders[headerkey].AppendFormat("|~|{0}", value);
                    }
                    lastHeaderKey = headerkey;
                }
                else
                {
                    //continuation line should start with whitespace
                    if (!string.IsNullOrEmpty(lastHeaderKey) && Regex.IsMatch(line, "^\\s"))
                    {
                        string h = line.TrimStart('\t', ' ');
                        headersBuilders[lastHeaderKey].AppendFormat("|~|{0}", h);
                    }
                    else //error in message format, skip ahead and attempt to continue parsing
                    {
                        lastHeaderKey = null;
                        continue;
                    }
                }
            }

            if (headersBuilders.Count == 0)
            {
                return(false);
            }

            headers = new Dictionary <string, string[]>(headersBuilders.Count, StringComparer.InvariantCultureIgnoreCase);
            foreach (string key in headersBuilders.Keys)
            {
                List <string> list = new List <string>(headersBuilders[key].ToString().Split(new[] { "|~|" }, StringSplitOptions.RemoveEmptyEntries));

                for (int i = 0; i < list.Count; i++)
                {
                    if (string.IsNullOrEmpty(list[i]))
                    {
                        list.RemoveAt(i);
                    }
                }
                headers.Add(key, list.ToArray());
            }

            InPlaceDecodeExtendedHeaders(headers);

            //add decoded headers to the ReceivedMessage parameter passed in to this method.

            /**************************************************************************
             * NOTE:
             * The NameValueCollction in MailMessage.Headers is actually an internal Type
             * called HeaderCollection. HeaderCollection has different behavior for header keys
             * that are defined as singleton. MailHeaderMsft.IsSingleton replicates the internal
             * test used by HeaderCollection.
             */
            Debug.WriteLine("Decoded:");
            foreach (string key in headers.Keys)
            {
                Debug.WriteLine("Key: " + key);
                //I believe IsSingleton is meant to indicate that the field should occur only once in the output
                //headers when the message is encoded for transport. The side-effect of the implementation is that it doesn't
                //allow adding multiple values to a single key in the NameValueCollection.
                if (MailHeaderInfo.IsSingleton(key))
                {
                    //HeaderCollection will use Set internally when Add is called
                    //need to join multiple values into a single string before adding or
                    //the last value to be added will be the final value and the others will be lost.
                    //therefore, components need to be combined into a single comma-separated string
                    //before being added.
                    string[] v     = headers[key];
                    string   value = string.Join(string.Empty, headers[key]);
                    //HeaderCollection.Add(string,string) throws an undocumented ArgumentException when being passed
                    //an empty string as a value. This is quite contrary to the behavior documented for NameValueCollection.Add(string,string)
                    //which explicitly permits null and empty strings to be added.
                    //the most common cause of this problem is a BCC: field with no value.
                    if (value != string.Empty)
                    {
                        messageHeaders.Add(key, value);
                    }
                }
                else
                {
                    for (int i = 0; i < headers[key].Length; i++)
                    {
                        if (!string.IsNullOrEmpty(headers[key][i]))
                        {
                            Debug.WriteLine(key + ": " + headers[key][i]);
                            messageHeaders.Add(key, headers[key][i]);
                        }
                    }
                }

                Debug.WriteLine(key + ": " + messageHeaders[key]);
            }

            return(true);
        }