Revision: 92
http://svn.sourceforge.net/nmailserver/?rev=92&view=rev
Author: tmyroadctfig
Date: 2006-11-23 03:34:41 -0800 (Thu, 23 Nov 2006)
Log Message:
-----------
Partially implemented search functionality. Fixed a defect with internal date (BUG 1601681).
Modified Paths:
--------------
NMail/trunk/NMail.ImapService/Command/ImapMessageList.cs
NMail/trunk/NMail.ImapService/Command/SearchCommand.cs
NMail/trunk/NMail.ImapService/Response/SearchResponse.cs
NMail/trunk/NMail.ImapService/State/ExamineState.cs
NMail/trunk/NMail.ImapService/State/SelectedState.cs
Modified: NMail/trunk/NMail.ImapService/Command/ImapMessageList.cs
===================================================================
--- NMail/trunk/NMail.ImapService/Command/ImapMessageList.cs 2006-11-23 11:09:39 UTC (rev 91)
+++ NMail/trunk/NMail.ImapService/Command/ImapMessageList.cs 2006-11-23 11:34:41 UTC (rev 92)
@@ -16,39 +16,23 @@
*/
using System;
-using System.Collections;
+using System.Collections.Generic;
namespace NMail.ImapService.Command {
/// <summary>
/// Represents a list of messages to process in an IMAP command.
/// </summary>
- public class ImapMessageList {
+ public class ImapMessageList : List<ImapMessageListItem> {
/// <summary>
- /// Internal storage for the message list.
- /// </summary>
- private ArrayList list;
-
- /// <summary>
/// Creates a new list from the given string.
/// </summary>
/// <param name="messageList">The IMAP message list to parse.</param>
public ImapMessageList(string messageList) {
- this.list = new ArrayList();
-
string[] listParts = messageList.Split(',');
foreach (string part in listParts) {
- this.list.Add(new ImapMessageListItem(part));
+ this.Add(new ImapMessageListItem(part));
}
}
-
- /// <summary>
- /// Returns the list of messages to retieve data for.
- /// </summary>
- public ImapMessageListItem[] ImapMessageListItem {
- get {
- return (ImapMessageListItem[]) this.list.ToArray(typeof(ImapMessageListItem));
- }
- }
}
#region ImapMessageListItemType
@@ -103,6 +87,27 @@
}
}
+ /// <summary>
+ /// Checks if an item number matches this list item.
+ /// </summary>
+ /// <param name="itemNumber">The number to check.</param>
+ /// <returns>True if the number matches.</returns>
+ public bool Matches(int itemNumber) {
+ switch (this.itemType) {
+ case ImapMessageListItemType.Single:
+ return (itemNumber == this.start);
+
+ case ImapMessageListItemType.BoundedRange:
+ return (itemNumber >= this.start && itemNumber <= this.end);
+
+ case ImapMessageListItemType.UnboundedRange:
+ return (itemNumber >= this.start);
+
+ default:
+ throw new ArgumentException("Invalid item list type.");
+ }
+ }
+
private ImapMessageListItemType itemType;
/// <summary>
Modified: NMail/trunk/NMail.ImapService/Command/SearchCommand.cs
===================================================================
--- NMail/trunk/NMail.ImapService/Command/SearchCommand.cs 2006-11-23 11:09:39 UTC (rev 91)
+++ NMail/trunk/NMail.ImapService/Command/SearchCommand.cs 2006-11-23 11:34:41 UTC (rev 92)
@@ -16,21 +16,57 @@
*/
using System;
+using System.Collections.Generic;
-namespace NMail.ImapService.Command
-{
+namespace NMail.ImapService.Command {
/// <summary>
/// Summary description for SearchCommand.
/// </summary>
[CommandToken("SEARCH")]
- public class SearchCommand : AbstractCommand
- {
+ public class SearchCommand : AbstractCommand, IUidCommand {
public override void Create(string tag, string data) {
base.Create(tag, data);
// Parse the arguments
- string[] tokens = GetDataTokens();
+ List<string> tokens = new List<string>(GetDataTokens());
+
+ // Check for charset
+
+ // Parse list of search items
+ while (tokens.Count > 0) {
+ switch (tokens[0].ToUpper()) {
+ case "UID":
+ if (tokens.Count == 1) {
+ throw new ArgumentException("UID search items requires a set of messages.");
+ }
+ this.searchItems.Add(new UidSearchItem(tokens[1]));
+ tokens.RemoveRange(0, 2);
+ break;
+
+ default:
+ throw new ArgumentException("Invalid item in SEARCH list.");
+ }
+ }
}
+
+ List<SearchItem> searchItems = new List<SearchItem>();
+
+ public SearchItem[] SearchItems {
+ get {
+ return this.searchItems.ToArray();
+ }
+ }
+
+ private bool uidCommand;
+
+ public bool UidCommand {
+ get {
+ return this.uidCommand;
+ }
+ set {
+ this.uidCommand = value;
+ }
+ }
}
#region SearchItemType
@@ -117,7 +153,7 @@
/// Messages that don't have the recent flag set.
/// </summary>
Old,
-
+
/// <summary>
/// The message is sent on the given date (ignoring time and timezone).
/// </summary>
@@ -192,7 +228,7 @@
/// Messages without the answered flag.
/// </summary>
Unanswered,
-
+
/// <summary>
/// Messages without the deleted flag.
/// </summary>
@@ -219,4 +255,32 @@
Unseen
}
#endregion
-}
+
+ public class SearchItem {
+
+ protected SearchItemType searchType;
+
+ /// <summary>
+ /// The search type for this item.
+ /// </summary>
+ public SearchItemType SearchType {
+ get { return searchType; }
+ }
+ }
+
+ public class UidSearchItem : SearchItem {
+ public UidSearchItem(string sequenceSet) {
+ this.searchType = SearchItemType.Uid;
+
+ this.messageList = new ImapMessageList(sequenceSet);
+ }
+
+ ImapMessageList messageList;
+
+ public ImapMessageList MessageList {
+ get {
+ return this.messageList;
+ }
+ }
+ }
+}
\ No newline at end of file
Modified: NMail/trunk/NMail.ImapService/Response/SearchResponse.cs
===================================================================
--- NMail/trunk/NMail.ImapService/Response/SearchResponse.cs 2006-11-23 11:09:39 UTC (rev 91)
+++ NMail/trunk/NMail.ImapService/Response/SearchResponse.cs 2006-11-23 11:34:41 UTC (rev 92)
@@ -16,19 +16,33 @@
*/
using System;
+using System.Collections.Generic;
+using System.Text;
-namespace NMail.ImapService.Response
-{
+namespace NMail.ImapService.Response {
/// <summary>
- /// Summary description for SearchResponse.
+ /// The response to a search command.
/// </summary>
- public class SearchResponse
- {
- public SearchResponse()
- {
- //
- // TODO: Add constructor logic here
- //
+ public class SearchResponse : AbstractResponse {
+ protected List<int> messageIds;
+
+ /// <summary>
+ /// Creates a new search response with the given list of message Ids.
+ /// </summary>
+ /// <param name="messageIds">The list of message Ids that match the search criteria.</param>
+ public SearchResponse(List<int> messageIds) {
+ this.messageIds = messageIds;
}
+
+ public override void WriteResponse(ImapServiceConnection cnn) {
+ StringBuilder messageList = new StringBuilder();
+
+ foreach (int messageId in this.messageIds) {
+ messageList.Append(messageId);
+ messageList.Append(" ");
+ }
+
+ cnn.WriteLine("* SEARCH {0}", messageList.ToString());
+ }
}
}
Modified: NMail/trunk/NMail.ImapService/State/ExamineState.cs
===================================================================
--- NMail/trunk/NMail.ImapService/State/ExamineState.cs 2006-11-23 11:09:39 UTC (rev 91)
+++ NMail/trunk/NMail.ImapService/State/ExamineState.cs 2006-11-23 11:34:41 UTC (rev 92)
@@ -16,6 +16,7 @@
*/
using System;
+using System.Collections.Generic;
using System.Text;
using NMail.DataTypes;
@@ -38,8 +39,6 @@
}
}
- // TODO: search command
-
#region Process Noop Command
public override void ProcessCommand(NoopCommand cmd) {
sendSelectResponses(this.selectedFolder);
@@ -71,7 +70,7 @@
if (dstFolder != null) {
// Process each list in the copy command
- foreach (ImapMessageListItem listItem in cmd.MessageList.ImapMessageListItem) {
+ foreach (ImapMessageListItem listItem in cmd.MessageList) {
if (listItem.ItemType == ImapMessageListItemType.Single) {
// Only a single message in this item
processMessageCopy(listItem.Start, cmd.UidCommand, dstFolder);
@@ -231,12 +230,12 @@
}
#endregion
- #region sendpublicDate
- protected virtual void sendpublicDate(FetchResponse response, int messageUid) {
- DateTime? publicDate = LocalStore.GetInternalDate(Session.AuthenticationToken, messageUid, this.selectedFolder);
+ #region sendInternalDate
+ protected virtual void sendInternalDate(FetchResponse response, int messageUid) {
+ DateTime? internalDate = LocalStore.GetInternalDate(Session.AuthenticationToken, messageUid, this.selectedFolder);
- if (publicDate.HasValue) {
- response.AppendResponseItem("publicDATE \"" + publicDate.Value.ToString("r") + "\"");
+ if (internalDate.HasValue) {
+ response.AppendResponseItem("INTERNALDATE \"" + internalDate.Value.ToString("r") + "\"");
}
}
#endregion
@@ -355,7 +354,7 @@
switch (dataItem.DataType) {
case FetchDataItemType.All:
sendMessageFlags(response, messageUid);
- sendpublicDate(response, messageUid);
+ sendInternalDate(response, messageUid);
sendMessageSize(response, messageUid);
ensureMessageHeaders(messageUid, ref messageHeaders);
sendEnvelope(response, messageHeaders);
@@ -380,7 +379,7 @@
case FetchDataItemType.Fast:
sendMessageFlags(response, messageUid);
- sendpublicDate(response, messageUid);
+ sendInternalDate(response, messageUid);
sendMessageSize(response, messageUid);
break;
@@ -390,14 +389,14 @@
case FetchDataItemType.Full:
sendMessageFlags(response, messageUid);
- sendpublicDate(response, messageUid);
+ sendInternalDate(response, messageUid);
sendMessageSize(response, messageUid);
ensureMessageHeaders(messageUid, ref messageHeaders);
sendEnvelope(response, messageHeaders);
break;
case FetchDataItemType.InternalDate:
- sendpublicDate(response, messageUid);
+ sendInternalDate(response, messageUid);
break;
case FetchDataItemType.Rfc822:
@@ -430,7 +429,7 @@
#region FetchCommand
public override void ProcessCommand(FetchCommand cmd) {
// Process each list in the fetch command
- foreach (ImapMessageListItem listItem in cmd.MessageList.ImapMessageListItem) {
+ foreach (ImapMessageListItem listItem in cmd.MessageList) {
if (listItem.ItemType == ImapMessageListItemType.Single) {
// Only a single message in this item
processMessageFetch(listItem.Start, cmd.UidCommand, cmd.DataList);
@@ -484,5 +483,70 @@
}
#endregion
#endregion
+
+ #region Process Search Command
+
+ void matchUidSearch(UidSearchItem searchItem, List<int> messageUids) {
+ List<int> removedIds = new List<int>();
+
+ foreach (int messageUid in messageUids) {
+ bool foundMatch = false;
+
+ foreach (ImapMessageListItem item in searchItem.MessageList) {
+ if (item.Matches(messageUid)) {
+ foundMatch = true;
+ break;
+ }
+ }
+
+ if (!foundMatch) {
+ removedIds.Add(messageUid);
+ }
+ }
+
+ // Remove any Ids that don't match
+ for (int i = 0; i < removedIds.Count; i++) {
+ messageUids.Remove(removedIds[i]);
+ }
+ }
+
+ #region Search Command
+ public override void ProcessCommand(SearchCommand cmd) {
+ // Get a list of Ids for the folder
+ List<int> messageUids = LocalStore.GetMessageIds(Session.AuthenticationToken, Session.SelectedFolder);
+
+ // Check if there was any messages in the folder
+ if (messageUids.Count > 0) {
+ // Process each list in the search command
+ foreach (SearchItem searchItem in cmd.SearchItems) {
+ switch (searchItem.SearchType) {
+ case SearchItemType.Uid:
+ matchUidSearch((UidSearchItem) searchItem, messageUids);
+ break;
+ }
+ }
+ }
+
+ // Check if any message Ids matched the search criteria
+ if (messageUids.Count > 0) {
+ if (!cmd.UidCommand) {
+ List<int> messageOffsets = new List<int>();
+
+ foreach (int messageUid in messageUids) {
+ int messageOffset = LocalStore.GetMessageOffset(Session.AuthenticationToken, messageUid, Session.SelectedFolder);
+ messageOffsets.Add(messageOffset);
+ }
+
+ // Replace the list of offset Ids with
+ messageUids = messageOffsets;
+ }
+
+ QueueResponse(new SearchResponse(messageUids));
+ }
+
+ QueueResponse(new SimpleResponse(cmd.Tag, ResponseType.Ok, "SEARCH completed."));
+ }
+ #endregion
+ #endregion
}
}
Modified: NMail/trunk/NMail.ImapService/State/SelectedState.cs
===================================================================
--- NMail/trunk/NMail.ImapService/State/SelectedState.cs 2006-11-23 11:09:39 UTC (rev 91)
+++ NMail/trunk/NMail.ImapService/State/SelectedState.cs 2006-11-23 11:34:41 UTC (rev 92)
@@ -91,7 +91,7 @@
public override void ProcessCommand(StoreCommand cmd) {
// Process each list in the store command
- foreach (ImapMessageListItem listItem in cmd.MessageList.ImapMessageListItem) {
+ foreach (ImapMessageListItem listItem in cmd.MessageList) {
if (listItem.ItemType == ImapMessageListItemType.Single) {
// Only a single message in this item
processMessageStore(listItem.Start, cmd.UidCommand, cmd.Command, cmd.Flags);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|