예제 #1
0
        /// <summary>
        /// Raises event 'GetMessagesInfo'.
        /// </summary>
        /// <param name="session">Reference to IMAP session.</param>
        /// <param name="folder">Folder which messages info to get.</param>
        /// <returns></returns>
        internal IMAP_eArgs_GetMessagesInfo OnGetMessagesInfo(IMAP_Session session, IMAP_SelectedFolder folder)
        {
            IMAP_eArgs_GetMessagesInfo eArgs = new IMAP_eArgs_GetMessagesInfo(session, folder);

            if (GetMessagesInfo != null)
            {
                GetMessagesInfo(session, eArgs);
            }

            return(eArgs);
        }
예제 #2
0
        /// <summary>
        /// Updates current folder messages info with new messages info.
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        internal string Update(IMAP_SelectedFolder folder)
        {
            StringBuilder retVal = new StringBuilder();
            long          maxUID = MessageUidNext - 1;

            long countExists = Messages.Count;
            long countRecent = RecentCount;

            // Add new messages
            for (int i = folder.Messages.Count - 1; i >= 0; i--)//FIX
            {
                IMAP_Message message = folder.Messages[i];
                // New message
                if (message.UID > maxUID)
                {
                    m_pMessages.Add(message.ID, message.UID, message.InternalDate, message.Size, message.Flags);
                }
                // New messages ended
                else
                {
                    break;
                }
            }

            // Remove deleted messages
            for (int i = 0; i < m_pMessages.Count; i++)
            {
                IMAP_Message message = m_pMessages[i];

                if (!folder.m_pMessages.ContainsUID(message.UID))
                {
                    retVal.Append("* " + message.SequenceNo + " EXPUNGE\r\n");
                    m_pMessages.Remove(message);
                    i--;
                }
            }

            if (countExists != Messages.Count)
            {
                retVal.Append("* " + Messages.Count + " EXISTS\r\n");
            }
            if (countRecent != RecentCount)
            {
                retVal.Append("* " + RecentCount + " RECENT\r\n");
            }

            return(retVal.ToString());
        }
예제 #3
0
        /// <summary>
        /// Updates current folder messages info with new messages info.
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        internal string Update(IMAP_SelectedFolder folder)
        {
            StringBuilder retVal = new StringBuilder();
            long maxUID = MessageUidNext - 1;

            long countExists = Messages.Count;
            long countRecent = RecentCount;

            // Add new messages
            for (int i = folder.Messages.Count - 1; i >= 0; i--)//FIX
            {
                IMAP_Message message = folder.Messages[i];
                // New message
                if (message.UID > maxUID)
                {
                    m_pMessages.Add(message.ID, message.UID, message.InternalDate, message.Size, message.Flags);
                }
                    // New messages ended
                else
                {
                    break;
                }
            }

            // Remove deleted messages
            for (int i = 0; i < m_pMessages.Count; i++)
            {
                IMAP_Message message = m_pMessages[i];

                if (!folder.m_pMessages.ContainsUID(message.UID))
                {
                    retVal.Append("* " + message.SequenceNo + " EXPUNGE\r\n");
                    m_pMessages.Remove(message);
                    i--;
                }
            }

            if (countExists != Messages.Count)
            {
                retVal.Append("* " + Messages.Count + " EXISTS\r\n");
            }
            if (countRecent != RecentCount)
            {
                retVal.Append("* " + RecentCount + " RECENT\r\n");
            }

            return retVal.ToString();
        }
예제 #4
0
        /// <summary>
        /// Processes changes and sends status responses if there are changes in selected mailbox.
        /// </summary>
        private void ProcessMailboxChanges(string mailBox)
        {
            //TODO: Many whelps! Handle it!
            // Get status
            IMAP_SelectedFolder folderInfo = new IMAP_SelectedFolder(mailBox);
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, folderInfo);

            // Join new info with exisiting
            if (m_pSelectedFolder != null)
            {
                string statusResponse = m_pSelectedFolder.Update(folderInfo);
                if (!string.IsNullOrEmpty(statusResponse))
                {
                    WriteLine(statusResponse);

                    m_pSelectedFolder = folderInfo;
                }
            }
            if (m_pAdditionalFolder != null)
            {
                string statusResponse = m_pAdditionalFolder.Update(folderInfo);
                if (!string.IsNullOrEmpty(statusResponse))
                {
                    WriteLine(statusResponse);

                    m_pAdditionalFolder = folderInfo;
                }
            }
        }
예제 #5
0
        private void Close(string cmdTag)
        {
            /* RFC 3501 6.4.2 CLOSE Command
			
				Arguments:  none

				Responses:  no specific responses for this command

				Result:     OK - close completed, now in authenticated state
							BAD - command unknown or arguments invalid
			   
				The CLOSE command permanently removes from the currently selected
				mailbox all messages that have the \Deleted flag set, and returns
				to authenticated state from selected state.  No untagged EXPUNGE
				responses are sent.

				No messages are removed, and no error is given, if the mailbox is
				selected by an EXAMINE command or is otherwise selected read-only.

				Even if a mailbox is selected, a SELECT, EXAMINE, or LOGOUT
				command MAY be issued without previously issuing a CLOSE command.
				The SELECT, EXAMINE, and LOGOUT commands implicitly close the
				currently selected mailbox without doing an expunge.  However,
				when many messages are deleted, a CLOSE-LOGOUT or CLOSE-SELECT
				sequence is considerably faster than an EXPUNGE-LOGOUT or
				EXPUNGE-SELECT because no untagged EXPUNGE responses (which the
				client would probably ignore) are sent.

				Example:    C: A341 CLOSE
							S: A341 OK CLOSE 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)
            {
                IMAP_Message[] messages = m_pSelectedFolder.Messages.GetWithFlags(IMAP_MessageFlags.Deleted);
                foreach (IMAP_Message msg in messages)
                {
                    ImapServer.OnDeleteMessage(this, msg);
                }
            }

            SelectedMailbox = "";
            m_pSelectedFolder = null;

            WriteLine(string.Format("{0} OK CLOSE completed", cmdTag));
            //EndSession();
        }
예제 #6
0
        private void Status(string cmdTag, string argsText)
        {
            /* RFC 3501 6.3.10 STATUS Command
			
				Arguments:  mailbox name
							status data item names

				Responses:  untagged responses: STATUS

				Result:     OK - status completed
							NO - status failure: no status for that name
							BAD - command unknown or arguments invalid
			   
				The STATUS command requests the status of the indicated mailbox.
				It does not change the currently selected mailbox, nor does it
				affect the state of any messages in the queried mailbox (in
				particular, STATUS MUST NOT cause messages to lose the \Recent
				flag).

				The STATUS command provides an alternative to opening a second
				IMAP4rev1 connection and doing an EXAMINE command on a mailbox to
				query that mailbox's status without deselecting the current
				mailbox in the first IMAP4rev1 connection.

				Unlike the LIST command, the STATUS command is not guaranteed to
				be fast in its response.  In some implementations, the server is
				obliged to open the mailbox read-only internally to obtain certain
				status information.  Also unlike the LIST command, the STATUS
				command does not accept wildcards.

				The currently defined status data items that can be requested are:

				MESSAGES
					The number of messages in the mailbox.

				RECENT
					The number of messages with the \Recent flag set.

				UIDNEXT
					The next unique identifier value of the mailbox.  Refer to
					section 2.3.1.1 for more information.

				UIDVALIDITY
					The unique identifier validity value of the mailbox.  Refer to
					section 2.3.1.1 for more information.

				UNSEEN
					The number of messages which do not have the \Seen flag set.


				Example:    C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
							S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
							S: A042 OK STATUS completed
				  
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = ParseParams(argsText);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD Invalid STATUS arguments. Syntax: {{<command-tag> STATUS \"<mailbox-name>\" \"(status-data-items)\"}}", cmdTag));
                return;
            }

            string folder = Core.Decode_IMAP_UTF7_String(args[0]);
            string wantedItems = args[1].ToUpper();

            // See wanted items are valid.
            if (
                wantedItems.Replace("MESSAGES", "").Replace("RECENT", "").Replace("UIDNEXT", "").Replace(
                    "UIDVALIDITY", "").Replace("UNSEEN", "").Trim().Length > 0)
            {
                WriteLine(string.Format("{0} BAD STATUS invalid arguments", cmdTag));
                return;
            }

            AdditionalSelect(folder);
            IMAP_SelectedFolder selectedFolder = new IMAP_SelectedFolder(folder);
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, selectedFolder);
            if (eArgs.ErrorText == null)
            {
                string itemsReply = "";
                if (wantedItems.IndexOf("MESSAGES") > -1)
                {
                    itemsReply += string.Format(" MESSAGES {0}", selectedFolder.Messages.Count);
                }
                if (wantedItems.IndexOf("RECENT") > -1)
                {
                    itemsReply += string.Format(" RECENT {0}", selectedFolder.RecentCount);
                }
                if (wantedItems.IndexOf("UNSEEN") > -1)
                {
                    itemsReply += string.Format(" UNSEEN {0}", selectedFolder.UnSeenCount);
                }
                if (wantedItems.IndexOf("UIDVALIDITY") > -1)
                {
                    itemsReply += string.Format(" UIDVALIDITY {0}", selectedFolder.FolderUID);
                }
                if (wantedItems.IndexOf("UIDNEXT") > -1)
                {
                    itemsReply += string.Format(" UIDNEXT {0}", selectedFolder.MessageUidNext);
                }
                itemsReply = itemsReply.Trim();

                WriteLine(string.Format("* STATUS {0} ({1})", args[0], itemsReply));
                WriteLine(string.Format("{0} OK STATUS completed", cmdTag));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, eArgs.ErrorText));
            }
        }
예제 #7
0
 private void AdditionalSelect(string folder)
 {
     m_StatusedMailbox = folder;
     m_pAdditionalFolder = new IMAP_SelectedFolder(folder);
     IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, m_pAdditionalFolder);
 }
예제 #8
0
        private void Examine(string cmdTag, string argsText)
        {
            /* Rfc 3501 6.3.2 EXAMINE Command
			
				Arguments:  mailbox name

				Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
							REQUIRED OK untagged responses:  UNSEEN,  PERMANENTFLAGS,
							UIDNEXT, UIDVALIDITY

				Result:     OK - examine completed, now in selected state
							NO - examine failure, now in authenticated state: no
									such mailbox, can't access mailbox
							BAD - command unknown or arguments invalid

				The EXAMINE command is identical to SELECT and returns the same
				output; however, the selected mailbox is identified as read-only.
				No changes to the permanent state of the mailbox, including
				per-user state, are permitted; in particular, EXAMINE MUST NOT
				cause messages to lose the \Recent flag.

				The text of the tagged OK response to the EXAMINE command MUST
				begin with the "[READ-ONLY]" response code.

				Example:    C: A932 EXAMINE blurdybloop
							S: * 17 EXISTS
							S: * 2 RECENT
							S: * OK [UNSEEN 8] Message 8 is first unseen
							S: * OK [UIDVALIDITY 3857529045] UIDs valid
							S: * OK [UIDNEXT 4392] Predicted next UID
							S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
							S: * OK [PERMANENTFLAGS ()] No permanent flags permitted
							S: A932 OK [READ-ONLY] EXAMINE completed
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD EXAMINE invalid arguments. Syntax: {{<command-tag> EXAMINE \"mailboxName\"}}", cmdTag));
                return;
            }

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

            IMAP_SelectedFolder selectedFolder = new IMAP_SelectedFolder(Core.Decode_IMAP_UTF7_String(args[0]));
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, selectedFolder);
            if (eArgs.ErrorText == null)
            {
                m_pSelectedFolder = selectedFolder;
                m_pSelectedFolder.ReadOnly = true;
                SelectedMailbox = Core.Decode_IMAP_UTF7_String(args[0]);

                string response = "";
                response += "* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n";
                response += string.Format("* {0} EXISTS\r\n", m_pSelectedFolder.Messages.Count);
                response += string.Format("* {0} RECENT\r\n", m_pSelectedFolder.RecentCount);
                response += string.Format("* OK [UNSEEN {0}] Message {1} is first unseen\r\n", m_pSelectedFolder.FirstUnseen, m_pSelectedFolder.FirstUnseen);
                response += string.Format("* OK [UIDVALIDITY {0}] UIDs valid\r\n", m_pSelectedFolder.FolderUID);
                response += string.Format("* OK [UIDNEXT {0}] Predicted next UID\r\n", m_pSelectedFolder.MessageUidNext);
                response +=
                    "* OK [PERMANENTFLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)] Available permanent falgs\r\n";
                response += string.Format("{0} OK [READ-ONLY] EXAMINE  Completed in {1} seconds\r\n", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2"));

                TcpStream.Write(response);
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, eArgs.ErrorText));
            }
        }
예제 #9
0
        //--- End of non-IsAuthenticated State 

        //--- IsAuthenticated State ------

        private void Select(string cmdTag, string argsText)
        {
            /* Rfc 3501 6.3.1 SELECT Command
			 
				Arguments:  mailbox name

				Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
							REQUIRED OK untagged responses:  UNSEEN,  PERMANENTFLAGS,
							UIDNEXT, UIDVALIDITY

				Result:     OK - select completed, now in selected state
							NO - select failure, now in authenticated state: no
									such mailbox, can't access mailbox
							BAD - command unknown or arguments invalid
							
				The SELECT command selects a mailbox so that messages in the
				mailbox can be accessed.  Before returning an OK to the client,
				the server MUST send the following untagged data to the client.
				Note that earlier versions of this protocol only required the
				FLAGS, EXISTS, and RECENT untagged data; consequently, client
				implementations SHOULD implement default behavior for missing data
				as discussed with the individual item.

					FLAGS       Defined flags in the mailbox.  See the description
								of the FLAGS response for more detail.

					<n> EXISTS  The number of messages in the mailbox.  See the
								description of the EXISTS response for more detail.

					<n> RECENT  The number of messages with the \Recent flag set.
								See the description of the RECENT response for more
								detail.

					OK [UNSEEN <n>]
								The message sequence number of the first unseen
								message in the mailbox.  If this is missing, the
								client can not make any assumptions about the first
								unseen message in the mailbox, and needs to issue a
								SEARCH command if it wants to find it.

					OK [PERMANENTFLAGS (<list of flags>)]
								A list of message flags that the client can change
								permanently.  If this is missing, the client should
								assume that all flags can be changed permanently.

					OK [UIDNEXT <n>]
								The next unique identifier value.  Refer to section
								2.3.1.1 for more information.  If this is missing,
								the client can not make any assumptions about the
								next unique identifier value.
								
					OK [UIDVALIDITY <n>]
                     The unique identifier validity value.  Refer to
                     section 2.3.1.1 for more information.  If this is
                     missing, the server does not support unique
                     identifiers.

				Only one mailbox can be selected at a time in a connection;
				simultaneous access to multiple mailboxes requires multiple
				connections.  The SELECT command automatically deselects any
				currently selected mailbox before attempting the new selection.
				Consequently, if a mailbox is selected and a SELECT command that
				fails is attempted, no mailbox is selected.

				If the client is permitted to modify the mailbox, the server
				SHOULD prefix the text of the tagged OK response with the
				"[READ-WRITE]" response code.

				If the client is not permitted to modify the mailbox but is
				permitted read access, the mailbox is selected as read-only, and
				the server MUST prefix the text of the tagged OK response to
				SELECT with the "[READ-ONLY]" response code.  Read-only access
				through SELECT differs from the EXAMINE command in that certain
				read-only mailboxes MAY permit the change of permanent state on a
				per-user (as opposed to global) basis.  Netnews messages marked in
				a server-based .newsrc file are an example of such per-user
				permanent state that can be modified with read-only mailboxes.

				Example:    C: A142 SELECT INBOX
							S: * 172 EXISTS
							S: * 1 RECENT
							S: * OK [UNSEEN 12] Message 12 is first unseen
							S: * OK [UIDVALIDITY 3857529045] UIDs valid
							S: * OK [UIDNEXT 4392] Predicted next UID
							S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
							S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
							S: A142 OK [READ-WRITE] SELECT completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD SELECT invalid arguments. Syntax: {{<command-tag> SELECT \"mailboxName\"}}", cmdTag));
                return;
            }

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

            IMAP_SelectedFolder selectedFolder = new IMAP_SelectedFolder(Core.Decode_IMAP_UTF7_String(args[0]));
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, selectedFolder);
            if (eArgs.ErrorText == null)
            {
                m_pSelectedFolder = selectedFolder;
                SelectedMailbox = Core.Decode_IMAP_UTF7_String(args[0]);

                string response = "";
                response += "* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n";
                response += string.Format("* {0} EXISTS\r\n", m_pSelectedFolder.Messages.Count);
                response += string.Format("* {0} RECENT\r\n", m_pSelectedFolder.RecentCount);
                response += string.Format("* OK [UNSEEN {0}] Message {1} is first unseen\r\n", m_pSelectedFolder.FirstUnseen, m_pSelectedFolder.FirstUnseen);
                response += string.Format("* OK [UIDVALIDITY {0}] Folder UID\r\n", m_pSelectedFolder.FolderUID);
                response += string.Format("* OK [UIDNEXT {0}] Predicted next message UID\r\n", m_pSelectedFolder.MessageUidNext);
                response +=
                    "* OK [PERMANENTFLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)] Available permanent flags\r\n";
                response += string.Format("{0} OK [{1}] SELECT Completed in {2} seconds\r\n", cmdTag, (m_pSelectedFolder.ReadOnly ? "READ-ONLY" : "READ-WRITE"), ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2"));

                TcpStream.Write(response);
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, eArgs.ErrorText));
            }
        }