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