Esempio n. 1
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * LSUB (\Noselect) "/" ~/Mail/foo

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* LSUB (");
            if (m_pFolderAttributes != null)
            {
                for (int i = 0; i < m_pFolderAttributes.Length; i++)
                {
                    if (i > 0)
                    {
                        retVal.Append(" ");
                    }
                    retVal.Append(m_pFolderAttributes[i]);
                }
            }
            retVal.Append(") ");
            retVal.Append("\"" + m_Delimiter + "\" ");
            retVal.Append(IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
            retVal.Append("\r\n");

            return(retVal.ToString());
        }
Esempio n. 2
0
        /// <summary>
        /// Parses MYRIGHTS response from MYRIGHTS-response string.
        /// </summary>
        /// <param name="myRightsResponse">MYRIGHTS response line.</param>
        /// <returns>Returns parsed MYRIGHTS response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>myRightsResponse</b> is null reference.</exception>
        public static IMAP_Response_MyRights Parse(string myRightsResponse)
        {
            if (myRightsResponse == null)
            {
                throw new ArgumentNullException("myRightsResponse");
            }

            /* RFC 4314 3.8. MYRIGHTS Response.
             *  Data:       mailbox name
             *              rights
             *
             *  The MYRIGHTS response occurs as a result of a MYRIGHTS command.  The
             *  first string is the mailbox name for which these rights apply.  The
             *  second string is the set of rights that the client has.
             *
             *  Section 2.1.1 details additional server requirements related to
             *  handling of the virtual "d" and "c" rights.
             *
             *  Example:    C: A003 MYRIGHTS INBOX
             *              S: * MYRIGHTS INBOX rwiptsldaex
             *              S: A003 OK Myrights complete
             */

            StringReader r = new StringReader(myRightsResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "MYRIGHTS"
            r.ReadWord();

            string folder = IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord(true));
            string rights = r.ReadToEnd().Trim();

            return(new IMAP_Response_MyRights(folder, rights));
        }
Esempio n. 3
0
        /// <summary>
        /// Encodes mailbox name.
        /// </summary>
        /// <param name="mailbox">Mailbox name.</param>
        /// <param name="encoding">Mailbox name encoding mechanism.</param>
        /// <returns>Renturns encoded mailbox name.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>mailbox</b> is null reference.</exception>
        public static string EncodeMailbox(string mailbox, IMAP_Mailbox_Encoding encoding)
        {
            if (mailbox == null)
            {
                throw new ArgumentNullException("mailbox");
            }

            /* RFC 6855 3.
             *  quoted        = DQUOTE *uQUOTED-CHAR DQUOTE
             *  uQUOTED-CHAR  = QUOTED-CHAR / UTF8-2 / UTF8-3 / UTF8-4
             */

            if (encoding == IMAP_Mailbox_Encoding.ImapUtf7)
            {
                return("\"" + IMAP_Utils.Encode_IMAP_UTF7_String(mailbox) + "\"");
            }
            else if (encoding == IMAP_Mailbox_Encoding.ImapUtf8)
            {
                return("\"" + mailbox + "\"");
            }
            else
            {
                return("\"" + mailbox + "\"");
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Parses LSUB response from lsub-response string.
        /// </summary>
        /// <param name="lSubResponse">LSub response string.</param>
        /// <returns>Returns parsed lsub response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>lSubResponse</b> is null reference.</exception>
        public static IMAP_r_u_LSub Parse(string lSubResponse)
        {
            if (lSubResponse == null)
            {
                throw new ArgumentNullException("lSubResponse");
            }

            /* RFC 3501 7.2.3. LSUB Response.
             *  Contents:   name attributes
             *              hierarchy delimiter
             *              name
             *
             *  The LSUB response occurs as a result of an LSUB command.  It
             *  returns a single name that matches the LSUB specification.  There
             *  can be multiple LSUB responses for a single LSUB command.  The
             *  data is identical in format to the LIST response.
             *
             *  Example:    S: * LSUB () "." #news.comp.mail.misc
             */

            StringReader r = new StringReader(lSubResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "LSUB"
            r.ReadWord();

            string attributes = r.ReadParenthesized();
            string delimiter  = r.ReadWord();
            string folder     = TextUtils.UnQuoteString(IMAP_Utils.DecodeMailbox(r.ReadToEnd().Trim()));

            return(new IMAP_r_u_LSub(folder, delimiter[0], attributes == string.Empty ? new string[0] : attributes.Split(' ')));
        }
Esempio n. 5
0
        /// <summary>
        /// Parses STATUS response from status-response string.
        /// </summary>
        /// <param name="response">Satatus response string.</param>
        /// <returns>Returns parsed STATUS response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public static IMAP_r_u_Status Parse(string response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            /* RFC 3501 7.2.4 STATUS Response.
             *  Contents:   name
             *              status parenthesized list
             *
             *  The STATUS response occurs as a result of an STATUS command.  It
             *  returns the mailbox name that matches the STATUS specification and
             *  the requested mailbox status information.
             *
             *  Example:    S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
             */

            StringReader r = new StringReader(response);

            // Eat "*"
            r.ReadWord();
            // Eat "STATUS"
            r.ReadWord();

            int  messages  = 0;
            int  recent    = 0;
            long uidNext   = 0;
            long folderUid = 0;
            int  unseen    = 0;

            string folder = TextUtils.UnQuoteString(IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord()));

            string[] items = r.ReadParenthesized().Split(' ');
            for (int i = 0; i < items.Length; i += 2)
            {
                if (items[i].Equals("MESSAGES", StringComparison.InvariantCultureIgnoreCase))
                {
                    messages = Convert.ToInt32(items[i + 1]);
                }
                else if (items[i].Equals("RECENT", StringComparison.InvariantCultureIgnoreCase))
                {
                    recent = Convert.ToInt32(items[i + 1]);
                }
                else if (items[i].Equals("UIDNEXT", StringComparison.InvariantCultureIgnoreCase))
                {
                    uidNext = Convert.ToInt64(items[i + 1]);
                }
                else if (items[i].Equals("UIDVALIDITY", StringComparison.InvariantCultureIgnoreCase))
                {
                    folderUid = Convert.ToInt64(items[i + 1]);
                }
                else if (items[i].Equals("UNSEEN", StringComparison.InvariantCultureIgnoreCase))
                {
                    unseen = Convert.ToInt32(items[i + 1]);
                }
            }

            return(new IMAP_r_u_Status(folder, messages, recent, uidNext, folderUid, unseen));
        }
Esempio n. 6
0
        /// <summary>
        /// Returns parsed IMAP SEARCH <b>HEADER (field-name) (string)</b> key.
        /// </summary>
        /// <param name="r">String reader.</param>
        /// <returns>Returns parsed IMAP SEARCH <b>HEADER (field-name) (string)</b> key.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>r</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when parsing fails.</exception>
        internal static IMAP_Search_Key_Header Parse(StringReader r)
        {
            if (r == null)
            {
                throw new ArgumentNullException("r");
            }

            string word = r.ReadWord();

            if (!string.Equals(word, "HEADER", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ParseException("Parse error: Not a SEARCH 'HEADER' key.");
            }
            string fieldName = IMAP_Utils.ReadString(r);

            if (fieldName == null)
            {
                throw new ParseException("Parse error: Invalid 'HEADER' field-name value.");
            }
            string value = IMAP_Utils.ReadString(r);

            if (value == null)
            {
                throw new ParseException("Parse error: Invalid 'HEADER' string value.");
            }

            return(new IMAP_Search_Key_Header(fieldName, value));
        }
Esempio n. 7
0
        /// <summary>
        /// Returns parsed IMAP SEARCH <b>SENTSINCE (string)</b> key.
        /// </summary>
        /// <param name="r">String reader.</param>
        /// <returns>Returns parsed IMAP SEARCH <b>SENTSINCE (string)</b> key.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>r</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when parsing fails.</exception>
        internal static IMAP_Search_Key_SentSince Parse(StringReader r)
        {
            if (r == null)
            {
                throw new ArgumentNullException("r");
            }

            string word = r.ReadWord();

            if (!string.Equals(word, "SENTSINCE", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ParseException("Parse error: Not a SEARCH 'SENTSINCE' key.");
            }
            string value = r.ReadWord();

            if (value == null)
            {
                throw new ParseException("Parse error: Invalid 'SENTSINCE' value.");
            }
            DateTime date;

            try{
                date = IMAP_Utils.ParseDate(value);
            }
            catch {
                throw new ParseException("Parse error: Invalid 'SENTSINCE' value.");
            }

            return(new IMAP_Search_Key_SentSince(date));
        }
Esempio n. 8
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* STATUS");
            retVal.Append(" " + IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
            retVal.Append(" (");
            bool firstItem = true;

            if (m_MessageCount >= 0)
            {
                retVal.Append("MESSAGES " + m_MessageCount);
                firstItem = false;
            }
            if (m_RecentCount >= 0)
            {
                if (!firstItem)
                {
                    retVal.Append(' ');
                }
                retVal.Append("RECENT " + m_RecentCount);
                firstItem = false;
            }
            if (m_UidNext >= 0)
            {
                if (!firstItem)
                {
                    retVal.Append(' ');
                }
                retVal.Append("UIDNEXT " + m_UidNext);
                firstItem = false;
            }
            if (m_FolderUid >= 0)
            {
                if (!firstItem)
                {
                    retVal.Append(' ');
                }
                retVal.Append("UIDVALIDITY " + m_FolderUid);
                firstItem = false;
            }
            if (m_UnseenCount >= 0)
            {
                if (!firstItem)
                {
                    retVal.Append(' ');
                }
                retVal.Append("UNSEEN " + m_UnseenCount);
                firstItem = false;
            }
            retVal.Append(")\r\n");

            return(retVal.ToString());
        }
Esempio n. 9
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * MYRIGHTS INBOX rwiptsldaex

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* MYRIGHTS " + IMAP_Utils.EncodeMailbox(m_FolderName, encoding) + " \"" + m_pRights + "\"\r\n");

            return(retVal.ToString());
        }
Esempio n. 10
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * LISTRIGHTS ~/Mail/saved smith la r swicdkxte

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* LISTRIGHTS " + IMAP_Utils.EncodeMailbox(m_FolderName, encoding) + " \"" + m_RequiredRights + "\" " + m_OptionalRights + "\r\n");

            return(retVal.ToString());
        }
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * QUOTAROOT INBOX ""

            StringBuilder retVal = new StringBuilder();
            retVal.Append("* QUOTAROOT " + IMAP_Utils.EncodeMailbox(m_FolderName,encoding));
            foreach(string root in m_QuotaRoots){
                retVal.Append(" \"" + root + "\"");
            }
            retVal.Append("\r\n");

            return retVal.ToString();
        }
Esempio n. 12
0
        /// <summary>
        /// Parses LISTRIGHTS response from LISTRIGHTS-response string.
        /// </summary>
        /// <param name="listRightsResponse">LISTRIGHTS response line.</param>
        /// <returns>Returns parsed LISTRIGHTS response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>listRightsResponse</b> is null reference.</exception>
        public static IMAP_r_u_ListRights Parse(string listRightsResponse)
        {
            if (listRightsResponse == null)
            {
                throw new ArgumentNullException("listRightsResponse");
            }

            /* RFC 4314 3.7. LISTRIGHTS Response.
             *  Data:       mailbox name
             *              identifier
             *              required rights
             *              list of optional rights
             *
             *  The LISTRIGHTS response occurs as a result of a LISTRIGHTS command.
             *  The first two strings are the mailbox name and identifier for which
             *  this rights list applies.  Following the identifier is a string
             *  containing the (possibly empty) set of rights the identifier will
             *  always be granted in the mailbox.
             *
             *  Following this are zero or more strings each containing a set of
             *  rights the identifier can be granted in the mailbox.  Rights
             *  mentioned in the same string are tied together.  The server MUST
             *  either grant all tied rights to the identifier in the mailbox or
             *  grant none.  Section 2.1.1 details additional server requirements
             *  related to handling of the virtual "d" and "c" rights.
             *
             *  The same right MUST NOT be listed more than once in the LISTRIGHTS
             *  command.
             *
             *  Example:    C: a001 LISTRIGHTS ~/Mail/saved smith
             *              S: * LISTRIGHTS ~/Mail/saved smith la r swicdkxte
             *              S: a001 OK Listrights completed
             */

            StringReader r = new StringReader(listRightsResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "LISTRIGHTS"
            r.ReadWord();

            string folder     = IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord(true));
            string identifier = r.ReadWord(true);
            string reqRights  = r.ReadWord(true);
            string optRights  = r.ReadWord(true);

            return(new IMAP_r_u_ListRights(folder, identifier, reqRights, optRights));
        }
Esempio n. 13
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * ACL INBOX Fred rwipslda test rwipslda

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* ACL ");
            retVal.Append(IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
            foreach (IMAP_Acl_Entry e in m_pEntries)
            {
                retVal.Append(" \"" + e.Identifier + "\" \"" + e.Rights + "\"");
            }
            retVal.Append("\r\n");

            return(retVal.ToString());
        }
Esempio n. 14
0
        /// <summary>
        /// Parses ACL response from acl-response string.
        /// </summary>
        /// <param name="aclResponse">ACL response.</param>
        /// <returns>Returns parsed ACL response.</returns>
        /// <exception cref="ArgumentNullException">Is raised wehn <b>aclResponse</b> is null reference.</exception>
        public static IMAP_r_u_Acl Parse(string aclResponse)
        {
            if (aclResponse == null)
            {
                throw new ArgumentNullException("aclResponse");
            }

            /* RFC 4314 3.6. ACL Response.
             *  Data:       mailbox name
             *              zero or more identifier rights pairs
             *
             *  The ACL response occurs as a result of a GETACL command.  The first
             *  string is the mailbox name for which this ACL applies.  This is
             *  followed by zero or more pairs of strings; each pair contains the
             *  identifier for which the entry applies followed by the set of rights
             *  that the identifier has.
             *
             *  Example:    C: A002 GETACL INBOX
             *              S: * ACL INBOX Fred rwipsldexta
             *              S: A002 OK Getacl complete
             */

            StringReader r = new StringReader(aclResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "ACL"
            r.ReadWord();

            string folderName = TextUtils.UnQuoteString(IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord()));

            string[] items = r.ReadToEnd().Split(' ');
            List <IMAP_Acl_Entry> entries = new List <IMAP_Acl_Entry>();

            for (int i = 0; i < items.Length; i += 2)
            {
                entries.Add(new IMAP_Acl_Entry(items[i], items[i + 1]));
            }

            return(new IMAP_r_u_Acl(folderName, entries.ToArray()));
        }
Esempio n. 15
0
        /// <summary>
        /// Returns parsed IMAP SEARCH <b>SUBJCET (string)</b> key.
        /// </summary>
        /// <param name="r">String reader.</param>
        /// <returns>Returns parsed IMAP SEARCH <b>SUBJECT (string)</b> key.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>r</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when parsing fails.</exception>
        internal static IMAP_Search_Key_Subject Parse(StringReader r)
        {
            if (r == null)
            {
                throw new ArgumentNullException("r");
            }

            string word = r.ReadWord();

            if (!string.Equals(word, "SUBJECT", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ParseException("Parse error: Not a SEARCH 'SUBJECT' key.");
            }
            string value = IMAP_Utils.ReadString(r);

            if (value == null)
            {
                throw new ParseException("Parse error: Invalid 'SUBJECT' value.");
            }

            return(new IMAP_Search_Key_Subject(value));
        }
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            /*
             *  Example:  S: * LIST (\Noselect) "/" ~/Mail/foo
             *
             *            C: A101 LIST "" ""
             *            S: * LIST (\Noselect) "/" ""
             *            S: A101 OK LIST Completed
             */

            // Hierarchy delimiter request.
            if (string.IsNullOrEmpty(m_FolderName))
            {
                return("* LIST (\\Noselect) \"/\" \"\"\r\n");
            }
            else
            {
                StringBuilder retVal = new StringBuilder();
                retVal.Append("* LIST (");
                if (m_pFolderAttributes != null)
                {
                    for (int i = 0; i < m_pFolderAttributes.Length; i++)
                    {
                        if (i > 0)
                        {
                            retVal.Append(" ");
                        }
                        retVal.Append(m_pFolderAttributes[i]);
                    }
                }
                retVal.Append(") ");
                retVal.Append("\"" + m_Delimiter + "\" ");
                retVal.Append(IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
                retVal.Append("\r\n");

                return(retVal.ToString());
            }
        }
        /// <summary>
        /// Parses QUOTAROOT response from quotaRoot-response string.
        /// </summary>
        /// <param name="response">QUOTAROOT response string.</param>
        /// <returns>Returns parsed QUOTAROOT response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public static IMAP_r_u_QuotaRoot Parse(string response)
        {
            if(response == null){
                throw new ArgumentNullException("response");
            }

            /* RFC 2087 5.2. QUOTAROOT Response.
                Data:       mailbox name
                            zero or more quota root names

                This response occurs as a result of a GETQUOTAROOT command.  The
                first string is the mailbox and the remaining strings are the
                names of the quota roots for the mailbox.

                Example:    S: * QUOTAROOT INBOX ""
                            S: * QUOTAROOT comp.mail.mime
            */

            StringReader r = new StringReader(response);
            // Eat "*"
            r.ReadWord();
            // Eat "QUOTAROOT"
            r.ReadWord();

            string folderName = TextUtils.UnQuoteString(IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord()));
            List<string> quotaRoots = new List<string>();
            while(r.Available > 0){
                string quotaRoot = r.ReadWord();
                if(quotaRoot != null){
                    quotaRoots.Add(quotaRoot);
                }
                else{
                    break;
                }
            }

            return new IMAP_r_u_QuotaRoot(folderName,quotaRoots.ToArray());
        }
        /// <summary>
        /// Parses LIST response from list-response string.
        /// </summary>
        /// <param name="listResponse">List response string.</param>
        /// <returns>Returns parsed list response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>listResponse</b> is null reference.</exception>
        public static IMAP_r_u_List Parse(string listResponse)
        {
            if (listResponse == null)
            {
                throw new ArgumentNullException("listResponse");
            }

            /* RFC 3501 7.2.2. LIST Response.
             *  Contents:   name attributes
             *              hierarchy delimiter
             *              name
             *
             *  The LIST response occurs as a result of a LIST command.  It
             *  returns a single name that matches the LIST specification.  There
             *  can be multiple LIST responses for a single LIST command.
             *
             *  Four name attributes are defined:
             *
             *  \Noinferiors
             *      It is not possible for any child levels of hierarchy to exist
             *      under this name; no child levels exist now and none can be
             *      created in the future.
             *
             *  \Noselect
             *      It is not possible to use this name as a selectable mailbox.
             *
             *  \Marked
             *      The mailbox has been marked "interesting" by the server; the
             *      mailbox probably contains messages that have been added since
             *      the last time the mailbox was selected.
             *
             *  \Unmarked
             *      The mailbox does not contain any additional messages since the
             *      last time the mailbox was selected.
             *
             *  If it is not feasible for the server to determine whether or not
             *  the mailbox is "interesting", or if the name is a \Noselect name,
             *  the server SHOULD NOT send either \Marked or \Unmarked.
             *
             *  The hierarchy delimiter is a character used to delimit levels of
             *  hierarchy in a mailbox name.  A client can use it to create child
             *  mailboxes, and to search higher or lower levels of naming
             *  hierarchy.  All children of a top-level hierarchy node MUST use
             *  the same separator character.  A NIL hierarchy delimiter means
             *  that no hierarchy exists; the name is a "flat" name.
             *
             *  The name represents an unambiguous left-to-right hierarchy, and
             *  MUST be valid for use as a reference in LIST and LSUB commands.
             *  Unless \Noselect is indicated, the name MUST also be valid as an
             *  argument for commands, such as SELECT, that accept mailbox names.
             *
             *  Example:    S: * LIST (\Noselect) "/" ~/Mail/foo
             */

            StringReader r = new StringReader(listResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "LIST"
            r.ReadWord();

            string attributes = r.ReadParenthesized();
            string delimiter  = r.ReadWord();
            string folder     = IMAP_Utils.DecodeMailbox(r.ReadToEnd().Trim());

            return(new IMAP_r_u_List(folder, delimiter[0], attributes == string.Empty ? new string[0] : attributes.Split(' ')));
        }
Esempio n. 19
0
        /// <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);
        }
        /// <summary>
        /// Starts parsing fetch data-items,
        /// </summary>
        /// <param name="imap">IMAP client.</param>
        /// <param name="r">Fetch line reader.</param>
        /// <param name="callback">Callback to be called when parsing completes.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>imap</b>,<b>r</b> or <b>callback</b> is null reference.</exception>
        private void ParseDataItems(IMAP_Client imap, StringReader r, EventHandler <EventArgs <Exception> > callback)
        {
            if (imap == null)
            {
                throw new ArgumentNullException("imap");
            }
            if (r == null)
            {
                throw new ArgumentNullException("r");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }

            /* RFC 3501 7.4.2. FETCH Response.
             *  Example:    S: * 23 FETCH (FLAGS (\Seen) RFC822.SIZE 44827)
             */

            while (true)
            {
                r.ReadToFirstChar();

                #region BODY[]

                if (r.StartsWith("BODY[", false))
                {
                    /* RFC 3501 7.4.2. FETCH Response.
                     *  BODY[<section>]<<origin octet>>
                     *   A string expressing the body contents of the specified section.
                     *   The string SHOULD be interpreted by the client according to the
                     *   content transfer encoding, body type, and subtype.
                     *
                     *   If the origin octet is specified, this string is a substring of
                     *   the entire body contents, starting at that origin octet.  This
                     *   means that BODY[]<0> MAY be truncated, but BODY[] is NEVER
                     *   truncated.
                     *
                     *      Note: The origin octet facility MUST NOT be used by a server
                     *      in a FETCH response unless the client specifically requested
                     *      it by means of a FETCH of a BODY[<section>]<<partial>> data
                     *      item.
                     *
                     *   8-bit textual data is permitted if a [CHARSET] identifier is
                     *   part of the body parameter parenthesized list for this section.
                     *   Note that headers (part specifiers HEADER or MIME, or the
                     *   header portion of a MESSAGE/RFC822 part), MUST be 7-bit; 8-bit
                     *   characters are not permitted in headers.  Note also that the
                     *   [RFC-2822] delimiting blank line between the header and the
                     *   body is not affected by header line subsetting; the blank line
                     *   is always included as part of header data, except in the case
                     *   of a message which has no body and no blank line.
                     *
                     *   Non-textual data such as binary data MUST be transfer encoded
                     *   into a textual form, such as BASE64, prior to being sent to the
                     *   client.  To derive the original binary data, the client MUST
                     *   decode the transfer encoded string.
                     */

                    // Eat BODY word.
                    r.ReadWord();

                    // Read body-section.
                    string section = r.ReadParenthesized();

                    // Read origin if any.
                    int offset = -1;
                    if (r.StartsWith("<"))
                    {
                        offset = Convert.ToInt32(r.ReadParenthesized().Split(' ')[0]);
                    }

                    IMAP_t_Fetch_r_i_Body dataItem = new IMAP_t_Fetch_r_i_Body(section, offset, new SwapableStream(32000));
                    m_pDataItems.Add(dataItem);

                    // Raise event, allow user to specify store stream.
                    IMAP_Client_e_FetchGetStoreStream eArgs = new IMAP_Client_e_FetchGetStoreStream(this, dataItem);
                    imap.OnFetchGetStoreStream(eArgs);
                    // User specified own stream, use it.
                    if (eArgs.Stream != null)
                    {
                        dataItem.Stream.Dispose();
                        dataItem.SetStream(eArgs.Stream);
                    }

                    // Read data will complete async and will continue data-items parsing, exit this method.
                    if (ReadData(imap, r, callback, dataItem.Stream))
                    {
                        return;
                    }
                    // Continue processing.
                    //else{
                }

                #endregion

                #region BODY

                else if (r.StartsWith("BODY ", false))
                {
                    // BODYSTRUCTURE can contain string literals, we just try to parse it.
                    // If parse fails, just get string literal and try again as long as all BODYSTRUCTURE data has read.

                    string bodyStructure = null;
                    while (true)
                    {
                        // Create temporary reader(we don't want to read partial BODYSTRUCTURE data from reader).
                        StringReader tmpReader = new StringReader(r.SourceString);

                        // Eat BODYSTRUCTURE word.
                        tmpReader.ReadWord();
                        tmpReader.ReadToFirstChar();

                        try{
                            bodyStructure = tmpReader.ReadParenthesized();
                            // We got full BODYSTRUCTURE, so use tmp reader as reader.
                            r = tmpReader;

                            break;
                        }
                        catch {
                            // Read completed async, it will continue parsing.
                            if (ReadStringLiteral(imap, r, callback))
                            {
                                return;
                            }
                        }
                    }

                    m_pDataItems.Add(IMAP_t_Fetch_r_i_BodyStructure.Parse(new StringReader(bodyStructure)));
                }

                #endregion

                #region BODYSTRUCTURE

                else if (r.StartsWith("BODYSTRUCTURE", false))
                {
                    // BODYSTRUCTURE can contain string literals, we just try to parse it.
                    // If parse fails, just get string literal and try again as long as all BODYSTRUCTURE data has read.

                    string bodyStructure = null;
                    while (true)
                    {
                        // Create temporary reader(we don't want to read partial BODYSTRUCTURE data from reader).
                        StringReader tmpReader = new StringReader(r.SourceString);

                        // Eat BODYSTRUCTURE word.
                        tmpReader.ReadWord();
                        tmpReader.ReadToFirstChar();

                        try{
                            bodyStructure = tmpReader.ReadParenthesized();
                            // We got full BODYSTRUCTURE, so use tmp reader as reader.
                            r = tmpReader;

                            break;
                        }
                        catch {
                            // Read completed async, it will continue parsing.
                            if (ReadStringLiteral(imap, r, callback))
                            {
                                return;
                            }
                        }
                    }

                    m_pDataItems.Add(IMAP_t_Fetch_r_i_BodyStructure.Parse(new StringReader(bodyStructure)));
                }

                #endregion

                #region ENVELOPE

                else if (r.StartsWith("ENVELOPE", false))
                {
                    // Envelope can contain string literals, we just try to parse it.
                    // If parse fails, just get string literal and try again as long as all ENVELOPE data has read.

                    string envelope = null;
                    while (true)
                    {
                        // Create temporary reader(we don't want to read partial ENVELOPE data from reader).
                        StringReader tmpReader = new StringReader(r.SourceString);

                        // Eat ENVELOPE word.
                        tmpReader.ReadWord();
                        tmpReader.ReadToFirstChar();

                        try{
                            envelope = tmpReader.ReadParenthesized();
                            // We got full ENVELOPE, so use tmp reader as reader.
                            r = tmpReader;

                            break;
                        }
                        catch {
                            // Read completed async, it will continue parsing.
                            if (ReadStringLiteral(imap, r, callback))
                            {
                                return;
                            }
                        }
                    }

                    m_pDataItems.Add(IMAP_t_Fetch_r_i_Envelope.Parse(new StringReader(envelope)));
                }

                #endregion

                #region FLAGS

                else if (r.StartsWith("FLAGS", false))
                {
                    /* RFC 3501 7.4.2. FETCH Response.
                     *  FLAGS
                     *      A parenthesized list of flags that are set for this message.
                     */

                    // Eat FLAGS word.
                    r.ReadWord();

                    m_pDataItems.Add(new IMAP_t_Fetch_r_i_Flags(IMAP_t_MsgFlags.Parse(r.ReadParenthesized())));
                }

                #endregion

                #region INTERNALDATE

                else if (r.StartsWith("INTERNALDATE", false))
                {
                    /* RFC 3501 7.4.2. FETCH Response.
                     *  INTERNALDATE
                     *      A string representing the internal date of the message.
                     */

                    // Eat INTERNALDATE word.
                    r.ReadWord();

                    m_pDataItems.Add(new IMAP_t_Fetch_r_i_InternalDate(IMAP_Utils.ParseDate(r.ReadWord())));
                }

                #endregion

                #region RFC822

                else if (r.StartsWith("RFC822 ", false))
                {
                    /* RFC 3501 7.4.2. FETCH Response.
                     *  RFC822
                     *      Equivalent to BODY[].
                     */

                    // Eat RFC822 word.
                    r.ReadWord();
                    r.ReadToFirstChar();

                    IMAP_t_Fetch_r_i_Rfc822 dataItem = new IMAP_t_Fetch_r_i_Rfc822(new SwapableStream(32000));
                    m_pDataItems.Add(dataItem);

                    // Raise event, allow user to specify store stream.
                    IMAP_Client_e_FetchGetStoreStream eArgs = new IMAP_Client_e_FetchGetStoreStream(this, dataItem);
                    imap.OnFetchGetStoreStream(eArgs);
                    // User specified own stream, use it.
                    if (eArgs.Stream != null)
                    {
                        dataItem.Stream.Dispose();
                        dataItem.SetStream(eArgs.Stream);
                    }

                    // Read data will complete async and will continue data-items parsing, exit this method.
                    if (ReadData(imap, r, callback, dataItem.Stream))
                    {
                        return;
                    }
                    // Continue processing.
                    //else{
                }

                #endregion

                #region RFC822.HEADER

                else if (r.StartsWith("RFC822.HEADER", false))
                {
                    /* RFC 3501 7.4.2. FETCH Response.
                     *  RFC822.HEADER
                     *      Equivalent to BODY[HEADER].  Note that this did not result in
                     *      \Seen being set, because RFC822.HEADER response data occurs as
                     *      a result of a FETCH of RFC822.HEADER.  BODY[HEADER] response
                     *      data occurs as a result of a FETCH of BODY[HEADER] (which sets
                     *      \Seen) or BODY.PEEK[HEADER] (which does not set \Seen).
                     */

                    // Eat RFC822.HEADER word.
                    r.ReadWord();
                    r.ReadToFirstChar();

                    IMAP_t_Fetch_r_i_Rfc822Header dataItem = new IMAP_t_Fetch_r_i_Rfc822Header(new SwapableStream(32000));
                    m_pDataItems.Add(dataItem);

                    // Raise event, allow user to specify store stream.
                    IMAP_Client_e_FetchGetStoreStream eArgs = new IMAP_Client_e_FetchGetStoreStream(this, dataItem);
                    imap.OnFetchGetStoreStream(eArgs);
                    // User specified own stream, use it.
                    if (eArgs.Stream != null)
                    {
                        dataItem.Stream.Dispose();
                        dataItem.SetStream(eArgs.Stream);
                    }

                    // Read data will complete async and will continue data-items parsing, exit this method.
                    if (ReadData(imap, r, callback, dataItem.Stream))
                    {
                        return;
                    }
                    // Continue processing.
                    //else{
                }

                #endregion

                #region RFC822.SIZE

                else if (r.StartsWith("RFC822.SIZE", false))
                {
                    /* RFC 3501 7.4.2. FETCH Response.
                     *  RFC822.SIZE
                     *      A number expressing the [RFC-2822] size of the message.
                     */

                    // Eat RFC822.SIZE word.
                    r.ReadWord();

                    m_pDataItems.Add(new IMAP_t_Fetch_r_i_Rfc822Size(Convert.ToInt32(r.ReadWord())));
                }

                #endregion

                #region RFC822.TEXT

                else if (r.StartsWith("RFC822.TEXT", false))
                {
                    /* RFC 3501 7.4.2. FETCH Response.
                     *  RFC822.TEXT
                     *      Equivalent to BODY[TEXT].
                     */

                    // Eat RFC822.TEXT word.
                    r.ReadWord();
                    r.ReadToFirstChar();

                    IMAP_t_Fetch_r_i_Rfc822Text dataItem = new IMAP_t_Fetch_r_i_Rfc822Text(new SwapableStream(32000));
                    m_pDataItems.Add(dataItem);

                    // Raise event, allow user to specify store stream.
                    IMAP_Client_e_FetchGetStoreStream eArgs = new IMAP_Client_e_FetchGetStoreStream(this, dataItem);
                    imap.OnFetchGetStoreStream(eArgs);
                    // User specified own stream, use it.
                    if (eArgs.Stream != null)
                    {
                        dataItem.Stream.Dispose();
                        dataItem.SetStream(eArgs.Stream);
                    }

                    // Read data will complete async and will continue data-items parsing, exit this method.
                    if (ReadData(imap, r, callback, dataItem.Stream))
                    {
                        return;
                    }
                    // Continue processing.
                    //else{
                }

                #endregion

                #region UID

                else if (r.StartsWith("UID", false))
                {
                    /* RFC 3501 7.4.2. FETCH Response.
                     *  UID
                     *      A number expressing the unique identifier of the message.
                     */

                    // Eat UID word.
                    r.ReadWord();

                    m_pDataItems.Add(new IMAP_t_Fetch_r_i_Uid(Convert.ToInt64(r.ReadWord())));
                }

                #endregion

                #region X-GM-MSGID

                else if (r.StartsWith("X-GM-MSGID", false))
                {
                    /* http://code.google.com/intl/et/apis/gmail/imap X-GM-MSGID.
                     *
                     */

                    // Eat X-GM-MSGID word.
                    r.ReadWord();

                    m_pDataItems.Add(new IMAP_t_Fetch_r_i_X_GM_MSGID(Convert.ToUInt64(r.ReadWord())));
                }

                #endregion

                #region X-GM-THRID

                else if (r.StartsWith("X-GM-THRID", false))
                {
                    /* http://code.google.com/intl/et/apis/gmail/imap X-GM-THRID.
                     *
                     */

                    // Eat X-GM-THRID word.
                    r.ReadWord();

                    m_pDataItems.Add(new IMAP_t_Fetch_r_i_X_GM_THRID(Convert.ToUInt64(r.ReadWord())));
                }

                #endregion

                #region ) - fetch closing.

                else if (r.StartsWith(")", false))
                {
                    break;
                }

                #endregion

                else
                {
                    throw new ParseException("Not supported FETCH data-item '" + r.ReadToEnd() + "'.");
                }
            }

            callback(this, new EventArgs <Exception>(null));
        }
        /// <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);
        }