From 5e342d5e9942529c441cf52a2ecb01e5893aac99 Mon Sep 17 00:00:00 2001 From: C Robert Date: Mon, 5 Oct 2009 19:15:14 +0000 Subject: [PATCH 1/6] See ChangeLog Monotone-Parent: 8260a03656dcb7042c36f5ed015c0e1691560468 Monotone-Revision: 11c5eefb2d127036af170d47dc0f555860e8c38a Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-10-05T19:15:14 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 ++ SoObjects/Mailer/EOQualifier+MailDAV.h | 37 +++++++ SoObjects/Mailer/EOQualifier+MailDAV.m | 141 +++++++++++++++++++++++++ SoObjects/Mailer/GNUmakefile | 1 + Tests/test-webdavlib.py | 18 ++++ Tests/webdavlib.py | 2 +- 6 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 SoObjects/Mailer/EOQualifier+MailDAV.h create mode 100644 SoObjects/Mailer/EOQualifier+MailDAV.m diff --git a/ChangeLog b/ChangeLog index 32c7aa978..dcc4dbf70 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-10-05 Cyril Robert + + * Tests/test-webdavlib.py: Added new tests for the URL parser / regexp. + * Tests/webdavlib.py: Fixed errors in the URL regexp. + * SoObjects/Mailer/EOQualifier+MailDAV.m: New category to generate IMAP + qualifiers from DAV filters. (REPORT) + 2009-10-04 Ludovic Marcotte * Adjusted the Welsh and Dutch templates for diff --git a/SoObjects/Mailer/EOQualifier+MailDAV.h b/SoObjects/Mailer/EOQualifier+MailDAV.h new file mode 100644 index 000000000..f779ca865 --- /dev/null +++ b/SoObjects/Mailer/EOQualifier+MailDAV.h @@ -0,0 +1,37 @@ +/* EOQualifier+MailDAV.h - this file is part of SOGo + * + * Copyright (C) 2009 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef EOQUALIFIER_MAILDAV_H +#define EOQUALIFIER_MAILDAV_H + +#import +#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav" + +@class DOMElement; + +@interface EOQualifier (SOGoMailDAVExtension) + ++ (id) qualifierFromMailDAVMailFilters: (DOMElement *) mailFilters; + +@end + +#endif /* EOQUALIFIER_MAILDAV_H */ diff --git a/SoObjects/Mailer/EOQualifier+MailDAV.m b/SoObjects/Mailer/EOQualifier+MailDAV.m new file mode 100644 index 000000000..8b404bbbf --- /dev/null +++ b/SoObjects/Mailer/EOQualifier+MailDAV.m @@ -0,0 +1,141 @@ +/* EOQualifier+MailDAV.m - this file is part of SOGo + * + * Copyright (C) 2009 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import + +#import +#import +#import +#import + +#import + +#import "EOQualifier+MailDAV.h" + +@implementation EOQualifier (SOGoMailDAVExtension) + ++ (NSString *) buildQualifierFromFilters: (DOMElement *) mailFilters +{ + NSMutableArray *qualifiers; + NSString *qual, *buffer; + id list; + DOMElement *current; + NSCalendarDate *startDate, *endDate; + int count, max; + + qualifiers = [NSMutableArray array]; + qual = nil; + + list = [mailFilters childNodes]; + if (list) + { + max = [list length]; + for (count = 0; count < max; count++) + { + current = [list objectAtIndex: count]; + if ([current nodeType] == DOM_ELEMENT_NODE) + { + // Received date + if ([[current tagName] isEqualToString: @"receive-date"]) + { + startDate = [[current attribute: @"from"] asCalendarDate]; + endDate = [[current attribute: @"to"] asCalendarDate]; + if (startDate && [startDate isEqual: endDate]) + [qualifiers addObject: + [NSString stringWithFormat: @"(on = '%@')", startDate]]; + else if (startDate) + [qualifiers addObject: + [NSString stringWithFormat: @"(since > '%@')", startDate]]; + if (endDate) + [qualifiers addObject: + [NSString stringWithFormat: @"(before < '%@')", endDate]]; + } + // Sent date + else if ([[current tagName] isEqualToString: @"date"]) + { + startDate = [[current attribute: @"from"] asCalendarDate]; + endDate = [[current attribute: @"to"] asCalendarDate]; + if (startDate && [startDate isEqual: endDate]) + [qualifiers addObject: + [NSString stringWithFormat: @"(senton = '%@')", startDate]]; + else if (startDate) + [qualifiers addObject: + [NSString stringWithFormat: @"(sentsince > '%@')", startDate]]; + if (endDate) + [qualifiers addObject: + [NSString stringWithFormat: @"(sentbefore < '%@')", endDate]]; + } + // Sequence + else if ([[current tagName] isEqualToString: @"sequence"]) + { + //TODO + } + // UID + else if ([[current tagName] isEqualToString: @"uid"]) + { + buffer = [current attribute: @"uid"]; + if (buffer) + [qualifiers addObject: + [NSString stringWithFormat: @"(uid = '%@')", buffer]]; + } + // From + else if ([[current tagName] isEqualToString: @"from"]) + { + buffer = [current attribute: @"from"]; + if (buffer) + [qualifiers addObject: + [NSString stringWithFormat: @"(from = '%@')", buffer]]; + } + // To + else if ([[current tagName] isEqualToString: @"to"]) + { + buffer = [current attribute: @"to"]; + if (buffer) + [qualifiers addObject: + [NSString stringWithFormat: @"(to = '%@')", buffer]]; + } + + } + } + } + + if ([qualifiers count]) + qual = [qualifiers componentsJoinedByString: @" AND "]; + + return qual; +} + + ++ (id) qualifierFromMailDAVMailFilters: (DOMElement *) mailFilters +{ + EOQualifier *newQualifier; + NSString *qual; + + qual = [EOQualifier buildQualifierFromFilters: mailFilters]; + + newQualifier = [EOQualifier qualifierWithQualifierFormat: qual]; + + return newQualifier; +} + +@end diff --git a/SoObjects/Mailer/GNUmakefile b/SoObjects/Mailer/GNUmakefile index 784695c14..c737fbed5 100644 --- a/SoObjects/Mailer/GNUmakefile +++ b/SoObjects/Mailer/GNUmakefile @@ -32,6 +32,7 @@ Mailer_OBJC_FILES += \ SOGoMailForward.m \ SOGoMailReply.m \ \ + EOQualifier+MailDAV.m \ NSData+Mail.m \ NSString+Mail.m diff --git a/Tests/test-webdavlib.py b/Tests/test-webdavlib.py index b12b42bf2..20a4f6f10 100755 --- a/Tests/test-webdavlib.py +++ b/Tests/test-webdavlib.py @@ -28,5 +28,23 @@ class HTTPUnparsedURLTest(unittest.TestCase): self.assertEquals(testURL.port, None) self.assertEquals(testURL.path, "/folder/folder/simplereference") + pathURL = "http://user:secret@bla.com/hooray" + testURL = HTTPUnparsedURL(pathURL) + self.assertEquals(testURL.protocol, "http") + self.assertEquals(testURL.username, "user") + self.assertEquals(testURL.password, "secret") + self.assertEquals(testURL.hostname, "bla.com") + self.assertEquals(testURL.port, None) + self.assertEquals(testURL.path, "/hooray") + + pathURL = "http://user@bla.com:80/hooray" + testURL = HTTPUnparsedURL(pathURL) + self.assertEquals(testURL.protocol, "http") + self.assertEquals(testURL.username, "user") + self.assertEquals(testURL.password, None) + self.assertEquals(testURL.hostname, "bla.com") + self.assertEquals(testURL.port, "80") + self.assertEquals(testURL.path, "/hooray") + if __name__ == "__main__": unittest.main() diff --git a/Tests/webdavlib.py b/Tests/webdavlib.py index 10111b565..5f5c7c834 100644 --- a/Tests/webdavlib.py +++ b/Tests/webdavlib.py @@ -24,7 +24,7 @@ class HTTPUnparsedURL: url_parts = url.split("?") alpha_match = "[a-zA-Z0-9%\._-]+" num_match = "[0-9]+" - pattern = ("((%s)://(((%s)(:(%s)?)@)?(%s)(:(%s))))?(/.*)" + pattern = ("((%s)://(((%s)(:(%s))?@)?(%s)(:(%s))?))?(/.*)" % (alpha_match, alpha_match, alpha_match, alpha_match, num_match)) url_re = re.compile(pattern) From 5a357311c6ea7b480095b0bc9cb20349c482894d Mon Sep 17 00:00:00 2001 From: C Robert Date: Mon, 5 Oct 2009 19:38:40 +0000 Subject: [PATCH 2/6] Format dates properly Monotone-Parent: 11c5eefb2d127036af170d47dc0f555860e8c38a Monotone-Revision: 778b3664ce06bfae56a07b260fb9b9a241276d08 Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-10-05T19:38:40 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 2 ++ SoObjects/Mailer/EOQualifier+MailDAV.m | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index dcc4dbf70..3bc90f1c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ * Tests/webdavlib.py: Fixed errors in the URL regexp. * SoObjects/Mailer/EOQualifier+MailDAV.m: New category to generate IMAP qualifiers from DAV filters. (REPORT) + * SoObjects/Mailer/EOQualifier+MailDAV.m: Formatted dates using + ([NSCalendarDate rfc822DateString]). 2009-10-04 Ludovic Marcotte diff --git a/SoObjects/Mailer/EOQualifier+MailDAV.m b/SoObjects/Mailer/EOQualifier+MailDAV.m index 8b404bbbf..5b26c1f39 100644 --- a/SoObjects/Mailer/EOQualifier+MailDAV.m +++ b/SoObjects/Mailer/EOQualifier+MailDAV.m @@ -29,6 +29,7 @@ #import #import +#import #import "EOQualifier+MailDAV.h" @@ -62,13 +63,16 @@ endDate = [[current attribute: @"to"] asCalendarDate]; if (startDate && [startDate isEqual: endDate]) [qualifiers addObject: - [NSString stringWithFormat: @"(on = '%@')", startDate]]; + [NSString stringWithFormat: @"(on = '%@')", + [startDate rfc822DateString]]]; else if (startDate) [qualifiers addObject: - [NSString stringWithFormat: @"(since > '%@')", startDate]]; + [NSString stringWithFormat: @"(since > '%@')", + [startDate rfc822DateString]]]; if (endDate) [qualifiers addObject: - [NSString stringWithFormat: @"(before < '%@')", endDate]]; + [NSString stringWithFormat: @"(before < '%@')", + [endDate rfc822DateString]]]; } // Sent date else if ([[current tagName] isEqualToString: @"date"]) @@ -77,13 +81,16 @@ endDate = [[current attribute: @"to"] asCalendarDate]; if (startDate && [startDate isEqual: endDate]) [qualifiers addObject: - [NSString stringWithFormat: @"(senton = '%@')", startDate]]; + [NSString stringWithFormat: @"(senton = '%@')", + [startDate rfc822DateString]]]; else if (startDate) [qualifiers addObject: - [NSString stringWithFormat: @"(sentsince > '%@')", startDate]]; + [NSString stringWithFormat: @"(sentsince > '%@')", + [startDate rfc822DateString]]]; if (endDate) [qualifiers addObject: - [NSString stringWithFormat: @"(sentbefore < '%@')", endDate]]; + [NSString stringWithFormat: @"(sentbefore < '%@')", + [endDate rfc822DateString]]]; } // Sequence else if ([[current tagName] isEqualToString: @"sequence"]) From 290d0e76d5113a272d8db2fdc827a9e3511364b1 Mon Sep 17 00:00:00 2001 From: C Robert Date: Mon, 5 Oct 2009 21:14:44 +0000 Subject: [PATCH 3/6] Added extra fields and NOT Monotone-Parent: 778b3664ce06bfae56a07b260fb9b9a241276d08 Monotone-Revision: dd01e619d1a581329304197499bcc223888f4535 Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-10-05T21:14:44 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 1 + SoObjects/Mailer/EOQualifier+MailDAV.m | 119 +++++++++++++++++++++---- 2 files changed, 103 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3bc90f1c0..6caa1acb3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ qualifiers from DAV filters. (REPORT) * SoObjects/Mailer/EOQualifier+MailDAV.m: Formatted dates using ([NSCalendarDate rfc822DateString]). + * SoObjects/Mailer/EOQualifier+MailDAV.m: Added NOT and extra fields. 2009-10-04 Ludovic Marcotte diff --git a/SoObjects/Mailer/EOQualifier+MailDAV.m b/SoObjects/Mailer/EOQualifier+MailDAV.m index 5b26c1f39..a9102de3e 100644 --- a/SoObjects/Mailer/EOQualifier+MailDAV.m +++ b/SoObjects/Mailer/EOQualifier+MailDAV.m @@ -42,11 +42,14 @@ id list; DOMElement *current; NSCalendarDate *startDate, *endDate; - int count, max; + int count, max, intValue; + NSString *negate; qualifiers = [NSMutableArray array]; qual = nil; +#warning Qualifiers may be invalid, need to be tested + list = [mailFilters childNodes]; if (list) { @@ -56,6 +59,12 @@ current = [list objectAtIndex: count]; if ([current nodeType] == DOM_ELEMENT_NODE) { + // Negate condition + if ([current attribute: @"not"]) + negate = @"NOT "; + else + negate = @""; + // Received date if ([[current tagName] isEqualToString: @"receive-date"]) { @@ -63,16 +72,16 @@ endDate = [[current attribute: @"to"] asCalendarDate]; if (startDate && [startDate isEqual: endDate]) [qualifiers addObject: - [NSString stringWithFormat: @"(on = '%@')", - [startDate rfc822DateString]]]; + [NSString stringWithFormat: @"%@(on = '%@')", + negate, [startDate rfc822DateString]]]; else if (startDate) [qualifiers addObject: - [NSString stringWithFormat: @"(since > '%@')", - [startDate rfc822DateString]]]; + [NSString stringWithFormat: @"%@(since > '%@')", + negate, [startDate rfc822DateString]]]; if (endDate) [qualifiers addObject: - [NSString stringWithFormat: @"(before < '%@')", - [endDate rfc822DateString]]]; + [NSString stringWithFormat: @"%@(before < '%@')", + negate, [endDate rfc822DateString]]]; } // Sent date else if ([[current tagName] isEqualToString: @"date"]) @@ -81,16 +90,16 @@ endDate = [[current attribute: @"to"] asCalendarDate]; if (startDate && [startDate isEqual: endDate]) [qualifiers addObject: - [NSString stringWithFormat: @"(senton = '%@')", - [startDate rfc822DateString]]]; + [NSString stringWithFormat: @"%@(senton = '%@')", + negate, [startDate rfc822DateString]]]; else if (startDate) [qualifiers addObject: - [NSString stringWithFormat: @"(sentsince > '%@')", - [startDate rfc822DateString]]]; + [NSString stringWithFormat: @"%@(sentsince > '%@')", + negate, [startDate rfc822DateString]]]; if (endDate) [qualifiers addObject: - [NSString stringWithFormat: @"(sentbefore < '%@')", - [endDate rfc822DateString]]]; + [NSString stringWithFormat: @"%@(sentbefore < '%@')", + negate, [endDate rfc822DateString]]]; } // Sequence else if ([[current tagName] isEqualToString: @"sequence"]) @@ -103,7 +112,8 @@ buffer = [current attribute: @"uid"]; if (buffer) [qualifiers addObject: - [NSString stringWithFormat: @"(uid = '%@')", buffer]]; + [NSString stringWithFormat: @"%@(uid = '%@')", + negate, buffer]]; } // From else if ([[current tagName] isEqualToString: @"from"]) @@ -111,7 +121,8 @@ buffer = [current attribute: @"from"]; if (buffer) [qualifiers addObject: - [NSString stringWithFormat: @"(from = '%@')", buffer]]; + [NSString stringWithFormat: @"%@(from doesContain: '%@')", + negate, buffer]]; } // To else if ([[current tagName] isEqualToString: @"to"]) @@ -119,9 +130,83 @@ buffer = [current attribute: @"to"]; if (buffer) [qualifiers addObject: - [NSString stringWithFormat: @"(to = '%@')", buffer]]; + [NSString stringWithFormat: @"%@(to doesContain: '%@')", + negate, buffer]]; + } + // Size + else if ([[current tagName] isEqualToString: @"size"]) + { + intValue = [[current attribute: @"min"] intValue]; + [qualifiers addObject: + [NSString stringWithFormat: @"%@(larger > '%d')", + negate, intValue]]; + intValue = [[current attribute: @"max"] intValue]; + if (intValue) + [qualifiers addObject: + [NSString stringWithFormat: @"%@(smaller < '%d')", + negate, intValue]]; + } + // Answered + else if ([[current tagName] isEqualToString: @"answered"]) + { + intValue = [[current attribute: @"answered"] intValue]; + if (intValue) + [qualifiers addObject: [NSString stringWithFormat: + @"%@(answered)", negate]]; + intValue = [[current attribute: @"unanswered"] intValue]; + if (intValue) + [qualifiers addObject: [NSString stringWithFormat: + @"%@(unanswered)", negate]]; + } + // Draft + else if ([[current tagName] isEqualToString: @"draft"]) + { + intValue = [[current attribute: @"draft"] intValue]; + if (intValue) + [qualifiers addObject: [NSString stringWithFormat: + @"%@(draft)", negate]]; + } + // Flagged + else if ([[current tagName] isEqualToString: @"flagged"]) + { + intValue = [[current attribute: @"flagged"] intValue]; + if (intValue) + [qualifiers addObject: [NSString stringWithFormat: + @"%@(flagged)", negate]]; + } + // Recent + else if ([[current tagName] isEqualToString: @"recent"]) + { + intValue = [[current attribute: @"recent"] intValue]; + if (intValue) + [qualifiers addObject: [NSString stringWithFormat: + @"%@(recent)", negate]]; + } + // Seen + else if ([[current tagName] isEqualToString: @"seen"]) + { + intValue = [[current attribute: @"seen"] intValue]; + if (intValue) + [qualifiers addObject: [NSString stringWithFormat: + @"%@(seen)", negate]]; + } + // Deleted + else if ([[current tagName] isEqualToString: @"deleted"]) + { + intValue = [[current attribute: @"deleted"] intValue]; + if (intValue) + [qualifiers addObject: [NSString stringWithFormat: + @"%@(deleted)", negate]]; + } + // Keywords + else if ([[current tagName] isEqualToString: @"keywords"]) + { + buffer = [current attribute: @"keywords"]; + if (buffer) + [qualifiers addObject: + [NSString stringWithFormat: @"%@(keywords doesContain: '%@')", + negate, buffer]]; } - } } } From dab23398766332fdbd0f239394d4996817be3e0c Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 5 Oct 2009 21:33:33 +0000 Subject: [PATCH 4/6] Monotone-Parent: dd01e619d1a581329304197499bcc223888f4535 Monotone-Revision: 51ccfad18d1d034a9fc87cc4604425a17598f0fd Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-10-05T21:33:33 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 28 ++++- SoObjects/Mailer/SOGoMailFolder.m | 168 +++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6caa1acb3..05c3a6f68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,12 +1,34 @@ +2009-10-05 Wolfgang Sourdeau + + * SoObjects/Mailer/SOGoMailFolder.m (-davMailQuery): new method + implementing the "mail-query" REPORT for Inverse's maildav + protocol. + (-parseDAVRequestedProperties:): new method making use of the + "davIMAPFieldsTable" method below for parsing fields in the + mail-query request. + (-_mailSortingFromSortElement:): new method to parse the "sort" + element of mail-query requests. + (-_fetchMessageProperties:matchingQualifier:andSorting:): new + stub for a method that will fetch the IMAP messages based on the + criteria found above. + (-_appendProperties:fromMessages:toResponse:) new stub for a + method that will add the content of the resulting set of message + properties to the DAV response. + 2009-10-05 Cyril Robert + * SoObjects/Mailer/SOGoMailFolder.m (-davIMAPFieldsTable): new + method designed to match maildav properties on mail objects with + IMAP fields, for PROPFIND and REPORT methods. + * Tests/test-webdavlib.py: Added new tests for the URL parser / regexp. + * Tests/webdavlib.py: Fixed errors in the URL regexp. + * SoObjects/Mailer/EOQualifier+MailDAV.m: New category to generate IMAP qualifiers from DAV filters. (REPORT) - * SoObjects/Mailer/EOQualifier+MailDAV.m: Formatted dates using - ([NSCalendarDate rfc822DateString]). - * SoObjects/Mailer/EOQualifier+MailDAV.m: Added NOT and extra fields. + Formatted dates using ([NSCalendarDate rfc822DateString]). Added + NOT and extra fields. 2009-10-04 Ludovic Marcotte diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 0b57495f6..a2d9d7cb8 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -34,18 +34,26 @@ #import #import +#import +#import +#import + #import #import -#import -#import -#import +#import +#import +#import +#import +#import "EOQualifier+MailDAV.h" #import "SOGoMailObject.h" #import "SOGoMailAccount.h" #import "SOGoMailManager.h" #import "SOGoMailFolder.h" +#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav" + static NSString *defaultUserID = @"anyone"; #warning this could be detected from the capabilities @@ -1102,7 +1110,159 @@ static NSString *spoolFolder = nil; return [self nameInContainer]; } -// For DAV PUT +- (NSDictionary *) davIMAPFieldsTable +{ + static NSMutableDictionary *davIMAPFieldsTable = nil; + + if (!davIMAPFieldsTable) + { + davIMAPFieldsTable = [NSMutableDictionary new]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (DATE)]" + forKey: @"{urn:schemas:httpmail:}date"]; + [davIMAPFieldsTable setObject: @"" + forKey: @"{urn:schemas:httpmail:}hasattachment"]; + [davIMAPFieldsTable setObject: @"" + forKey: @"{urn:schemas:httpmail:}read"]; + [davIMAPFieldsTable setObject: @"BODY" + forKey: @"{urn:schemas:httpmail:}textdescription"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (CC)]" + forKey: @"{urn:schemas:mailheader:}cc"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (DATE)]" + forKey: @"{urn:schemas:mailheader:}date"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (FROM)]" + forKey: @"{urn:schemas:mailheader:}from"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (INREPLYTO)]" + forKey: @"{urn:schemas:mailheader:}in-reply-to"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (MESSAGEID)]" + forKey: @"{urn:schemas:mailheader:}message-id"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (RECEIVED)]" + forKey: @"{urn:schemas:mailheader:}received"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (REFERENCES)]" + forKey: @"{urn:schemas:mailheader:}references"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (SUBJECT)]" + forKey: @"{urn:schemas:mailheader:}displayname"]; + [davIMAPFieldsTable setObject: @"BODY[HEADER.FIELDS (TO)]" + forKey: @"{urn:schemas:mailheader:}to"]; + } + + return davIMAPFieldsTable; +} + +- (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; +} + +- (NSString *) _mailSortingFromSortElement: (DOMElement *) sortElement +{ + NSArray *imapFields; + NSString *davReverseAttr; + NSMutableString *imapSortCriteria; + + imapSortCriteria = [NSMutableString string]; + + imapFields = [[self parseDAVRequestedProperties: sortElement] allValues]; + davReverseAttr = [[sortElement attribute: @"order"] uppercaseString]; + if ([davReverseAttr isEqualToString: @"descending"]) + [imapSortCriteria appendString: @"REVERSE "]; + else if ([davReverseAttr length] + && ![davReverseAttr isEqualToString: @"ascending"]) + [self errorWithFormat: @"unrecognized sort order: '%@'", + davReverseAttr]; + [imapSortCriteria + appendString: [imapFields componentsJoinedByString: @" "]]; + + return imapSortCriteria; +} + +- (NSArray *) _fetchMessageProperties: (NSDictionary *) properties + matchingQualifier: (EOQualifier *) searchQualifier + andSorting: (NSString *) sorting +{ +#warning not implemented + return nil; +} + +- (void) _appendProperties: (NSArray *) keys + fromMessages: (NSArray *) messages + toResponse: (WOResponse *) response +{ +#warning not implemented +} + +- (id) davMailQuery: (id) queryContext +{ + WOResponse *r; + id document; + DOMElement *documentElement, *propElement, *filterElement, *sortElement; + NSDictionary *properties; + NSArray *messages; + EOQualifier *searchQualifier; + NSString *sorting; + + r = [context response]; + [r setContentEncoding: NSUTF8StringEncoding]; + [r setHeader: @"text/xml; charset=\"utf-8\"" forKey: @"content-type"]; + [r setHeader: @"no-cache" forKey: @"pragma"]; + [r setHeader: @"no-cache" forKey: @"cache-control"]; + + document = [[context request] contentAsDOMDocument]; + documentElement = (DOMElement *) [document documentElement]; + + propElement = [documentElement firstElementWithTag: @"prop" + inNamespace: XMLNS_WEBDAV]; + properties = [self parseDAVRequestedProperties: propElement]; + filterElement = [documentElement firstElementWithTag: @"mail-filters" + inNamespace: XMLNS_INVERSEDAV]; + searchQualifier = [EOQualifier + qualifierFromMailDAVMailFilters: filterElement]; + sortElement = [documentElement firstElementWithTag: @"sort" + inNamespace: XMLNS_INVERSEDAV]; + sorting = [self _mailSortingFromSortElement: sortElement]; + + messages = [self _fetchMessageProperties: properties + matchingQualifier: searchQualifier + andSorting: sorting]; + [r setStatus: 207]; + [r appendContentString: @"\n"]; + [self _appendProperties: [properties allKeys] + fromMessages: messages + toResponse: r]; + + return r; +} + - (NSException *) _appendMessageData: (NSData *) data usingId: (int *) imap4id; { From 0d27d67b2f9ddb65831297ac546f1256db5d1fa9 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 5 Oct 2009 21:33:45 +0000 Subject: [PATCH 5/6] Monotone-Parent: 51ccfad18d1d034a9fc87cc4604425a17598f0fd Monotone-Revision: a883e310f52e0f28b3e8072ce973038481072fe2 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-10-05T21:33:45 Monotone-Branch: ca.inverse.sogo --- SoObjects/SOGo/DAVReportMap.plist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SoObjects/SOGo/DAVReportMap.plist b/SoObjects/SOGo/DAVReportMap.plist index a3413d406..a541f60cb 100644 --- a/SoObjects/SOGo/DAVReportMap.plist +++ b/SoObjects/SOGo/DAVReportMap.plist @@ -22,4 +22,7 @@ = davCollectionQuery; "{urn:inverse:params:xml:ns:inverse-dav}acl-query" = davAclQuery; "{urn:inverse:params:xml:ns:inverse-dav}user-query" = davUserQuery; + + /* Inverse MailDAV */ + "{urn:inverse:params:xml:ns:inverse-dav}mail-query" = davMailQuery; } From 088cb7587d308afb38d8175c822f5a6f2b4d3c67 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 5 Oct 2009 21:34:16 +0000 Subject: [PATCH 6/6] Monotone-Parent: a883e310f52e0f28b3e8072ce973038481072fe2 Monotone-Revision: ce654c24f2f00574570b6f4719cccc588905dc0e Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-10-05T21:34:16 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 4 ++++ Tests/test-maildav.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 05c3a6f68..ffa451500 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-10-05 Wolfgang Sourdeau + * Tests/test-maildav.py (DAVMailCollectionTest._testFilter): fixed + to use the "test-dav-mail" folder name as collection during the + tests. + * SoObjects/Mailer/SOGoMailFolder.m (-davMailQuery): new method implementing the "mail-query" REPORT for Inverse's maildav protocol. diff --git a/Tests/test-maildav.py b/Tests/test-maildav.py index 14e1f8dd3..1994c16ff 100755 --- a/Tests/test-maildav.py +++ b/Tests/test-maildav.py @@ -310,8 +310,8 @@ class DAVMailCollectionTest(unittest.TestCase): expected_hrefs[href] = True received_count = 0 - query = webdavlib.MailDAVMailQuery(self.resource, ["displayname"], - filter[0]) + url = "%sfolder%s" % (self.resource, "test-dav-mail") + query = webdavlib.MailDAVMailQuery(url, ["displayname"], filter[0]) self.client.execute(query) self.assertEquals(query.response["status"], 207, "filter %s:\n\tunexpected status: %d"