/// <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 or unknown-data. else if(r.StartsWith(";")){ // Eat ';' r.Char(false); try{ retVal.m_Time = MIME_Utils.ParseRfc2822DateTime(r.QuotedReadToDelimiter(new char[]{';'})); } catch{ // We hane some unknown data, skip it. } } 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){ string ip = parts[1].Trim(); if (ip.StartsWith("[")) ip = ip.Substring(1); if (ip.EndsWith("]")) ip = ip.Substring(0, ip.Length - 1); if(Net_Utils.IsIPAddress(ip)){ retVal.m_pFrom_TcpInfo = new Mail_t_TcpInfo(IPAddress.Parse(ip),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: 'Return-Path: <[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_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; }
/// <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; }