コード例 #1
0
 /// <summary>
 /// Checks if specified message matches to specified criteria.
 /// </summary>
 /// <param name="matchExpression">Match expression.</param>
 /// <param name="mailFrom">SMTP MAIL FROM: command email value.</param>
 /// <param name="rcptTo">SMTP RCPT TO: command email values.</param>
 /// <param name="smtpSession">SMTP current session.</param>
 /// <param name="mime">Message to match.</param>
 /// <param name="messageSize">Message size in bytes.</param>
 /// <returns>Returns true if message matches to specified criteria.</returns>
 public bool Match(string matchExpression, string mailFrom, string[] rcptTo, SMTP_Session smtpSession, Mail_Message mime, int messageSize)
 {
     LumiSoft.Net.StringReader r = new LumiSoft.Net.StringReader(matchExpression);
     return(Match(false, r, mailFrom, rcptTo, smtpSession, mime, messageSize));
 }
コード例 #2
0
        /// <summary>
        /// Checks if specified message matches to specified criteria.
        /// </summary>
        /// <param name="syntaxCheckOnly">Specifies if syntax check is only done. If true no matching is done.</param>
        /// <param name="r">Match expression reader what contains match expression.</param>
        /// <param name="mailFrom">SMTP MAIL FROM: command email value.</param>
        /// <param name="rcptTo">SMTP RCPT TO: command email values.</param>
        /// <param name="smtpSession">SMTP current session.</param>
        /// <param name="mime">Message to match.</param>
        /// <param name="messageSize">Message size in bytes.</param>
        /// <returns>Returns true if message matches to specified criteria.</returns>
        private bool Match(bool syntaxCheckOnly, LumiSoft.Net.StringReader r, string mailFrom, string[] rcptTo, SMTP_Session smtpSession, Mail_Message mime, int messageSize)
        {
            /* Possible keywords order
             *  At first there can be NOT,parethesized or matcher
             *      After NOT, parethesized or matcher
             *      After matcher, AND or OR
             *      After OR, NOT,parethesized or matcher
             *      After AND, NOT,parethesized or matcher
             *      After parethesized, NOT or matcher
             */

            PossibleClauseItem possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.NOT | PossibleClauseItem.Matcher;
            bool lastMatchValue = false;

            // Empty string passed
            r.ReadToFirstChar();
            if (r.Available == 0)
            {
                throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected !");
            }

            // Parse while there are expressions or get error
            while (r.Available > 0)
            {
                r.ReadToFirstChar();

                // Syntax check must consider that there is alwas match !!!
                if (syntaxCheckOnly)
                {
                    lastMatchValue = true;
                }

                #region () Groupped matchers

                // () Groupped matchers
                if (r.StartsWith("("))
                {
                    lastMatchValue = Match(syntaxCheckOnly, new LumiSoft.Net.StringReader(r.ReadParenthesized()), mailFrom, rcptTo, smtpSession, mime, messageSize);

                    possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.Matcher | PossibleClauseItem.NOT;
                }

                #endregion

                #region AND clause

                // AND clause
                else if (r.StartsWith("and", false))
                {
                    // See if AND allowed
                    if ((possibleClauseItems & PossibleClauseItem.AND) == 0)
                    {
                        throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected !");
                    }

                    // Last match value is false, no need to check next conditions
                    if (!lastMatchValue)
                    {
                        return(false);
                    }

                    // Remove AND
                    r.ReadWord();
                    r.ReadToFirstChar();

                    lastMatchValue = Match(syntaxCheckOnly, r, mailFrom, rcptTo, smtpSession, mime, messageSize);

                    possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.Matcher | PossibleClauseItem.NOT;
                }

                #endregion

                #region OR clause

                // OR clause
                else if (r.StartsWith("or", false))
                {
                    // See if OR allowed
                    if ((possibleClauseItems & PossibleClauseItem.OR) == 0)
                    {
                        throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected !");
                    }

                    // Remove OR
                    r.ReadWord();
                    r.ReadToFirstChar();

                    // Last match value is false, then we need to check next condition.
                    // Otherwise OR is matched already, just eat next matcher.
                    if (lastMatchValue)
                    {
                        // Skip next clause
                        Match(syntaxCheckOnly, r, mailFrom, rcptTo, smtpSession, mime, messageSize);
                    }
                    else
                    {
                        lastMatchValue = Match(syntaxCheckOnly, r, mailFrom, rcptTo, smtpSession, mime, messageSize);
                    }

                    possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.Matcher | PossibleClauseItem.NOT;
                }

                #endregion

                #region NOT clause

                // NOT clause
                else if (r.StartsWith("not", false))
                {
                    // See if NOT allowed
                    if ((possibleClauseItems & PossibleClauseItem.NOT) == 0)
                    {
                        throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected !");
                    }

                    // Remove NOT
                    r.ReadWord();
                    r.ReadToFirstChar();

                    // Just reverse match result value
                    lastMatchValue = !Match(syntaxCheckOnly, r, mailFrom, rcptTo, smtpSession, mime, messageSize);

                    possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.Matcher;
                }

                #endregion

                else
                {
                    // See if matcher allowed
                    if ((possibleClauseItems & PossibleClauseItem.Matcher) == 0)
                    {
                        throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected ! \r\n\r\n Near: '" + r.OriginalString.Substring(0, r.Position) + "'");
                    }

                    // 1) matchsource
                    // 2) keyword

                    // Read match source
                    string word = r.ReadWord();
                    if (word == null)
                    {
                        throw new Exception("Invalid syntax: matcher is missing !");
                    }
                    word = word.ToLower();
                    string[] matchSourceValues = new string[] {};


                    #region smtp.mail_from

                    // SMTP command MAIL FROM: value.
                    //  smtp.mail_from
                    if (word == "smtp.mail_from")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { mailFrom };
                        }
                    }

                    #endregion

                    #region smtp.rcpt_to

                    // SMTP command RCPT TO: values.
                    //  smtp.mail_to
                    else if (word == "smtp.rcpt_to")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = rcptTo;
                        }
                    }

                    #endregion

                    #region smtp.ehlo

                    // SMTP command EHLO/HELO: value.
                    //  smtp.ehlo
                    else if (word == "smtp.ehlo")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { smtpSession.EhloHost };
                        }
                    }

                    #endregion

                    #region smtp.authenticated

                    // Specifies if SMTP session is authenticated.
                    //  smtp.authenticated
                    else if (word == "smtp.authenticated")
                    {
                        if (!syntaxCheckOnly)
                        {
                            if (smtpSession != null)
                            {
                                matchSourceValues = new string[] { smtpSession.IsAuthenticated.ToString() };
                            }
                        }
                    }

                    #endregion

                    #region smtp.user

                    // SMTP authenticated user name. Empy string "" if not authenticated.
                    //  smtp.user
                    else if (word == "smtp.user")
                    {
                        if (!syntaxCheckOnly)
                        {
                            if (smtpSession != null && smtpSession.AuthenticatedUserIdentity != null)
                            {
                                matchSourceValues = new string[] { smtpSession.AuthenticatedUserIdentity.Name };
                            }
                        }
                    }

                    #endregion

                    #region smtp.remote_ip

                    // SMTP session connected client IP address.
                    //  smtp.remote_ip
                    else if (word == "smtp.remote_ip")
                    {
                        if (!syntaxCheckOnly)
                        {
                            if (smtpSession != null)
                            {
                                matchSourceValues = new string[] { smtpSession.RemoteEndPoint.Address.ToString() };
                            }
                        }
                    }

                    #endregion


                    #region message.size

                    // Message size in bytes.
                    //  message.size
                    else if (word == "message.size")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { messageSize.ToString() };
                        }
                    }

                    #endregion

                    #region message.header <SP> "HeaderFieldName:"

                    // Message main header header field. If multiple header fields, then all are checked.
                    //  message.header <SP> "HeaderFieldName:"
                    else if (word == "message.header")
                    {
                        string headerFieldName = r.ReadWord();
                        if (headerFieldName == null)
                        {
                            throw new Exception("Match source MainHeaderField HeaderFieldName is missing ! Syntax:{MainHeaderField <SP> \"HeaderFieldName:\"}");
                        }

                        if (!syntaxCheckOnly)
                        {
                            if (mime.Header.Contains(headerFieldName))
                            {
                                MIME_h[] fields = mime.Header[headerFieldName];
                                matchSourceValues = new string[fields.Length];
                                for (int i = 0; i < matchSourceValues.Length; i++)
                                {
                                    matchSourceValues[i] = fields[i].ValueToString();
                                }
                            }
                        }
                    }

                    #endregion

                    #region message.all_headers <SP> "HeaderFieldName:"

                    // Any mime entity header header field. If multiple header fields, then all are checked.
                    //  message.all_headers <SP> "HeaderFieldName:"
                    else if (word == "message.all_headers")
                    {
                        string headerFieldName = r.ReadWord();
                        if (headerFieldName == null)
                        {
                            throw new Exception("Match source MainHeaderField HeaderFieldName is missing ! Syntax:{MainHeaderField <SP> \"HeaderFieldName:\"}");
                        }

                        if (!syntaxCheckOnly)
                        {
                            List <string> values = new List <string>();
                            foreach (MIME_Entity entity in mime.AllEntities)
                            {
                                if (entity.Header.Contains(headerFieldName))
                                {
                                    MIME_h[] fields = entity.Header[headerFieldName];
                                    for (int i = 0; i < fields.Length; i++)
                                    {
                                        values.Add(fields[i].ValueToString());
                                    }
                                }
                            }
                            matchSourceValues = values.ToArray();
                        }
                    }

                    #endregion

                    #region message.body_text

                    // Message body text.
                    //  message.body_text
                    else if (word == "message.body_text")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { mime.BodyText };
                        }
                    }

                    #endregion

                    #region message.body_html

                    // Message body html.
                    //  message.body_html
                    else if (word == "message.body_html")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { mime.BodyHtmlText };
                        }
                    }

                    #endregion

                    #region message.content_md5

                    // Message any mime entity decoded data MD5 hash.
                    //  message.content_md5
                    else if (word == "message.content_md5")
                    {
                        if (!syntaxCheckOnly)
                        {
                            List <string> values = new List <string>();
                            foreach (MIME_Entity entity in mime.AllEntities)
                            {
                                try{
                                    if (entity.Body is MIME_b_SinglepartBase)
                                    {
                                        byte[] data = ((MIME_b_SinglepartBase)entity.Body).Data;
                                        if (data != null)
                                        {
                                            System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                                            values.Add(System.Text.Encoding.Default.GetString(md5.ComputeHash(data)));
                                        }
                                    }
                                }
                                catch {
                                    // Message data parsing failed, just skip that entity md5
                                }
                            }
                            matchSourceValues = values.ToArray();
                        }
                    }

                    #endregion


                    #region sys.date_time

                    // System current date time. Format: yyyy.MM.dd HH:mm:ss.
                    //  sys.date_time
                    else if (word == "sys.date_time")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") };
                        }
                    }

                    #endregion

                    #region sys.date

                    // System current date. Format: yyyy.MM.dd.
                    //  sys.date
                    else if (word == "sys.date")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { DateTime.Today.ToString("dd.MM.yyyy") };
                        }
                    }

                    #endregion

                    #region sys.time

                    // System current time. Format: HH:mm:ss.
                    //  sys.time
                    else if (word == "sys.time")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { DateTime.Now.ToString("HH:mm:ss") };
                        }
                    }

                    #endregion

                    #region sys.day_of_week

                    // Day of week. Days: sunday,monday,tuesday,wednesday,thursday,friday,saturday.
                    //  sys.day_of_week
                    else if (word == "sys.day_of_week")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { DateTime.Today.DayOfWeek.ToString() };
                        }
                    }

                    #endregion

                    /*
                     * // Day of month. Format: 1 - 31. If no so much days in month, then replaced with month max days.
                     * // sys.day_of_month
                     * else if(word == "sys.day_of_month"){
                     * }
                     */
                    #region sys.day_of_year

                    // Month of year. Format: 1 - 12.
                    // sys.day_of_year
                    else if (word == "sys.day_of_year")
                    {
                        if (!syntaxCheckOnly)
                        {
                            matchSourceValues = new string[] { DateTime.Today.ToString("M") };
                        }
                    }

                    #endregion

                    #region Unknown

                    // Unknown
                    else
                    {
                        throw new Exception("Unknown match source '" + word + "' !");
                    }

                    #endregion


                    /* If we reach so far, then we have valid match sorce and compare value.
                     * Just do compare.
                     */

                    // Reset lastMatch result
                    lastMatchValue = false;

                    // Read matcher
                    word = r.ReadWord(true, new char[] { ' ' }, true);
                    if (word == null)
                    {
                        throw new Exception("Invalid syntax: operator is missing ! \r\n\r\n Near: '" + r.OriginalString.Substring(0, r.Position) + "'");
                    }
                    word = word.ToLower();

                    #region * <SP> "astericPattern"

                    // * <SP> "astericPattern"
                    if (word == "*")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (SCore.IsAstericMatch(val, matchSourceValue.ToLower()))
                                {
                                    lastMatchValue = true;
                                    break;
                                }
                            }
                        }
                    }

                    #endregion

                    #region !* <SP> "astericPattern"

                    // !* <SP> "astericPattern"
                    else if (word == "!*")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (SCore.IsAstericMatch(val, matchSourceValue.ToLower()))
                                {
                                    lastMatchValue = false;
                                    break;
                                }
                            }
                        }
                    }

                    #endregion

                    #region == <SP> "value"

                    // == <SP> "value"
                    else if (word == "==")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (val == matchSourceValue.ToLower())
                                {
                                    lastMatchValue = true;
                                    break;
                                }
                            }
                        }
                    }

                    #endregion

                    #region != <SP> "value"

                    // != <SP> "value"
                    else if (word == "!=")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found, then already value equals
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (val == matchSourceValue.ToLower())
                                {
                                    lastMatchValue = false;
                                    break;
                                }
                                lastMatchValue = true;
                            }
                        }
                    }

                    #endregion

                    #region >= <SP> "value"

                    // >= <SP> "value"
                    else if (word == ">=")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (matchSourceValue.ToLower().CompareTo(val) >= 0)
                                {
                                    lastMatchValue = true;
                                    break;
                                }
                            }
                        }
                    }

                    #endregion

                    #region <= <SP> "value"

                    // <= <SP> "value"
                    else if (word == "<=")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (matchSourceValue.ToLower().CompareTo(val) <= 0)
                                {
                                    lastMatchValue = true;
                                    break;
                                }
                            }
                        }
                    }

                    #endregion

                    #region > <SP> "value"

                    // > <SP> "value"
                    else if (word == ">")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (matchSourceValue.ToLower().CompareTo(val) > 0)
                                {
                                    lastMatchValue = true;
                                    break;
                                }
                            }
                        }
                    }

                    #endregion

                    #region < <SP> "value"

                    // < <SP> "value"
                    else if (word == "<")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (matchSourceValue.ToLower().CompareTo(val) < 0)
                                {
                                    lastMatchValue = true;
                                    break;
                                }
                            }
                        }
                    }

                    #endregion

                    #region regex <SP> "value"

                    // Regex <SP> "value"
                    else if (word == "regex")
                    {
                        string val = r.ReadWord();
                        if (val == null)
                        {
                            throw new Exception("Invalid syntax: <SP> \"value\" is missing !");
                        }
                        val = val.ToLower();

                        if (!syntaxCheckOnly)
                        {
                            // We check matchSourceValues when first is found
                            foreach (string matchSourceValue in matchSourceValues)
                            {
                                if (Regex.IsMatch(val, matchSourceValue.ToLower()))
                                {
                                    lastMatchValue = true;
                                    break;
                                }
                            }
                        }
                    }

                    #endregion

                    #region Unknown

                    // Unknown
                    else
                    {
                        throw new Exception("Unknown keword '" + word + "' !");
                    }

                    #endregion

                    possibleClauseItems = PossibleClauseItem.AND | PossibleClauseItem.OR;
                }
            }

            return(lastMatchValue);
        }
コード例 #3
0
ファイル: wfrm_User_MessageRule.cs プロジェクト: dioptre/nkd
        private void m_pTab_General_MatchExpression_TextChanged(object sender,EventArgs e)
        {
            m_pTab_General_MatchExpression.SuspendPaint = true;

            string text = m_pTab_General_MatchExpression.Text;
            int selectionStart = m_pTab_General_MatchExpression.SelectionStart;
            int startPos = 0;

            StringReader r = new StringReader(text);
            while(r.Available > 0){
                r.ReadToFirstChar();
                startPos = r.Position;
                                                
                string word = r.ReadWord(false);
                if(word == null){
                    break;
                }
                // We must have ()[]{}<>
                if(word == ""){
                    word = r.ReadSpecifiedLength(1);
                }
                                
                if(word.StartsWith("\"") && word.EndsWith("\"")){
                    m_pTab_General_MatchExpression.SelectionStart = startPos;
                    m_pTab_General_MatchExpression.SelectionLength = word.Length;
                    m_pTab_General_MatchExpression.SelectionColor = Color.Brown;
                    continue;
                }

                bool isKeyWord = false;
                string[] keyWords = new string[]{
                    "and",
                    "or",
                    "not"                
                };                
                foreach(string keyWord in keyWords){
                    if(word.ToLower() == keyWord.ToLower()){
                        isKeyWord = true;
                        break;
                    }
                }

                bool isMatcher = false;
                string[] matchers = new string[]{
                    "smtp.mail_from",
                    "smtp.rcpt_to",
                    "smtp.ehlo",
                    "smtp.authenticated",
                    "smtp.user",
                    "smtp.remote_ip",
                    "message.size",
                    "message.header",
                    "message.all_headers",
                    "message.body_text",
                    "message.body_html",
                    "message.content_md5",
                    "sys.date_time",
                    "sys.date",
                    "sys.time",
                    "sys.day_of_week",
                    "sys.day_of_month",
                    "sys.day_of_year"
                };
                foreach(string keyWord in matchers){
                    if(word.ToLower() == keyWord.ToLower()){
                        isMatcher = true;
                        break;
                    }
                }

                if(isKeyWord){
                    m_pTab_General_MatchExpression.SelectionStart = startPos;
                    m_pTab_General_MatchExpression.SelectionLength = word.Length;
                    m_pTab_General_MatchExpression.SelectionColor = Color.Blue;
                }
                else if(isMatcher){
                    m_pTab_General_MatchExpression.SelectionStart = startPos;
                    m_pTab_General_MatchExpression.SelectionLength = word.Length;
                    m_pTab_General_MatchExpression.SelectionColor = Color.DarkMagenta;
                }
                else{
                    m_pTab_General_MatchExpression.SelectionStart = startPos;
                    m_pTab_General_MatchExpression.SelectionLength = word.Length;
                    m_pTab_General_MatchExpression.SelectionColor = Color.Black;
                }
            }

            m_pTab_General_MatchExpression.SelectionStart = selectionStart;
            m_pTab_General_MatchExpression.SelectionLength = 0;

            m_pTab_General_MatchExpression.SuspendPaint = false;
        }
コード例 #4
0
 /// <summary>
 /// Checks if specified message matches to specified criteria.
 /// </summary>
 /// <param name="matchExpression">Match expression.</param>
 /// <param name="mailFrom">SMTP MAIL FROM: command email value.</param>
 /// <param name="rcptTo">SMTP RCPT TO: command email values.</param>
 /// <param name="smtpSession">SMTP current session.</param>
 /// <param name="mime">Message to match.</param>
 /// <param name="messageSize">Message size in bytes.</param>
 /// <returns>Returns true if message matches to specified criteria.</returns>
 public bool Match(string matchExpression,string mailFrom,string[] rcptTo,SMTP_Session smtpSession,Mail_Message mime,int messageSize)
 {
     LumiSoft.Net.StringReader r = new LumiSoft.Net.StringReader(matchExpression);
     return Match(false,r,mailFrom,rcptTo,smtpSession,mime,messageSize);
 }
コード例 #5
0
        /// <summary>
        /// Parses search key from current position.
        /// </summary>
        /// <param name="reader"></param>
        public void Parse(StringReader reader)
        {
            //Remove spaces from string start
            reader.ReadToFirstChar();

            if(reader.StartsWith("(")){
                reader = new StringReader(reader.ReadParenthesized().Trim());
            }

            //--- Start parsing search keys --------------//
            while(reader.Available > 0){
                object searchKey = ParseSearchKey(reader);
                if(searchKey != null){
                    m_pSearchKeys.Add(searchKey);
                }
            }
            //--------------------------------------------//
        }
コード例 #6
0
ファイル: SIP_Uri.cs プロジェクト: dioptre/nkd
        /// <summary>
        /// Parses SIP_Uri from SIP-URI string.
        /// </summary>
        /// <param name="value">SIP-URI  string.</param>
        /// <returns>Returns parsed SIP_Uri object.</returns>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        protected override void ParseInternal(string value)
        {
            // Syntax: sip:/sips: username@host:port *[;parameter] [?header *[&header]]

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

            value = Uri.UnescapeDataString(value);

            if(!(value.ToLower().StartsWith("sip:") || value.ToLower().StartsWith("sips:"))){
                throw new SIP_ParseException("Specified value is invalid SIP-URI !");
            }

            StringReader r = new StringReader(value);

            // IsSecure
            this.IsSecure = r.QuotedReadToDelimiter(':').ToLower() == "sips";
                                    
            // Get username
            if(r.SourceString.IndexOf('@') > -1){
                this.User = r.QuotedReadToDelimiter('@');
            }
            
            // Gets host[:port]
            string[] host_port = r.QuotedReadToDelimiter(new char[]{';','?'},false).Split(':');
            this.Host = host_port[0];
            // Optional port specified
            if(host_port.Length == 2){
                this.Port = Convert.ToInt32(host_port[1]);
            }
          
            // We have parameters and/or header
            if(r.Available > 0){
                // Get parameters
                string[] parameters = TextUtils.SplitQuotedString(r.QuotedReadToDelimiter('?'),';');
                foreach(string parameter in parameters){
                    if(parameter.Trim() != ""){
                        string[] name_value = parameter.Trim().Split(new char[]{'='},2);
                        if(name_value.Length == 2){
                            this.Parameters.Add(name_value[0],TextUtils.UnQuoteString(name_value[1]));
                        }
                        else{
                            this.Parameters.Add(name_value[0],null);
                        }
                    }
                }

                // We have header
                if(r.Available > 0){
                    this.m_Header = r.ReadToEnd();
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Parses SearchGroup or SearchItem from reader. If reader starts with (, then parses searchGroup, otherwise SearchItem.
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        internal static object ParseSearchKey(StringReader reader)
        {
            //Remove spaces from string start
            reader.ReadToFirstChar();

            // SearchGroup
            if(reader.StartsWith("(")){
                SearchGroup searchGroup = new SearchGroup();
                searchGroup.Parse(reader);

                return searchGroup;
            }
            // SearchItem
            else{
                return SearchKey.Parse(reader);
            }
        }
コード例 #8
0
        /// <summary>
        /// Parses one search key from current position. Returns null if there isn't any search key left.
        /// </summary>
        /// <param name="reader"></param>
        public static SearchKey Parse(StringReader reader)
        {
            string searchKeyName  = "";
            object searchKeyValue = null;

            //Remove spaces from string start
            reader.ReadToFirstChar();

            // Search keyname is always 1 word
            string word = reader.ReadWord();
            if(word == null){
                return null;
            }
            word = word.ToUpper().Trim();

            //Remove spaces from string start
            reader.ReadToFirstChar();

            #region ALL

            // ALL
            //		All messages in the mailbox; the default initial key for ANDing.
            if(word == "ALL"){
                searchKeyName = "ALL";
            }

            #endregion

            #region ANSWERED

            // ANSWERED
            //		Messages with the \Answered flag set.
            else if(word == "ANSWERED"){
                // We internally use KEYWORD ANSWERED
                searchKeyName = "KEYWORD";
                searchKeyValue = "ANSWERED";
            }

            #endregion

            #region BCC

            // BCC <string>
            //		Messages that contain the specified string in the envelope structure's BCC field.
            else if(word == "BCC"){
                // We internally use HEADER "BCC:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if(val != null){
                    searchKeyValue = new string[]{"BCC:",TextUtils.UnQuoteString(val)};
                }
                else{
                    throw new Exception("BCC <string> value is missing !");
                }
            }

            #endregion

            #region BEFORE

            //	BEFORE <date>
            //		Messages whose internal date (disregarding time and timezone) is earlier than the specified date.
            else if(word == "BEFORE"){
                searchKeyName = "BEFORE";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    // Parse date
                    try{
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                    // Invalid date
                    catch{
                        throw new Exception("Invalid BEFORE <date> value '" + val + "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else{
                    throw new Exception("BEFORE <date> value is missing !");
                }
            }

            #endregion

            #region BODY

            //	BODY <string>
            //		Messages that contain the specified string in the body of the message.
            else if(word == "BODY"){
                searchKeyName = "BODY";

                string val = ReadString(reader);
                if(val != null){
                    searchKeyValue = val;
                }
                else{
                    throw new Exception("BODY <string> value is missing !");
                }
            }

            #endregion

            #region CC

            //	CC <string>
            //		Messages that contain the specified string in the envelope structure's CC field.
            else if(word == "CC"){
                // We internally use HEADER "CC:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if(val != null){
                    searchKeyValue = new string[]{"CC:",TextUtils.UnQuoteString(val)};
                }
                else{
                    throw new Exception("CC <string> value is missing !");
                }
            }

            #endregion

            #region DELETED

            // DELETED
            //		Messages with the \Deleted flag set.
            else if(word == "DELETED"){
                // We internally use KEYWORD DELETED
                searchKeyName = "KEYWORD";
                searchKeyValue = "DELETED";
            }

            #endregion

            #region DRAFT

            //	DRAFT
            //		Messages with the \Draft flag set.
            else if(word == "DRAFT"){
                // We internally use KEYWORD DRAFT
                searchKeyName = "KEYWORD";
                searchKeyValue = "DRAFT";
            }

            #endregion

            #region FLAGGED

            //	FLAGGED
            //		Messages with the \Flagged flag set.
            else if(word == "FLAGGED"){
                // We internally use KEYWORD FLAGGED
                searchKeyName = "KEYWORD";
                searchKeyValue = "FLAGGED";
            }

            #endregion

            #region FROM

            //	FROM <string>
            //		Messages that contain the specified string in the envelope structure's FROM field.
            else if(word == "FROM"){
                // We internally use HEADER "FROM:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if(val != null){
                    searchKeyValue = new string[]{"FROM:",TextUtils.UnQuoteString(val)};
                }
                else{
                    throw new Exception("FROM <string> value is missing !");
                }
            }

            #endregion

            #region HEADER

            //	HEADER <field-name> <string>
            //		Messages that have a header with the specified field-name (as
            //		defined in [RFC-2822]) and that contains the specified string
            //		in the text of the header (what comes after the colon).  If the
            //		string to search is zero-length, this matches all messages that
            //		have a header line with the specified field-name regardless of
            //		the contents.
            else if(word == "HEADER"){
                searchKeyName = "HEADER";

                // Read <field-name>
                string fieldName = ReadString(reader);
                if(fieldName != null){
                    fieldName = TextUtils.UnQuoteString(fieldName);
                }
                else{
                    throw new Exception("HEADER <field-name> value is missing !");
                }

                // Read <string>
                string val = ReadString(reader);
                if(val != null){
                    searchKeyValue = new string[]{fieldName,TextUtils.UnQuoteString(val)};
                }
                else{
                    throw new Exception("(HEADER <field-name>) <string> value is missing !");
                }
            }

            #endregion

            #region KEYWORD

            //	KEYWORD <flag>
            //		Messages with the specified keyword flag set.
            else if(word == "KEYWORD"){
                searchKeyName = "KEYWORD";

                // Read <flag>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    searchKeyValue = TextUtils.UnQuoteString(val);
                }
                else{
                    throw new Exception("KEYWORD <flag> value is missing !");
                }
            }

            #endregion

            #region LARGER

            //	LARGER <n>
            //		Messages with an [RFC-2822] size larger than the specified number of octets.
            else if(word == "LARGER"){
                searchKeyName = "LARGER";

                // Read <n>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    // Parse <n> - must be integer value
                    try{
                        searchKeyValue = Convert.ToInt64(TextUtils.UnQuoteString(val));
                    }
                    // Invalid <n>
                    catch{
                        throw new Exception("Invalid LARGER <n> value '" + val + "', it must be numeric value !");
                    }
                }
                else{
                    throw new Exception("LARGER <n> value is missing !");
                }
            }

            #endregion

            #region NEW

            //	NEW
            //		Messages that have the \Recent flag set but not the \Seen flag.
            //		This is functionally equivalent to "(RECENT UNSEEN)".
            else if(word == "NEW"){
                // We internally use KEYWORD RECENT
                searchKeyName = "KEYWORD";
                searchKeyValue = "RECENT";
            }

            #endregion

            #region NOT

            //	NOT <search-key> or (<search-key> <search-key> ...)(SearchGroup)
            //		Messages that do not match the specified search key.
            else if(word == "NOT"){
                searchKeyName = "NOT";

                object searchItem = SearchGroup.ParseSearchKey(reader);
                if(searchItem != null){
                    searchKeyValue = searchItem;
                }
                else{
                    throw new Exception("Required NOT <search-key> isn't specified !");
                }
            }

            #endregion

            #region OLD

            //	OLD
            //		Messages that do not have the \Recent flag set.  This is
            //		functionally equivalent to "NOT RECENT" (as opposed to "NOT	NEW").
            else if(word == "OLD"){
                // We internally use UNKEYWORD RECENT
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "RECENT";
            }

            #endregion

            #region ON

            //	ON <date>
            //		Messages whose internal date (disregarding time and timezone) is within the specified date.
            else if(word == "ON"){
                searchKeyName = "ON";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    // Parse date
                    try{
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                    // Invalid date
                    catch{
                        throw new Exception("Invalid ON <date> value '" + val + "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else{
                    throw new Exception("ON <date> value is missing !");
                }
            }

            #endregion

            #region OR

            //	OR <search-key1> <search-key2> - SearckKey can be parenthesis list of keys !
            //		Messages that match either search key.
            else if(word == "OR"){
                searchKeyName = "OR";

                //--- <search-key1> ----------------------------------------------------//
                object searchKey1 = SearchGroup.ParseSearchKey(reader);
                if(searchKey1 == null){
                    throw new Exception("Required OR <search-key1> isn't specified !");
                }
                //----------------------------------------------------------------------//

                //--- <search-key2> ----------------------------------------------------//
                object searchKey2 = SearchGroup.ParseSearchKey(reader);
                if(searchKey2 == null){
                    throw new Exception("Required (OR <search-key1>) <search-key2> isn't specified !");
                }
                //-----------------------------------------------------------------------//

                searchKeyValue = new object[]{searchKey1,searchKey2};
            }

            #endregion

            #region RECENT

            //	RECENT
            //		Messages that have the \Recent flag set.
            else if(word == "RECENT"){
                // We internally use KEYWORD RECENT
                searchKeyName = "KEYWORD";
                searchKeyValue = "RECENT";
            }

            #endregion

            #region SEEN

            //	SEEN
            //		Messages that have the \Seen flag set.
            else if(word == "SEEN"){
                // We internally use KEYWORD SEEN
                searchKeyName = "KEYWORD";
                searchKeyValue = "SEEN";
            }

            #endregion

            #region SENTBEFORE

            //	SENTBEFORE <date>
            //		Messages whose [RFC-2822] Date: header (disregarding time and
            //		timezone) is earlier than the specified date.
            else if(word == "SENTBEFORE"){
                searchKeyName = "SENTBEFORE";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    // Parse date
                    try{
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                    // Invalid date
                    catch{
                        throw new Exception("Invalid SENTBEFORE <date> value '" + val + "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else{
                    throw new Exception("SENTBEFORE <date> value is missing !");
                }
            }

            #endregion

            #region SENTON

            //	SENTON <date>
            //		Messages whose [RFC-2822] Date: header (disregarding time and
            //		timezone) is within the specified date.
            else if(word == "SENTON"){
                searchKeyName = "SENTON";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    // Parse date
                    try{
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                    // Invalid date
                    catch{
                        throw new Exception("Invalid SENTON <date> value '" + val + "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else{
                    throw new Exception("SENTON <date> value is missing !");
                }
            }

            #endregion

            #region SENTSINCE

            //	SENTSINCE <date>
            //		Messages whose [RFC-2822] Date: header (disregarding time and
            //		timezone) is within or later than the specified date.
            else if(word == "SENTSINCE"){
                searchKeyName = "SENTSINCE";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    // Parse date
                    try{
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                    // Invalid date
                    catch{
                        throw new Exception("Invalid SENTSINCE <date> value '" + val + "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else{
                    throw new Exception("SENTSINCE <date> value is missing !");
                }
            }

            #endregion

            #region SINCE

            //	SINCE <date>
            //		Messages whose internal date (disregarding time and timezone)
            //		is within or later than the specified date.
            else if(word == "SINCE"){
                searchKeyName = "SINCE";

                // Read <date>
                string val = reader.ReadWord();
                if(val != null){
                    // Parse date
                    try{
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                    // Invalid date
                    catch{
                        throw new Exception("Invalid SINCE <date> value '" + val + "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else{
                    throw new Exception("SINCE <date> value is missing !");
                }
            }

            #endregion

            #region SMALLER

            //	SMALLER <n>
            //		Messages with an [RFC-2822] size smaller than the specified number of octets.
            else if(word == "SMALLER"){
                searchKeyName = "SMALLER";

                // Read <n>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    val = TextUtils.UnQuoteString(val);

                    // Parse <n> - must be integer value
                    try{
                        searchKeyValue = Convert.ToInt64(val);
                    }
                    // Invalid <n>
                    catch{
                        throw new Exception("Invalid SMALLER <n> value '" + val + "', it must be numeric value !");
                    }
                }
                else{
                    throw new Exception("SMALLER <n> value is missing !");
                }
            }

            #endregion

            #region SUBJECT

            //	SUBJECT <string>
            //		Messages that contain the specified string in the envelope structure's SUBJECT field.
            else if(word == "SUBJECT"){
                // We internally use HEADER "SUBJECT:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if(val != null){
                    searchKeyValue = new string[]{"SUBJECT:",TextUtils.UnQuoteString(val)};
                }
                else{
                    throw new Exception("SUBJECT <string> value is missing !");
                }
            }

            #endregion

            #region TEXT

            //	TEXT <string>
            //		Messages that contain the specified string in the header or body of the message.
            else if(word == "TEXT"){
                searchKeyName = "TEXT";

                string val = ReadString(reader);
                if(val != null){
                    searchKeyValue = val;
                }
                else{
                    throw new Exception("TEXT <string> value is missing !");
                }
            }

            #endregion

            #region TO

            //	TO <string>
            //		Messages that contain the specified string in the envelope structure's TO field.
            else if(word == "TO"){
                // We internally use HEADER "TO:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if(val != null){
                    searchKeyValue = new string[]{"TO:",TextUtils.UnQuoteString(val)};
                }
                else{
                    throw new Exception("TO <string> value is missing !");
                }
            }

            #endregion

            #region UID

            //	UID <sequence set>
            //		Messages with unique identifiers corresponding to the specified
            //		unique identifier set.  Sequence set ranges are permitted.
            else if(word == "UID"){
                searchKeyName = "UID";

                // Read <sequence set>
                string val = reader.QuotedReadToDelimiter(' ');

                if(val != null){
                    try{
                        IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
                        sequenceSet.Parse(TextUtils.UnQuoteString(val),long.MaxValue);

                        searchKeyValue = sequenceSet;
                    }
                    catch{
                        throw new Exception("Invalid UID <sequence-set> value '" + val + "' !");
                    }
                }
                else{
                    throw new Exception("UID <sequence-set> value is missing !");
                }
            }

            #endregion

            #region UNANSWERED

            //	UNANSWERED
            //		Messages that do not have the \Answered flag set.
            else if(word == "UNANSWERED"){
                // We internally use UNKEYWORD SEEN
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "ANSWERED";
            }

            #endregion

            #region UNDELETED

            //	UNDELETED
            //		Messages that do not have the \Deleted flag set.
            else if(word == "UNDELETED"){
                // We internally use UNKEYWORD UNDELETED
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "DELETED";
            }

            #endregion

            #region UNDRAFT

            //	UNDRAFT
            //		Messages that do not have the \Draft flag set.
            else if(word == "UNDRAFT"){
                // We internally use UNKEYWORD UNDRAFT
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "DRAFT";
            }

            #endregion

            #region UNFLAGGED

            //	UNFLAGGED
            //		Messages that do not have the \Flagged flag set.
            else if(word == "UNFLAGGED"){
                // We internally use UNKEYWORD UNFLAGGED
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "FLAGGED";
            }

            #endregion

            #region UNKEYWORD

            //	UNKEYWORD <flag>
            //		Messages that do not have the specified keyword flag set.
            else if(word == "UNKEYWORD"){
                searchKeyName = "UNKEYWORD";

                // Read <flag>
                string val = reader.QuotedReadToDelimiter(' ');
                if(val != null){
                    searchKeyValue = TextUtils.UnQuoteString(val);
                }
                else{
                    throw new Exception("UNKEYWORD <flag> value is missing !");
                }
            }

            #endregion

            #region UNSEEN

            //	UNSEEN
            //		Messages that do not have the \Seen flag set.
            else if(word == "UNSEEN"){
                // We internally use UNKEYWORD UNSEEN
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "SEEN";
            }

            #endregion

            #region Unknown or SEQUENCESET

            // Unkown keyword or <sequence set>
            else{
                // DUMMY palce(bad design) in IMAP.
                // Active keyword can be <sequence set> or bad keyword, there is now way to distinguish what is meant.
                // Why they don't key work SEQUENCESET <sequence set> ?

                // <sequence set>
                //		Messages with message sequence numbers corresponding to the
                //		specified message sequence number set.

                // Just try if it can be parsed as sequence-set
                try{
                    IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
                    sequenceSet.Parse(word,long.MaxValue);

                    searchKeyName = "SEQUENCESET";
                    searchKeyValue = sequenceSet;
                }
                // This isn't vaild sequnce-set value
                catch{
                    throw new Exception("Invalid search key or <sequnce-set> value '" + word + "' !");
                }
            }

            #endregion

            // REMOVE ME:
            //	Console.WriteLine(searchKeyName + " : " + Convert.ToString(searchKeyValue));

            return new SearchKey(searchKeyName,searchKeyValue);
        }
コード例 #9
0
        /// <summary>
        /// Reads search-key &lt;string&gt; value.
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        private static string ReadString(StringReader reader)
        {
            //Remove spaces from string start
            reader.ReadToFirstChar();

            // We must support:
            //	word
            //  "text"
            //	{string_length}data(string_length)

            // {string_length}data(string_length)
            if(reader.StartsWith("{")){
                // Remove {
                reader.ReadSpecifiedLength("{".Length);

                int dataLength = Convert.ToInt32(reader.QuotedReadToDelimiter('}'));
                return reader.ReadSpecifiedLength(dataLength);
            }

            return TextUtils.UnQuoteString(reader.QuotedReadToDelimiter(' '));
        }
        /// <summary>
        /// Parses IMAP FETCH BODYSTRUCTURE multipart entity from reader.
        /// </summary>
        /// <param name="r">Fetch reader.</param>
        /// <returns>Returns parsed bodystructure entity.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>r</b> is null reference.</exception>
        public static IMAP_t_Fetch_r_i_BodyStructure_e_Multipart Parse(StringReader r)
        {
            if(r == null){
                throw new ArgumentNullException("r");
            }

            IMAP_t_Fetch_r_i_BodyStructure_e_Multipart retVal = new IMAP_t_Fetch_r_i_BodyStructure_e_Multipart();

            /* RFC 3501 7.4.2.
            
                Normal fields.
                    1*(body-parts)  - parenthesized list of body parts
                    subtype
                    --- extention fields
              
                Extention fields.
                    body parameter parenthesized list
                    body disposition
                    body language
                    body location
            */

            #region Normal fields

            // Read child entities.
            while(r.Available > 0){
                r.ReadToFirstChar();
                if(r.StartsWith("(")){
                    StringReader bodyPartReader = new StringReader(r.ReadParenthesized());
                    bodyPartReader.ReadToFirstChar();

                    IMAP_t_Fetch_r_i_BodyStructure_e part = null;
                    // multipart
                    if(bodyPartReader.StartsWith("(")){
                        part = IMAP_t_Fetch_r_i_BodyStructure_e_Multipart.Parse(bodyPartReader);
                    }
                    // single-part
                    else{
                        part = IMAP_t_Fetch_r_i_BodyStructure_e_SinglePart.Parse(bodyPartReader);
                       
                    }
                    part.SetParent(retVal);
                    retVal.m_pBodyParts.Add(part);
                }
                else{
                    break;
                }
            }

            // subtype
            string subtype = IMAP_Utils.ReadString(r);
            if(!string.IsNullOrEmpty(subtype)){
                retVal.m_pContentType = new MIME_h_ContentType("multipart/" + subtype);
            }

            #endregion

            #region Extention field

            // body parameter parenthesized list
            r.ReadToFirstChar();
            if(r.StartsWith("(")){
                StringReader pramsReader = new StringReader(r.ReadParenthesized());
                if(retVal.m_pContentType != null){
                    while(pramsReader.Available > 0){
                        string name = IMAP_Utils.ReadString(pramsReader);
                        if(string.IsNullOrEmpty(name)){
                            break;
                        }
                        string value = IMAP_Utils.ReadString(pramsReader);
                        if(value == null){
                            value = "";
                        }
                        retVal.m_pContentType.Parameters[name] = MIME_Encoding_EncodedWord.DecodeTextS(value);
                    }
                }
            }
            // NIL
            else{
                IMAP_Utils.ReadString(r);
            }
            
            // body disposition - "(" string SP body-fld-param ")" / nil
            //                    body-fld-param  = "(" string SP string *(SP string SP string) ")" / nil            
            if(r.StartsWith("(")){
                string disposition = IMAP_Utils.ReadString(r);
                if(!string.IsNullOrEmpty(disposition)){
                    retVal.m_pContentDisposition = new MIME_h_ContentDisposition(disposition);
                }
                r.ReadToFirstChar();

                // Parse Content-Dispostion parameters.
                if(r.StartsWith("(")){
                    StringReader pramsReader = new StringReader(r.ReadParenthesized());
                    if(retVal.m_pContentDisposition != null){
                        while(pramsReader.Available > 0){
                            string name = IMAP_Utils.ReadString(pramsReader);
                            if(string.IsNullOrEmpty(name)){
                                break;
                            }
                            string value = IMAP_Utils.ReadString(pramsReader);
                            if(value == null){
                                value = "";
                            }
                            retVal.m_pContentDisposition.Parameters[name] = MIME_Encoding_EncodedWord.DecodeTextS(value);                            
                        }
                    }
                }
                // NIL
                else{
                    IMAP_Utils.ReadString(r);
                }               
            }
            // NIL
            else{
                IMAP_Utils.ReadString(r);
            }

            // body language - nstring / "(" string *(SP string) ")"
            r.ReadToFirstChar();
            if(r.StartsWith("(")){
                retVal.m_Language = r.ReadParenthesized();
            }
            else{
                retVal.m_Language = IMAP_Utils.ReadString(r);
            }            

            // body location - nstring
            retVal.m_Location = IMAP_Utils.ReadString(r);

            #endregion

            return retVal;
        }
        /// <summary>
        /// Parses IMAP FETCH BODYSTRUCTURE single part entity from reader.
        /// </summary>
        /// <param name="r">Fetch reader.</param>
        /// <returns>Returns parsed bodystructure entity.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>r</b> is null reference.</exception>
        public static IMAP_t_Fetch_r_i_BodyStructure_e_SinglePart Parse(StringReader r)
        {
            if(r == null){
                throw new ArgumentNullException("r");
            }

            IMAP_t_Fetch_r_i_BodyStructure_e_SinglePart retVal = new IMAP_t_Fetch_r_i_BodyStructure_e_SinglePart();

            /* RFC 3501 7.4.2.
                
                Normal single part entity fields.
                    body type
                    body subtype
                    body parameter parenthesized list
                    body id
                    body description
                    body encoding
                    body size - Encoded bytes count.
                    --- extention fields
            
                Message/xxx type entity fields.
                    body type
                    body subtype
                    body parameter parenthesized list
                    body id
                    body description
                    body encoding
                    body size - Encoded bytes count.
                    --- message special fields
                    envelope structure
                    body structure
                    body encoded text lines count
                    --- extention fields
            
                Text/xxx type entity fields.
                    body type
                    body subtype
                    body parameter parenthesized list
                    body id
                    body description
                    body encoding
                    body size - Encoded bytes count.
                    --- text special fields
                    body encoded text lines count
                    --- extention fields
             
                Extention fields.
                    body MD5
                    body disposition
                    body language
                    body location
            */

            #region Common fields

            // body type
            // body subtype
            // body parameter parenthesized list
            string type    = IMAP_Utils.ReadString(r);
            string subtype = IMAP_Utils.ReadString(r);
            if(!string.IsNullOrEmpty(type) && !string.IsNullOrEmpty(subtype)){
                retVal.m_pContentType = new MIME_h_ContentType(type + "/" + subtype);
            }
            r.ReadToFirstChar();
            // Parse Content-Type parameters
            if(r.StartsWith("(")){
                StringReader pramsReader = new StringReader(r.ReadParenthesized());
                if(retVal.m_pContentType != null){
                    while(pramsReader.Available > 0){
                        string name = IMAP_Utils.ReadString(pramsReader);
                        if(string.IsNullOrEmpty(name)){
                            break;
                        }
                        string value = IMAP_Utils.ReadString(pramsReader);
                        if(value == null){
                            value = "";
                        }
                        retVal.m_pContentType.Parameters[name] = MIME_Encoding_EncodedWord.DecodeTextS(value);
                    }
                }
            }
            // NIL
            else{
                IMAP_Utils.ReadString(r);
            }

            // body id - nstring
            retVal.m_ContentID = IMAP_Utils.ReadString(r);

            // body description - nstring
            retVal.m_ContentDescription = IMAP_Utils.ReadString(r);

            // body encoding - string
            retVal.m_ContentTransferEncoding = IMAP_Utils.ReadString(r);

            // body size - Encoded bytes count.
            string size = IMAP_Utils.ReadString(r);
            if(string.IsNullOrEmpty(size)){
                retVal.m_ContentSize = -1;
            }
            else{
                retVal.m_ContentSize = Convert.ToInt64(size);
            }

            #endregion

            #region Text/xxx fields

            if(string.Equals("text",type,StringComparison.InvariantCultureIgnoreCase)){
                // body encoded text lines count
                string linesCount = IMAP_Utils.ReadString(r);
                if(string.IsNullOrEmpty(size)){
                    retVal.m_LinesCount = -1;
                }
                else{
                    retVal.m_LinesCount = Convert.ToInt32(linesCount);
                }
            }

            #endregion

            #region Message/xxx fields

            if(string.Equals("message",type,StringComparison.InvariantCultureIgnoreCase)){
                // envelope structure
                r.ReadToFirstChar();
                // Read ENVELOPE
                if(r.StartsWith("(")){
                    string prams = r.ReadParenthesized();
                }
                // NIL
                else{
                    IMAP_Utils.ReadString(r);
                }
                
                // body structure
                r.ReadToFirstChar();
                // Read BODYSTRUCTURE
                if(r.StartsWith("(")){
                    string prams = r.ReadParenthesized();
                }
                // NIL
                else{
                    IMAP_Utils.ReadString(r);
                }

                // body encoded text lines count
                string linesCount = IMAP_Utils.ReadString(r);
                if(string.IsNullOrEmpty(size)){
                    retVal.m_LinesCount = -1;
                }
                else{
                    retVal.m_LinesCount = Convert.ToInt32(linesCount);
                }
            }

            #endregion

            #region Extention fields

            // body MD5 - nstring
            retVal.m_Md5 = IMAP_Utils.ReadString(r);

            // body disposition - "(" string SP body-fld-param ")" / nil
            //                    body-fld-param  = "(" string SP string *(SP string SP string) ")" / nil            
            if(r.StartsWith("(")){
                string disposition = IMAP_Utils.ReadString(r);
                if(!string.IsNullOrEmpty(disposition)){
                    retVal.m_pContentDisposition = new MIME_h_ContentDisposition(disposition);
                }
                r.ReadToFirstChar();

                // Parse Content-Dispostion parameters.
                if(r.StartsWith("(")){
                    StringReader pramsReader = new StringReader(r.ReadParenthesized());
                    if(retVal.m_pContentDisposition != null){
                        while(pramsReader.Available > 0){
                            string name = IMAP_Utils.ReadString(pramsReader);
                            if(string.IsNullOrEmpty(name)){
                                break;
                            }
                            string value = IMAP_Utils.ReadString(pramsReader);
                            if(value == null){
                                value = "";
                            }
                            retVal.m_pContentDisposition.Parameters[name] = MIME_Encoding_EncodedWord.DecodeTextS(value);                            
                        }
                    }
                }
                // NIL
                else{
                    IMAP_Utils.ReadString(r);
                }               
            }
            // NIL
            else{
                IMAP_Utils.ReadString(r);
            }

            // body language - nstring / "(" string *(SP string) ")"
            r.ReadToFirstChar();
            if(r.StartsWith("(")){
                retVal.m_Language = r.ReadParenthesized();
            }
            else{
                retVal.m_Language = IMAP_Utils.ReadString(r);
            }            

            // body location - nstring
            retVal.m_Location = IMAP_Utils.ReadString(r);

            #endregion

            return retVal;
        }