/// <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", Helpers.GetDefaultIgnoreCaseComparison())) { 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)); }
/// <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)); }
/// <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.Decode_IMAP_UTF7_String(r.ReadToEnd().Trim())); return(new IMAP_r_u_LSub(folder, delimiter[0], attributes == string.Empty ? new string[0] : attributes.Split(' '))); }
/// <summary> /// Returns this as string. /// </summary> /// <param name="encode">If true, folder name is encoded with IMAP UTF-7 encoding.</param> /// <returns>Returns this as string.</returns> public string ToString(bool encode) { // 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 + "\" "); if (encode) { retVal.Append("\"" + IMAP_Utils.Encode_IMAP_UTF7_String(m_FolderName) + "\"\r\n"); } else { retVal.Append("\"" + m_FolderName + "\"\r\n"); } return(retVal.ToString()); }
/// <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", Helpers.GetDefaultIgnoreCaseComparison())) { 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)); }
/// <summary> /// Returns parsed IMAP SEARCH <b>SENTBEFORE (string)</b> key. /// </summary> /// <param name="r">String reader.</param> /// <returns>Returns parsed IMAP SEARCH <b>SENTBEFORE (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_SentBefore Parse(StringReader r) { if (r == null) { throw new ArgumentNullException("r"); } string word = r.ReadWord(); if (!string.Equals(word, "SENTBEFORE", StringComparison.InvariantCultureIgnoreCase)) { throw new ParseException("Parse error: Not a SEARCH 'SENTBEFORE' key."); } string value = r.ReadWord(); if (value == null) { throw new ParseException("Parse error: Invalid 'SENTBEFORE' value."); } DateTime date; try{ date = IMAP_Utils.ParseDate(value); } catch { throw new ParseException("Parse error: Invalid 'SENTBEFORE' value."); } return(new IMAP_Search_Key_SentBefore(date)); }
/// <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()); }
/// <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 + "\""); } }
/// <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)); }
/// <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()); }
/// <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: * MYRIGHTS INBOX rwiptsldaex StringBuilder retVal = new StringBuilder(); retVal.Append("* MYRIGHTS " + IMAP_Utils.EncodeMailbox(m_FolderName, encoding) + " \"" + m_pRights + "\"\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()); }
/// <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)); }
/// <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()); }
/// <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 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())); }
/// <summary> /// Returns parsed IMAP SEARCH <b>CC (string)</b> key. /// </summary> /// <param name="r">String reader.</param> /// <returns>Returns parsed IMAP SEARCH <b>CC (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_Cc Parse(StringReader r) { if (r == null) { throw new ArgumentNullException("r"); } string word = r.ReadWord(); if (!string.Equals(word, "CC", Helpers.GetDefaultIgnoreCaseComparison())) { throw new ParseException("Parse error: Not a SEARCH 'CC' key."); } string value = IMAP_Utils.ReadString(r); if (value == null) { throw new ParseException("Parse error: Invalid 'CC' value."); } return(new IMAP_Search_Key_Cc(value)); }
/// <summary> /// Returns parsed IMAP SEARCH <b>BODY (string)</b> key. /// </summary> /// <param name="r">String reader.</param> /// <returns>Returns parsed IMAP SEARCH <b>BODY (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_Body Parse(StringReader r) { if (r == null) { throw new ArgumentNullException("r"); } string word = r.ReadWord(); if (!string.Equals(word, "BODY", StringComparison.InvariantCultureIgnoreCase)) { throw new ParseException("Parse error: Not a SEARCH 'BODY' key."); } string value = IMAP_Utils.ReadString(r); if (value == null) { throw new ParseException("Parse error: Invalid 'BODY' value."); } return(new IMAP_Search_Key_Body(value)); }
/// <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 (!String2.Equals(word, "SUBJECT", StringComparison2.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 IMAP FETCH ENVELOPE data-item. /// </summary> /// <param name="fetchReader">Fetch reader.</param> /// <returns>Returns parsed IMAP FETCH ENVELOPE data-item.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>fetchReader</b> is null reference value.</exception> internal static IMAP_Envelope Parse(IMAP_Client._FetchResponseReader fetchReader) { if (fetchReader == null) { throw new ArgumentNullException("fetchReader"); } /* RFC 3501 7.4.2 ENVELOPE. * A parenthesized list that describes the envelope structure of a * message. This is computed by the server by parsing the * [RFC-2822] header into the component parts, defaulting various * fields as necessary. * * The fields of the envelope structure are in the following * order: date, subject, from, sender, reply-to, to, cc, bcc, * in-reply-to, and message-id. The date, subject, in-reply-to, * and message-id fields are strings. The from, sender, reply-to, * to, cc, and bcc fields are parenthesized lists of address * structures. * * An address structure is a parenthesized list that describes an * electronic mail address. The fields of an address structure * are in the following order: personal name, [SMTP] * at-domain-list (source route), mailbox name, and host name. * * [RFC-2822] group syntax is indicated by a special form of * address structure in which the host name field is NIL. If the * mailbox name field is also NIL, this is an end of group marker * (semi-colon in RFC 822 syntax). If the mailbox name field is * non-NIL, this is a start of group marker, and the mailbox name * field holds the group name phrase. * * If the Date, Subject, In-Reply-To, and Message-ID header lines * are absent in the [RFC-2822] header, the corresponding member * of the envelope is NIL; if these header lines are present but * empty the corresponding member of the envelope is the empty * string. * * Note: some servers may return a NIL envelope member in the * "present but empty" case. Clients SHOULD treat NIL and * empty string as identical. * * Note: [RFC-2822] requires that all messages have a valid * Date header. Therefore, the date member in the envelope can * not be NIL or the empty string. * * Note: [RFC-2822] requires that the In-Reply-To and * Message-ID headers, if present, have non-empty content. * Therefore, the in-reply-to and message-id members in the * envelope can not be the empty string. * * If the From, To, cc, and bcc header lines are absent in the * [RFC-2822] header, or are present but empty, the corresponding * member of the envelope is NIL. * * If the Sender or Reply-To lines are absent in the [RFC-2822] * header, or are present but empty, the server sets the * corresponding member of the envelope to be the same value as * the from member (the client is not expected to know to do * this). * * Note: [RFC-2822] requires that all messages have a valid * From header. Therefore, the from, sender, and reply-to * members in the envelope can not be NIL. */ // Eat "ENVELOPE". fetchReader.GetReader().ReadWord(); fetchReader.GetReader().ReadToFirstChar(); // Eat starting "(". fetchReader.GetReader().ReadSpecifiedLength(1); // Read "date". DateTime date = DateTime.MinValue; string dateS = fetchReader.ReadString(); if (dateS != null) { date = IMAP_Utils.ParseDate(dateS); } // Read "subject". string subject = fetchReader.ReadString(); // Read "from" Mail_t_Address[] from = ReadAddresses(fetchReader); //Read "sender" Mail_t_Address[] sender = ReadAddresses(fetchReader); // Read "reply-to" Mail_t_Address[] replyTo = ReadAddresses(fetchReader); // Read "to" Mail_t_Address[] to = ReadAddresses(fetchReader); // Read "cc" Mail_t_Address[] cc = ReadAddresses(fetchReader); // Read "bcc" Mail_t_Address[] bcc = ReadAddresses(fetchReader); // Read "in-reply-to" string inReplyTo = fetchReader.ReadString(); // Read "message-id" string messageID = fetchReader.ReadString(); // Eat ending ")". fetchReader.GetReader().ReadToFirstChar(); fetchReader.GetReader().ReadSpecifiedLength(1); return(new IMAP_Envelope(date, subject, from, sender, replyTo, to, cc, bcc, inReplyTo, messageID)); }
/// <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 MemoryStreamEx(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 MemoryStreamEx(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 MemoryStreamEx(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 MemoryStreamEx(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); }
/// <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 = TextUtils.UnQuoteString(IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadToEnd().Trim())); return(new IMAP_r_u_List(folder, delimiter[0], attributes == string.Empty ? new string[0] : attributes.Split(' '))); }
/// <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 */ // 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); } 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); } } 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); } } // 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); return(retVal); }