/// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Return-Path: &lt;[email protected]&gt;'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static Mail_h_ReturnPath Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            string[] name_value = value.Split(new char[]{':'},2);
            if(name_value.Length != 2){
                throw new ParseException("Invalid header field value '" + value + "'.");
            }

            Mail_h_ReturnPath retVal = new Mail_h_ReturnPath(null);

            MIME_Reader r = new MIME_Reader(name_value[1].Trim());
            r.ToFirstChar();
            // Return-Path missing <>, some server won't be honor RFC.
            if(!r.StartsWith("<")){
                retVal.m_Address = r.ToEnd();
            }
            else{
                retVal.m_Address = r.ReadParenthesized();
            }

            return retVal;
        }
Exemple #2
0
        /// <summary>
        /// Reads SMTP "Mailbox" from the specified MIME reader.
        /// </summary>
        /// <param name="reader">MIME reader.</param>
        /// <returns>Returns SMTP "Mailbox" or null if no SMTP mailbox available.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>reader</b> is null reference.</exception>
        internal static string SMTP_Mailbox(MIME_Reader reader)
        {
            if(reader == null){
                throw new ArgumentNullException("reader");
            }

            // TODO:

            /* RFC 5321.
                Mailbox        = Local-part "@" ( Domain / address-literal )
                Local-part     = Dot-string / Quoted-string ; MAY be case-sensitive
                Dot-string     = Atom *("."  Atom)
            */

            StringBuilder retVal = new StringBuilder();
            if(reader.Peek(true) == '\"'){
                retVal.Append("\"" + reader.QuotedString() + "\"");
            }
            else{
                retVal.Append(reader.DotAtom());
            }

            if(reader.Peek(true) != '@'){
                return null;
            }
            else{
                // Eat "@".
                reader.Char(true);

                retVal.Append('@');
                retVal.Append(reader.DotAtom());
            }

            return retVal.ToString();
        }
        /// <summary>
        /// Parses <b>mailbox-list</b> from specified string value.
        /// </summary>
        /// <param name="value">The <b>mailbox-list</b> string value.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when <b>value</b> is not valid <b>mailbox-list</b> value.</exception>
        public static Mail_t_MailboxList Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            MIME_Reader        r      = new MIME_Reader(value);
            Mail_t_MailboxList retVal = new Mail_t_MailboxList();
            while(true){
                string word = r.QuotedReadToDelimiter(new char[]{',','<'});
                // We processed all data.
                if(string.IsNullOrEmpty(word) && r.Available == 0){
                    break;
                }
                // name-addr
                else if(r.Peek(true) == '<'){
                    retVal.Add(new Mail_t_Mailbox(word != null ? MIME_Encoding_EncodedWord.DecodeS(TextUtils.UnQuoteString(word.Trim())) : null,r.ReadParenthesized()));                    
                }
                // addr-spec
                else{
                    retVal.Add(new Mail_t_Mailbox(null,word));
                }

                // We have more addresses.
                if(r.Peek(true) == ','){
                    r.Char(false);
                }
            }

            return retVal;
        }
        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Sender: [email protected]'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static Mail_h_Mailbox Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            string[] name_value = value.Split(new char[]{':'},2);
            if(name_value.Length != 2){
                throw new ParseException("Invalid header field value '" + value + "'.");
            }

            MIME_Reader r = new MIME_Reader(name_value[1].Trim());

            string word = r.QuotedReadToDelimiter(new char[]{',','<',':'});
            // Invalid value.
            if(word == null){
                throw new ParseException("Invalid header field value '" + value + "'.");
            }
            // name-addr
            else if(r.Peek(true) == '<'){
                Mail_h_Mailbox h = new Mail_h_Mailbox(name_value[0],new Mail_t_Mailbox(word != null ? MIME_Encoding_EncodedWord.DecodeS(TextUtils.UnQuoteString(word)) : null,r.ReadParenthesized()));
                h.m_ParseValue = value;

                return h;
            }
            // addr-spec
            else{
                Mail_h_Mailbox h = new Mail_h_Mailbox(name_value[0],new Mail_t_Mailbox(null,word));
                h.m_ParseValue = value;

                return h;
            }
        }
        /// <summary>
        /// Parses RFC 2822 date-time from the specified value.
        /// </summary>
        /// <param name="value">RFC 2822 date-time string value.</param>
        /// <returns>Returns parsed datetime value.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public static DateTime ParseRfc2822DateTime(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException(value);
            }

            /* RFC 2822 3.
             *      date-time       =       [ day-of-week "," ] date FWS time [CFWS]
             *      day-of-week     =       ([FWS] day-name) / obs-day-of-week
             *      day-name        =       "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
             *      date            =       day month year
             *      year            =       4*DIGIT / obs-year
             *      month           =       (FWS month-name FWS) / obs-month
             *      month-name      =       "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
             *      day             =       ([FWS] 1*2DIGIT) / obs-day
             *      time            =       time-of-day FWS zone
             *      time-of-day     =       hour ":" minute [ ":" second ]
             *      hour            =       2DIGIT / obs-hour
             *      minute          =       2DIGIT / obs-minute
             *      second          =       2DIGIT / obs-second
             *      zone            =       (( "+" / "-" ) 4DIGIT) / obs-zone
             *
             *      The date and time-of-day SHOULD express local time.
             */

            try{
                MIME_Reader r = new MIME_Reader(value);
                string      v = r.Atom();
                // Skip optional [ day-of-week "," ] and read "day".
                if (v.Length == 3)
                {
                    r.Char(true);
                    v = r.Atom();
                }
                int day = Convert.ToInt32(v);
                v = r.Atom().ToLower();
                int month = 1;
                if (v == "jan")
                {
                    month = 1;
                }
                else if (v == "feb")
                {
                    month = 2;
                }
                else if (v == "mar")
                {
                    month = 3;
                }
                else if (v == "apr")
                {
                    month = 4;
                }
                else if (v == "may")
                {
                    month = 5;
                }
                else if (v == "jun")
                {
                    month = 6;
                }
                else if (v == "jul")
                {
                    month = 7;
                }
                else if (v == "aug")
                {
                    month = 8;
                }
                else if (v == "sep")
                {
                    month = 9;
                }
                else if (v == "oct")
                {
                    month = 10;
                }
                else if (v == "nov")
                {
                    month = 11;
                }
                else if (v == "dec")
                {
                    month = 12;
                }
                else
                {
                    throw new ArgumentException("Invalid month-name value '" + value + "'.");
                }
                int year = Convert.ToInt32(r.Atom());
                int hour = Convert.ToInt32(r.Atom());
                r.Char(true);
                int minute = Convert.ToInt32(r.Atom());
                int second = 0;
                // We have optional "second".
                if (r.Peek(true) == ':')
                {
                    r.Char(true);
                    second = Convert.ToInt32(r.Atom());
                }
                int timeZoneMinutes = 0;
                v = r.Atom();
                // Time zone missing. Not RFC syntax, but some servers will send such dates.
                if (v == null)
                {
                    // Just consider time zone as 0(GMT).
                }
                // We have RFC 2822 date. For example: +2000.
                else if (v[0] == '+' || v[0] == '-')
                {
                    if (v[0] == '+')
                    {
                        timeZoneMinutes = (Convert.ToInt32(v.Substring(1, 2)) * 60 + Convert.ToInt32(v.Substring(3, 2)));
                    }
                    else
                    {
                        timeZoneMinutes = -(Convert.ToInt32(v.Substring(1, 2)) * 60 + Convert.ToInt32(v.Substring(3, 2)));
                    }
                }
                // We have RFC 822 date with abbrevated time zone name. For example: GMT.
                else
                {
                    v = v.ToUpper();

                    #region time zones

                    // Alpha Time Zone (military).
                    if (v == "A")
                    {
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Australian Central Daylight Time.
                    else if (v == "ACDT")
                    {
                        timeZoneMinutes = ((10 * 60) + 30);
                    }
                    // Australian Central Standard Time.
                    else if (v == "ACST")
                    {
                        timeZoneMinutes = ((09 * 60) + 30);
                    }
                    // Atlantic Daylight Time.
                    else if (v == "ADT")
                    {
                        timeZoneMinutes = -((03 * 60) + 00);
                    }
                    // Australian Eastern Daylight Time.
                    else if (v == "AEDT")
                    {
                        timeZoneMinutes = ((11 * 60) + 00);
                    }
                    // Australian Eastern Standard Time.
                    else if (v == "AEST")
                    {
                        timeZoneMinutes = ((10 * 60) + 00);
                    }
                    // Alaska Daylight Time.
                    else if (v == "AKDT")
                    {
                        timeZoneMinutes = -((08 * 60) + 00);
                    }
                    // Alaska Standard Time.
                    else if (v == "AKST")
                    {
                        timeZoneMinutes = -((09 * 60) + 00);
                    }
                    // Atlantic Standard Time.
                    else if (v == "AST")
                    {
                        timeZoneMinutes = -((04 * 60) + 00);
                    }
                    // Australian Western Daylight Time.
                    else if (v == "AWDT")
                    {
                        timeZoneMinutes = ((09 * 60) + 00);
                    }
                    // Australian Western Standard Time.
                    else if (v == "AWST")
                    {
                        timeZoneMinutes = ((08 * 60) + 00);
                    }
                    // Bravo Time Zone (millitary).
                    else if (v == "B")
                    {
                        timeZoneMinutes = ((02 * 60) + 00);
                    }
                    // British Summer Time.
                    else if (v == "BST")
                    {
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Charlie Time Zone (millitary).
                    else if (v == "C")
                    {
                        timeZoneMinutes = ((03 * 60) + 00);
                    }
                    // Central Daylight Time.
                    else if (v == "CDT")
                    {
                        timeZoneMinutes = -((05 * 60) + 00);
                    }
                    // Central European Daylight Time.
                    else if (v == "CEDT")
                    {
                        timeZoneMinutes = ((02 * 60) + 00);
                    }
                    // Central European Summer Time.
                    else if (v == "CEST")
                    {
                        timeZoneMinutes = ((02 * 60) + 00);
                    }
                    // Central European Time.
                    else if (v == "CET")
                    {
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Central Standard Time.
                    else if (v == "CST")
                    {
                        timeZoneMinutes = -((06 * 60) + 00);
                    }
                    // Christmas Island Time.
                    else if (v == "CXT")
                    {
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Delta Time Zone (military).
                    else if (v == "D")
                    {
                        timeZoneMinutes = ((04 * 60) + 00);
                    }
                    // Echo Time Zone (military).
                    else if (v == "E")
                    {
                        timeZoneMinutes = ((05 * 60) + 00);
                    }
                    // Eastern Daylight Time.
                    else if (v == "EDT")
                    {
                        timeZoneMinutes = -((04 * 60) + 00);
                    }
                    // Eastern European Daylight Time.
                    else if (v == "EEDT")
                    {
                        timeZoneMinutes = ((03 * 60) + 00);
                    }
                    // Eastern European Summer Time.
                    else if (v == "EEST")
                    {
                        timeZoneMinutes = ((03 * 60) + 00);
                    }
                    // Eastern European Time.
                    else if (v == "EET")
                    {
                        timeZoneMinutes = ((02 * 60) + 00);
                    }
                    // Eastern Standard Time.
                    else if (v == "EST")
                    {
                        timeZoneMinutes = -((05 * 60) + 00);
                    }
                    // Foxtrot Time Zone (military).
                    else if (v == "F")
                    {
                        timeZoneMinutes = (06 * 60 + 00);
                    }
                    // Golf Time Zone (military).
                    else if (v == "G")
                    {
                        timeZoneMinutes = ((07 * 60) + 00);
                    }
                    // Greenwich Mean Time.
                    else if (v == "GMT")
                    {
                        timeZoneMinutes = 0000;
                    }
                    // Hotel Time Zone (military).
                    else if (v == "H")
                    {
                        timeZoneMinutes = ((08 * 60) + 00);
                    }
                    // India Time Zone (military).
                    else if (v == "I")
                    {
                        timeZoneMinutes = ((09 * 60) + 00);
                    }
                    // Irish Summer Time.
                    else if (v == "IST")
                    {
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Kilo Time Zone (millitary).
                    else if (v == "K")
                    {
                        timeZoneMinutes = ((10 * 60) + 00);
                    }
                    // Lima Time Zone (millitary).
                    else if (v == "L")
                    {
                        timeZoneMinutes = ((11 * 60) + 00);
                    }
                    // Mike Time Zone (millitary).
                    else if (v == "M")
                    {
                        timeZoneMinutes = ((12 * 60) + 00);
                    }
                    // Mountain Daylight Time.
                    else if (v == "MDT")
                    {
                        timeZoneMinutes = -((06 * 60) + 00);
                    }
                    // Mountain Standard Time.
                    else if (v == "MST")
                    {
                        timeZoneMinutes = -((07 * 60) + 00);
                    }
                    // November Time Zone (military).
                    else if (v == "N")
                    {
                        timeZoneMinutes = -((01 * 60) + 00);
                    }
                    // Newfoundland Daylight Time.
                    else if (v == "NDT")
                    {
                        timeZoneMinutes = -((02 * 60) + 30);
                    }
                    // Norfolk (Island) Time.
                    else if (v == "NFT")
                    {
                        timeZoneMinutes = ((11 * 60) + 30);
                    }
                    // Newfoundland Standard Time.
                    else if (v == "NST")
                    {
                        timeZoneMinutes = -((03 * 60) + 30);
                    }
                    // Oscar Time Zone (military).
                    else if (v == "O")
                    {
                        timeZoneMinutes = -((02 * 60) + 00);
                    }
                    // Papa Time Zone (military).
                    else if (v == "P")
                    {
                        timeZoneMinutes = -((03 * 60) + 00);
                    }
                    // Pacific Daylight Time.
                    else if (v == "PDT")
                    {
                        timeZoneMinutes = -((07 * 60) + 00);
                    }
                    // Pacific Standard Time.
                    else if (v == "PST")
                    {
                        timeZoneMinutes = -((08 * 60) + 00);
                    }
                    // Quebec Time Zone (military).
                    else if (v == "Q")
                    {
                        timeZoneMinutes = -((04 * 60) + 00);
                    }
                    // Romeo Time Zone (military).
                    else if (v == "R")
                    {
                        timeZoneMinutes = -((05 * 60) + 00);
                    }
                    // Sierra Time Zone (military).
                    else if (v == "S")
                    {
                        timeZoneMinutes = -((06 * 60) + 00);
                    }
                    // Tango Time Zone (military).
                    else if (v == "T")
                    {
                        timeZoneMinutes = -((07 * 60) + 00);
                    }
                    // Uniform Time Zone (military).
                    else if (v == "")
                    {
                        timeZoneMinutes = -((08 * 60) + 00);
                    }
                    // Coordinated Universal Time.
                    else if (v == "UTC")
                    {
                        timeZoneMinutes = 0000;
                    }
                    // Victor Time Zone (militray).
                    else if (v == "V")
                    {
                        timeZoneMinutes = -((09 * 60) + 00);
                    }
                    // Whiskey Time Zone (military).
                    else if (v == "W")
                    {
                        timeZoneMinutes = -((10 * 60) + 00);
                    }
                    // Western European Daylight Time.
                    else if (v == "WEDT")
                    {
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Western European Summer Time.
                    else if (v == "WEST")
                    {
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Western European Time.
                    else if (v == "WET")
                    {
                        timeZoneMinutes = 0000;
                    }
                    // Western Standard Time.
                    else if (v == "WST")
                    {
                        timeZoneMinutes = ((08 * 60) + 00);
                    }
                    // X-ray Time Zone (military).
                    else if (v == "X")
                    {
                        timeZoneMinutes = -((11 * 60) + 00);
                    }
                    // Yankee Time Zone (military).
                    else if (v == "Y")
                    {
                        timeZoneMinutes = -((12 * 60) + 00);
                    }
                    // Zulu Time Zone (military).
                    else if (v == "Z")
                    {
                        timeZoneMinutes = 0000;
                    }

                    #endregion
                }

                // Convert time to UTC and then back to local.
                DateTime timeUTC = new DateTime(year, month, day, hour, minute, second).AddMinutes(-(timeZoneMinutes));
                return(new DateTime(timeUTC.Year, timeUTC.Month, timeUTC.Day, timeUTC.Hour, timeUTC.Minute, timeUTC.Second, DateTimeKind.Utc).ToLocalTime());
            }
            catch (Exception x) {
                string dymmy = x.Message;
                throw new ArgumentException("Argumnet 'value' value '" + value + "' is not valid RFC 822/2822 date-time string.");
            }
        }
        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static Mail_h_AddressList Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            string[] name_value = value.Split(new char[]{':'},2);
            if(name_value.Length != 2){
                throw new ParseException("Invalid header field value '" + value + "'.");
            }

            MIME_Reader r = new MIME_Reader(name_value[1]);

            /* RFC 5322 3.4.
                address         =   mailbox / group

                mailbox         =   name-addr / addr-spec

                name-addr       =   [display-name] angle-addr

                angle-addr      =   [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr

                group           =   display-name ":" [group-list] ";" [CFWS]

                display-name    =   phrase

                mailbox-list    =   (mailbox *("," mailbox)) / obs-mbox-list

                address-list    =   (address *("," address)) / obs-addr-list

                group-list      =   mailbox-list / CFWS / obs-group-list
            */

            Mail_h_AddressList retVal = new Mail_h_AddressList(name_value[0],new Mail_t_AddressList());

            while(true){
                string word = r.QuotedReadToDelimiter(new char[]{',','<',':'});
                // We processed all data.
                if(word == null && r.Available == 0){
                    break;
                }
                // group
                else if(r.Peek(true) == ':'){
                    Mail_t_Group group = new Mail_t_Group(word != null ? MIME_Encoding_EncodedWord.DecodeS(TextUtils.UnQuoteString(word)) : null);
                    // Consume ':'
                    r.Char(true);

                    while(true){
                        word = r.QuotedReadToDelimiter(new char[]{',','<',':',';'});
                        // We processed all data.
                        if(word == null && r.Available == 0){
                            break;
                        }
                        // name-addr
                        else if(r.Peek(true) == '<'){
                            group.Members.Add(new Mail_t_Mailbox(word != null ? MIME_Encoding_EncodedWord.DecodeS(TextUtils.UnQuoteString(word)) : null,r.ReadParenthesized()));
                        }
                        // addr-spec
                        else{
                            group.Members.Add(new Mail_t_Mailbox(null,word));
                        }

                        // We reached at the end of group.
                        if(r.Peek(true) == ';'){
                            r.Char(true);
                            break;
                        }
                        // We have more addresses.
                        if(r.Peek(true) == ','){
                            r.Char(false);
                        }
                    }

                    retVal.m_pAddresses.Add(group);
                }
                // name-addr
                else if(r.Peek(true) == '<'){
                    retVal.m_pAddresses.Add(new Mail_t_Mailbox(word != null ? MIME_Encoding_EncodedWord.DecodeS(TextUtils.UnQuoteString(word)) : null,r.ReadParenthesized()));
                }
                // addr-spec
                else{
                    retVal.m_pAddresses.Add(new Mail_t_Mailbox(null,word));
                }

                // We have more addresses.
                if(r.Peek(true) == ','){
                    r.Char(false);
                }
            }

            retVal.m_ParseValue = value;
            retVal.m_pAddresses.AcceptChanges();

            return retVal;
        }
        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static MIME_h_ContentType Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            // We should not have encoded words here, but some email clients do this, so encoded them if any.
            string valueDecoded = MIME_Encoding_EncodedWord.DecodeS(value);

            MIME_h_ContentType retVal = new MIME_h_ContentType();
            
            string[] name_value = valueDecoded.Split(new char[]{':'},2);
            if(name_value.Length != 2){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }
            
            MIME_Reader r = new MIME_Reader(name_value[1]);
            string type = r.Token();
            if(type == null){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }
            retVal.m_Type = type;

            if(r.Char(false) != '/'){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }

            string subtype = r.Token();
            if(subtype == null){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }
            retVal.m_SubType = subtype;

            if(r.Available > 0){
                retVal.m_pParameters.Parse(r);
            }

            retVal.m_ParseValue = value;
            retVal.m_IsModified = false;

            return retVal;
        }
        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Sender: [email protected]'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static Mail_h_Received Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            string[] name_value = value.Split(new char[]{':'},2);
            if(name_value.Length != 2){
                throw new ParseException("Invalid header field value '" + value + "'.");
            }

            Mail_h_Received retVal = new Mail_h_Received("a","b",DateTime.MinValue);

            MIME_Reader r = new MIME_Reader(name_value[1]);

            while(true){
                string word = r.Word();
                // We processed all data.
                if(word == null && r.Available == 0){
                    break;
                }
                // We have comment, just eat it.
                else if(r.StartsWith("(")){
                    r.ReadParenthesized();
                }
                // We have date-time.
                else if(r.StartsWith(";")){
                    // Eat ';'
                    r.Char(false);

                    retVal.m_Time = MIME_Utils.ParseRfc2822DateTime(r.ToEnd());
                }
                else{
                    // We have some unexpected char like: .,= ... . Just eat it.
                    if(word == null){
                        r.Char(true);
                        continue;
                    }

                    word = word.ToUpperInvariant();

                    if(word == "FROM"){
                        retVal.m_From = r.DotAtom();

                        r.ToFirstChar();
                        if(r.StartsWith("(")){
                            string[] parts = r.ReadParenthesized().Split(' ');
                            if(parts.Length == 1){
                                if(Net_Utils.IsIPAddress(parts[0])){
                                    retVal.m_pFrom_TcpInfo = new Mail_t_TcpInfo(IPAddress.Parse(parts[0]),null);
                                }
                            }
                            else if(parts.Length == 2){
                                if(Net_Utils.IsIPAddress(parts[1])){
                                    retVal.m_pFrom_TcpInfo = new Mail_t_TcpInfo(IPAddress.Parse(parts[1]),parts[0]);
                                }
                            }
                        }
                    }
                    else if(word == "BY"){
                        retVal.m_By = r.DotAtom();

                        r.ToFirstChar();
                        if(r.StartsWith("(")){
                            string[] parts = r.ReadParenthesized().Split(' ');
                            if(parts.Length == 1){
                                if(Net_Utils.IsIPAddress(parts[0])){
                                    retVal.m_pBy_TcpInfo = new Mail_t_TcpInfo(IPAddress.Parse(parts[0]),null);
                                }
                            }
                            else if(parts.Length == 2){
                                if(Net_Utils.IsIPAddress(parts[1])){
                                    retVal.m_pBy_TcpInfo = new Mail_t_TcpInfo(IPAddress.Parse(parts[1]),parts[0]);
                                }
                            }
                        }
                    }
                    else if(word == "VIA"){
                        retVal.m_Via = r.Word();
                    }
                    else if(word == "WITH"){
                        retVal.m_With = r.Word();
                    }
                    else if(word == "ID"){
                        // msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]

                        if(r.StartsWith("<")){
                            retVal.m_ID = r.ReadParenthesized();
                        }
                        else{
                            retVal.m_ID = r.Atom();
                        }
                    }
                    else if(word == "FOR"){
                        r.ToFirstChar();

                        // path / angle-address
                        if(r.StartsWith("<")){
                            retVal.m_For = r.ReadParenthesized();
                        }
                        else{
                            string mailbox = Mail_Utils.SMTP_Mailbox(r);
                            if(mailbox == null){
                                throw new ParseException("Invalid Received: For parameter value '" + r.ToEnd() + "'.");
                            }
                            retVal.m_For = mailbox;
                        }
                    }
                    // Unknown, just eat value.
                    else{
                         r.Word();
                    }
                }
            }

            retVal.m_ParseValue = value;

            return retVal;
        }
        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static MIME_h_ContentDisposition Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            // We should not have encoded words here, but some email clients do this, so encoded them if any.
            string valueDecoded = MIME_Encoding_EncodedWord.DecodeS(value);

            MIME_h_ContentDisposition retVal = new MIME_h_ContentDisposition();
            
            string[] name_value = valueDecoded.Split(new char[]{':'},2);
            if(name_value.Length != 2){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }

            MIME_Reader r = new MIME_Reader(name_value[1]);
            string type = r.Token();
            if(type == null){
                throw new ParseException("Invalid Content-Disposition: header field value '" + value + "'.");
            }
            retVal.m_DispositionType = type.Trim();

            retVal.m_pParameters.Parse(r);

            retVal.m_ParseValue = value;

            return retVal;
        }
        /// <summary>
        /// Parses parameters from the specified reader.
        /// </summary>
        /// <param name="reader">MIME reader.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>reader</b> is null reference.</exception>
        public void Parse(MIME_Reader reader)
        {
            if(reader == null){
                throw new ArgumentNullException("reader");
            }

            /* RFC 2231.
            */

            while(true){
                // End os stream reached.
                if(reader.Peek(true) == -1){
                    break;
                }
                // Next parameter start, just eat that char.
                else if(reader.Peek(true) == ';'){
                    reader.Char(false);
                }
                else{
                    string name = reader.Token();

                    string value = "";
                    // Parameter value specified.
                    if(reader.Peek(true) == '='){
                        reader.Char(false);

                        string v = reader.Word();
                        // Normally value may not be null, but following case: paramName=EOS.
                        if(v != null){
                            value = v;
                        }
                    }

                    // RFC 2231 encoded/splitted parameter.
                    if(name.IndexOf('*') > -1){
                        string[] name_x_no_x = name.Split('*');
                        name = name_x_no_x[0];

                        Encoding      charset     = Encoding.ASCII;
                        StringBuilder valueBuffer = new StringBuilder();
                        // We must have charset'language'value.
                        // Examples:
                        //      URL*=utf-8''test;
                        //      URL*0*=utf-8''"test";
                        if((name_x_no_x.Length == 2 && name_x_no_x[1] == "") || name_x_no_x.Length == 3){
                            string[] charset_language_value = value.Split('\'');
                            charset = Encoding.GetEncoding(charset_language_value[0]);
                            valueBuffer.Append(DecodeExtOctet(charset_language_value[2],charset));
                        }
                        // No encoding, probably just splitted ASCII value.
                        // Example:
                        //     URL*0="value1";
                        //     URL*1="value2";
                        else{
                            valueBuffer.Append(value);
                        }

                        // Read while value continues.
                        while(true){
                            // End os stream reached.
                            if(reader.Peek(true) == -1){
                                break;
                            }
                            // Next parameter start, just eat that char.
                            else if(reader.Peek(true) == ';'){
                                reader.Char(false);
                            }
                            else{
                                if(!reader.StartsWith(name + "*")){
                                    break;
                                }
                                reader.Token();

                                // Parameter value specified.
                                if(reader.Peek(true) == '='){
                                    reader.Char(false);

                                    string v = reader.Word();
                                    // Normally value may not be null, but following case: paramName=EOS.
                                    if(v != null){
                                        valueBuffer.Append(DecodeExtOctet(v,charset));
                                    }
                                }
                            }
                        }

                        this[name] = valueBuffer.ToString();
                    }
                    // Regular parameter.
                    else{
                        this[name] = value;
                    }
                }
            }

            m_IsModified = false;
        }
Exemple #11
0
        /// <summary>
        /// Parses parameters from the specified reader.
        /// </summary>
        /// <param name="reader">MIME reader.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>reader</b> is null reference.</exception>
        public void Parse(MIME_Reader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            /* RFC 2231.
             *  Asterisks ("*") are reused to provide the indicator that language and
             *  character set information is present and encoding is being used. A
             *  single quote ("'") is used to delimit the character set and language
             *  information at the beginning of the parameter value. Percent signs
             *  ("%") are used as the encoding flag, which agrees with RFC 2047.
             *
             *  Character set and language information may be combined with the
             *  parameter continuation mechanism. For example:
             *
             *  Content-Type: application/x-stuff
             *      title*0*=us-ascii'en'This%20is%20even%20more%20
             *      title*1*=%2A%2A%2Afun%2A%2A%2A%20
             *      title*2="isn't it!"
             *
             *  Note that:
             *
             *  (1) Language and character set information only appear at
             *      the beginning of a given parameter value.
             *
             *  (2) Continuations do not provide a facility for using more
             *      than one character set or language in the same
             *      parameter value.
             *
             *  (3) A value presented using multiple continuations may
             *      contain a mixture of encoded and unencoded segments.
             *
             *  (4) The first segment of a continuation MUST be encoded if
             *      language and character set information are given.
             *
             *  (5) If the first segment of a continued parameter value is
             *      encoded the language and character set field delimiters
             *      MUST be present even when the fields are left blank.
             */

            KeyValueCollection <string, _ParameterBuilder> parameters = new KeyValueCollection <string, _ParameterBuilder>();

            // Parse all parameter parts.
            string[] parameterParts = TextUtils.SplitQuotedString(reader.ToEnd(), ';');
            foreach (string part in parameterParts)
            {
                if (string.IsNullOrEmpty(part))
                {
                    continue;
                }

                string[] name_value = part.Trim().Split(new char[] { '=' }, 2);
                string   paramName  = name_value[0].Trim();
                string   paramValue = null;
                if (name_value.Length == 2)
                {
                    paramValue = TextUtils.UnQuoteString(MIME_Utils.UnfoldHeader(name_value[1].Trim()));
                }
                // Valueless parameter.
                //else{

                string[] nameParts = paramName.Split('*');
                int      index     = 0;
                bool     encoded   = nameParts.Length == 3;
                // Get multi value parameter index.
                if (nameParts.Length >= 2)
                {
                    try{
                        index = Convert.ToInt32(nameParts[1]);
                    }
                    catch {
                    }
                }

                // Single value parameter and we already have parameter with such name, skip it.
                if (nameParts.Length < 2 && parameters.ContainsKey(nameParts[0]))
                {
                    continue;
                }

                // Parameter builder doesn't exist for the specified parameter, create it.
                if (!parameters.ContainsKey(nameParts[0]))
                {
                    parameters.Add(nameParts[0], new _ParameterBuilder(nameParts[0]));
                }

                parameters[nameParts[0]].AddPart(index, encoded, paramValue);
            }

            // Build parameters from parts.
            foreach (_ParameterBuilder b in parameters)
            {
                m_pParameters.Add(b.Name, b.GetParamter());
            }

            m_IsModified = false;
        }
Exemple #12
0
        /// <summary>
        /// Returns header field parameters as string.
        /// </summary>
        /// <param name="charset">Charset to use to encode 8-bit characters. Value null means parameters not encoded.</param>
        /// <returns>Returns header field parameters as string.</returns>
        public string ToString(Encoding charset)
        {
            /* RFC 2231.
             *      If parameter conatins 8-bit byte, we need to encode parameter value
             *      If parameter value length bigger than MIME maximum allowed line length,
             *      we need split value.
             */

            if (charset == null)
            {
                charset = Encoding.Default;
            }

            StringBuilder retVal = new StringBuilder();

            foreach (MIME_h_Parameter parameter in this.ToArray())
            {
                if (string.IsNullOrEmpty(parameter.Value))
                {
                    retVal.Append(";\r\n\t" + parameter.Name);
                }
                // We don't need to encode or split value.
                else if ((charset == null || Net_Utils.IsAscii(parameter.Value)) && parameter.Value.Length < 76)
                {
                    retVal.Append(";\r\n\t" + parameter.Name + "=" + TextUtils.QuoteString(parameter.Value));
                }
                // Use RFC 2047 to encode parameter.
                else if (m_EncodeRfc2047)
                {
                    retVal.Append(";\r\n\t" + parameter.Name + "=" + TextUtils.QuoteString(MIME_Encoding_EncodedWord.EncodeS(MIME_EncodedWordEncoding.B, Encoding.UTF8, false, parameter.Value)));
                }
                // We need to RFC 2231 encode/split value.
                else
                {
                    byte[] byteValue = charset.GetBytes(parameter.Value);

                    List <string> values = new List <string>();
                    // Do encoding/splitting.
                    int    offset    = 0;
                    char[] valueBuff = new char[50];
                    foreach (byte b in byteValue)
                    {
                        // We need split value as RFC 2231 says.
                        if (offset >= (50 - 3))
                        {
                            values.Add(new string(valueBuff, 0, offset));
                            offset = 0;
                        }

                        // Normal char, we don't need to encode.
                        if (MIME_Reader.IsAttributeChar((char)b))
                        {
                            valueBuff[offset++] = (char)b;
                        }
                        // We need to encode byte as %X2.
                        else
                        {
                            valueBuff[offset++] = '%';
                            valueBuff[offset++] = (b >> 4).ToString("X")[0];
                            valueBuff[offset++] = (b & 0xF).ToString("X")[0];
                        }
                    }
                    // Add pending buffer value.
                    if (offset > 0)
                    {
                        values.Add(new string(valueBuff, 0, offset));
                    }

                    for (int i = 0; i < values.Count; i++)
                    {
                        // Only fist value entry has charset and language info.
                        if (charset != null && i == 0)
                        {
                            retVal.Append(";\r\n\t" + parameter.Name + "*" + i.ToString() + "*=" + charset.WebName + "''" + values[i]);
                        }
                        else
                        {
                            retVal.Append(";\r\n\t" + parameter.Name + "*" + i.ToString() + "*=" + values[i]);
                        }
                    }
                }
            }

            return(retVal.ToString());
        }
        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static MIME_h_ContentDisposition Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            MIME_h_ContentDisposition retVal = new MIME_h_ContentDisposition();

            string[] name_value = value.Split(new char[]{':'},2);
            if(name_value.Length != 2){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }

            MIME_Reader r = new MIME_Reader(name_value[1]);
            string type = r.Token();
            if(type == null){
                throw new ParseException("Invalid Content-Disposition: header field value '" + value + "'.");
            }
            retVal.m_DispositionType = type;

            retVal.m_pParameters.Parse(r);

            retVal.m_ParseValue = value;

            return retVal;
        }
        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static MIME_h_ContentType Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            MIME_h_ContentType retVal = new MIME_h_ContentType();

            string[] name_value = value.Split(new char[]{':'},2);
            if(name_value.Length != 2){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }

            MIME_Reader r = new MIME_Reader(name_value[1]);
            string type = r.Token();
            if(type == null){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }
            retVal.m_Type = type;

            if(r.Char(false) != '/'){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }

            string subtype = r.Token();
            if(subtype == null){
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }
            retVal.m_SubType = subtype;

            retVal.m_pParameters.Parse(r);

            retVal.m_ParseValue = value;
            retVal.m_IsModified = false;

            return retVal;
        }
Exemple #15
0
        /// <summary>
        /// Parses RFC 2822 date-time from the specified value.
        /// </summary>
        /// <param name="value">RFC 2822 date-time string value.</param>
        /// <returns>Returns parsed datetime value.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public static DateTime ParseRfc2822DateTime(string value)
        {
            if(value == null){
                throw new ArgumentNullException(value);
            }

            /* RFC 2822 3.
             *      date-time       =       [ day-of-week "," ] date FWS time [CFWS]
             *      day-of-week     =       ([FWS] day-name) / obs-day-of-week
             *      day-name        =       "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
             *      date            =       day month year
             *      year            =       4*DIGIT / obs-year
             *      month           =       (FWS month-name FWS) / obs-month
             *      month-name      =       "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
             *      day             =       ([FWS] 1*2DIGIT) / obs-day
             *      time            =       time-of-day FWS zone
             *      time-of-day     =       hour ":" minute [ ":" second ]
             *      hour            =       2DIGIT / obs-hour
             *      minute          =       2DIGIT / obs-minute
             *      second          =       2DIGIT / obs-second
             *      zone            =       (( "+" / "-" ) 4DIGIT) / obs-zone
             *
             *      The date and time-of-day SHOULD express local time.
            */

            try{
                MIME_Reader r = new MIME_Reader(value);
                string v = r.Atom();
                // Skip optional [ day-of-week "," ] and read "day".
                if(v.Length == 3){
                    r.Char(true);
                    v = r.Atom();
                }
                int day    = Convert.ToInt32(v);
                v = r.Atom().ToLower();
                int month  = 1;
                if(v == "jan"){
                    month  = 1;
                }
                else if(v == "feb"){
                    month  = 2;
                }
                else if(v == "mar"){
                    month  = 3;
                }
                else if(v == "apr"){
                    month  = 4;
                }
                else if(v == "may"){
                    month  = 5;
                }
                else if(v == "jun"){
                    month  = 6;
                }
                else if(v == "jul"){
                    month  = 7;
                }
                else if(v == "aug"){
                    month  = 8;
                }
                else if(v == "sep"){
                    month  = 9;
                }
                else if(v == "oct"){
                    month  = 10;
                }
                else if(v == "nov"){
                    month  = 11;
                }
                else if(v == "dec"){
                    month  = 12;
                }
                else{
                    throw new ArgumentException("Invalid month-name value '" + value + "'.");
                }
                int year   = Convert.ToInt32(r.Atom());
                int hour   = Convert.ToInt32(r.Atom());
                r.Char(true);
                int minute = Convert.ToInt32(r.Atom());
                int second = 0;
                // We have optional "second".
                if(r.Peek(true) == ':'){
                    r.Char(true);
                    second = Convert.ToInt32(r.Atom());
                }
                int timeZoneMinutes = 0;
                v = r.Atom();
                // We have RFC 2822 date. For example: +2000.
                if(v[0] == '+' || v[0] == '-'){
                    if(v[0] == '+'){
                        timeZoneMinutes = (Convert.ToInt32(v.Substring(1,2)) * 60 + Convert.ToInt32(v.Substring(3,2)));
                    }
                    else{
                        timeZoneMinutes = -(Convert.ToInt32(v.Substring(1,2)) * 60 + Convert.ToInt32(v.Substring(3,2)));
                    }
                }
                // We have RFC 822 date with abbrevated time zone name. For example: GMT.
                else{
                    v = v.ToUpper();

                    #region time zones

                    // Alpha Time Zone (military).
                    if(v == "A"){
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Australian Central Daylight Time.
                    else if(v == "ACDT"){
                        timeZoneMinutes = ((10 * 60) + 30);
                    }
                    // Australian Central Standard Time.
                    else if(v == "ACST"){
                        timeZoneMinutes = ((09 * 60) + 30);
                    }
                    // Atlantic Daylight Time.
                    else if(v == "ADT"){
                        timeZoneMinutes = -((03 * 60) + 00);
                    }
                    // Australian Eastern Daylight Time.
                    else if(v == "AEDT"){
                        timeZoneMinutes = ((11 * 60) + 00);
                    }
                    // Australian Eastern Standard Time.
                    else if(v == "AEST"){
                        timeZoneMinutes = ((10 * 60) + 00);
                    }
                    // Alaska Daylight Time.
                    else if(v == "AKDT"){
                        timeZoneMinutes = -((08 * 60) + 00);
                    }
                    // Alaska Standard Time.
                    else if(v == "AKST"){
                        timeZoneMinutes = -((09 * 60) + 00);
                    }
                    // Atlantic Standard Time.
                    else if(v == "AST"){
                        timeZoneMinutes = -((04 * 60) + 00);
                    }
                    // Australian Western Daylight Time.
                    else if(v == "AWDT"){
                        timeZoneMinutes = ((09 * 60) + 00);
                    }
                    // Australian Western Standard Time.
                    else if(v == "AWST"){
                        timeZoneMinutes = ((08 * 60) + 00);
                    }
                    // Bravo Time Zone (millitary).
                    else if(v == "B"){
                        timeZoneMinutes = ((02 * 60) + 00);
                    }
                    // British Summer Time.
                    else if(v == "BST"){
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Charlie Time Zone (millitary).
                    else if(v == "C"){
                        timeZoneMinutes = ((03 * 60) + 00);
                    }
                    // Central Daylight Time.
                    else if(v == "CDT"){
                        timeZoneMinutes = -((05 * 60) + 00);
                    }
                    // Central European Daylight Time.
                    else if(v == "CEDT"){
                        timeZoneMinutes = ((02 * 60) + 00);
                    }
                    // Central European Summer Time.
                    else if(v == "CEST"){
                        timeZoneMinutes = ((02 * 60) + 00);
                    }
                    // Central European Time.
                    else if(v == "CET"){
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Central Standard Time.
                    else if(v == "CST"){
                        timeZoneMinutes = -((06 * 60) + 00);
                    }
                    // Christmas Island Time.
                    else if(v == "CXT"){
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Delta Time Zone (military).
                    else if(v == "D"){
                        timeZoneMinutes = ((04 * 60) + 00);
                    }
                    // Echo Time Zone (military).
                    else if(v == "E"){
                        timeZoneMinutes = ((05 * 60) + 00);
                    }
                    // Eastern Daylight Time.
                    else if(v == "EDT"){
                        timeZoneMinutes = -((04 * 60) + 00);
                    }
                    // Eastern European Daylight Time.
                    else if(v == "EEDT"){
                        timeZoneMinutes = ((03 * 60) + 00);
                    }
                    // Eastern European Summer Time.
                    else if(v == "EEST"){
                        timeZoneMinutes = ((03 * 60) + 00);
                    }
                    // Eastern European Time.
                    else if(v == "EET"){
                        timeZoneMinutes = ((02 * 60) + 00);
                    }
                    // Eastern Standard Time.
                    else if(v == "EST"){
                        timeZoneMinutes = -((05 * 60) + 00);
                    }
                    // Foxtrot Time Zone (military).
                    else if(v == "F"){
                        timeZoneMinutes = (06 * 60 + 00);
                    }
                    // Golf Time Zone (military).
                    else if(v == "G"){
                        timeZoneMinutes = ((07 * 60) + 00);
                    }
                    // Greenwich Mean Time.
                    else if(v == "GMT"){
                        timeZoneMinutes = 0000;
                    }
                    // Hotel Time Zone (military).
                    else if(v == "H"){
                        timeZoneMinutes = ((08 * 60) + 00);
                    }
                    // India Time Zone (military).
                    else if(v == "I"){
                        timeZoneMinutes = ((09 * 60) + 00);
                    }
                    // Irish Summer Time.
                    else if(v == "IST"){
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Kilo Time Zone (millitary).
                    else if(v == "K"){
                        timeZoneMinutes = ((10 * 60) + 00);
                    }
                    // Lima Time Zone (millitary).
                    else if(v == "L"){
                        timeZoneMinutes = ((11 * 60) + 00);
                    }
                    // Mike Time Zone (millitary).
                    else if(v == "M"){
                        timeZoneMinutes = ((12 * 60) + 00);
                    }
                    // Mountain Daylight Time.
                    else if(v == "MDT"){
                        timeZoneMinutes = -((06 * 60) + 00);
                    }
                    // Mountain Standard Time.
                    else if(v == "MST"){
                        timeZoneMinutes = -((07 * 60) + 00);
                    }
                    // November Time Zone (military).
                    else if(v == "N"){
                        timeZoneMinutes = -((01 * 60) + 00);
                    }
                    // Newfoundland Daylight Time.
                    else if(v == "NDT"){
                        timeZoneMinutes = -((02 * 60) + 30);
                    }
                    // Norfolk (Island) Time.
                    else if(v == "NFT"){
                        timeZoneMinutes = ((11 * 60) + 30);
                    }
                    // Newfoundland Standard Time.
                    else if(v == "NST"){
                        timeZoneMinutes = -((03 * 60) + 30);
                    }
                    // Oscar Time Zone (military).
                    else if(v == "O"){
                        timeZoneMinutes = -((02 * 60) + 00);
                    }
                    // Papa Time Zone (military).
                    else if(v == "P"){
                        timeZoneMinutes = -((03 * 60) + 00);
                    }
                    // Pacific Daylight Time.
                    else if(v == "PDT"){
                        timeZoneMinutes = -((07 * 60) + 00);
                    }
                    // Pacific Standard Time.
                    else if(v == "PST"){
                        timeZoneMinutes = -((08 * 60) + 00);
                    }
                    // Quebec Time Zone (military).
                    else if(v == "Q"){
                        timeZoneMinutes = -((04 * 60) + 00);
                    }
                    // Romeo Time Zone (military).
                    else if(v == "R"){
                        timeZoneMinutes = -((05 * 60) + 00);
                    }
                    // Sierra Time Zone (military).
                    else if(v == "S"){
                        timeZoneMinutes = -((06 * 60) + 00);
                    }
                    // Tango Time Zone (military).
                    else if(v == "T"){
                        timeZoneMinutes = -((07 * 60) + 00);
                    }
                    // Uniform Time Zone (military).
                    else if(v == ""){
                        timeZoneMinutes = -((08 * 60) + 00);
                    }
                    // Coordinated Universal Time.
                    else if(v == "UTC"){
                        timeZoneMinutes = 0000;
                    }
                    // Victor Time Zone (militray).
                    else if(v == "V"){
                        timeZoneMinutes = -((09 * 60) + 00);
                    }
                    // Whiskey Time Zone (military).
                    else if(v == "W"){
                        timeZoneMinutes = -((10 * 60) + 00);
                    }
                    // Western European Daylight Time.
                    else if(v == "WEDT"){
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Western European Summer Time.
                    else if(v == "WEST"){
                        timeZoneMinutes = ((01 * 60) + 00);
                    }
                    // Western European Time.
                    else if(v == "WET"){
                        timeZoneMinutes = 0000;
                    }
                    // Western Standard Time.
                    else if(v == "WST"){
                        timeZoneMinutes = ((08 * 60) + 00);
                    }
                    // X-ray Time Zone (military).
                    else if(v == "X"){
                        timeZoneMinutes = -((11 * 60) + 00);
                    }
                    // Yankee Time Zone (military).
                    else if(v == "Y"){
                        timeZoneMinutes = -((12 * 60) + 00);
                    }
                    // Zulu Time Zone (military).
                    else if(v == "Z"){
                        timeZoneMinutes = 0000;
                    }

                    #endregion
                }

                // Convert time to UTC and then back to local.
                DateTime timeUTC = new DateTime(year,month,day,hour,minute,second).AddMinutes(-(timeZoneMinutes));
                return new DateTime(timeUTC.Year,timeUTC.Month,timeUTC.Day,timeUTC.Hour,timeUTC.Minute,timeUTC.Second,DateTimeKind.Utc).ToLocalTime();
            }
            catch(Exception x){
                string dymmy = x.Message;
                throw new ArgumentException("Argumnet 'value' value '" + value + "' is not valid RFC 822/2822 date-time string.");
            }
        }
        /// <summary>
        /// Parses parameters from the specified reader.
        /// </summary>
        /// <param name="reader">MIME reader.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>reader</b> is null reference.</exception>
        public void Parse(MIME_Reader reader)
        {
            if(reader == null){
                throw new ArgumentNullException("reader");
            }

            /* RFC 2231.
                Asterisks ("*") are reused to provide the indicator that language and
                character set information is present and encoding is being used. A
                single quote ("'") is used to delimit the character set and language
                information at the beginning of the parameter value. Percent signs
                ("%") are used as the encoding flag, which agrees with RFC 2047.

                Character set and language information may be combined with the
                parameter continuation mechanism. For example:

                Content-Type: application/x-stuff
                    title*0*=us-ascii'en'This%20is%20even%20more%20
                    title*1*=%2A%2A%2Afun%2A%2A%2A%20
                    title*2="isn't it!"

                Note that:

                (1) Language and character set information only appear at
                    the beginning of a given parameter value.

                (2) Continuations do not provide a facility for using more
                    than one character set or language in the same
                    parameter value.

                (3) A value presented using multiple continuations may
                    contain a mixture of encoded and unencoded segments.

                (4) The first segment of a continuation MUST be encoded if
                    language and character set information are given.

                (5) If the first segment of a continued parameter value is
                    encoded the language and character set field delimiters
                    MUST be present even when the fields are left blank.
            */

            KeyValueCollection<string,_ParameterBuilder> parameters = new KeyValueCollection<string,_ParameterBuilder>();

            // Parse all parameter parts.
            string[] parameterParts = TextUtils.SplitQuotedString(reader.ToEnd(),';');
            foreach(string part in parameterParts){
                if(string.IsNullOrEmpty(part)){
                    continue;
                }

                string[] name_value = part.Trim().Split(new char[]{'='},2);
                string   paramName  = name_value[0].Trim();
                string   paramValue = null;
                if(name_value.Length == 2){
                    paramValue = TextUtils.UnQuoteString(name_value[1].Trim());
                }
                // Valueless parameter.
                //else{

                string[] nameParts = paramName.Split('*');
                int      index     = 0;
                bool     encoded   = nameParts.Length == 3;
                // Get multi value parameter index.
                if(nameParts.Length >= 2){
                    try{
                        index = Convert.ToInt32(nameParts[1]);
                    }
                    catch{
                    }
                }

                // Single value parameter and we already have parameter with such name, skip it.
                if(nameParts.Length < 2 && parameters.ContainsKey(nameParts[0])){
                    continue;
                }

                // Parameter builder doesn't exist for the specified parameter, create it.
                if(!parameters.ContainsKey(nameParts[0])){
                    parameters.Add(nameParts[0],new _ParameterBuilder(nameParts[0]));
                }

                parameters[nameParts[0]].AddPart(index,encoded,paramValue);
            }

            // Build parameters from parts.
            foreach(_ParameterBuilder b in parameters){
                m_pParameters.Add(b.Name,b.GetParamter());
            }

            m_IsModified = false;
        }
        /// <summary>
        /// Parses parameters from the specified reader.
        /// </summary>
        /// <param name="reader">MIME reader.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>reader</b> is null reference.</exception>
        public void Parse(MIME_Reader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            /* RFC 2231.
             */

            while (true)
            {
                // End os stream reached.
                if (reader.Peek(true) == -1)
                {
                    break;
                }
                // Next parameter start, just eat that char.
                else if (reader.Peek(true) == ';')
                {
                    reader.Char(false);
                }
                else
                {
                    string name = reader.Token();

                    string value = "";
                    // Parameter value specified.
                    if (reader.Peek(true) == '=')
                    {
                        reader.Char(false);

                        string v = reader.Word();
                        // Normally value may not be null, but following case: paramName=EOS.
                        if (v != null)
                        {
                            value = v;
                        }
                    }

                    // RFC 2231 encoded/splitted parameter.
                    if (name.IndexOf('*') > -1)
                    {
                        string[] name_x_no_x = name.Split('*');
                        name = name_x_no_x[0];

                        Encoding      charset     = Encoding.ASCII;
                        StringBuilder valueBuffer = new StringBuilder();
                        // We must have charset'language'value.
                        // Examples:
                        //      URL*=utf-8''test;
                        //      URL*0*=utf-8''"test";
                        if ((name_x_no_x.Length == 2 && name_x_no_x[1] == "") || name_x_no_x.Length == 3)
                        {
                            string[] charset_language_value = value.Split('\'');
                            charset = Encoding.GetEncoding(charset_language_value[0]);
                            valueBuffer.Append(DecodeExtOctet(charset_language_value[2], charset));
                        }
                        // No encoding, probably just splitted ASCII value.
                        // Example:
                        //     URL*0="value1";
                        //     URL*1="value2";
                        else
                        {
                            valueBuffer.Append(value);
                        }

                        // Read while value continues.
                        while (true)
                        {
                            // End os stream reached.
                            if (reader.Peek(true) == -1)
                            {
                                break;
                            }
                            // Next parameter start, just eat that char.
                            else if (reader.Peek(true) == ';')
                            {
                                reader.Char(false);
                            }
                            else
                            {
                                if (!reader.StartsWith(name + "*"))
                                {
                                    break;
                                }
                                reader.Token();

                                // Parameter value specified.
                                if (reader.Peek(true) == '=')
                                {
                                    reader.Char(false);

                                    string v = reader.Word();
                                    // Normally value may not be null, but following case: paramName=EOS.
                                    if (v != null)
                                    {
                                        valueBuffer.Append(DecodeExtOctet(v, charset));
                                    }
                                }
                            }
                        }

                        this[name] = valueBuffer.ToString();
                    }
                    // Regular parameter.
                    else
                    {
                        this[name] = value;
                    }
                }
            }

            m_IsModified = false;
        }