Monotone-Parent: d0eac9f630a7bec45962ad611bb2025a0a264075

Monotone-Revision: d4cbb070b0884fc3766c385032a8d95bc3f432a4

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2009-10-08T13:04:00
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2009-10-08 13:04:00 +00:00
parent 08a60d5746
commit 20b3d4919a
4 changed files with 216 additions and 91 deletions
+30 -8
View File
@@ -1,15 +1,37 @@
2009-10-08 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Tests/webdavlib.py (MailDAVMailQuery._initSort): now handles the
"order" attribute from the "ascending" parameter.
* Tests/test-maildav.py (DAVMailCollectionTest._testSort): added a
boolean "ascending" parameter that defaults to True.
(DAVMailCollectionTest.testREPORTMailQueryFilters): method
replacing the filter part of testREPORTMailQuery.
(DAVMailCollectionTest.testREPORTMailQuerySort): method
replacing the sort part of testREPORTMailQuery.
* SoObjects/Mailer/SOGoMailFolder.m (_sortElementIsAscending:):
new method that determines whether the sort ordering is ascending
or not.
(_sortOrderingsFromSortElement:): new method relacing
"_mailSortingFromSortElement:", that returns an array of
EOSortOrdering instances based on the "sort" element passed as
parameter.
2009-10-07 Cyril Robert <crobert@inverse.ca>
* SoObjects/Mailer/EOQualifier+MailDAV.m (buildQualifierFromFilters:): Now
returns an EOQualifier, fixed qualifier formats and constructor, refactored
to regroup code.
* Tests/test-maildav.py (testREPORTMailQuery): Disabled a few tests that
don't pass for now.
* SoObjects/Mailer/EOQualifier+MailDAV.m
(buildQualifierFromFilters:): Now returns an EOQualifier, fixed
qualifier formats and constructor, refactored to regroup code.
* Tests/test-maildav.py (testREPORTMailQuery): Disabled a few
tests that don't pass for now.
* SoObjects/Mailer/EOQualifier+MailDAV.m (buildQualifierFromFilters:):
Removed, everything is now done in (qualifierFromMailDAVMailFilters:).
(qualifierFromMailDAVMailFilters:): Removed all parentheses in qualifier.
* SoObjects/Mailer/EOQualifier+MailDAV.m (qualifierFromMailDAVMailFilters:):
Fixed segfault when there are no filters.
(qualifierFromMailDAVMailFilters:): Removed all parentheses in
qualifier.
* SoObjects/Mailer/EOQualifier+MailDAV.m
(qualifierFromMailDAVMailFilters:): Fixed segfault when there are
no filters.
2009-10-07 Francis Lachapelle <flachapelle@inverse.ca>
+125 -59
View File
@@ -38,6 +38,8 @@
#import <DOM/DOMProtocols.h>
#import <SaxObjC/XMLNamespaces.h>
#import <EOControl/EOSortOrdering.h>
#import <NGImap4/NGImap4Connection.h>
#import <NGImap4/NGImap4Client.h>
@@ -1151,84 +1153,108 @@ static NSString *spoolFolder = nil;
return davIMAPFieldsTable;
}
- (NSDictionary *) _davIMAPFieldsForProperties: (NSArray *) properties
- (BOOL) _sortElementIsAscending: (DOMElement *) sortElement
{
NSMutableDictionary *davIMAPFields;
NSDictionary *davIMAPFieldsTable;
NSString *imapField, *property;
unsigned int count, max;
davIMAPFieldsTable = [self davIMAPFieldsTable];
max = [properties count];
davIMAPFields = [NSMutableDictionary dictionaryWithCapacity: max];
for (count = 0; count < max; count++)
{
property = [properties objectAtIndex: count];
imapField = [davIMAPFieldsTable objectForKey: property];
if (imapField)
[davIMAPFields setObject: imapField forKey: property];
else
[self errorWithFormat: @"DAV property '%@' has no matching IMAP field,"
@" response could be incomplete", property];
}
return davIMAPFields;
}
- (NSDictionary *) parseDAVRequestedProperties: (DOMElement *) propElement
{
NSArray *properties;
NSDictionary *imapFieldsTable;
properties = [propElement flatPropertyNameOfSubElements];
imapFieldsTable = [self _davIMAPFieldsForProperties: properties];
return imapFieldsTable;
}
- (NSString *) _mailSortingFromSortElement: (DOMElement *) sortElement
{
NSArray *imapFields;
NSString *davReverseAttr;
NSMutableString *imapSortCriteria;
BOOL orderIsAscending;
imapSortCriteria = [NSMutableString string];
orderIsAscending = YES;
imapFields = [[self parseDAVRequestedProperties: sortElement] allValues];
davReverseAttr = [[sortElement attribute: @"order"] uppercaseString];
davReverseAttr = [sortElement attribute: @"order"];
if ([davReverseAttr isEqualToString: @"descending"])
[imapSortCriteria appendString: @"REVERSE "];
orderIsAscending = NO;
else if ([davReverseAttr length]
&& ![davReverseAttr isEqualToString: @"ascending"])
[self errorWithFormat: @"unrecognized sort order: '%@'",
davReverseAttr];
[imapSortCriteria
appendString: [imapFields componentsJoinedByString: @" "]];
return imapSortCriteria;
return orderIsAscending;
}
- (NSArray *) _sortOrderingsFromSortElement: (DOMElement *) sortElement
{
NSArray *davSortCriterias;
NSMutableArray *sortOrderings;
SEL sortOrderingOrder;
NSString *davSortVerb, *imapSortVerb;
EOSortOrdering *currentOrdering;
static NSMutableDictionary *criteriasMap = nil;
int count, max;
if (!criteriasMap)
{
criteriasMap = [NSMutableDictionary new];
[criteriasMap setObject: @"ARRIVAL"
forKey: @"{urn:schemas:mailheader:}received"];
[criteriasMap setObject: @"DATE"
forKey: @"{urn:schemas:mailheader:}date"];
[criteriasMap setObject: @"FROM"
forKey: @"{urn:schemas:mailheader:}from"];
[criteriasMap setObject: @"TO"
forKey: @"{urn:schemas:mailheader:}to"];
[criteriasMap setObject: @"CC"
forKey: @"{urn:schemas:mailheader:}cc"];
[criteriasMap setObject: @"SUBJECT"
forKey: @"{DAV:}displayname"];
[criteriasMap setObject: @"SUBJECT"
forKey: @"{urn:schemas:mailheader:}subject"];
[criteriasMap setObject: @"SIZE"
forKey: @"{DAV:}getcontentlength"];
}
sortOrderings = [NSMutableArray array];
if ([self _sortElementIsAscending: sortElement])
sortOrderingOrder = EOCompareAscending;
else
sortOrderingOrder = EOCompareDescending;
davSortCriterias = [sortElement flatPropertyNameOfSubElements];
max = [davSortCriterias count];
for (count = 0; count < max; count++)
{
davSortVerb = [davSortCriterias objectAtIndex : count];
imapSortVerb = [criteriasMap objectForKey: davSortVerb];
if (imapSortVerb)
{
currentOrdering
= [EOSortOrdering sortOrderingWithKey: imapSortVerb
selector: sortOrderingOrder];
[sortOrderings addObject: currentOrdering];
}
else
[self errorWithFormat: @"unrecognized sort key: '%@'", davSortVerb];
}
return sortOrderings;
}
- (NSArray *) _fetchMessageProperties: (NSDictionary *) properties
matchingQualifier: (EOQualifier *) searchQualifier
andSorting: (NSString *) sorting
andSortOrderings: (NSArray *) sortOrderings
{
NGImap4Client *client;
NSDictionary *response;
NSArray *messages;
NSString *resultKey;
client = [[self imap4Connection] client];
[imap4 selectFolder: [self imap4URL]];
if ([sorting length])
response = [client sort: sorting
qualifier: searchQualifier
encoding: @"UTF-8"];
if ([sortOrderings count])
{
response = [client sort: sortOrderings qualifier: searchQualifier
encoding: @"UTF-8"];
resultKey = @"sort";
}
else
response = [client searchWithQualifier: searchQualifier];
{
response = [client searchWithQualifier: searchQualifier];
resultKey = @"search";
}
if ([[response objectForKey: @"result"] boolValue])
messages = [response objectForKey: @"search"];
messages = [response objectForKey: resultKey];
else
messages = nil;
@@ -1278,7 +1304,7 @@ static NSString *spoolFolder = nil;
}
messageUrl = [NSString stringWithFormat: @"%@%@.eml",
[self davURL], messageId];
[self davURL], messageId];
[propstats addObject: davElementWithContent (@"href", XMLNS_WEBDAV,
messageUrl)];
@@ -1325,20 +1351,60 @@ static NSString *spoolFolder = nil;
}
davString = [davElementWithContent (@"multistatus", XMLNS_WEBDAV, all)
asWebDavStringWithNamespaces: nil];
asWebDavStringWithNamespaces: nil];
[response appendContentString: davString];
NSZoneFree (NULL, selectors);
}
- (NSDictionary *) _davIMAPFieldsForProperties: (NSArray *) properties
{
NSMutableDictionary *davIMAPFields;
NSDictionary *davIMAPFieldsTable;
NSString *imapField, *property;
unsigned int count, max;
davIMAPFieldsTable = [self davIMAPFieldsTable];
max = [properties count];
davIMAPFields = [NSMutableDictionary dictionaryWithCapacity: max];
for (count = 0; count < max; count++)
{
property = [properties objectAtIndex: count];
imapField = [davIMAPFieldsTable objectForKey: property];
if (imapField)
[davIMAPFields setObject: imapField forKey: property];
else
[self errorWithFormat: @"DAV property '%@' has no matching IMAP field,"
@" response could be incomplete", property];
}
return davIMAPFields;
}
- (NSDictionary *) parseDAVRequestedProperties: (DOMElement *) propElement
{
NSArray *properties;
NSDictionary *imapFieldsTable;
properties = [propElement flatPropertyNameOfSubElements];
imapFieldsTable = [self _davIMAPFieldsForProperties: properties];
return imapFieldsTable;
}
/* TODO:
- populate only required keys in returned SOGoMailObject rather that
fetching the whole envelope and stuff
- use EOSortOrdering rather than an NSString
*/
- (id) davMailQuery: (id) queryContext
{
WOResponse *r;
id <DOMDocument> document;
DOMElement *documentElement, *propElement, *filterElement, *sortElement;
NSDictionary *properties;
NSArray *messages;
NSArray *messages, *sortOrderings;
EOQualifier *searchQualifier;
NSString *sorting;
r = [context response];
[r setContentEncoding: NSUTF8StringEncoding];
@@ -1358,11 +1424,11 @@ static NSString *spoolFolder = nil;
qualifierFromMailDAVMailFilters: filterElement];
sortElement = [documentElement firstElementWithTag: @"sort"
inNamespace: XMLNS_INVERSEDAV];
sorting = [self _mailSortingFromSortElement: sortElement];
sortOrderings = [self _sortOrderingsFromSortElement: sortElement];
messages = [self _fetchMessageProperties: properties
matchingQualifier: searchQualifier
andSorting: sorting];
andSortOrderings: sortOrderings];
[r setStatus: 207];
[r appendContentString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"];
[self _appendProperties: [properties allKeys]
+52 -20
View File
@@ -7,6 +7,9 @@ import unittest
import webdavlib
import time
# TODO
# add test with multiple sort criterias
def fetchUserEmail(login):
client = webdavlib.WebDAVClient(hostname, port,
username, password)
@@ -330,14 +333,14 @@ class DAVMailCollectionTest(unittest.TestCase):
"filter %s:\n\tunexpected amount of refs: %d"
% (filter[0], received_count))
def _testSort(self, sortOrder):
def _testSort(self, sortOrder, ascending = True):
expected_hrefs = sortOrder[1]
expected_count = len(expected_hrefs)
received_count = 0
url = "%sfolder%s" % (self.resource, "test-dav-mail")
query = webdavlib.MailDAVMailQuery(url, ["displayname"],
None, sortOrder[0])
None, sortOrder[0], ascending)
self.client.execute(query)
self.assertEquals(query.response["status"], 207,
"sortOrder %s:\n\tunexpected status: %d"
@@ -348,18 +351,18 @@ class DAVMailCollectionTest(unittest.TestCase):
for response_node in response_nodes:
href_node = query.xpath_evaluate("D:href", response_node)[0]
href = href_node.childNodes[0].nodeValue
received_count = received_count + 1
self.assertEquals(expected_hrefs[received_count], href,
"sortOrder %s:\n\tunexpected href: %s (expecting: %s)"
% (sortOrder[0], href,
expected_hrefs[received_count]))
received_count = received_count + 1
self.assertEquals(expected_count, received_count,
"sortOrder %s:\n\tunexpected amount of refs: %d"
% (sortOrder[0], received_count))
def testREPORTMailQuery(self):
"""mail-query"""
def testREPORTMailQueryFilters(self):
"""mail-query filters"""
self._deleteCollection("test-dav-mail")
self._makeCollection("test-dav-mail")
@@ -549,6 +552,7 @@ class DAVMailCollectionTest(unittest.TestCase):
"not": "true" }},
[ msg2Loc, msg3Loc ]))
print "message flags are not handled yet"
## 1. test filter: answered
# ANSWERED, UNANSWERED
## 1. test filter: draft
@@ -579,33 +583,57 @@ class DAVMailCollectionTest(unittest.TestCase):
[]))
self._testFilters(filters)
self._deleteCollection("test-dav-mail")
def testREPORTMailQuerySort(self):
"""mail-query sort"""
self._deleteCollection("test-dav-mail")
self._makeCollection("test-dav-mail")
msg1Loc = self._putMessage(self.client, "test-dav-mail", message1)
parsed = webdavlib.HTTPUnparsedURL(msg1Loc)
msg1Path = parsed.path
msg2Loc = self._putMessage(self.client, "test-dav-mail", message2)
parsed = webdavlib.HTTPUnparsedURL(msg2Loc)
msg2Path = parsed.path
msg3Loc = self._putMessage(self.client, "test-dav-mail", message3)
parsed = webdavlib.HTTPUnparsedURL(msg3Loc)
msg3Path = parsed.path
# 1. test sort: (receive-date) ARRIVAL
self._testSort(([ "{urn:schemas:mailheader:}received" ],
[ msg2Loc, msg3Loc, msg1Loc ]))
[ msg1Loc, msg2Loc, msg3Loc ]))
# 1. test sort: (date) DATE
self._testSort(([ "{urn:schemas:mailheader:}date" ],
[ msg2Loc, msg1Loc, msg3Loc ]))
# 1. test sort: FROM
self._testSort(([ "{urn:schemas:mailheader:}from" ],
[ msg1Loc, msg2Loc, msg3Loc ]))
# 1. test sort: TO
self._testSort(([ "{urn:schemas:mailheader:}to" ],
[ msg1Loc, msg2Loc, msg3Loc ]))
# 1. test sort: CC
self._testSort(([ "{urn:schemas:mailheader:}cc" ],
[ msg3Loc, msg1Loc, msg2Loc ]))
# 1. test sort: FROM
self._testSort(([ "{urn:schemas:mailheader:}from" ],
[ msg1Loc, msg2Loc, msg3Loc ]))
# 1. test sort: SUBJECT
self._testSort(([ "{DAV:}displayname" ],
[ msg3Loc, msg1Loc, msg2Loc ]))
self._testSort(([ "{urn:schemas:mailheader:}subject" ],
[ msg3Loc, msg1Loc, msg2Loc ]))
# 1. test sort: SIZE
self._testSort(([ "{DAV:}getcontentlength" ],
[ msg3Loc, msg1Loc, msg2Loc ]))
# 1. test sort: SUBJECT
self._testSort(([ "{urn:schemas:mailheader:}displayName" ],
[ msg3Loc, msg1Loc, msg2Loc ]))
# 1. test sort: TO
self._testSort(([ "{urn:schemas:mailheader:}to" ],
[ msg1Loc, msg2Loc, msg3Loc ]))
# 1. test sort: REVERSE CC
self._testSort(([ "{urn:schemas:mailheader:}cc" ],
[ msg2Loc, msg1Loc, msg3Loc ]),
False)
self._deleteCollection("test-dav-mail")
@@ -629,11 +657,15 @@ class DAVMailCollectionTest(unittest.TestCase):
("{urn:schemas:httpmail:}textdescription",
"<![CDATA[%s]]>" % message1, 0),
("{urn:schemas:httpmail:}unreadcount", None, 0),
("{urn:schemas:mailheader:}cc","2message1cc@cyril.dev, user10@cyril.dev", 0),
("{urn:schemas:mailheader:}date", "Mon, 28 Sep 2009 11:42:14 GMT", 0),
("{urn:schemas:mailheader:}from", "Cyril <message1from@cyril.dev>", 0),
("{urn:schemas:mailheader:}cc",
"2message1cc@cyril.dev, user10@cyril.dev", 0),
("{urn:schemas:mailheader:}date",
"Mon, 28 Sep 2009 11:42:14 GMT", 0),
("{urn:schemas:mailheader:}from",
"Cyril <message1from@cyril.dev>", 0),
("{urn:schemas:mailheader:}in-reply-to", None, 0),
("{urn:schemas:mailheader:}message-id","<4AC1F29sept6.5060801@cyril.dev>", 0),
("{urn:schemas:mailheader:}message-id",
"<4AC1F29sept6.5060801@cyril.dev>", 0),
("{urn:schemas:mailheader:}received", message1_received, 0),
("{urn:schemas:mailheader:}references",
"<4AC3BF1B.3010806@inverse.ca>", 0),
+9 -4
View File
@@ -315,7 +315,8 @@ class WebDAVSyncQuery(WebDAVREPORT):
self._initProperties(properties)
class MailDAVMailQuery(WebDAVREPORT):
def __init__(self, url, properties, filters = None, sort = None):
def __init__(self, url, properties, filters = None,
sort = None, ascending = True):
WebDAVQuery.__init__(self, url)
mailquery_tag = self.ns_mgr.register("mail-query",
xmlns_inversedav)
@@ -327,7 +328,7 @@ class MailDAVMailQuery(WebDAVREPORT):
self._initFilters(filters)
if sort is not None and len(sort) > 0:
self._initSort(sort)
self._initSort(sort, ascending)
def _initFilters(self, filters):
mailfilter_tag = self.ns_mgr.register("mail-filters",
@@ -341,9 +342,13 @@ class MailDAVMailQuery(WebDAVREPORT):
filters[filterk])
mailfilter_node.append(filter_node)
def _initSort(self, sort):
def _initSort(self, sort, ascending):
sort_tag = self.ns_mgr.register("sort", xmlns_inversedav)
sort_node = _WD_XMLTreeElement(sort_tag)
if ascending:
sort_attrs = { "order": "ascending" }
else:
sort_attrs = { "order": "descending" }
sort_node = _WD_XMLTreeElement(sort_tag, sort_attrs)
self.top_node.append(sort_node)
for item in sort: