/// <summary> /// Raises event 'GetMessage'. /// </summary> /// <param name="session">Reference to IMAP session.</param> /// <param name="msg">Message which to get.</param> /// <param name="headersOnly">Specifies if message header or full message is wanted.</param> /// <returns></returns> internal Message_EventArgs OnGetMessage(IMAP_Session session, IMAP_Message msg, bool headersOnly) { Message_EventArgs eArgs = new Message_EventArgs(session.SelectedMailbox, msg, headersOnly); if (this.GetMessage != null) { this.GetMessage(session, eArgs); } return(eArgs); }
/// <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 = this.MessageUidNext - 1; long countExists = this.Messages.Count; long countRecent = this.RecentCount; // Add new messages for (int i = folder.Messages.Count - 1; i > 0; i--) { 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 - 1; 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 != this.Messages.Count) { retVal.Append("* " + this.Messages.Count + " EXISTS\r\n"); } if (countRecent != this.RecentCount) { retVal.Append("* " + this.RecentCount + " RECENT\r\n"); } return(retVal.ToString()); }
/// <summary> /// Raises event 'CopyMessage'. /// </summary> /// <param name="session">Reference to IMAP session.</param> /// <param name="msg">Message which to copy.</param> /// <param name="location">New message location.</param> /// <returns></returns> internal string OnCopyMessage(IMAP_Session session, IMAP_Message msg, string location) { Message_EventArgs eArgs = new Message_EventArgs(session.SelectedMailbox, msg, location); if (this.CopyMessage != null) { this.CopyMessage(session, eArgs); } return(eArgs.ErrorText); }
/// <summary> /// Raises event 'StoreMessageFlags'. /// </summary> /// <param name="session">Reference to IMAP session.</param> /// <param name="msg">Message which flags to store.</param> /// <returns></returns> internal string OnStoreMessageFlags(IMAP_Session session, IMAP_Message msg) { Message_EventArgs eArgs = new Message_EventArgs(session.SelectedMailbox, msg); if (this.StoreMessageFlags != null) { this.StoreMessageFlags(session, eArgs); } return(eArgs.ErrorText); }
/// <summary> /// Adds new message info to the collection. /// </summary> /// <param name="id">Message ID.</param> /// <param name="uid">Message IMAP UID value.</param> /// <param name="internalDate">Message store date.</param> /// <param name="size">Message size in bytes.</param> /// <param name="flags">Message flags.</param> /// <returns>Returns added IMAp message info.</returns> public IMAP_Message Add(string id,long uid,DateTime internalDate,long size,IMAP_MessageFlags flags) { if(uid < 1){ throw new ArgumentException("Message UID value must be > 0 !"); } IMAP_Message message = new IMAP_Message(this,id,uid,internalDate,size,flags); m_pMessages.Add(uid,message); return message; }
/// <summary> /// Raises event 'DeleteMessage'. /// </summary> /// <param name="session">Reference to IMAP session.</param> /// <param name="message">Message which to delete.</param> /// <returns></returns> internal string OnDeleteMessage(IMAP_Session session, IMAP_Message message) { Message_EventArgs eArgs = new Message_EventArgs(session.SelectedMailbox, message); if (this.DeleteMessage != null) { this.DeleteMessage(session, eArgs); } return(eArgs.ErrorText); }
/// <summary> /// Raises event 'StoreMessage'. /// </summary> /// <param name="session">Reference to IMAP session.</param> /// <param name="folder">Folder where to store.</param> /// <param name="msg">Message which to store.</param> /// <param name="messageData">Message data which to store.</param> /// <returns></returns> internal string OnStoreMessage(IMAP_Session session, string folder, IMAP_Message msg, byte[] messageData) { Message_EventArgs eArgs = new Message_EventArgs(folder, msg); eArgs.MessageData = messageData; if (this.StoreMessage != null) { this.StoreMessage(session, eArgs); } return(eArgs.ErrorText); }
/// <summary> /// Adds new message info to the collection. /// </summary> /// <param name="id">Message ID.</param> /// <param name="uid">Message IMAP UID value.</param> /// <param name="internalDate">Message store date.</param> /// <param name="size">Message size in bytes.</param> /// <param name="flags">Message flags.</param> /// <returns>Returns added IMAp message info.</returns> public IMAP_Message Add(string id, long uid, DateTime internalDate, long size, IMAP_MessageFlags flags) { if (uid < 1) { throw new ArgumentException("Message UID value must be > 0 !"); } IMAP_Message message = new IMAP_Message(this, id, uid, internalDate, size, flags); m_pMessages.Add(uid, message); return(message); }
/// <summary> /// Gets messages marked for delete. /// </summary> /// <returns></returns> public IMAP_Message[] GetDeleteMessages() { ArrayList retVal = new ArrayList(); foreach (IMAP_Message msg in m_Messages.GetValueList()) { if (((int)IMAP_MessageFlags.Deleted & (int)msg.Flags) != 0) { retVal.Add(msg); } } IMAP_Message[] messages = new IMAP_Message[retVal.Count]; retVal.CopyTo(messages); return(messages); }
/// <summary> /// Gets index of specified message in the collection. /// </summary> /// <param name="message">Message indesx to get.</param> /// <returns>Returns index of specified message in the collection or -1 if message doesn't belong to this collection.</returns> public int IndexOf(IMAP_Message message) { return(m_pMessages.IndexOfKey(message.UID)); }
/// <summary> /// Gets message 1-based index. /// </summary> /// <param name="message"></param> /// <returns></returns> public int IndexOf(IMAP_Message message) { return m_Messages.IndexOfValue(message) + 1; }
/// <summary> /// Copy constructor. /// </summary> /// <param name="folder">IMAP folder which message is.</param> /// <param name="msg"></param> /// <param name="copyLocation"></param> public Message_EventArgs(string folder,IMAP_Message msg,string copyLocation) { m_Folder = folder; m_pMessage = msg; m_CopyLocation = copyLocation; }
/// <summary> /// Removes specified IMAP message from the collection. /// </summary> /// <param name="message">IMAP message to remove.</param> public void Remove(IMAP_Message message) { m_pMessages.Remove(message.UID); }
/// <summary> /// Gets index of specified message in the collection. /// </summary> /// <param name="message">Message indesx to get.</param> /// <returns>Returns index of specified message in the collection or -1 if message doesn't belong to this collection.</returns> public int IndexOf(IMAP_Message message) { return m_pMessages.IndexOfKey(message.UID); }
/// <summary> /// GetMessage constructor. /// </summary> /// <param name="folder">IMAP folder which message is.</param> /// <param name="msg"></param> /// <param name="headersOnly">Specifies if messages headers or full message is needed.</param> public Message_EventArgs(string folder,IMAP_Message msg,bool headersOnly) { m_Folder = folder; m_pMessage = msg; m_HeadersOnly = headersOnly; }
/// <summary> /// Default constructor. /// </summary> /// <param name="folder">IMAP folder which message is.</param> /// <param name="msg"></param> public Message_EventArgs(string folder,IMAP_Message msg) { m_Folder = folder; m_pMessage = msg; }
/// <summary> /// Removes specified IMAP message from the collection. /// </summary> /// <param name="message">IMAP message to remove.</param> public void Remove(IMAP_Message message) { m_pMessages.Remove(message.UID); }
/// <summary> /// Default constructor. /// </summary> /// <param name="session">Reference to current IMAP session.</param> /// <param name="messageInfo">Message info what message items to get.</param> /// <param name="messageItems">Specifies message items what must be filled.</param> public IMAP_eArgs_MessageItems(IMAP_Session session,IMAP_Message messageInfo,IMAP_MessageItems_enum messageItems) { m_pSession = session; m_pMessageInfo = messageInfo; m_MessageItems = messageItems; }
/// <summary> /// Copy constructor. /// </summary> /// <param name="folder">IMAP folder which message is.</param> /// <param name="msg"></param> /// <param name="copyLocation"></param> public Message_EventArgs(string folder, IMAP_Message msg, string copyLocation) { m_Folder = folder; m_pMessage = msg; m_CopyLocation = copyLocation; }
/// <summary> /// Removes message from list. /// </summary> /// <param name="msg">Message which to remove.</param> public void RemoveMessage(IMAP_Message msg) { m_Messages.RemoveAt(msg.MessageNo - 1); }
/// <summary> /// Gets messages marked for delete. /// </summary> /// <returns></returns> public IMAP_Message[] GetDeleteMessages() { ArrayList retVal = new ArrayList(); foreach(IMAP_Message msg in m_Messages.GetValueList()){ if(((int)IMAP_MessageFlags.Deleted & (int)msg.Flags) != 0){ retVal.Add(msg); } } IMAP_Message[] messages = new IMAP_Message[retVal.Count]; retVal.CopyTo(messages); return messages; }
/// <summary> /// Raises event GetMessageItems. /// </summary> /// <param name="session">Reference to IMAP session.</param> /// <param name="messageInfo">Message info what message items to get.</param> /// <param name="messageItems">Specifies message items what must be filled.</param> /// <returns></returns> internal protected IMAP_eArgs_MessageItems OnGetMessageItems(IMAP_Session session, IMAP_Message messageInfo, IMAP_MessageItems_enum messageItems) { IMAP_eArgs_MessageItems eArgs = new IMAP_eArgs_MessageItems(session, messageInfo, messageItems); if (this.GetMessageItems != null) { this.GetMessageItems(session, eArgs); } return(eArgs); }
/// <summary> /// Is called when DATA command is finnished. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void EndAppendCmd(SocketCallBackResult result,long count,Exception exception,object tag) { try{ if(m_pServer.LogCommands){ m_pLogWriter.AddEntry("big binary " + count.ToString() + " bytes",this.SessionID,this.RemoteEndPoint.Address.ToString(),"S"); } switch(result) { case SocketCallBackResult.Ok: Hashtable param = (Hashtable)tag; string cmdTag = (string)param["cmdTag"]; string mailbox = (string)param["mailbox"]; IMAP_MessageFlags mFlags = (IMAP_MessageFlags)param["mFlags"]; DateTime date = (DateTime)param["date"]; MemoryStream strm = (MemoryStream)param["strm"]; IMAP_Message msg = new IMAP_Message(null,"",0,mFlags,0,date); string errotText = m_pServer.OnStoreMessage(this,mailbox,msg,strm.ToArray()); if(errotText == null){ SendData(cmdTag + " OK APPEND completed, recieved " + strm.Length + " bytes\r\n"); } else{ SendData(cmdTag + " NO " + errotText + "\r\n"); } break; case SocketCallBackResult.LengthExceeded: // SendData("552 Requested mail action aborted: exceeded storage allocation\r\n"); // BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); return; case SocketCallBackResult.Exception: OnError(exception); return; } // Command completed ok, get next command BeginRecieveCmd(); } catch(Exception x){ OnError(x); } }
/// <summary> /// Default constructor. /// </summary> /// <param name="session">Reference to current IMAP session.</param> /// <param name="messageInfo">Message info what message items to get.</param> /// <param name="messageItems">Specifies message items what must be filled.</param> public IMAP_eArgs_MessageItems(IMAP_Session session, IMAP_Message messageInfo, IMAP_MessageItems_enum messageItems) { m_pSession = session; m_pMessageInfo = messageInfo; m_MessageItems = messageItems; }
/// <summary> /// Gets message 1-based index. /// </summary> /// <param name="message"></param> /// <returns></returns> public int IndexOf(IMAP_Message message) { return(m_Messages.IndexOfValue(message) + 1); }
/// <summary> /// Removes message from list. /// </summary> /// <param name="msg">Message which to remove.</param> public void RemoveMessage(IMAP_Message msg) { m_Messages.RemoveAt(msg.MessageNo - 1); }
/// <summary> /// Default constructor. /// </summary> /// <param name="folder">IMAP folder which message is.</param> /// <param name="msg"></param> public Message_EventArgs(string folder, IMAP_Message msg) { m_Folder = folder; m_pMessage = msg; }
/// <summary> /// Checks if message matches for specified search key. /// </summary> /// <param name="searchKey"></param> /// <param name="searchKeyValue"></param> /// <param name="messageInfo"></param> /// <param name="msg"></param> /// <returns></returns> public static bool MatchSearchKey(string searchKey,object searchKeyValue,IMAP_Message messageInfo,LumiSoft.Net.Mime.Mime msg) { // BEFORE <date> // Messages whose internal date (disregarding time and timezone) // is earlier than the specified date. if(searchKey == "BEFORE"){ if(messageInfo.Date.Date < (DateTime)searchKeyValue){ return true; } } // BODY <string> // Messages that contain the specified string in the body of the message. else if(searchKey == "BODY"){ if(msg.BodyText.IndexOf((string)searchKeyValue) > -1){ return true; } } // 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(searchKey == "HEADER"){ string[] headerField_value = (string[])searchKeyValue; if(msg.MainEntity.Header.Contains(headerField_value[0])){ if(headerField_value[1].Length == 0){ return true; } else if(msg.MainEntity.Header.GetFirst(headerField_value[0]).Value.IndexOf(headerField_value[1]) > -1){ return true; } } } // KEYWORD <flag> // Messages with the specified keyword flag set. else if(searchKey == "KEYWORD"){ if((messageInfo.Flags & IMAP_Utils.ParseMessageFalgs((string)searchKeyValue)) != 0){ return true; } } // LARGER <n> // Messages with an [RFC-2822] size larger than the specified number of octets. else if(searchKey == "LARGER"){ if(messageInfo.Size > Convert.ToInt64(searchKeyValue)){ return true; } } // ON <date> // Messages whose internal date (disregarding time and timezone) // is within the specified date. else if(searchKey == "ON"){ if(messageInfo.Date.Date == (DateTime)searchKeyValue){ return true; } } // SENTBEFORE <date> // Messages whose [RFC-2822] Date: header (disregarding time and // timezone) is earlier than the specified date. else if(searchKey == "SENTBEFORE"){ if(msg.MainEntity.Date.Date < (DateTime)searchKeyValue){ return true; } } // SENTON <date> // Messages whose [RFC-2822] Date: header (disregarding time and // timezone) is within the specified date. else if(searchKey == "SENTON"){ if(msg.MainEntity.Date.Date == (DateTime)searchKeyValue){ return true; } } // SENTSINCE <date> // Messages whose [RFC-2822] Date: header (disregarding time and // timezone) is within or later than the specified date. else if(searchKey == "SENTSINCE"){ if(msg.MainEntity.Date.Date >= (DateTime)searchKeyValue){ return true; } } // SINCE <date> // Messages whose internal date (disregarding time and timezone) // is within or later than the specified date. else if(searchKey == "SINCE"){ if(msg.MainEntity.Date.Date >= (DateTime)searchKeyValue){ return true; } } // SMALLER <n> // Messages with an [RFC-2822] size smaller than the specified number of octets. else if(searchKey == "SMALLER"){ if(messageInfo.Size < Convert.ToInt64(searchKeyValue)){ return true; } } // TEXT <string> // Messages that contain the specified string in the header or body of the message. else if(searchKey == "TEXT"){ // TODO: } // UID <sequence set> // Messages with unique identifiers corresponding to the specified // unique identifier set. Sequence set ranges are permitted. else if(searchKey == "UID"){ if(((string)searchKeyValue).IndexOf(":") > -1){ string[] start_end = ((string)searchKeyValue).Split(':'); if(messageInfo.MessageUID >= Convert.ToInt64(start_end[0]) && messageInfo.MessageUID <= Convert.ToInt64(start_end[1])){ return true; } } else{ if(messageInfo.MessageUID == Convert.ToInt64(searchKeyValue)){ return true; } } } // UNKEYWORD <flag> // Messages that do not have the specified keyword flag set. else if(searchKey == "UNKEYWORD"){ if((messageInfo.Flags & IMAP_Utils.ParseMessageFalgs((string)searchKeyValue)) == 0){ return true; } } return false; }
/// <summary> /// GetMessage constructor. /// </summary> /// <param name="folder">IMAP folder which message is.</param> /// <param name="msg"></param> /// <param name="headersOnly">Specifies if messages headers or full message is needed.</param> public Message_EventArgs(string folder, IMAP_Message msg, bool headersOnly) { m_Folder = folder; m_pMessage = msg; m_HeadersOnly = headersOnly; }
private void Append(string cmdTag,string argsText) { /* Rfc 3501 6.3.11 APPEND Command Arguments: mailbox name OPTIONAL flag parenthesized list OPTIONAL date/time string message literal Responses: no specific responses for this command Result: OK - append completed NO - append error: can't append to that mailbox, error in flags or date/time or message text BAD - command unknown or arguments invalid The APPEND command appends the literal argument as a new message to the end of the specified destination mailbox. This argument SHOULD be in the format of an [RFC-2822] message. 8-bit characters are permitted in the message. A server implementation that is unable to preserve 8-bit data properly MUST be able to reversibly convert 8-bit APPEND data to 7-bit using a [MIME-IMB] content transfer encoding. If a flag parenthesized list is specified, the flags SHOULD be set in the resulting message; otherwise, the flag list of the resulting message is set to empty by default. In either case, the Recent flag is also set. If a date-time is specified, the internal date SHOULD be set in the resulting message; otherwise, the internal date of the resulting message is set to the current date and time by default. If the append is unsuccessful for any reason, the mailbox MUST be restored to its state before the APPEND attempt; no partial appending is permitted. If the destination mailbox does not exist, a server MUST return an error, and MUST 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 APPEND if the CREATE is successful. Example: C: A003 APPEND saved-messages (\Seen) {310} S: + Ready for literal data C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) C: From: Fred Foobar <*****@*****.**> C: Subject: afternoon meeting C: To: [email protected] C: Message-Id: <*****@*****.**> C: MIME-Version: 1.0 C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII C: C: Hello Joe, do you think we can meet at 3:30 tomorrow? C: S: A003 OK APPEND completed */ if(!m_Authenticated){ SendData(cmdTag + " NO Authenticate first !\r\n"); return; } string[] args = ParseParams(argsText); if(args.Length < 2 || args.Length > 4){ SendData(cmdTag + " BAD APPEND Invalid arguments\r\n"); return; } string mailbox = args[0]; IMAP_MessageFlags mFlags = 0; DateTime date = DateTime.Now; long msgLen = Convert.ToInt64(args[args.Length - 1].Replace("{","").Replace("}","")); if(args.Length == 4){ //--- Parse flags, see if valid ---------------- string flags = args[1].ToUpper(); if(flags.Replace("\\ANSWERED","").Replace("\\FLAGGED","").Replace("\\DELETED","").Replace("\\SEEN","").Replace("\\DRAFT","").Trim().Length > 0){ SendData(cmdTag + " BAD arguments invalid\r\n"); return; } if(flags.IndexOf("\\ANSWERED") > -1){ mFlags |= IMAP_MessageFlags.Answered; } if(flags.IndexOf("\\FLAGGED") > -1){ mFlags |= IMAP_MessageFlags.Flagged; } if(flags.IndexOf("\\DELETED") > -1){ mFlags |= IMAP_MessageFlags.Deleted; } if(flags.IndexOf("\\SEEN") > -1){ mFlags |= IMAP_MessageFlags.Seen; } if(flags.IndexOf("\\DRAFT") > -1){ mFlags |= IMAP_MessageFlags.Draft; } //--------------------------------------------- date = LumiSoft.Net.Mime.MimeParser.ParseDateS(args[2]); } else if(args.Length == 3){ // See if date or flags specified, try date first try { date = LumiSoft.Net.Mime.MimeParser.ParseDateS(args[2]); } catch{ //--- Parse flags, see if valid ---------------- string flags = args[1].ToUpper(); if(flags.Replace("\\ANSWERED","").Replace("\\FLAGGED","").Replace("\\DELETED","").Replace("\\SEEN","").Replace("\\DRAFT","").Trim().Length > 0){ SendData(cmdTag + " BAD arguments invalid\r\n"); return; } if(flags.IndexOf("\\ANSWERED") > -1){ mFlags |= IMAP_MessageFlags.Answered; } if(flags.IndexOf("\\FLAGGED") > -1){ mFlags |= IMAP_MessageFlags.Flagged; } if(flags.IndexOf("\\DELETED") > -1){ mFlags |= IMAP_MessageFlags.Deleted; } if(flags.IndexOf("\\SEEN") > -1){ mFlags |= IMAP_MessageFlags.Seen; } if(flags.IndexOf("\\DRAFT") > -1){ mFlags |= IMAP_MessageFlags.Draft; } //--------------------------------------------- } } // Request data SendData("+ Ready for literal data\r\n"); using(MemoryStream storeStrm = new MemoryStream()){ // Why needed msgLen+2 ??? LumiSoft.Net.ReadReplyCode rCode = LumiSoft.Net.Core.ReadData(m_pClientSocket,msgLen+2,storeStrm,true,10000); if(rCode == LumiSoft.Net.ReadReplyCode.Ok){ IMAP_Message msg = new IMAP_Message(null,"",0,mFlags,0,date); string errotText = m_pIMAP_Server.OnStoreMessage(this,mailbox,msg,storeStrm.ToArray()); if(errotText == null){ SendData(cmdTag + " OK APPEND completed, recieved " + storeStrm.Length + " bytes\r\n"); } else{ SendData(cmdTag + " NO " + errotText + "\r\n"); } } else{ SendData(cmdTag + " NO " + rCode.ToString() + "\r\n"); } } }