From 7524610f5c1f30178bc00dd54fd71fb921083dce Mon Sep 17 00:00:00 2001 From: C Robert Date: Thu, 1 Oct 2009 20:16:52 +0000 Subject: [PATCH] Added methods for PROPFIND Monotone-Parent: 2b6cf9ec13774912de440dcfe08a03df4a580d4e Monotone-Revision: 8db3f67f47d18d68431d7ffb603fcf636ac4bc9b Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-10-01T20:16:52 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 9 ++ SoObjects/Mailer/SOGoMailObject.m | 180 ++++++++++++++++++++++++++++++ Tests/test-maildav.py | 63 ++++++++++- 3 files changed, 251 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8963da946..98e380da1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-10-01 Cyril Robert + + * SoObjects/Mailer/SOGoMailObject.m: Added methods required for PROPFIND / + REPORT: _fetchProperty:, _hasFlag:, _emailAddressesFrom:, davDate, + hasAttachment, read, textDescription, cc, from, inReplyTo, messageId, + received, references, davDisplayName, to + * Tests/test-maildav.py (testPROPFIND): Added tests for the new MailDAV + PROPFIND. + 2009-10-01 Cyril Robert * SoObjects/Mailer/SOGoMailFolder.m diff --git a/SoObjects/Mailer/SOGoMailObject.m b/SoObjects/Mailer/SOGoMailObject.m index ff34c46b3..670cfe061 100644 --- a/SoObjects/Mailer/SOGoMailObject.m +++ b/SoObjects/Mailer/SOGoMailObject.m @@ -1269,4 +1269,184 @@ static BOOL debugSoParts = NO; return response; } +// For DAV REPORT +- (id) _fetchProperty: (NSString *) property +{ + NSArray *parts; + id rc, msgs; + + rc = nil; + + if (property) + { + parts = [NSArray arrayWithObjects: property, nil]; + + msgs = [self fetchParts: parts]; + msgs = [msgs valueForKey: @"fetch"]; + if ([msgs count]) { + rc = [msgs objectAtIndex: 0]; + } + } + + return rc; +} + +- (BOOL) _hasFlag: (NSString *) flag +{ + BOOL rc; + NSDictionary *values; + NSArray *flags; + + rc = NO; + values = [self _fetchProperty: @"FLAGS"]; + + if (values) + { + flags = [values objectForKey: @"flags"]; + rc = [flags containsObject: flag]; + } + return rc; +} + +- (NSString *) _emailAddressesFrom: (NSArray *) enveloppeAddresses +{ + //voir spec + NSMutableArray *addresses; + NSString *rc; + NGImap4EnvelopeAddress *address; + NSString *email; + int count, max; + + rc = nil; + max = [enveloppeAddresses count]; + + if (max > 0) + { + addresses = [NSMutableArray array]; + for (count = 0; count < max; count++) + { + address = [enveloppeAddresses objectAtIndex: count]; + email = [NSString stringWithFormat: @"%@", [address email]]; + + [addresses addObject: email]; + } + rc = [addresses componentsJoinedByString: @", "]; + } + + return rc; +} + +// Properties + +//{urn:schemas:httpmail:} + +// date already exists, but this one is the correct format +- (NSString *) davDate +{ + return [[self date] + descriptionWithCalendarFormat: @"%a, %d %b %Y %H:%M:%S %z"]; +} + +- (BOOL) hasAttachment +{ + return ([[self fetchAttachmentIds] count] > 0); +} + +- (BOOL) read +{ + return [self _hasFlag: @"seen"]; +} + +- (NSString *) textDescription +{ + return [NSString stringWithFormat: @"", [self contentAsString]]; +} + + +//{urn:schemas:mailheader:} + +- (NSString *) cc +{ + return [self _emailAddressesFrom: [self ccEnvelopeAddresses]]; +} + +- (NSString *) from +{ + return [self _emailAddressesFrom: [self fromEnvelopeAddresses]]; +} + +- (NSString *) inReplyTo +{ + return [[self envelope] inReplyTo]; +} + +- (NSString *) messageId +{ + return [[self envelope] messageID]; +} + +- (NSString *) received +{ + NSDictionary *fetch; + NSData *data; + NSString *value, *rc; + NSRange range; + + rc = nil; + fetch = [self _fetchProperty: @"BODY[HEADER.FIELDS (RECEIVED)]"]; + + if ([fetch count]) + { + data = [fetch objectForKey: @"header"]; + value = [[NSString alloc] initWithData: data + encoding: NSUTF8StringEncoding]; + range = [value rangeOfString: @"received:" + options: NSCaseInsensitiveSearch + range: NSMakeRange (10, [value length]-11)]; + if (range.length) + { + // We want to keep the first part + range.length = range.location; + range.location = 0; + rc = [[value substringWithRange: range] stringByTrimmingSpaces]; + } + else + rc = [value stringByTrimmingSpaces]; + + [value release]; + } + + return rc; +} + +- (NSString *) references +{ + NSDictionary *fetch; + NSData *data; + NSString *value, *rc;; + + rc = nil; + fetch = [self _fetchProperty: @"BODY[HEADER.FIELDS (REFERENCES)]"]; + + if ([fetch count]) + { + data = [fetch objectForKey: @"header"]; + value = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; + rc = [[value substringFromIndex: 11] stringByTrimmingSpaces]; + [value release]; + } + + return rc; +} + +- (NSString *) davDisplayName +{ + return [self subject]; +} + +- (NSString *) to +{ + return [self _emailAddressesFrom: [self toEnvelopeAddresses]]; +} + @end /* SOGoMailObject */ diff --git a/Tests/test-maildav.py b/Tests/test-maildav.py index d5291d071..fb630a35b 100755 --- a/Tests/test-maildav.py +++ b/Tests/test-maildav.py @@ -26,15 +26,19 @@ message1 = """Return-Path: Received: from cyril.dev (localhost [127.0.0.1]) by cyril.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA; Tue, 29 Sep 2009 07:42:16 -0400 +Received: from aloha.dev (localhost [127.0.0.1]) + by aloha.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA; + Tue, 29 Sep 2009 07:42:16 -0400 X-Virus-Scanned: Debian amavisd-new at inverse.ca Message-ID: <4AC1F296.5060801@cyril.dev> +References: <4AC3BF1B.3010806@inverse.ca> Date: Tue, 29 Sep 2009 07:42:14 -0400 From: Cyril Organization: Inverse inc. User-Agent: Thunderbird 2.0.0.22 (Macintosh/20090605) MIME-Version: 1.0 To: jacques@cyril.dev -CC: support@inverse.ca +CC: support@inverse.ca, user10@cyril.dev Subject: Hallo Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit @@ -47,6 +51,9 @@ Can you read me? -- Cyril """ +message1_received = """Received: from cyril.dev (localhost [127.0.0.1]) + by cyril.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA; + Tue, 29 Sep 2009 07:42:16 -0400""" class DAVMailCollectionTest(unittest.TestCase): resource = '/SOGo/dav/%s/Mail/' % username @@ -93,6 +100,23 @@ class DAVMailCollectionTest(unittest.TestCase): " expected status code '%d' (received '%d')" % (filename, exp_status, put.response["status"])) + def _testProperty (self, url, property, expected): + propfind = webdavlib.WebDAVPROPFIND(url, (property, ), 0) + self.client.execute(propfind) + key = property.replace("{urn:schemas:httpmail:}", "a:") + key = key.replace("{urn:schemas:mailheader:}", "a:") + tmp = propfind.xpath_evaluate("/D:multistatus/D:response/D:propstat/D:prop") + prop = tmp[0].firstChild; + result = None + + if prop: + result = prop._get_firstChild()._get_nodeValue() + #print key, result + + self.assertEquals(result, expected, + "failure in propfind" + "(%s != %s)" % (result, expected)) + def testMKCOL(self): """Folder creation""" self._makeCollection ("test-dav-mail-%40-abc") @@ -153,5 +177,42 @@ class DAVMailCollectionTest(unittest.TestCase): self._deleteCollection ("test-dav-mail") + def testPROPFIND(self): + """Message properties""" + self._deleteCollection ("test-dav-mail") + self._makeCollection ("test-dav-mail") + + url = "%s%s" % (self.resource, "foldertest-dav-mail/") + put = webdavlib.HTTPPUT (url, message1) + put.content_type = "message/rfc822" + self.client.execute (put) + self.assertEquals(put.response["status"], 201, + "failure putting message" + "(code = %d)" % put.response["status"]) + + itemLocation = put.response["headers"]["location"] + tests = (("{urn:schemas:httpmail:}date", "Tue, 29 Sep 2009 11:42:14 GMT"), + ("{urn:schemas:httpmail:}hasattachment", "0"), + ("{urn:schemas:httpmail:}read", "0"), + ("{urn:schemas:httpmail:}textdescription", + "" % message1), + ("{urn:schemas:httpmail:}unreadcount", None), + ("{urn:schemas:mailheader:}cc","support@inverse.ca, user10@cyril.dev"), + ("{urn:schemas:mailheader:}date", "Tue, 29 Sep 2009 11:42:14 GMT"), + ("{urn:schemas:mailheader:}from", "Cyril "), + ("{urn:schemas:mailheader:}in-reply-to", None), + ("{urn:schemas:mailheader:}message-id","<4AC1F296.5060801@cyril.dev>"), + ("{urn:schemas:mailheader:}received", message1_received), + ("{urn:schemas:mailheader:}references", "<4AC3BF1B.3010806@inverse.ca>"), + ("{urn:schemas:mailheader:}subject", "Hallo"), + ("{urn:schemas:mailheader:}to", "jacques@cyril.dev")) + + for test in tests: + property, expected = test + self._testProperty(itemLocation, property, expected) + + self._deleteCollection ("test-dav-mail") + + if __name__ == "__main__": unittest.main()