Revision: 152
http://svn.sourceforge.net/nmailserver/?rev=152&view=rev
Author: tmyroadctfig
Date: 2007-02-17 17:53:57 -0800 (Sat, 17 Feb 2007)
Log Message:
-----------
Applied fixes for defects: 1601117, 1601133, 1601681, 1607841 and 1607846.
Modified Paths:
--------------
NMail/branches/v1.0.x/NMail/Helper/MimeHelper.cs
NMail/branches/v1.0.x/NMail/NMail.build
NMail/branches/v1.0.x/NMail.ImapService/Command/FetchCommand.cs
NMail/branches/v1.0.x/NMail.ImapService/Command/ImapMessageList.cs
NMail/branches/v1.0.x/NMail.ImapService/Command/SearchCommand.cs
NMail/branches/v1.0.x/NMail.ImapService/Response/SearchResponse.cs
NMail/branches/v1.0.x/NMail.ImapService/State/ExamineState.cs
NMail/branches/v1.0.x/NMail.ImapService/State/SelectedState.cs
NMail/branches/v1.0.x/NMail.LocalStore/LocalStore.cs
NMail/branches/v1.0.x/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs
NMail/branches/v1.0.x/NMail.build
Modified: NMail/branches/v1.0.x/NMail/Helper/MimeHelper.cs
===================================================================
--- NMail/branches/v1.0.x/NMail/Helper/MimeHelper.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail/Helper/MimeHelper.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -57,16 +57,17 @@
preamble = new MessageDataPart(data);
break;
- } else {
+ } else if (boundaryOffset > 0) {
// Extract the preamble
preamble = new MessageDataPart(data.SubString(0, boundaryOffset - Message.Terminator.Length));
+ }
- // Find the end of the boundary line and move to the next block
- int terminatorOffset =
- data.IndexOf(Message.Terminator, boundaryOffset + boundary.Length);
- blockStartOffset = terminatorOffset + Message.Terminator.Length;
- inPreamble = false;
- }
+ // Find the end of the boundary line and move to the next block
+ int terminatorOffset =
+ data.IndexOf(Message.Terminator, boundaryOffset + boundary.Length);
+ blockStartOffset = terminatorOffset + Message.Terminator.Length;
+ inPreamble = false;
+
} else {
boundaryOffset = data.IndexOf(boundary, blockStartOffset);
Modified: NMail/branches/v1.0.x/NMail/NMail.build
===================================================================
--- NMail/branches/v1.0.x/NMail/NMail.build 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail/NMail.build 2007-02-18 01:53:57 UTC (rev 152)
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<project name="nant" default="build">
<!-- default configuration -->
- <property name="project.config" value="Release" />
+ <property name="project.config" value="Debug" />
<property name="current.build.defines" value="" />
<target name="Debug" description="Perform a 'debug' build">
Modified: NMail/branches/v1.0.x/NMail.ImapService/Command/FetchCommand.cs
===================================================================
--- NMail/branches/v1.0.x/NMail.ImapService/Command/FetchCommand.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.ImapService/Command/FetchCommand.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -294,7 +294,11 @@
} else if (bodyString == "TEXT") {
this.sectionType = FetchBodySectionType.Text;
- } else {
+ } else if (bodyString == string.Empty) {
+ // No sections specified, default to all
+ this.sectionType = FetchBodySectionType.All;
+
+ } else {
this.sectionType = FetchBodySectionType.Section;
}
Modified: NMail/branches/v1.0.x/NMail.ImapService/Command/ImapMessageList.cs
===================================================================
--- NMail/branches/v1.0.x/NMail.ImapService/Command/ImapMessageList.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.ImapService/Command/ImapMessageList.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -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/branches/v1.0.x/NMail.ImapService/Command/SearchCommand.cs
===================================================================
--- NMail/branches/v1.0.x/NMail.ImapService/Command/SearchCommand.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.ImapService/Command/SearchCommand.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -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/branches/v1.0.x/NMail.ImapService/Response/SearchResponse.cs
===================================================================
--- NMail/branches/v1.0.x/NMail.ImapService/Response/SearchResponse.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.ImapService/Response/SearchResponse.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -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/branches/v1.0.x/NMail.ImapService/State/ExamineState.cs
===================================================================
--- NMail/branches/v1.0.x/NMail.ImapService/State/ExamineState.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.ImapService/State/ExamineState.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -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
@@ -245,7 +244,14 @@
protected virtual void sendBody(FetchResponse response, int messageUid, ref MessageHeaders messageHeaders, FetchBodyItem bodyItem, bool peek) {
string data = "BODY";
- if (bodyItem.SectionType == FetchBodySectionType.HeaderFields) {
+ if (bodyItem.SectionType == FetchBodySectionType.All) {
+ // Get the entire message from the local store
+ Message message = LocalStore.GetMessage(Session.AuthenticationToken, messageUid, this.selectedFolder);
+
+ data += "[] {" + message.Size + "}" + this.Session.Connection.Terminator + message.Data.ToString();
+ response.AppendResponseItem(data);
+
+ } else if (bodyItem.SectionType == FetchBodySectionType.HeaderFields) {
ensureMessageHeaders(messageUid, ref messageHeaders);
sendHeaders(response, bodyItem.HeaderFields, messageHeaders, false);
@@ -348,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);
@@ -373,7 +379,7 @@
case FetchDataItemType.Fast:
sendMessageFlags(response, messageUid);
- sendpublicDate(response, messageUid);
+ sendInternalDate(response, messageUid);
sendMessageSize(response, messageUid);
break;
@@ -383,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:
@@ -423,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);
@@ -477,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/branches/v1.0.x/NMail.ImapService/State/SelectedState.cs
===================================================================
--- NMail/branches/v1.0.x/NMail.ImapService/State/SelectedState.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.ImapService/State/SelectedState.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -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);
Modified: NMail/branches/v1.0.x/NMail.LocalStore/LocalStore.cs
===================================================================
--- NMail/branches/v1.0.x/NMail.LocalStore/LocalStore.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.LocalStore/LocalStore.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -186,8 +186,8 @@
// Save the message to the store data
LocalStoreData.DeliverMessage(lsd);
} catch (Exception) {
- result.Type = DeliveryResultType.TemporaryError;
- result.Message = "Internal error while delivering message.";
+ deliveryResult.Type = DeliveryResultType.TemporaryError;
+ deliveryResult.Message = "Internal error while delivering message.";
}
}
Modified: NMail/branches/v1.0.x/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs
===================================================================
--- NMail/branches/v1.0.x/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs 2007-02-18 01:53:57 UTC (rev 152)
@@ -130,10 +130,11 @@
cmd = cnn.CreateCommand();
cmd.Transaction = transaction;
cmd.Connection = cnn;
+
+ // Part 0 is not counted below in GetMessageMimePartCount
cmd.CommandText = "INSERT INTO MessageData (MessageId, Part, Data) " +
- "VALUES (?MessageId, ?Part, ?Data)";
+ "VALUES (?MessageId, 0, ?Data)";
cmd.Parameters.Add("?MessageId", messageId);
- cmd.Parameters.Add("?Part", 0); // Part 0 is not counted below in GetMessageMimePartCount
cmd.Parameters.Add("?Data", message.BodyData.Bytes);
count = cmd.ExecuteNonQuery();
Modified: NMail/branches/v1.0.x/NMail.build
===================================================================
--- NMail/branches/v1.0.x/NMail.build 2007-02-18 01:18:59 UTC (rev 151)
+++ NMail/branches/v1.0.x/NMail.build 2007-02-18 01:53:57 UTC (rev 152)
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<project name="nant" default="all">
<!-- default configuration -->
- <property name="project.config" value="Release" />
+ <property name="project.config" value="Debug" />
<property name="current.build.defines" value="" />
<target name="all" decription="Builds all assemblies and the installer." depends="build-Installer" />
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|