/// <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 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> /// 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 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)); }