Esempio n. 1
0
        public IMAP_FetchItem[] FetchMessages(int uid)
        {
            var sequenceMessages = new IMAP_SequenceSet();

            sequenceMessages.Parse(uid.ToString(), long.MaxValue);
            return(_imapClient.FetchMessages(sequenceMessages, IMAP_FetchItem_Flags.Message, false, true));
        }
Esempio n. 2
0
        /// <summary>
        /// Удаляет все сообщения из IMAP папки по фильтру subject
        /// </summary>
        public static void ClearImapFolder(string mailbox, string password, string folder, string subject)
        {
            using (var imapClient = new IMAP_Client()) {
                imapClient.Connect(Settings.Default.IMAPHost, Convert.ToInt32(Settings.Default.IMAPPort));
                imapClient.Authenticate(mailbox, password);
                imapClient.SelectFolder(folder);
                var sequenceSet = new IMAP_SequenceSet();
                sequenceSet.Parse("1:*", Int64.MaxValue);
                var items = String.IsNullOrEmpty(subject)
                                        ? imapClient.FetchMessages(sequenceSet, IMAP_FetchItem_Flags.UID, false, false)
                                        : imapClient.FetchMessages(sequenceSet, IMAP_FetchItem_Flags.UID | IMAP_FetchItem_Flags.Envelope, false, false);

                //производим фильтрацию, если параметр subject установлен
                if (!String.IsNullOrEmpty(subject) && items != null && items.Length > 0)
                {
                    items = items
                            .Where(i => i.Envelope.Subject?.Equals(subject, StringComparison.CurrentCultureIgnoreCase) == true)
                            .ToArray();
                }

                if ((items != null) && (items.Length > 0))
                {
                    var sequenceMessages = new IMAP_SequenceSet();
                    sequenceMessages.Parse(String.Join(",", items.Select(i => i.UID.ToString()).ToArray()), long.MaxValue);
                    imapClient.DeleteMessages(sequenceMessages, true);
                }
            }
        }
Esempio n. 3
0
        public void getEmail(string login, string password)
        {
            IMAP_Client client = new IMAP_Client();

            client.Connect("imap.yandex.ru", 993, true);
            client.Login(login, password);
            client.SelectFolder("INBOX");

            IMAP_SequenceSet sequence = new IMAP_SequenceSet();
            //sequence.Parse("*:1"); // from first to last
            IMAP_Client_FetchHandler fetchHandler = new IMAP_Client_FetchHandler();

            fetchHandler.NextMessage += new EventHandler(delegate(object s, EventArgs e)
            {
                Console.WriteLine("next message");
            });

            fetchHandler.Envelope += new EventHandler <EventArgs <IMAP_Envelope> >(delegate(object s, EventArgs <IMAP_Envelope> e)
            {
                IMAP_Envelope envelope = e.Value;
                if (envelope.From != null && !String.IsNullOrWhiteSpace(envelope.Subject))
                {
                    Console.WriteLine(envelope.Subject);
                }
            });
            // the best way to find unread emails is to perform server search
            int[] unseen_ids = client.Search(false, "UTF-8", "unseen");
            Console.WriteLine("unseen count: " + unseen_ids.Count().ToString());
            // now we need to initiate our sequence of messages to be fetched
            sequence.Parse(string.Join(",", unseen_ids));
            // fetch messages now
            client.Fetch(false, sequence, new IMAP_Fetch_DataItem[] { new IMAP_Fetch_DataItem_Envelope() }, fetchHandler);
            // uncomment this line to mark messages as read
            // client.StoreMessageFlags(false, sequence, IMAP_Flags_SetType.Add, IMAP_MessageFlags.Seen);
        }
Esempio n. 4
0
        public IMAP_FetchItem[] FetchUIDs()
        {
            var sequenceUids = new IMAP_SequenceSet();

            sequenceUids.Parse("1:*", long.MaxValue);
            return(_imapClient.FetchMessages(sequenceUids, IMAP_FetchItem_Flags.UID, false, false)
                   ?? Enumerable.Empty <IMAP_FetchItem>().ToArray());
        }
Esempio n. 5
0
        public static List <IMAP_FetchItem> CheckImapFolder(string mailbox, string password, string folder)
        {
            using (var imapClient = new IMAP_Client()) {
                imapClient.Connect(Settings.Default.IMAPHost, Convert.ToInt32(Settings.Default.IMAPPort));
                imapClient.Authenticate(mailbox, password);
                imapClient.SelectFolder(folder);
                var sequenceSet = new IMAP_SequenceSet();
                sequenceSet.Parse("1:*", Int64.MaxValue);
                var items = imapClient.FetchMessages(sequenceSet, IMAP_FetchItem_Flags.UID | IMAP_FetchItem_Flags.Envelope, false, false);
                if ((items != null) && (items.Length > 0))
                {
                    return(items.ToList());
                }
            }

            return(new List <IMAP_FetchItem>());
        }
        IEnumerable <ChannelMessageHeader> FetchImapSet(IMAP_SequenceSet set)
        {
            var result = connection.Client.FetchMessages(set,
                                                         IMAP_FetchItem_Flags.UID | IMAP_FetchItem_Flags.MessageFlags |
                                                         IMAP_FetchItem_Flags.InternalDate | IMAP_FetchItem_Flags.Size |
                                                         IMAP_FetchItem_Flags.Header | IMAP_FetchItem_Flags.Envelope, false, true);

            if (result != null && result.Length > 0)
            {
                foreach (var item in result)
                {
                    var header = new ChannelMessageHeader();
                    header.MessageNumber = item.UID.ToString();
                    header.SourceFolder  = connection.Client.SelectedFolder;
                    header.Size          = item.Size;
                    header.Context       = item.Envelope.Subject;
                    header.DateReceived  = item.Envelope.Date;
                    header.IsRead        = !item.IsNewMessage;

                    // Message is starred
                    if ((item.MessageFlags & IMAP_MessageFlags.Flagged) == IMAP_MessageFlags.Flagged)
                    {
                        header.IsStarred = true;
                    }

                    header.MessageIdentifier = item.Envelope.MessageID;
                    header.InReplyTo         = item.Envelope.InReplyTo;

                    var provider = new MIME_h_Provider();
                    var headers  = new MIME_h_Collection(provider);
                    headers.Parse(item.HeaderData);

                    var i2mpMessageId = headers.GetFirst("x-i2mp-messageid");
                    if (i2mpMessageId != null)
                    {
                        var unstructured = (MIME_h_Unstructured)i2mpMessageId;
                        header.Metadata.i2mpMessageId = unstructured.Value;
                    }

                    yield return(header);
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Deletes specified messages.
        /// </summary>
        /// <param name="sequence_set">IMAP sequence-set.</param>
        /// <param name="uidDelete">Specifies if sequence-set contains message UIDs or message numbers.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when IMAP client is not connected,not authenticated and folder not selected.</exception>
        public void DeleteMessages(IMAP_SequenceSet sequence_set, bool uidDelete)
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (!this.IsConnected)
            {
                throw new InvalidOperationException("You must connect first.");
            }
            if (!this.IsAuthenticated)
            {
                throw new InvalidOperationException("The command is only valid in authenticated state.");
            }
            if (m_SelectedFolder.Length == 0)
            {
                throw new InvalidOperationException("The command is only valid in selected state.");
            }

            // 1) Set deleted flag
            // 2) Delete messages with EXPUNGE command

            string line = "";
            if (uidDelete)
            {
                line = GetNextCmdTag() + " UID STORE " + sequence_set.ToSequenceSetString() + " " + "+FLAGS.SILENT (\\Deleted)";
            }
            else
            {
                line = GetNextCmdTag() + " STORE " + sequence_set.ToSequenceSetString() + " " + "+FLAGS.SILENT (\\Deleted)";
            }
            int countWritten = this.TcpStream.WriteLine(line);
            LogAddWrite(countWritten, line);

            // Read un-tagged response lines while we get final response line.
            while (true)
            {
                line = this.ReadLine();

                // We have un-tagged resposne.
                if (line.StartsWith("*"))
                {
                    ProcessStatusResponse(line);
                }
                else
                {
                    break;
                }
            }

            if (!RemoveCmdTag(line).ToUpper().StartsWith("OK"))
            {
                throw new IMAP_ClientException(line);
            }

            line = GetNextCmdTag() + " EXPUNGE";
            countWritten = this.TcpStream.WriteLine(line);
            LogAddWrite(countWritten, line);

            // Read un-tagged response lines while we get final response line.
            while (true)
            {
                line = this.ReadLine();

                // We have un-tagged resposne.
                if (line.StartsWith("*"))
                {
                    ProcessStatusResponse(line);
                }
                else
                {
                    break;
                }
            }

            if (!RemoveCmdTag(line).ToUpper().StartsWith("OK"))
            {
                throw new IMAP_ClientException(line);
            }
        }
        /// <summary>
        /// Deletes specified messages.
        /// </summary>
        /// <param name="sequence_set">IMAP sequence-set.</param>
        /// <param name="uidDelete">Specifies if sequence-set contains message UIDs or message numbers.</param>
        public void DeleteMessages(IMAP_SequenceSet sequence_set,bool uidDelete)
        {
            if(!m_Connected){
                throw new Exception("You must connect first !");
            }
            if(!m_Authenticated){
                throw new Exception("You must authenticate first !");
            }
            if(m_SelectedFolder.Length == 0){
                throw new Exception("You must select folder first !");
            }

            // 1) Set deleted flag
            // 2) Delete messages with EXPUNGE command

            if(uidDelete){
                m_pSocket.WriteLine("a1 UID STORE " + sequence_set.ToSequenceSetString()  + " +FLAGS.SILENT (\\Deleted)");
            }
            else{
                m_pSocket.WriteLine("a1 STORE " + sequence_set.ToSequenceSetString()  + " +FLAGS.SILENT (\\Deleted)");
            }

            // Read server resposnse
            string reply = m_pSocket.ReadLine();

            // There is STATUS reponse, read and process it
            while(reply.StartsWith("*")){
                ProcessStatusResponse(reply);

                reply = m_pSocket.ReadLine();
            }

            // We must get OK or otherwise there is error
            if(!RemoveCmdTag(reply).ToUpper().StartsWith("OK")){
                throw new Exception("Server returned:" + reply);
            }

            m_pSocket.WriteLine("a1 EXPUNGE");

            // Read server resposnse
            reply = m_pSocket.ReadLine();

            // There is STATUS reponse, read and process it
            while(reply.StartsWith("*")){
                ProcessStatusResponse(reply);

                reply = m_pSocket.ReadLine();
            }

            // We must get OK or otherwise there is error
            if(!RemoveCmdTag(reply).ToUpper().StartsWith("OK")){
                throw new Exception("Server returned:" + reply);
            }
        }
Esempio n. 9
0
        private void Copy(string cmdTag, string argsText, bool uidCopy)
        {
            /* RFC 3501 6.4.7 COPY Command
			
				Arguments:  message set
							mailbox name

				Responses:  no specific responses for this command

				Result:     OK - copy completed
							NO - copy error: can't copy those messages or to that
									name
							BAD - command unknown or arguments invalid
			   
				The COPY command copies the specified message(s) to the end of the
				specified destination mailbox.  The flags and internal date of the
				message(s) SHOULD be preserved in the copy.

				If the destination mailbox does not exist, a server SHOULD return
				an error.  It SHOULD NOT automatically create the mailbox.  Unless
				it is certain that the destination mailbox can not be created, the
				server MUST send the response code "[TRYCREATE]" as the prefix of
				the text of the tagged NO response.  This gives a hint to the
				client that it can attempt a CREATE command and retry the COPY if
				
				If the COPY command is unsuccessful for any reason, server
				implementations MUST restore the destination mailbox to its state
				before the COPY attempt.

				Example:    C: A003 COPY 2:4 MEETING
							S: A003 OK COPY completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            string[] args = ParseParams(argsText);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD Invalid arguments", cmdTag));
                return;
            }

            IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
            // Just try if it can be parsed as sequence-set
            try
            {
                if (uidCopy)
                {
                    if (m_pSelectedFolder.Messages.Count > 0)
                    {
                        sequenceSet.Parse(args[0],
                                          m_pSelectedFolder.Messages[m_pSelectedFolder.Messages.Count - 1].UID);
                    }
                }
                else
                {
                    sequenceSet.Parse(args[0], m_pSelectedFolder.Messages.Count);
                }
            }
            // This isn't vaild sequnce-set value
            catch
            {
                WriteLine(string.Format("{0}BAD Invalid <sequnce-set> value '{1}' Syntax: {{<command-tag> COPY <sequnce-set> \"<mailbox-name>\"}}!", cmdTag, args[0]));
                return;
            }

            string errorText = "";
            for (int i = 0; i < m_pSelectedFolder.Messages.Count; i++)
            {
                IMAP_Message msg = m_pSelectedFolder.Messages[i];

                // For UID COPY we must compare UIDs and for normal COPY message numbers. 
                bool sequenceSetContains = false;
                if (uidCopy)
                {
                    sequenceSetContains = sequenceSet.Contains(msg.UID);
                }
                else
                {
                    sequenceSetContains = sequenceSet.Contains(i + 1);
                }

                if (sequenceSetContains)
                {
                    errorText = ImapServer.OnCopyMessage(this, msg, Core.Decode_IMAP_UTF7_String(args[1]));
                    if (errorText != null)
                    {
                        break; // Errors return error text, don't try to copy other messages
                    }
                }
            }

            if (errorText == null)
            {
                WriteLine(string.Format("{0} OK COPY completed", cmdTag));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
            }
        }
Esempio n. 10
0
        private void Store(string cmdTag, string argsText, bool uidStore)
        {
            /* Rfc 3501 6.4.6 STORE Command
				
				Arguments:  message set
							message data item name
							value for message data item

				Responses:  untagged responses: FETCH

				Result:     OK - store completed
							NO - store error: can't store that data
							BAD - command unknown or arguments invalid
							
				The STORE command alters data associated with a message in the
				mailbox.  Normally, STORE will return the updated value of the
				data with an untagged FETCH response.  A suffix of ".SILENT" in
				the data item name prevents the untagged FETCH, and the server
				SHOULD assume that the client has determined the updated value
				itself or does not care about the updated value.
				
				Note: regardless of whether or not the ".SILENT" suffix was
					used, the server SHOULD send an untagged FETCH response if a
					change to a message's flags from an external source is
					observed.  The intent is that the status of the flags is
					determinate without a race condition.

				The currently defined data items that can be stored are:

				FLAGS <flag list>
					Replace the flags for the message (other than \Recent) with the
					argument.  The new value of the flags is returned as if a FETCH
					of those flags was done.

				FLAGS.SILENT <flag list>
					Equivalent to FLAGS, but without returning a new value.

				+FLAGS <flag list>
					Add the argument to the flags for the message.  The new value
					of the flags is returned as if a FETCH of those flags was done.

				+FLAGS.SILENT <flag list>
					Equivalent to +FLAGS, but without returning a new value.

				-FLAGS <flag list>
					Remove the argument from the flags for the message.  The new
					value of the flags is returned as if a FETCH of those flags was
					done.

				-FLAGS.SILENT <flag list>
					Equivalent to -FLAGS, but without returning a new value.
		 

				Example:    C: A003 STORE 2:4 +FLAGS (\Deleted)
							S: * 2 FETCH FLAGS (\Deleted \Seen)
							S: * 3 FETCH FLAGS (\Deleted)
							S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
							S: A003 OK STORE completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }
            if (m_pSelectedFolder.ReadOnly)
            {
                WriteLine(string.Format("{0} NO Mailbox is read-only", cmdTag));
                return;
            }

            // Store start time
            long startTime = DateTime.Now.Ticks;

            string[] args = ParseParams(argsText);
            if (args.Length != 3)
            {
                WriteLine(string.Format("{0} BAD STORE invalid arguments. Syntax: {{<command-tag> STORE <sequnce-set> <data-item> (<message-flags>)}}", cmdTag));
                return;
            }

            IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
            // Just try if it can be parsed as sequence-set
            try
            {
                if (uidStore)
                {
                    if (m_pSelectedFolder.Messages.Count > 0)
                    {
                        sequenceSet.Parse(args[0],
                                          m_pSelectedFolder.Messages[m_pSelectedFolder.Messages.Count - 1].UID);
                    }
                }
                else
                {
                    sequenceSet.Parse(args[0], m_pSelectedFolder.Messages.Count);
                }
            }
            // This isn't vaild sequnce-set value
            catch
            {
                WriteLine(string.Format("{0}BAD Invalid <sequnce-set> value '{1}' Syntax: {{<command-tag> STORE <sequnce-set> <data-item> (<message-flags>)}}!", cmdTag, args[0]));
                return;
            }

            //--- Parse Flags behaviour ---------------//
            string flagsAction = "";
            bool silent = false;
            string flagsType = args[1].ToUpper();
            switch (flagsType)
            {
                case "FLAGS":
                    flagsAction = "REPLACE";
                    break;

                case "FLAGS.SILENT":
                    flagsAction = "REPLACE";
                    silent = true;
                    break;

                case "+FLAGS":
                    flagsAction = "ADD";
                    break;

                case "+FLAGS.SILENT":
                    flagsAction = "ADD";
                    silent = true;
                    break;

                case "-FLAGS":
                    flagsAction = "REMOVE";
                    break;

                case "-FLAGS.SILENT":
                    flagsAction = "REMOVE";
                    silent = true;
                    break;

                default:
                    WriteLine(cmdTag + " BAD arguments invalid");
                    return;
            }
            //-------------------------------------------//

            //--- Parse flags, see if valid ----------------
            string flags = args[2].ToUpper();
            if (
                flags.Replace("\\ANSWERED", "").Replace("\\FLAGGED", "").Replace("\\DELETED", "").Replace(
                    "\\SEEN", "").Replace("\\DRAFT", "").Trim().Length > 0)
            {
                WriteLine(string.Format("{0} BAD arguments invalid", cmdTag));
                return;
            }

            IMAP_MessageFlags mFlags = IMAP_Utils.ParseMessageFlags(flags);

            // Call OnStoreMessageFlags for each message in sequence set
            // Calulate new flags(using old message flags + new flags) for message 
            // and request to store all flags to message, don't specify if add, remove or replace falgs.

            for (int i = 0; i < m_pSelectedFolder.Messages.Count; i++)
            {
                IMAP_Message msg = m_pSelectedFolder.Messages[i];

                // For UID STORE we must compare UIDs and for normal STORE message numbers. 
                bool sequenceSetContains = false;
                if (uidStore)
                {
                    sequenceSetContains = sequenceSet.Contains(msg.UID);
                }
                else
                {
                    sequenceSetContains = sequenceSet.Contains(i + 1);
                }

                if (sequenceSetContains)
                {
                    // Calculate new flags and set to msg
                    switch (flagsAction)
                    {
                        case "REPLACE":
                            msg.SetFlags(mFlags);
                            break;

                        case "ADD":
                            msg.SetFlags(msg.Flags | mFlags);
                            break;

                        case "REMOVE":
                            msg.SetFlags(msg.Flags & ~mFlags);
                            break;
                    }

                    // ToDo: see if flags changed, if not don't call OnStoreMessageFlags

                    string errorText = ImapServer.OnStoreMessageFlags(this, msg);
                    if (errorText == null)
                    {
                        if (!silent)
                        {
                            // Silent doesn't reply untagged lines
                            if (!uidStore)
                            {
                                WriteLine(string.Format("* {0} FETCH FLAGS ({1})", (i + 1), msg.FlagsString));
                            }
                            // Called from UID command, need to add UID response
                            else
                            {
                                WriteLine(string.Format("* {0} FETCH (FLAGS ({1}) UID {2}))", (i + 1), msg.FlagsString, msg.UID));
                            }
                        }
                    }
                    else
                    {
                        WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
                        return;
                    }
                }
            }

            WriteLine(string.Format("{0} OK STORE completed in {1} seconds", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2")));
        }
Esempio n. 11
0
        private void Fetch(string cmdTag, string argsText, bool uidFetch)
        {
            /* Rfc 3501 6.4.5 FETCH Command
			
                Arguments:  message set
                            message data item names

                Responses:  untagged responses: FETCH

                Result:     OK - fetch completed
                            NO - fetch error: can't fetch that data
                            BAD - command unknown or arguments invalid

                The FETCH command retrieves data associated with a message in the
                mailbox.  The data items to be fetched can be either a single atom
                or a parenthesized list.
				
            Most data items, identified in the formal syntax under the
            msg-att-static rule, are static and MUST NOT change for any
            particular message.  Other data items, identified in the formal
            syntax under the msg-att-dynamic rule, MAY change, either as a
            result of a STORE command or due to external events.

                For example, if a client receives an ENVELOPE for a
                message when it already knows the envelope, it can
                safely ignore the newly transmitted envelope.

            There are three macros which specify commonly-used sets of data
            items, and can be used instead of data items.  A macro must be
            used by itself, and not in conjunction with other macros or data
            items.
			
            ALL
                Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)

            FAST
                Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)

            FULL
                Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE
                BODY)

            The currently defined data items that can be fetched are:

            BODY
                Non-extensible form of BODYSTRUCTURE.

            BODY[<section>]<<partial>>
                The text of a particular body section.  The section
                specification is a set of zero or more part specifiers
                delimited by periods.  A part specifier is either a part number
                or one of the following: HEADER, HEADER.FIELDS,
                HEADER.FIELDS.NOT, MIME, and TEXT.  An empty section
                specification refers to the entire message, including the
                header.

                Every message has at least one part number.  Non-[MIME-IMB]
                messages, and non-multipart [MIME-IMB] messages with no
                encapsulated message, only have a part 1.

                Multipart messages are assigned consecutive part numbers, as
                they occur in the message.  If a particular part is of type
                message or multipart, its parts MUST be indicated by a period
                followed by the part number within that nested multipart part.

                A part of type MESSAGE/RFC822 also has nested part numbers,
                referring to parts of the MESSAGE part's body.

                The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT part
                specifiers can be the sole part specifier or can be prefixed by
                one or more numeric part specifiers, provided that the numeric
                part specifier refers to a part of type MESSAGE/RFC822.  The
                MIME part specifier MUST be prefixed by one or more numeric
                part specifiers.

                The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT part
                specifiers refer to the [RFC-2822] header of the message or of
                an encapsulated [MIME-IMT] MESSAGE/RFC822 message.
                HEADER.FIELDS and HEADER.FIELDS.NOT are followed by a list of
                field-name (as defined in [RFC-2822]) names, and return a
                subset of the header.  The subset returned by HEADER.FIELDS
                contains only those header fields with a field-name that
                matches one of the names in the list; similarly, the subset
                returned by HEADER.FIELDS.NOT contains only the header fields
                with a non-matching field-name.  The field-matching is
                case-insensitive but otherwise exact.  Subsetting does not
                exclude the [RFC-2822] delimiting blank line between the header
                and the body; the blank line is included in all header fetches,
                except in the case of a message which has no body and no blank
                line.

                The MIME part specifier refers to the [MIME-IMB] header for
                this part.

                The TEXT part specifier refers to the text body of the message,
                omitting the [RFC-2822] header.

                    Here is an example of a complex message with some of its
                    part specifiers:

                    HEADER     ([RFC-2822] header of the message)
                    TEXT       ([RFC-2822] text body of the message) MULTIPART/MIXED
                    1          TEXT/PLAIN
                    2          APPLICATION/OCTET-STREAM
                    3          MESSAGE/RFC822
                    3.HEADER   ([RFC-2822] header of the message)
                    3.TEXT     ([RFC-2822] text body of the message) MULTIPART/MIXED
                    3.1        TEXT/PLAIN
                    3.2        APPLICATION/OCTET-STREAM
                    4          MULTIPART/MIXED
                    4.1        IMAGE/GIF
                    4.1.MIME   ([MIME-IMB] header for the IMAGE/GIF)
                    4.2        MESSAGE/RFC822
                    4.2.HEADER ([RFC-2822] header of the message)
                    4.2.TEXT   ([RFC-2822] text body of the message) MULTIPART/MIXED
                    4.2.1      TEXT/PLAIN
                    4.2.2      MULTIPART/ALTERNATIVE
                    4.2.2.1    TEXT/PLAIN
                    4.2.2.2    TEXT/RICHTEXT


                It is possible to fetch a substring of the designated text.
                This is done by appending an open angle bracket ("<"), the
                octet position of the first desired octet, a period, the
                maximum number of octets desired, and a close angle bracket
                (">") to the part specifier.  If the starting octet is beyond
                the end of the text, an empty string is returned.
				
                Any partial fetch that attempts to read beyond the end of the
                text is truncated as appropriate.  A partial fetch that starts
                at octet 0 is returned as a partial fetch, even if this
                truncation happened.

                    Note: This means that BODY[]<0.2048> of a 1500-octet message
                    will return BODY[]<0> with a literal of size 1500, not
                    BODY[].

                    Note: A substring fetch of a HEADER.FIELDS or
                    HEADER.FIELDS.NOT part specifier is calculated after
                    subsetting the header.

                The \Seen flag is implicitly set; if this causes the flags to
                change, they SHOULD be included as part of the FETCH responses.

            BODY.PEEK[<section>]<<partial>>
                An alternate form of BODY[<section>] that does not implicitly
                set the \Seen flag.

            BODYSTRUCTURE
                The [MIME-IMB] body structure of the message.  This is computed
                by the server by parsing the [MIME-IMB] header fields in the
                [RFC-2822] header and [MIME-IMB] headers.

            ENVELOPE
                The envelope structure of the message.  This is computed by the
                server by parsing the [RFC-2822] header into the component
                parts, defaulting various fields as necessary.

            FLAGS
                The flags that are set for this message.

            INTERNALDATE
                The internal date of the message.

            RFC822
                Functionally equivalent to BODY[], differing in the syntax of
                the resulting untagged FETCH data (RFC822 is returned).

            RFC822.HEADER
                Functionally equivalent to BODY.PEEK[HEADER], differing in the
                syntax of the resulting untagged FETCH data (RFC822.HEADER is
                returned).

            RFC822.SIZE
                The [RFC-2822] size of the message.
				
            RFC822.TEXT
                Functionally equivalent to BODY[TEXT], differing in the syntax
                of the resulting untagged FETCH data (RFC822.TEXT is returned).

            UID
                The unique identifier for the message.


            Example:    C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
                        S: * 2 FETCH ....
                        S: * 3 FETCH ....
                        S: * 4 FETCH ....
                        S: A654 OK FETCH completed
	  
            */
            if (!this.IsAuthenticated)
            {
                TcpStream.WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                this.TcpStream.WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            TcpStream.MemoryBuffer = true;

            // Store start time
            long startTime = DateTime.Now.Ticks;

            IMAP_MessageItems_enum messageItems = IMAP_MessageItems_enum.None;

            #region Parse parameters

            string[] args = ParseParams(argsText);
            if (args.Length != 2)
            {
                this.TcpStream.WriteLine(string.Format("{0} BAD Invalid arguments", cmdTag));
                return;
            }

            IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
            // Just try if it can be parsed as sequence-set
            try
            {
                if (uidFetch)
                {
                    if (m_pSelectedFolder.Messages.Count > 0)
                    {
                        sequenceSet.Parse(args[0], m_pSelectedFolder.Messages[m_pSelectedFolder.Messages.Count - 1].UID);
                    }
                }
                else
                {
                    sequenceSet.Parse(args[0], m_pSelectedFolder.Messages.Count);
                }
            }
            // This isn't valid sequnce-set value
            catch
            {
                this.TcpStream.WriteLine(string.Format("{0} BAD Invalid <sequnce-set> value '{1}' Syntax: {{<command-tag> FETCH <sequnce-set> (<fetch-keys>)}}!", cmdTag, args[0]));
                return;
            }

            // Replace macros
            string fetchItems = args[1].ToUpper();
            fetchItems = fetchItems.Replace("ALL", "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE");
            fetchItems = fetchItems.Replace("FAST", "FLAGS INTERNALDATE RFC822.SIZE");
            fetchItems = fetchItems.Replace("FULL", "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY");

            // If UID FETCH and no UID, we must implicity add it, it's required 
            if (uidFetch && fetchItems.ToUpper().IndexOf("UID") == -1)
            {
                fetchItems += " UID";
            }

            // Start parm parsing from left to end in while loop while params parsed or bad param found
            ArrayList fetchFlags = new ArrayList();
            StringReader argsReader = new StringReader(fetchItems.Trim());
            while (argsReader.Available > 0)
            {
                argsReader.ReadToFirstChar();

                #region BODYSTRUCTURE

                // BODYSTRUCTURE
                if (argsReader.StartsWith("BODYSTRUCTURE"))
                {
                    argsReader.ReadSpecifiedLength("BODYSTRUCTURE".Length);

                    fetchFlags.Add(new object[] { "BODYSTRUCTURE" });
                    messageItems |= IMAP_MessageItems_enum.BodyStructure;
                }

                #endregion

                #region BODY, BODY[<section>]<<partial>>, BODY.PEEK[<section>]<<partial>>

                // BODY, BODY[<section>]<<partial>>, BODY.PEEK[<section>]<<partial>>
                else if (argsReader.StartsWith("BODY"))
                {
                    // Remove BODY
                    argsReader.ReadSpecifiedLength("BODY".Length);

                    bool peek = false;
                    // BODY.PEEK
                    if (argsReader.StartsWith(".PEEK"))
                    {
                        // Remove .PEEK
                        argsReader.ReadSpecifiedLength(".PEEK".Length);

                        peek = true;
                    }

                    // [<section>]<<partial>>
                    if (argsReader.StartsWith("["))
                    {
                        // Read value between []
                        string section = "";
                        try
                        {
                            section = argsReader.ReadParenthesized();
                        }
                        catch
                        {
                            this.TcpStream.WriteLine(cmdTag + " BAD Invalid BODY[], closing ] parenthesize is missing !");
                            return;
                        }

                        string originalSectionValue = section;
                        string mimePartsSpecifier = "";
                        string sectionType = "";
                        string sectionArgs = "";
                        /* Validate <section>
                             Section can be:
                                ""                                                    - entire message								
                                [MimePartsSepcifier.]HEADER                           - message header
                                [MimePartsSepcifier.]HEADER.FIELDS (headerFields)     - message header fields
                                [MimePartsSepcifier.]HEADER.FIELDS.NOT (headerFields) - message header fields except requested
                                [MimePartsSepcifier.]TEXT                             - message text
                                [MimePartsSepcifier.]MIME                             - same as header, different response
                        */
                        if (section.Length > 0)
                        {
                            string[] section_args = section.Split(new char[] { ' ' }, 2);
                            section = section_args[0];
                            if (section_args.Length == 2)
                            {
                                sectionArgs = section_args[1];
                            }

                            if (section.EndsWith("HEADER"))
                            {
                                // Remove HEADER from end
                                section = section.Substring(0, section.Length - "HEADER".Length);

                                sectionType = "HEADER";
                                messageItems |= IMAP_MessageItems_enum.Header;
                            }
                            else if (section.EndsWith("HEADER.FIELDS"))
                            {
                                // Remove HEADER.FIELDS from end
                                section = section.Substring(0, section.Length - "HEADER.FIELDS".Length);

                                sectionType = "HEADER.FIELDS";
                                messageItems |= IMAP_MessageItems_enum.Header;
                            }
                            else if (section.EndsWith("HEADER.FIELDS.NOT"))
                            {
                                // Remove HEADER.FIELDS.NOT from end
                                section = section.Substring(0, section.Length - "HEADER.FIELDS.NOT".Length);

                                sectionType = "HEADER.FIELDS.NOT";
                                messageItems |= IMAP_MessageItems_enum.Header;
                            }
                            else if (section.EndsWith("TEXT"))
                            {
                                // Remove TEXT from end
                                section = section.Substring(0, section.Length - "TEXT".Length);

                                sectionType = "TEXT";
                                messageItems |= IMAP_MessageItems_enum.Message;
                            }
                            else if (section.EndsWith("MIME"))
                            {
                                // Remove MIME from end
                                section = section.Substring(0, section.Length - "MIME".Length);

                                sectionType = "MIME";
                                messageItems = IMAP_MessageItems_enum.Header;
                            }

                            // Remove last ., if there is any
                            if (section.EndsWith("."))
                            {
                                section = section.Substring(0, section.Length - 1);
                            }

                            // MimePartsSepcifier is specified, validate it. It can contain numbers only.
                            if (section.Length > 0)
                            {
                                // Now we certainly need full message, because nested mime parts wanted
                                messageItems |= IMAP_MessageItems_enum.Message;

                                string[] sectionParts = section.Split('.');
                                foreach (string sectionPart in sectionParts)
                                {
                                    if (!Core.IsNumber(sectionPart))
                                    {
                                        this.TcpStream.WriteLine(string.Format("{0} BAD Invalid BODY[<section>] argument. Invalid <section>: {1}", cmdTag, section));
                                        return;
                                    }
                                }

                                mimePartsSpecifier = section;
                            }
                        }
                        else
                        {
                            messageItems |= IMAP_MessageItems_enum.Message;
                        }

                        long startPosition = -1;
                        long length = -1;
                        // See if partial fetch
                        if (argsReader.StartsWith("<"))
                        {
                            /* <partial> syntax:
									startPosition[.endPosition]							  
							*/

                            // Read partial value between <>
                            string partial = "";
                            try
                            {
                                partial = argsReader.ReadParenthesized();
                            }
                            catch
                            {
                                this.TcpStream.WriteLine(string.Format("{0} BAD Invalid BODY[]<start[.length]>, closing > parenthesize is missing !", cmdTag));
                                return;
                            }

                            string[] start_length = partial.Split('.');

                            // Validate <partial>
                            if (start_length.Length == 0 || start_length.Length > 2 || !Core.IsNumber(start_length[0]) || (start_length.Length == 2 && !Core.IsNumber(start_length[1])))
                            {
                                this.TcpStream.WriteLine(string.Format("{0} BAD Invalid BODY[]<partial> argument. Invalid <partial>: {1}", cmdTag, partial));
                                return;
                            }

                            startPosition = Convert.ToInt64(start_length[0]);
                            if (start_length.Length == 2)
                            {
                                length = Convert.ToInt64(start_length[1]);
                            }
                        }

                        // object[] structure for BODY[]
                        //	fetchFlagName
                        //	isPeek
                        //	mimePartsSpecifier
                        //  originalSectionValue
                        //	sectionType
                        //	sectionArgs
                        //	startPosition
                        //	length
                        fetchFlags.Add(new object[] { "BODY[]", peek, mimePartsSpecifier, originalSectionValue, sectionType, sectionArgs, startPosition, length });
                    }
                    // BODY
                    else
                    {
                        fetchFlags.Add(new object[] { "BODY" });
                        messageItems |= IMAP_MessageItems_enum.BodyStructure;
                    }
                }

                #endregion

                #region ENVELOPE

                // ENVELOPE
                else if (argsReader.StartsWith("ENVELOPE"))
                {
                    argsReader.ReadSpecifiedLength("ENVELOPE".Length);

                    fetchFlags.Add(new object[] { "ENVELOPE" });
                    messageItems |= IMAP_MessageItems_enum.Envelope;
                }

                #endregion

                #region FLAGS

                // FLAGS
                //	The flags that are set for this message.
                else if (argsReader.StartsWith("FLAGS"))
                {
                    argsReader.ReadSpecifiedLength("FLAGS".Length);

                    fetchFlags.Add(new object[] { "FLAGS" });
                }

                #endregion

                #region INTERNALDATE

                // INTERNALDATE
                else if (argsReader.StartsWith("INTERNALDATE"))
                {
                    argsReader.ReadSpecifiedLength("INTERNALDATE".Length);

                    fetchFlags.Add(new object[] { "INTERNALDATE" });
                }

                #endregion

                #region RFC822.HEADER

                // RFC822.HEADER
                else if (argsReader.StartsWith("RFC822.HEADER"))
                {
                    argsReader.ReadSpecifiedLength("RFC822.HEADER".Length);

                    fetchFlags.Add(new object[] { "RFC822.HEADER" });
                    messageItems |= IMAP_MessageItems_enum.Header;
                }

                #endregion

                #region RFC822.SIZE

                // RFC822.SIZE
                //	The [RFC-2822] size of the message.
                else if (argsReader.StartsWith("RFC822.SIZE"))
                {
                    argsReader.ReadSpecifiedLength("RFC822.SIZE".Length);

                    fetchFlags.Add(new object[] { "RFC822.SIZE" });
                }

                #endregion

                #region RFC822.TEXT

                // RFC822.TEXT
                else if (argsReader.StartsWith("RFC822.TEXT"))
                {
                    argsReader.ReadSpecifiedLength("RFC822.TEXT".Length);

                    fetchFlags.Add(new object[] { "RFC822.TEXT" });
                    messageItems |= IMAP_MessageItems_enum.Message;
                }

                #endregion

                #region RFC822

                // RFC822 NOTE: RFC822 must be below RFC822.xxx or is parsed wrong !
                else if (argsReader.StartsWith("RFC822"))
                {
                    argsReader.ReadSpecifiedLength("RFC822".Length);

                    fetchFlags.Add(new object[] { "RFC822" });
                    messageItems |= IMAP_MessageItems_enum.Message;
                }

                #endregion

                #region UID

                // UID
                //	The unique identifier for the message.
                else if (argsReader.StartsWith("UID"))
                {
                    argsReader.ReadSpecifiedLength("UID".Length);

                    fetchFlags.Add(new object[] { "UID" });
                }

                #endregion

                // This must be unknown fetch flag
                else
                {
                    this.TcpStream.WriteLine(string.Format("{0} BAD Invalid fetch-items argument. Unkown part starts from: {1}", cmdTag, argsReader.SourceString));
                    return;
                }
            }

            #endregion

            // ToDo: ??? But non of the servers do it ?
            // The server should respond with a tagged BAD response to a command that uses a message
            // sequence number greater than the number of messages in the selected mailbox.  This
            // includes "*" if the selected mailbox is empty.
            //	if(m_Messages.Count == 0 || ){
            //		SendData(cmdTag + " BAD Sequence number greater than the number of messages in the selected mailbox !\r\n");
            //		return;
            //	}

            // Create buffered writer, so we make less network calls.

            for (int i = 0; i < m_pSelectedFolder.Messages.Count; i++)
            {
                IMAP_Message msg = m_pSelectedFolder.Messages[i];

                // For UID FETCH we must compare UIDs and for normal FETCH message numbers. 
                bool sequenceSetContains = false;
                if (uidFetch)
                {
                    sequenceSetContains = sequenceSet.Contains(msg.UID);
                }
                else
                {
                    sequenceSetContains = sequenceSet.Contains(i + 1);
                }

                if (sequenceSetContains)
                {
                    IMAP_eArgs_MessageItems eArgs = null;
                    // Get message items only if they are needed.
                    if (messageItems != IMAP_MessageItems_enum.None)
                    {
                        // Raise event GetMessageItems to get all neccesary message itmes
                        eArgs = ImapServer.OnGetMessageItems(this, msg, messageItems);

                        // Message doesn't exist any more, notify email client.
                        if (!eArgs.MessageExists)
                        {
                            TcpStream.Write("* " + msg.SequenceNo + " EXPUNGE");
                            ImapServer.OnDeleteMessage(this, msg);
                            m_pSelectedFolder.Messages.Remove(msg);
                            i--;
                            continue;
                        }
                        try
                        {
                            // Ensure that all requested items were provided.
                            eArgs.Validate();
                        }
                        catch (Exception x)
                        {
                            ImapServer.OnSysError(x.Message, x);
                            this.TcpStream.WriteLine(string.Format("{0} NO Internal IMAP server component error: {1}", cmdTag, x.Message));
                            return;
                        }
                    }

                    // Write fetch start data "* msgNo FETCH ("
                    TcpStream.Write("* " + (i + 1) + " FETCH (");

                    IMAP_MessageFlags msgFlagsOr = msg.Flags;
                    // Construct reply here, based on requested fetch items
                    int nCount = 0;
                    foreach (object[] fetchFlag in fetchFlags)
                    {
                        string fetchFlagName = (string)fetchFlag[0];

                        #region BODY

                        // BODY
                        if (fetchFlagName == "BODY")
                        {
                            // Sets \seen flag
                            msg.SetFlags(msg.Flags | IMAP_MessageFlags.Seen);

                            // BODY ()
                            TcpStream.Write("BODY " + eArgs.BodyStructure);
                        }

                        #endregion

                        #region BODY[], BODY.PEEK[]

                        // BODY[<section>]<<partial>>, BODY.PEEK[<section>]<<partial>>
                        else if (fetchFlagName == "BODY[]")
                        {
                            // Force to write all buffered data.
                            TcpStream.Flush();

                            // object[] structure for BODY[]
                            //	fetchFlagName
                            //	isPeek
                            //	mimePartsSpecifier
                            //  originalSectionValue
                            //	sectionType
                            //	sectionArgs
                            //	startPosition
                            //	length
                            bool isPeek = (bool)fetchFlag[1];
                            string mimePartsSpecifier = (string)fetchFlag[2];
                            string originalSectionValue = (string)fetchFlag[3];
                            string sectionType = (string)fetchFlag[4];
                            string sectionArgs = (string)fetchFlag[5];
                            long startPosition = (long)fetchFlag[6];
                            long length = (long)fetchFlag[7];

                            // Difference between BODY[] and BODY.PEEK[] is that .PEEK won't set seen flag
                            if (!isPeek)
                            {
                                // Sets \seen flag
                                msg.SetFlags(msg.Flags | IMAP_MessageFlags.Seen);
                            }

                            /* Section value:
                                ""                - entire message								
                                HEADER            - message header
                                HEADER.FIELDS     - message header fields
                                HEADER.FIELDS.NOT - message header fields except requested
                                TEXT              - message text
                                MIME              - same as header, different response
                            */
                            Stream dataStream = null;
                            if (sectionType == "" && mimePartsSpecifier == "")
                            {
                                dataStream = eArgs.MessageStream;
                            }
                            else
                            {
                                Mime parser = null;
                                try
                                {
                                    if (eArgs.MessageStream == null)
                                    {
                                        parser = Mime.Parse(eArgs.Header);
                                    }
                                    else
                                    {
                                        parser = Mime.Parse(eArgs.MessageStream);
                                    }
                                }
                                // Invalid message, parsing failed
                                catch
                                {
                                    parser = Mime.CreateSimple(new AddressList(), new AddressList(), "BAD Message", "This is BAD message, mail server failed to parse it !", "");
                                }
                                MimeEntity currentEntity = parser.MainEntity;
                                // Specific mime entity requested, get it
                                if (mimePartsSpecifier != "")
                                {
                                    currentEntity = FetchHelper.GetMimeEntity(parser, mimePartsSpecifier);
                                }

                                if (currentEntity != null)
                                {
                                    if (sectionType == "HEADER")
                                    {
                                        dataStream = new MemoryStream(FetchHelper.GetMimeEntityHeader(currentEntity));
                                    }
                                    else if (sectionType == "HEADER.FIELDS")
                                    {
                                        dataStream = new MemoryStream(FetchHelper.ParseHeaderFields(sectionArgs, currentEntity));
                                    }
                                    else if (sectionType == "HEADER.FIELDS.NOT")
                                    {
                                        dataStream = new MemoryStream(FetchHelper.ParseHeaderFieldsNot(sectionArgs, currentEntity));
                                    }
                                    else if (sectionType == "TEXT")
                                    {
                                        try
                                        {
                                            if (currentEntity.DataEncoded != null)
                                            {
                                                dataStream = new MemoryStream(currentEntity.DataEncoded);
                                            }
                                        }
                                        catch
                                        { // This probably multipart entity, data isn't available
                                        }
                                    }
                                    else if (sectionType == "MIME")
                                    {
                                        dataStream = new MemoryStream(FetchHelper.GetMimeEntityHeader(currentEntity));
                                    }
                                    else if (sectionType == "")
                                    {
                                        try
                                        {
                                            dataStream = new MemoryStream(currentEntity.DataEncoded);
                                        }
                                        catch
                                        { // This probably multipart entity, data isn't available
                                        }
                                    }
                                }
                            }

                            // Partial fetch. Reports <origin position> in fetch reply.
                            if (startPosition > -1)
                            {
                                if (dataStream == null)
                                {
                                    this.TcpStream.Write("BODY[" + originalSectionValue + "]<" + startPosition.ToString() + "> \"\"\r\n");
                                }
                                else
                                {
                                    long lengthToSend = length;
                                    if (lengthToSend == -1)
                                    {
                                        lengthToSend = (dataStream.Length - dataStream.Position) - startPosition;
                                    }
                                    if ((lengthToSend + startPosition) > (dataStream.Length - dataStream.Position))
                                    {
                                        lengthToSend = (dataStream.Length - dataStream.Position) - startPosition;
                                    }

                                    if (startPosition >= (dataStream.Length - dataStream.Position))
                                    {
                                        this.TcpStream.Write("BODY[" + originalSectionValue + "]<" + startPosition.ToString() + "> \"\"\r\n");
                                    }
                                    else
                                    {
                                        this.TcpStream.Write("BODY[" + originalSectionValue + "]<" + startPosition.ToString() + "> {" + lengthToSend + "}\r\n");
                                        dataStream.Position += startPosition;
                                        this.TcpStream.WriteStream(dataStream, lengthToSend);
                                    }
                                }
                            }
                            // Normal fetch
                            else
                            {
                                if (dataStream == null)
                                {
                                    this.TcpStream.Write("BODY[" + originalSectionValue + "] \"\"\r\n");
                                }
                                else
                                {
                                    this.TcpStream.Write("BODY[" + originalSectionValue + "] {" + (dataStream.Length - dataStream.Position) + "}\r\n");
                                    this.TcpStream.WriteStream(dataStream);
                                }
                            }
                        }

                        #endregion

                        #region BODYSTRUCTURE

                        // BODYSTRUCTURE
                        else if (fetchFlagName == "BODYSTRUCTURE")
                        {
                            TcpStream.Write("BODYSTRUCTURE " + eArgs.BodyStructure);
                        }

                        #endregion

                        #region ENVELOPE

                        // ENVELOPE
                        else if (fetchFlagName == "ENVELOPE")
                        {
                            TcpStream.Write("ENVELOPE " + eArgs.Envelope);
                        }

                        #endregion

                        #region FLAGS

                        // FLAGS
                        else if (fetchFlagName == "FLAGS")
                        {
                            TcpStream.Write("FLAGS (" + msg.FlagsString + ")");
                        }

                        #endregion

                        #region INTERNALDATE

                        // INTERNALDATE
                        else if (fetchFlagName == "INTERNALDATE")
                        {
                            // INTERNALDATE "date"
                            TcpStream.Write("INTERNALDATE \"" + IMAP_Utils.DateTimeToString(msg.InternalDate) + "\"");
                        }

                        #endregion

                        #region RFC822

                        // RFC822
                        else if (fetchFlagName == "RFC822")
                        {
                            // Force to write all buffered data.
                            TcpStream.Flush();

                            // Sets \seen flag
                            msg.SetFlags(msg.Flags | IMAP_MessageFlags.Seen);

                            // RFC822 {size}
                            // msg data
                            this.TcpStream.Write("RFC822 {" + eArgs.MessageSize.ToString() + "}\r\n");
                            this.TcpStream.WriteStream(eArgs.MessageStream);
                        }

                        #endregion

                        #region RFC822.HEADER

                        // RFC822.HEADER
                        else if (fetchFlagName == "RFC822.HEADER")
                        {
                            // Force to write all buffered data.
                            TcpStream.Flush();

                            // RFC822.HEADER {size}
                            // msg header data
                            this.TcpStream.Write("RFC822.HEADER {" + eArgs.Header.Length + "}\r\n");
                            this.TcpStream.Write(eArgs.Header);
                        }

                        #endregion

                        #region RFC822.SIZE

                        // RFC822.SIZE
                        else if (fetchFlagName == "RFC822.SIZE")
                        {
                            // RFC822.SIZE size
                            TcpStream.Write("RFC822.SIZE " + msg.Size);
                        }

                        #endregion

                        #region RFC822.TEXT

                        // RFC822.TEXT
                        else if (fetchFlagName == "RFC822.TEXT")
                        {
                            // Force to write all buffered data.
                            TcpStream.Flush();

                            // Sets \seen flag
                            msg.SetFlags(msg.Flags | IMAP_MessageFlags.Seen);

                            //--- Find body text entity ------------------------------------//
                            Mime parser = Mime.Parse(eArgs.MessageStream);
                            MimeEntity bodyTextEntity = null;
                            if (parser.MainEntity.ContentType == MediaType_enum.NotSpecified)
                            {
                                if (parser.MainEntity.DataEncoded != null)
                                {
                                    bodyTextEntity = parser.MainEntity;
                                }
                            }
                            else
                            {
                                MimeEntity[] entities = parser.MimeEntities;
                                foreach (MimeEntity entity in entities)
                                {
                                    if (entity.ContentType == MediaType_enum.Text_plain)
                                    {
                                        bodyTextEntity = entity;
                                        break;
                                    }
                                }
                            }
                            //----------------------------------------------------------------//

                            // RFC822.TEXT {size}
                            // msg text	
                            byte[] data = null;
                            if (bodyTextEntity != null)
                            {
                                data = bodyTextEntity.DataEncoded;
                            }
                            else
                            {
                                data = System.Text.Encoding.ASCII.GetBytes("");
                            }

                            this.TcpStream.Write("RFC822.TEXT {" + data.Length + "}\r\n");
                            this.TcpStream.Write(data);
                        }

                        #endregion

                        #region UID

                        // UID
                        else if (fetchFlagName == "UID")
                        {
                            TcpStream.Write("UID " + msg.UID);
                        }

                        #endregion

                        nCount++;

                        // Write fetch item separator data " "
                        // We don't write it for last item
                        if (nCount < fetchFlags.Count)
                        {
                            TcpStream.Write(" ");
                        }
                    }

                    // Write fetch end data ")"
                    TcpStream.Write(")\r\n");

                    // Free event args, close message stream, ... .
                    if (eArgs != null)
                    {
                        eArgs.Dispose();
                    }

                    // Set message flags here if required or changed
                    if (((int)IMAP_MessageFlags.Recent & (int)msg.Flags) != 0 || msgFlagsOr != msg.Flags)
                    {
                        msg.SetFlags(msg.Flags & ~IMAP_MessageFlags.Recent);

                        ImapServer.OnStoreMessageFlags(this, msg);
                    }
                }
            }

            // Force to write all buffered data.
            TcpStream.Flush();

            this.TcpStream.WriteLine(string.Format("{0} OK FETCH completed in {1} seconds", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2")));
        }
        /// <summary>
        /// Parses one search key from current position. Returns null if there isn't any search key left.
        /// </summary>
        /// <param name="reader"></param>
        public static SearchKey Parse(StringReader reader)
        {
            string searchKeyName  = "";
            object searchKeyValue = null;

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

            // Search keyname is always 1 word
            string word = reader.ReadWord();

            if (word == null)
            {
                return(null);
            }
            word = word.ToUpper().Trim();

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

            #region ALL

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

            #endregion

            #region ANSWERED

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

            #endregion

            #region BCC

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

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

            #endregion

            #region BEFORE

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

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

            #endregion

            #region BODY

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

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

            #endregion

            #region CC

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

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

            #endregion

            #region DELETED

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

            #endregion

            #region DRAFT

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

            #endregion

            #region FLAGGED

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

            #endregion

            #region FROM

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

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

            #endregion

            #region HEADER

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

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

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

            #endregion

            #region KEYWORD

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

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

            #endregion

            #region LARGER

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

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

            #endregion

            #region NEW

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

            #endregion

            #region NOT

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

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

            #endregion

            #region OLD

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

            #endregion

            #region ON

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

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

            #endregion

            #region OR

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

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

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

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

            #endregion

            #region RECENT

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

            #endregion

            #region SEEN

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

            #endregion

            #region SENTBEFORE

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

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

            #endregion

            #region SENTON

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

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

            #endregion

            #region SENTSINCE

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

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

            #endregion

            #region SINCE

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

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

            #endregion

            #region SMALLER

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

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

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

            #endregion

            #region SUBJECT

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

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

            #endregion

            #region TEXT

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

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

            #endregion

            #region TO

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

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

            #endregion

            #region UID

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

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

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

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

            #endregion

            #region UNANSWERED

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

            #endregion

            #region UNDELETED

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

            #endregion

            #region UNDRAFT

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

            #endregion

            #region UNFLAGGED

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

            #endregion

            #region UNKEYWORD

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

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

            #endregion

            #region UNSEEN

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

            #endregion

            #region Unknown or SEQUENCESET

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

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

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

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

            #endregion

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

            return(new SearchKey(searchKeyName, searchKeyValue));
        }
        /// <summary>
        /// Copies specified messages to specified folder.
        /// </summary>
        /// <param name="sequence_set">IMAP sequence-set.</param>
        /// <param name="destFolder">Destination folder name.</param>
        /// <param name="uidCopy">Specifies if UID COPY or COPY. 
        /// For UID COPY all sequence_set numers must be message UID values and for normal COPY message numbers.</param>
        public void CopyMessages(IMAP_SequenceSet sequence_set,string destFolder,bool uidCopy)
        {
            if(!m_Connected){
                throw new Exception("You must connect first !");
            }
            if(!m_Authenticated){
                throw new Exception("You must authenticate first !");
            }
            if(m_SelectedFolder.Length == 0){
                throw new Exception("You must select folder first !");
            }

            if(uidCopy){
                m_pSocket.WriteLine("a1 UID COPY " + sequence_set.ToSequenceSetString() + " \"" + Core.Encode_IMAP_UTF7_String(destFolder) + "\"");
            }
            else{
                m_pSocket.WriteLine("a1 COPY " + sequence_set.ToSequenceSetString() + " \"" + Core.Encode_IMAP_UTF7_String(destFolder) + "\"");
            }

            // Read server resposnse
            string reply = m_pSocket.ReadLine();

            // There is STATUS reponse, read and process it
            while(reply.StartsWith("*")){
                ProcessStatusResponse(reply);

                reply = m_pSocket.ReadLine();
            }

            // We must get OK or otherwise there is error
            if(!RemoveCmdTag(reply).ToUpper().StartsWith("OK")){
                throw new Exception("Server returned:" + reply);
            }
        }
Esempio n. 14
0
            /// <summary>
            /// Gets messages which match to the specified sequence set.
            /// </summary>
            /// <param name="uid">Specifies if sequence set contains UID or sequence numbers.</param>
            /// <param name="seqSet">Sequence set.</param>
            /// <returns>Returns messages which match to the specified sequence set.</returns>
            /// <exception cref="ArgumentNullException">Is raised when <b>seqSet</b> is null reference.</exception>
            internal IMAP_MessageInfo[] Filter(bool uid,IMAP_SequenceSet seqSet)
            {
                if(seqSet == null){
                    throw new ArgumentNullException("seqSet");
                }

                List<IMAP_MessageInfo> retVal = new List<IMAP_MessageInfo>();
                for(int i=0;i<m_pMessagesInfo.Count;i++){
                    IMAP_MessageInfo msgInfo = m_pMessagesInfo[i];
                    if(uid){
                        if(seqSet.Contains(msgInfo.UID)){
                            retVal.Add(msgInfo);
                        }
                    }
                    else{
                        if(seqSet.Contains(i + 1)){
                            retVal.Add(msgInfo);
                        }
                    }
                }

                return retVal.ToArray();
            }
        /// <summary>
        /// Fetches specifes messages specified fetch items.
        /// </summary>
        /// <param name="sequence_set">IMAP sequence-set.</param>
        /// <param name="fetchFlags">Specifies what data to fetch from IMAP server.</param>
        /// <param name="setSeenFlag">If true message seen flag is setted.</param>
        /// <param name="uidFetch">Specifies if sequence-set contains message UIDs or message numbers.</param>
        /// <returns></returns>
        public IMAP_FetchItem[] FetchMessages(IMAP_SequenceSet sequence_set,IMAP_FetchItem_Flags fetchFlags,bool setSeenFlag,bool uidFetch)
        {
            if(!m_Connected){
                throw new Exception("You must connect first !");
            }
            if(!m_Authenticated){
                throw new Exception("You must authenticate first !");
            }
            if(m_SelectedFolder.Length == 0){
                throw new Exception("You must select folder first !");
            }

            List<IMAP_FetchItem> fetchItems = new List<IMAP_FetchItem>();

            //--- Construct FETCH command line -----------------------------------------------------------------------//
            string fetchCmdLine = "a1";
            if(uidFetch){
                fetchCmdLine += " UID";
            }
            fetchCmdLine += " FETCH " + sequence_set.ToSequenceSetString() + " (UID";

            // FLAGS
            if((fetchFlags & IMAP_FetchItem_Flags.MessageFlags) != 0){
                fetchCmdLine += " FLAGS";
            }
            // RFC822.SIZE
            if((fetchFlags & IMAP_FetchItem_Flags.Size) != 0){
                fetchCmdLine += " RFC822.SIZE";
            }
            // INTERNALDATE
            if((fetchFlags & IMAP_FetchItem_Flags.InternalDate) != 0){
                fetchCmdLine += " INTERNALDATE";
            }
            // ENVELOPE
            if((fetchFlags & IMAP_FetchItem_Flags.Envelope) != 0){
                fetchCmdLine += " ENVELOPE";
            }
            // BODYSTRUCTURE
            if((fetchFlags & IMAP_FetchItem_Flags.BodyStructure) != 0){
                fetchCmdLine += " BODYSTRUCTURE";
            }
            // BODY[] or BODY.PEEK[]
            if((fetchFlags & IMAP_FetchItem_Flags.Message) != 0){
                if(setSeenFlag){
                    fetchCmdLine += " BODY[]";
                }
                else{
                    fetchCmdLine += " BODY.PEEK[]";
                }
            }
            // BODY[HEADER] or BODY.PEEK[HEADER] ---> This needed only if full message isn't requested.
            if((fetchFlags & IMAP_FetchItem_Flags.Message) == 0 && (fetchFlags & IMAP_FetchItem_Flags.Header) != 0){
                if(setSeenFlag){
                    fetchCmdLine += " BODY[HEADER]";
                }
                else{
                    fetchCmdLine += " BODY.PEEK[HEADER]";
                }
            }
            //--------------------------------------------------------------------------------------------------------//

            fetchCmdLine += ")";

            // Send fetch command line to server
            m_pSocket.WriteLine(fetchCmdLine);

            // Must get lines with * and cmdTag + OK or cmdTag BAD/NO
            string reply = m_pSocket.ReadLine(50000);
            // Read multiline response
            while(reply.StartsWith("*")){
                // Fetch may return status response there, skip them
                if(IsStatusResponse(reply)){
                    // Read next fetch item or server response
                    reply = m_pSocket.ReadLine(50000);
                    continue;
                }

                int               no            = 0;
                int               uid           = 0;
                int               size          = 0;
                byte[]            data          = null;
                IMAP_MessageFlags flags         = IMAP_MessageFlags.Recent;
                string            envelope      = "";
                string            bodystructure = "";
                string            internalDate  = "";

                // Remove *
                reply = reply.Substring(1).TrimStart();

                // Get message number
                no = Convert.ToInt32(reply.Substring(0,reply.IndexOf(" ")));

                // Get rid of FETCH  and parse params. Reply:* 1 FETCH (UID 12 BODY[] ...)
                reply = reply.Substring(reply.IndexOf("FETCH (") + 7);

                StringReader r = new StringReader(reply);
                // Loop fetch result fields
                while(r.Available > 0){
                    r.ReadToFirstChar();

                    // Fetch command closing ) parenthesis
                    if(r.SourceString == ")"){
                        break;
                    }

                    #region UID <value>

                    // UID <value>
                    else if(r.StartsWith("UID",false)){
                        // Remove UID word from reply
                        r.ReadSpecifiedLength("UID".Length);
                        r.ReadToFirstChar();

                        // Read <value>
                        string word = r.ReadWord();
                        if(word == null){
                            throw new Exception("IMAP server didn't return UID <value> !");
                        }
                        else{
                            uid = Convert.ToInt32(word);
                        }
                    }

                    #endregion

                    #region RFC822.SIZE <value>

                    // RFC822.SIZE <value>
                    else if(r.StartsWith("RFC822.SIZE",false)){
                        // Remove RFC822.SIZE word from reply
                        r.ReadSpecifiedLength("RFC822.SIZE".Length);
                        r.ReadToFirstChar();

                        // Read <value>
                        string word = r.ReadWord();
                        if(word == null){
                            throw new Exception("IMAP server didn't return RFC822.SIZE <value> !");
                        }
                        else{
                            try{
                                size = Convert.ToInt32(word);
                            }
                            catch{
                                throw new Exception("IMAP server returned invalid RFC822.SIZE <value> '" + word + "' !");
                            }
                        }
                    }

                    #endregion

                    #region INTERNALDATE <value>

                    // INTERNALDATE <value>
                    else if(r.StartsWith("INTERNALDATE",false)){
                        // Remove INTERNALDATE word from reply
                        r.ReadSpecifiedLength("INTERNALDATE".Length);
                        r.ReadToFirstChar();

                        // Read <value>
                        string word = r.ReadWord();
                        if(word == null){
                            throw new Exception("IMAP server didn't return INTERNALDATE <value> !");
                        }
                        else{
                            internalDate = word;
                        }
                    }

                    #endregion

                    #region ENVELOPE (<envelope-string>)

                    else if(r.StartsWith("ENVELOPE",false)){
                        // Remove ENVELOPE word from reply
                        r.ReadSpecifiedLength("ENVELOPE".Length);
                        r.ReadToFirstChar();

                        /*
                            Handle string literals {count-to-read}<CRLF>data(length = count-to-read).
                            (string can be quoted string or literal)
                            Loop while get envelope,invalid response or timeout.
                        */

                        while(true){
                            try{
                                envelope = r.ReadParenthesized();
                                break;
                            }
                            catch(Exception x){
                                string s = r.ReadToEnd();

                                /* partial_envelope {count-to-read}
                                   Example: ENVELOPE ("Mon, 03 Apr 2006 10:10:10 GMT" {35}
                                */
                                if(s.EndsWith("}")){
                                    // Get partial envelope and append it back to reader
                                    r.AppenString(s.Substring(0,s.LastIndexOf('{')));

                                    // Read remaining envelope and append it to reader
                                    int countToRead = Convert.ToInt32(s.Substring(s.LastIndexOf('{') + 1,s.LastIndexOf('}') - s.LastIndexOf('{') - 1));
                                    MemoryStream strm = new MemoryStream();
                                    m_pSocket.ReadSpecifiedLength(countToRead,strm);
                                    r.AppenString(TextUtils.QuoteString(System.Text.Encoding.Default.GetString(strm.ToArray())));

                                    // Read fetch continuing line
                                    r.AppenString(m_pSocket.ReadLine(50000));
                                }
                                // Unexpected response
                                else{
                                    throw x;
                                }
                            }
                        }
                    }

                    #endregion

                    #region BODYSTRUCTURE (<bodystructure-string>)

                    else if(r.StartsWith("BODYSTRUCTURE",false)){
                        // Remove BODYSTRUCTURE word from reply
                        r.ReadSpecifiedLength("BODYSTRUCTURE".Length);
                        r.ReadToFirstChar();

                        bodystructure = r.ReadParenthesized();
                    }

                    #endregion

                    #region BODY[] or BODY[HEADER]

                    // BODY[] or BODY[HEADER]
                    else if(r.StartsWith("BODY",false)){
                        if(r.StartsWith("BODY[]",false)){
                            // Remove BODY[]
                            r.ReadSpecifiedLength("BODY[]".Length);
                        }
                        else if(r.StartsWith("BODY[HEADER]",false)){
                            // Remove BODY[HEADER]
                            r.ReadSpecifiedLength("BODY[HEADER]".Length);
                        }
                        else{
                            throw new Exception("Invalid FETCH response: " + r.SourceString);
                        }
                        r.ReadToFirstChar();

                        // We must now have {<size-to-read>}, or there is error
                        if(!r.StartsWith("{")){
                            throw new Exception("Invalid FETCH BODY[] or BODY[HEADER] response: " + r.SourceString);
                        }
                        // Read <size-to-read>
                        int dataLength = Convert.ToInt32(r.ReadParenthesized());

                        // Read data
                        MemoryStream storeStrm = new MemoryStream(dataLength);
                        m_pSocket.ReadSpecifiedLength(dataLength,storeStrm);
                        data = storeStrm.ToArray();

                        // Read fetch continuing line
                        r.AppenString(m_pSocket.ReadLine(50000).Trim());
                    }

                    #endregion

                    #region FLAGS (<flags-list>)

                    // FLAGS (<flags-list>)
                    else if(r.StartsWith("FLAGS",false)){
                        // Remove FLAGS word from reply
                        r.ReadSpecifiedLength("FLAGS".Length);
                        r.ReadToFirstChar();

                        // Read (<flags-list>)
                        string flagsList = r.ReadParenthesized();
                        if(flagsList == null){
                            throw new Exception("IMAP server didn't return FLAGS (<flags-list>) !");
                        }
                        else{
                            flags = IMAP_Utils.ParseMessageFlags(flagsList);
                        }
                    }

                    #endregion

                    else{
                        throw new Exception("Not supported fetch reply: " + r.SourceString);
                    }
                }

                fetchItems.Add(new IMAP_FetchItem(no,uid,size,data,flags,internalDate,envelope,bodystructure,fetchFlags));

                // Read next fetch item or server response
                reply = m_pSocket.ReadLine(50000);
            }

            // We must get OK or otherwise there is error
            if(!RemoveCmdTag(reply).ToUpper().StartsWith("OK")){
                if(!reply.ToUpper().StartsWith("NO")){
                    throw new Exception("Server returned:" + reply);
                }
            }

            return fetchItems.ToArray();
        }
Esempio n. 16
0
        /// <summary>
        /// Copies specified messages to specified folder.
        /// </summary>
        /// <param name="sequence_set">IMAP sequence-set.</param>
        /// <param name="destFolder">Destination folder name.</param>
        /// <param name="uidCopy">Specifies if UID COPY or COPY. 
        /// For UID COPY all sequence_set numers must be message UID values and for normal COPY message numbers.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when IMAP client is not connected,not authenticated and folder not selected.</exception>
        public void CopyMessages(IMAP_SequenceSet sequence_set, string destFolder, bool uidCopy)
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (!this.IsConnected)
            {
                throw new InvalidOperationException("You must connect first.");
            }
            if (!this.IsAuthenticated)
            {
                throw new InvalidOperationException("The COPY command is only valid in authenticated state.");
            }
            if (m_SelectedFolder.Length == 0)
            {
                throw new InvalidOperationException("The COPY command is only valid in selected state.");
            }

            // Ensure that we send right separator to server, we accept both \ and /.
            destFolder = destFolder.Replace('\\', this.PathSeparator).Replace('/', this.PathSeparator);

            string line = "";
            if (uidCopy)
            {
                line = GetNextCmdTag() + " UID COPY " + sequence_set.ToSequenceSetString() + " " + TextUtils.QuoteString(Core.Encode_IMAP_UTF7_String(destFolder));
            }
            else
            {
                line = GetNextCmdTag() + " COPY " + sequence_set.ToSequenceSetString() + " " + TextUtils.QuoteString(Core.Encode_IMAP_UTF7_String(destFolder));
            }
            int countWritten = this.TcpStream.WriteLine(line);
            LogAddWrite(countWritten, line);

            // Read un-tagged response lines while we get final response line.
            while (true)
            {
                line = this.ReadLine();

                // We have un-tagged resposne.
                if (line.StartsWith("*"))
                {
                    ProcessStatusResponse(line);
                }
                else
                {
                    break;
                }
            }

            if (!RemoveCmdTag(line).ToUpper().StartsWith("OK"))
            {
                throw new IMAP_ClientException(line);
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Moves specified messages to specified folder.
        /// </summary>
        /// <param name="sequence_set">IMAP sequence-set.</param>
        /// <param name="destFolder">Folder where to copy messages.</param>
        /// <param name="uidMove">Specifies if sequence-set contains message UIDs or message numbers.</param>
        public void MoveMessages(IMAP_SequenceSet sequence_set, string destFolder, bool uidMove)
        {
            if (!this.IsConnected)
            {
                throw new Exception("You must connect first !");
            }
            if (!this.IsAuthenticated)
            {
                throw new Exception("You must authenticate first !");
            }
            if (m_SelectedFolder.Length == 0)
            {
                throw new Exception("You must select folder first !");
            }

            CopyMessages(sequence_set, destFolder, uidMove);
            DeleteMessages(sequence_set, uidMove);
        }
Esempio n. 18
0
        public void RemoveMessageFlags(IMAP_SequenceSet sequence_set,
                                       IMAP_MessageFlags msgFlags,
                                       bool uidStore)
        {
            if (IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (!IsConnected)
            {
                throw new InvalidOperationException("You must connect first.");
            }
            if (!IsAuthenticated)
            {
                throw new InvalidOperationException("The command is only valid in authenticated state.");
            }
            if (m_SelectedFolder.Length == 0)
            {
                throw new InvalidOperationException("The command is only valid in selected state.");
            }

            string line = "";
            if (uidStore)
            {
                line = GetNextCmdTag() + " UID STORE " + sequence_set.ToSequenceSetString() +
                       " -FLAGS.SILENT (" + IMAP_Utils.MessageFlagsToString(msgFlags) + ")";
            }
            else
            {
                line = GetNextCmdTag() + " STORE " + sequence_set.ToSequenceSetString() + " -FLAGS.SILENT (" +
                       IMAP_Utils.MessageFlagsToString(msgFlags) + ")";
            }
            int countWritten = TcpStream.WriteLine(line);
            LogAddWrite(countWritten, line);

            // Read un-tagged response lines while we get final response line.
            while (true)
            {
                line = ReadLine();

                // We have un-tagged resposne.
                if (line.StartsWith("*"))
                {
                    ProcessStatusResponse(line);
                }
                else
                {
                    break;
                }
            }

            if (!RemoveCmdTag(line).ToUpper().StartsWith("OK"))
            {
                throw new IMAP_ClientException(line);
            }
        }
        public IEnumerable <ChannelMessageHeader> GetHeaders()
        {
            var set = new IMAP_SequenceSet(String.Format("{0}:{1}", StartIndex <= 1 ? 1 : StartIndex, EndIndex < 0 ? "*" : EndIndex.ToString()));

            return(FetchImapSet(set));
        }
Esempio n. 20
0
        public void ProcessIMAPFolder()
        {
            using (var imapClient = new IMAP_Client()) {
                _imapClient = imapClient;
                ConnectToIMAP();

                try {
                    var items    = Enumerable.Empty <IMAP_FetchItem>().ToArray();
                    var toDelete = new List <IMAP_FetchItem>();
                    do
                    {
                        toDelete.Clear();
                        ImapReader.PingReader();
                        items = FetchUIDs();
                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat("Получено {0} UIDs", items.Length);
                        }
                        //обрабатываем мисьма пачками что бы уменьшить вероятность появления дублей
                        //при остановке шатной или аварийной остановке
                        items = items.Take(100).ToArray();
                        ImapReader.PingReader();

                        foreach (var item in items)
                        {
                            if (log.IsDebugEnabled)
                            {
                                log.DebugFormat("Обработка {0} UID", item.UID);
                            }

                            IMAP_FetchItem[] OneItem = null;
                            try {
                                OneItem = FetchMessages(item.UID);

                                Message = Mime.Parse(OneItem[0].MessageData);

                                CurrentUID = item.UID;

                                ImapReader.PingReader();
                                ImapReader.ProcessMime(Message);
                                toDelete.Add(item);
                            }
                            catch (Exception ex) {
                                if (log.IsDebugEnabled)
                                {
                                    log.Debug(String.Format("Не удалось обработать письмо {0} UID", item.UID), ex);
                                }
                                Message = null;
                                var errorInfo = GetErrorInfo(item.UID);
                                if (UIDTimeout(errorInfo))
                                {
                                    ErrorInfos.Remove(errorInfo);
                                    toDelete.Add(item);
                                    ImapReader.ProcessBrokenMessage(item, OneItem, ex);
                                }
                            }
                        }

                        //Производим удаление писем
                        if (toDelete.Count > 0)
                        {
                            var sequence = new IMAP_SequenceSet();

                            sequence.Parse(String.Join(",", toDelete.Select(i => i.UID.ToString())), long.MaxValue);
                            imapClient.DeleteMessages(sequence, true);
                        }
                    } while (items.Length > 0 && toDelete.Count > 0);
                }
                finally {
                    Message = null;
                }
            }
        }
Esempio n. 21
0
        /// <summary>
        /// Fetches specifes messages specified fetch items.
        /// </summary>
        /// <param name="sequence_set">IMAP sequence-set.</param>
        /// <param name="fetchFlags">Specifies what data to fetch from IMAP server.</param>
        /// <param name="setSeenFlag">If true message seen flag is setted.</param>
        /// <param name="uidFetch">Specifies if sequence-set contains message UIDs or message numbers.</param>
        /// <returns>Returns requested fetch items.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when IMAP client is not connected,not authenticated and folder not selected.</exception>
        public IMAP_FetchItem[] FetchMessages(IMAP_SequenceSet sequence_set, IMAP_FetchItem_Flags fetchFlags, bool setSeenFlag, bool uidFetch)
        {
            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (!this.IsConnected)
            {
                throw new InvalidOperationException("You must connect first.");
            }
            if (!this.IsAuthenticated)
            {
                throw new InvalidOperationException("The command is only valid in authenticated state.");
            }
            if (m_SelectedFolder.Length == 0)
            {
                throw new InvalidOperationException("The command is only valid in selected state.");
            }

            List<IMAP_FetchItem> fetchItems = new List<IMAP_FetchItem>();

            //--- Construct FETCH command line -----------------------------------------------------------------------//
            string fetchCmdLine = GetNextCmdTag();
            if (uidFetch)
            {
                fetchCmdLine += " UID";
            }
            fetchCmdLine += " FETCH " + sequence_set.ToSequenceSetString() + " (UID";

            // FLAGS
            if ((fetchFlags & IMAP_FetchItem_Flags.MessageFlags) != 0)
            {
                fetchCmdLine += " FLAGS";
            }
            // RFC822.SIZE
            if ((fetchFlags & IMAP_FetchItem_Flags.Size) != 0)
            {
                fetchCmdLine += " RFC822.SIZE";
            }
            // INTERNALDATE
            if ((fetchFlags & IMAP_FetchItem_Flags.InternalDate) != 0)
            {
                fetchCmdLine += " INTERNALDATE";
            }
            // ENVELOPE
            if ((fetchFlags & IMAP_FetchItem_Flags.Envelope) != 0)
            {
                fetchCmdLine += " ENVELOPE";
            }
            // BODYSTRUCTURE
            if ((fetchFlags & IMAP_FetchItem_Flags.BodyStructure) != 0)
            {
                fetchCmdLine += " BODYSTRUCTURE";
            }
            // BODY[] or BODY.PEEK[]
            if ((fetchFlags & IMAP_FetchItem_Flags.Message) != 0)
            {
                if (setSeenFlag)
                {
                    fetchCmdLine += " BODY[]";
                }
                else
                {
                    fetchCmdLine += " BODY.PEEK[]";
                }
            }
            // BODY[HEADER] or BODY.PEEK[HEADER] ---> This needed only if full message isn't requested.
            if ((fetchFlags & IMAP_FetchItem_Flags.Message) == 0 && (fetchFlags & IMAP_FetchItem_Flags.Header) != 0)
            {
                if (setSeenFlag)
                {
                    fetchCmdLine += " BODY[HEADER]";
                }
                else
                {
                    fetchCmdLine += " BODY.PEEK[HEADER]";
                }
            }
            //--------------------------------------------------------------------------------------------------------//

            fetchCmdLine += ")";

            // Send fetch command line to server.
            int countWritten = this.TcpStream.WriteLine(fetchCmdLine);
            LogAddWrite(countWritten, fetchCmdLine);

            // Read un-tagged response lines while we get final response line.
            byte[] lineBuffer = new byte[100000];
            string line = "";
            while (true)
            {
                SmartStream.ReadLineAsyncOP args = new SmartStream.ReadLineAsyncOP(lineBuffer, SizeExceededAction.JunkAndThrowException);
                this.TcpStream.ReadLine(args, false);
                if (args.Error != null)
                {
                    throw args.Error;
                }
                line = args.LineUtf8;
                LogAddRead(args.BytesInBuffer, line);

                // We have un-tagged resposne.
                if (line.StartsWith("*"))
                {
                    if (IsStatusResponse(line))
                    {
                        ProcessStatusResponse(line);
                    }
                    else
                    {
                        int no = 0;
                        int uid = 0;
                        int size = 0;
                        byte[] data = null;
                        IMAP_MessageFlags flags = IMAP_MessageFlags.Recent;
                        string envelope = "";
                        string bodystructure = "";
                        string internalDate = "";

                        // Remove *
                        line = RemoveCmdTag(line);

                        // Get message number
                        no = Convert.ToInt32(line.Substring(0, line.IndexOf(" ")));

                        // Get rid of FETCH  and parse params. Reply:* 1 FETCH (UID 12 BODY[] ...)
                        line = line.Substring(line.IndexOf("FETCH (") + 7);

                        StringReader r = new StringReader(line);
                        // Loop fetch result fields
                        while (r.Available > 0)
                        {
                            r.ReadToFirstChar();

                            // Fetch command closing ) parenthesis
                            if (r.SourceString == ")")
                            {
                                break;
                            }

                            #region UID <value>

                            // UID <value>
                            else if (r.StartsWith("UID", false))
                            {
                                // Remove UID word from reply
                                r.ReadSpecifiedLength("UID".Length);
                                r.ReadToFirstChar();

                                // Read <value>
                                string word = r.ReadWord();
                                if (word == null)
                                {
                                    throw new Exception("IMAP server didn't return UID <value> !");
                                }
                                else
                                {
                                    uid = Convert.ToInt32(word);
                                }
                            }

                            #endregion

                            #region RFC822.SIZE <value>

                            // RFC822.SIZE <value>
                            else if (r.StartsWith("RFC822.SIZE", false))
                            {
                                // Remove RFC822.SIZE word from reply
                                r.ReadSpecifiedLength("RFC822.SIZE".Length);
                                r.ReadToFirstChar();

                                // Read <value>
                                string word = r.ReadWord();
                                if (word == null)
                                {
                                    throw new Exception("IMAP server didn't return RFC822.SIZE <value> !");
                                }
                                else
                                {
                                    try
                                    {
                                        size = Convert.ToInt32(word);
                                    }
                                    catch
                                    {
                                        throw new Exception("IMAP server returned invalid RFC822.SIZE <value> '" + word + "' !");
                                    }
                                }
                            }

                            #endregion

                            #region INTERNALDATE <value>

                            // INTERNALDATE <value>
                            else if (r.StartsWith("INTERNALDATE", false))
                            {
                                // Remove INTERNALDATE word from reply
                                r.ReadSpecifiedLength("INTERNALDATE".Length);
                                r.ReadToFirstChar();

                                // Read <value>
                                string word = r.ReadWord();
                                if (word == null)
                                {
                                    throw new Exception("IMAP server didn't return INTERNALDATE <value> !");
                                }
                                else
                                {
                                    internalDate = word;
                                }
                            }

                            #endregion

                            #region ENVELOPE (<envelope-string>)

                            else if (r.StartsWith("ENVELOPE", false))
                            {
                                // Remove ENVELOPE word from reply
                                r.ReadSpecifiedLength("ENVELOPE".Length);
                                r.ReadToFirstChar();

                                /*
                                    Handle string literals {count-to-read}<CRLF>data(length = count-to-read).
                                    (string can be quoted string or literal)
                                    Loop while get envelope,invalid response or timeout.
                                */

                                while (true)
                                {
                                    try
                                    {
                                        envelope = r.ReadParenthesized();
                                        break;
                                    }
                                    catch (Exception x)
                                    {
                                        string s = r.ReadToEnd();

                                        /* partial_envelope {count-to-read}
                                            Example: ENVELOPE ("Mon, 03 Apr 2006 10:10:10 GMT" {35}
                                        */
                                        if (s.EndsWith("}"))
                                        {
                                            // Get partial envelope and append it back to reader
                                            r.AppenString(s.Substring(0, s.LastIndexOf('{')));

                                            // Read remaining envelope and append it to reader.
                                            int countToRead = Convert.ToInt32(s.Substring(s.LastIndexOf('{') + 1, s.LastIndexOf('}') - s.LastIndexOf('{') - 1));
                                            string reply = this.TcpStream.ReadFixedCountString(countToRead);
                                            LogAddRead(countToRead, reply);
                                            r.AppenString(TextUtils.QuoteString(reply));

                                            // Read fetch continuing line.
                                            this.TcpStream.ReadLine(args, false);
                                            if (args.Error != null)
                                            {
                                                throw args.Error;
                                            }
                                            line = args.LineUtf8;
                                            LogAddRead(args.BytesInBuffer, line);
                                            r.AppenString(line);
                                        }
                                        // Unexpected response
                                        else
                                        {
                                            throw x;
                                        }
                                    }
                                }
                            }

                            #endregion

                            #region BODYSTRUCTURE (<bodystructure-string>)

                            else if (r.StartsWith("BODYSTRUCTURE", false))
                            {
                                // Remove BODYSTRUCTURE word from reply
                                r.ReadSpecifiedLength("BODYSTRUCTURE".Length);
                                r.ReadToFirstChar();

                                bodystructure = r.ReadParenthesized();
                            }

                            #endregion

                            #region BODY[] or BODY[HEADER]

                            // BODY[] or BODY[HEADER]
                            else if (r.StartsWith("BODY", false))
                            {
                                if (r.StartsWith("BODY[]", false))
                                {
                                    // Remove BODY[]
                                    r.ReadSpecifiedLength("BODY[]".Length);
                                }
                                else if (r.StartsWith("BODY[HEADER]", false))
                                {
                                    // Remove BODY[HEADER]
                                    r.ReadSpecifiedLength("BODY[HEADER]".Length);
                                }
                                else
                                {
                                    throw new Exception("Invalid FETCH response: " + r.SourceString);
                                }
                                r.ReadToFirstChar();

                                // We must now have {<size-to-read>}, or there is error
                                if (!r.StartsWith("{"))
                                {
                                    throw new Exception("Invalid FETCH BODY[] or BODY[HEADER] response: " + r.SourceString);
                                }
                                // Read <size-to-read>
                                int dataLength = Convert.ToInt32(r.ReadParenthesized());

                                // Read data
                                MemoryStream storeStrm = new MemoryStream(dataLength);
                                this.TcpStream.ReadFixedCount(storeStrm, dataLength);
                                LogAddRead(dataLength, "Readed " + dataLength.ToString() + " bytes.");
                                data = storeStrm.ToArray();

                                // Read fetch continuing line.
                                this.TcpStream.ReadLine(args, false);
                                if (args.Error != null)
                                {
                                    throw args.Error;
                                }
                                line = args.LineUtf8;
                                LogAddRead(args.BytesInBuffer, line);
                                r.AppenString(line);
                            }

                            #endregion

                            #region FLAGS (<flags-list>)

                            // FLAGS (<flags-list>)
                            else if (r.StartsWith("FLAGS", false))
                            {
                                // Remove FLAGS word from reply
                                r.ReadSpecifiedLength("FLAGS".Length);
                                r.ReadToFirstChar();

                                // Read (<flags-list>)
                                string flagsList = r.ReadParenthesized();
                                if (flagsList == null)
                                {
                                    throw new Exception("IMAP server didn't return FLAGS (<flags-list>) !");
                                }
                                else
                                {
                                    flags = IMAP_Utils.ParseMessageFlags(flagsList);
                                }
                            }

                            #endregion

                            else
                            {
                                throw new Exception("Not supported fetch reply: " + r.SourceString);
                            }
                        }

                        fetchItems.Add(new IMAP_FetchItem(no, uid, size, data, flags, internalDate, envelope, bodystructure, fetchFlags));
                    }
                }
                else
                {
                    break;
                }
            }

            if (!RemoveCmdTag(line).ToUpper().StartsWith("OK"))
            {
                throw new IMAP_ClientException(line);
            }

            return fetchItems.ToArray();
        }
Esempio n. 22
0
        /// <summary>
        /// Parses one search key from current position. Returns null if there isn't any search key left.
        /// </summary>
        /// <param name="reader"></param>
        public static SearchKey Parse(StringReader reader)
        {
            string searchKeyName = "";
            object searchKeyValue = null;

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

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

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

            #region ALL

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

                #endregion

                #region ANSWERED

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

                #endregion

                #region BCC

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

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

                #endregion

                #region BEFORE

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

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

                #endregion

                #region BODY

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

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

                #endregion

                #region CC

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

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

                #endregion

                #region DELETED

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

                #endregion

                #region DRAFT

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

                #endregion

                #region FLAGGED

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

                #endregion

                #region FROM

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

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

                #endregion

                #region HEADER

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

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

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

                #endregion

                #region KEYWORD

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

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

                #endregion

                #region LARGER

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

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

                #endregion

                #region NEW

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

                #endregion

                #region NOT

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

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

                #endregion

                #region OLD

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

                #endregion

                #region ON

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

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

                #endregion

                #region OR

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

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

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

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

                #endregion

                #region RECENT

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

                #endregion

                #region SEEN

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

                #endregion

                #region SENTBEFORE

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

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

                #endregion

                #region SENTON

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

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

                #endregion

                #region SENTSINCE

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

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

                #endregion

                #region SINCE

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

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

                #endregion

                #region SMALLER

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

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

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

                #endregion

                #region SUBJECT

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

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

                #endregion

                #region TEXT

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

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

                #endregion

                #region TO

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

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

                #endregion

                #region UID

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

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

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

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

                #endregion

                #region UNANSWERED

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

                #endregion

                #region UNDELETED

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

                #endregion

                #region UNDRAFT

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

                #endregion

                #region UNFLAGGED

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

                #endregion

                #region UNKEYWORD

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

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

                #endregion

                #region UNSEEN

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

                #endregion

                #region Unknown or SEQUENCESET

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

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

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

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

            #endregion

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

            return new SearchKey(searchKeyName, searchKeyValue);
        }
        /// <summary>
        /// Stores specified message flags to specified messages.
        /// </summary>
        /// <param name="sequence_set">IMAP sequence-set.</param>
        /// <param name="msgFlags">Message flags.</param>
        /// <param name="uidStore">Specifies if UID STORE or STORE. 
        /// For UID STORE all sequence_set numers must be message UID values and for normal STORE message numbers.</param>
        public void StoreMessageFlags(IMAP_SequenceSet sequence_set,IMAP_MessageFlags msgFlags,bool uidStore)
        {
            if(!m_Connected){
                throw new Exception("You must connect first !");
            }
            if(!m_Authenticated){
                throw new Exception("You must authenticate first !");
            }
            if(m_SelectedFolder.Length == 0){
                throw new Exception("You must select folder first !");
            }

            if(uidStore){
                m_pSocket.WriteLine("a1 UID STORE " + sequence_set.ToSequenceSetString() + " FLAGS (" + IMAP_Utils.MessageFlagsToString(msgFlags) + ")");
            }
            else{
                m_pSocket.WriteLine("a1 STORE " + sequence_set.ToSequenceSetString() + " FLAGS (" + IMAP_Utils.MessageFlagsToString(msgFlags) + ")");
            }

            // Read server resposnse
            string reply = m_pSocket.ReadLine();

            // There is STATUS reponse, read and process it
            while(reply.StartsWith("*")){
                ProcessStatusResponse(reply);

                reply = m_pSocket.ReadLine();
            }

            // We must get OK or otherwise there is error
            if(!RemoveCmdTag(reply).ToUpper().StartsWith("OK")){
                throw new Exception("Server returned:" + reply);
            }
        }