/// <summary>
 /// Log a new mime exception and then throw it.
 /// </summary>
 /// <param name="message"></param>
 /// <param name="callingType"></param>
 public static void ThrowAndLog(string message, Type callingType)
 {
     var err = new MimeException(message);
     ILog logger = LogManager.GetLogger(callingType);
     logger.Error(err);
     throw err;
 }
        /// <summary>
        /// Parse a line in the form name: value
        /// </summary>
        /// <param name="line">The line to parse.</param>
        /// <param name="name">(out) the name.</param>
        /// <param name="val">(out) the value.</param>
        /// <exception cref="MimeException">If the header param is not in the expected format.</exception>
        public override void ParseLine(string line, out string name, out string val)
        {
            string [] parts = line.Trim().Split(':');
            if (parts.Length < 2) {
                var err = new MimeException(string.Format(Messages.MimeHeader_ParseLine_HeaderIsNotInCorrectForm, line));
                logger.Error(err);
                throw err;
            }
            name = parts[0].Trim();
            //Attempt to parse
            if (parts.Length > 2)
            {
                parts = new string[2];
                parts[0] = name;
                int firstColon = line.IndexOf(":");
                parts[1] = line.Substring(firstColon + 1, line.Length - (firstColon + 1));
            }

            string [] valParts = parts[1].Split(';');
            if (valParts.Length > 1)
            {
                val = valParts[0];

                for (int parmIndex = 1; parmIndex < valParts.Length; parmIndex++)
                {
                    _parameters.Add(new MimeHeaderParam(valParts[parmIndex]));
                }
            }
            else
            {
                val = parts[1];
            }
        }
 /// <summary>
 /// Add a mime param header.
 /// </summary>
 /// <param name="header">The header to add.</param>
 /// <returns>The newly added header.</returns>
 public MimeHeaderParam Add(MimeHeaderParam header)
 {
     if (_headers.Contains(header.Name)) {
         var err = new MimeException(string.Format(Messages.MimeHeaderParamCollection_Add_HeaderParamWithNameExists, header));
         logger.Error(err);
         throw err;
     }
     _listHeaders.Add(header);
     _headers.Add(header.Name, header);
     return header;
 }
        /// <summary>
        /// Parse a line in the form name = value
        /// </summary>
        /// <param name="line">The line to parse.</param>
        /// <param name="name">(out) the name.</param>
        /// <param name="val">(out) the value.</param>
        /// <exception cref="MimeException">If the header param is not in the expected format.</exception>
        public override void ParseLine(string line, out string name, out string val)
        {
            line = line.Trim();
            if (line.IndexOf("=") == -1 ) {
                var err = new MimeException(string.Format("Header Parameter is not in the expected name=value form.  The raw data is {0}", line));
                logger.Error(err);
                throw err;
            }

            //Note handle
            //if val is in the encoded form such as "SeparationTestDoublePage%E2%82%AC_1.pdf"
            Regex r;
            Match m;
            name = "";
            val = "";

            //support RFC2231 standard
            /*
            an asterisk at the end of a parameter name acts as an
            indicator that character set and language information may appear at
            the beginning of the parameter value. A single quote is used to
            separate the character set, language, and actual value information in
            the parameter value string, and an percent sign is used to flag
            octets encoded in hexadecimal.  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!"
            */

            //TODO: RFC2231 supports the parameter continuation mechanism
            //We don't implement this mechanism yet.
            //We only read it in and write it out.

            //For example, filename*=<charset>'<language>'percentencodedstring --> take the percentencodedstring, decode the %xx and use this as filename;
            //don't care about <language> (could be empty), <charset> could be utf-8 or us-ascii
            r = new Regex(@"^(?<name>.+)(\*(?<index>\d+))?\*=(?<charset>.*)'(?<language>.*)'(?<value>.*)");
            m = r.Match(line);
            if (m.Success)
            {
                name = m.Groups["name"].Value;
                if (m.Groups["index"] != null && m.Groups["index"].Value.Length > 0)
                    _section = Convert.ToInt32(m.Groups["index"].Value);
                _charset = m.Groups["charset"].Value.ToLower();
                _language = m.Groups["language"].Value.ToLower();
                //Check if the charset is present
                //support only utf-8 or us-ascii at this time
                if (_charset.Length > 0 && (_charset.Equals("utf-8") || _charset.Equals("utf-7") || _charset.Equals("us-ascii")))
                {
                    val = System.Web.HttpUtility.UrlDecode(m.Groups["value"].Value,
                        (_charset.Equals("utf-8"))?System.Text.Encoding.UTF8:((_charset.Equals("utf-8"))?System.Text.Encoding.UTF8:System.Text.Encoding.ASCII));
                }
                else
                {
                    val = m.Groups["value"].Value;
                }
            }
            else
            {
                //filename=string    (string not between double quotes)  --> just take this string for the filename
                int splitPos;
                int lineLength = line.Length;
                splitPos = line.IndexOf("=");
                if (splitPos > 0)
                {
                    name = line.Substring(0, splitPos);
                    val = line.Substring(splitPos + 1);
                }

                //Refer to RFC2822 for quoted-string
                //filename="quotestring"  --> take the quotestring and replace any \CHAR by CHAR, use this for the filename
                //TODO: Resolve the issue.  If \" is present in the string, we can read ".  However, later on in the code, Regex _findParen in MimeHeaderBase takes out the "
                if (val.Length >= 2 && val.StartsWith("\"") && val.EndsWith("\""))
                {
                    val = val.Substring(1, val.Length - 2);
                    //Check for \CHAR
                    int bslashPos;
                    int startingIndex = 0;
                    do
                    {
                        bslashPos = val.IndexOf("\\", startingIndex);
                        if (bslashPos >= 0)
                        {
                            //take out the \
                            val = val.Substring(0, bslashPos) + val.Substring(bslashPos + 1, val.Length - (bslashPos + 1));
                            startingIndex = bslashPos + 1;
                        }
                    }while(bslashPos >= 0 && startingIndex < val.Length);
                }
            }
        }
        /// <summary>
        /// Add a mime param header at a specific position.
        /// </summary>
        /// <param name="index">the zero-based position to add.</param>
        /// <param name="header">The header to add.</param>
        /// <returns>The newly added header.</returns>
        public MimeHeaderParam AddAt(int index, MimeHeaderParam header)
        {
            if (_headers.Contains(header.Name)) {
                var err = new MimeException(string.Format(Messages.MimeHeaderParamCollection_Add_HeaderParamWithNameExists, header));
                logger.Error(err);
                throw err;
            }
            if (index < 0) {
                var err = new MimeException(string.Format(Messages.MimeHeaderParamCollection_AddAt_InvalidPositionForMiimeHeader, index));
                logger.Error(err);
                throw err;
            }
            if (index >= _listHeaders.Count)
            {
                return Add(header);
            }

            //Copy the last item
            _listHeaders.Add((MimeHeaderParam)_listHeaders[_listHeaders.Count - 1]);

            //Move other items
            if (_listHeaders.Count > 2 && index <= _listHeaders.Count - 2)
            {
                for(int i = _listHeaders.Count - 2; i >= index; i--)
                {
                    _listHeaders[i + 1] = (MimeHeaderParam)_listHeaders[i];
                }
            }

            //Save this item at the specific index
            _listHeaders[index] = header;
            _headers.Add(header.Name, header);
            return header;
        }