mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-06-09 12:29:44 +00:00
Monotone-Parent: 7364cc475f410932b1e40c6ff6e9d7d8210c29b3
Monotone-Revision: 0e81c91aff9e32e69e1dda8e416902bf2f902245 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-10-02T14:00:58 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
@@ -1,3 +1,16 @@
|
||||
2009-10-02 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* Tests/webdavlib.py (MailDAVMailQuery): new class that implements
|
||||
the "mail-query" DAV REPORT.
|
||||
(WebDAVQuery._initProperties): new helper methods invoked by
|
||||
PROPFIND and REPORT classes at initialization to format the "prop"
|
||||
part of their query.
|
||||
(HTTPUnparsedURL._parse): accept more valid URL characters.
|
||||
|
||||
* Tests/test-maildav.py
|
||||
(DAVMailCollectionTest.testREPORTMailQuery): new method with
|
||||
initial tests for "mail-query" report.
|
||||
|
||||
2009-10-01 Cyril Robert <crobert@inverse.ca>
|
||||
|
||||
* SoObjects/Mailer/SOGoMailObject.m: Added methods required for PROPFIND /
|
||||
|
||||
+372
-46
@@ -25,35 +25,149 @@ def fetchUserEmail(login):
|
||||
message1 = """Return-Path: <cyril@cyril.dev>
|
||||
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
|
||||
Tue, 17 Dec 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>
|
||||
Message-ID: <4AC1F29sept6.5060801@cyril.dev>
|
||||
Date: Tue, 29 Sep 2009 07:42:14 -0400
|
||||
From: Cyril <cyril@cyril.dev>
|
||||
Organization: Inverse inc.
|
||||
From: Cyril <message1from@cyril.dev>
|
||||
User-Agent: Thunderbird 2.0.0.22 (Macintosh/20090605)
|
||||
MIME-Version: 1.0
|
||||
To: jacques@cyril.dev
|
||||
CC: support@inverse.ca, user10@cyril.dev
|
||||
Subject: Hallo
|
||||
Content-Type: text/plain; charset=UTF-8; format=flowed
|
||||
To: message1to@cyril.dev
|
||||
CC: message1cc@cyril.dev, user10@cyril.dev
|
||||
Subject: message1subject
|
||||
Content-Type: text/plain; charset=us-ascii; format=flowed
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Reply-To: support@inverse.ca,Cyril <cyril@cyril.dev>
|
||||
Reply-To: support@inverse.ca
|
||||
|
||||
Hello Jacques,
|
||||
|
||||
Can you read me?
|
||||
|
||||
--
|
||||
Cyril <cyril@cyril.dev>
|
||||
"""
|
||||
|
||||
message2 = """Return-Path: <cyril@cyril.dev>
|
||||
Received: from cyril.dev (localhost [127.0.0.1])
|
||||
by cyril.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA;
|
||||
Tue, 09 Dec 2009 07:42:16 -0400
|
||||
Message-ID: <410sepAC1F296.5060801a@cyril.dev>
|
||||
Date: Tue, 10 Sep 2009 07:42:14 -0400
|
||||
User-Agent: Thunderbird 2.0.0.22 (Macintosh/20090605)
|
||||
MIME-Version: 1.0
|
||||
From: Cyril <message2from@cyril.dev>
|
||||
To: message2to@cyril.dev
|
||||
CC: message2cc@cyril.dev
|
||||
Subject: message2subject
|
||||
Content-Type: text/plain; charset=us-ascii; format=flowed
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Reply-To: support@inverse.ca
|
||||
|
||||
Hello Jacques,
|
||||
|
||||
Can you read me?
|
||||
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff
|
||||
--
|
||||
Cyril <cyril@cyril.dev>
|
||||
"""
|
||||
|
||||
message3 = """Return-Path: <cyril@cyril.dev>
|
||||
Received: from cyril.dev (localhost [127.0.0.1])
|
||||
by cyril.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA;
|
||||
Tue, 15 Dec 2009 07:42:16 -0400
|
||||
Message-ID: <4AC1aF2dec96.5060801a@cyril.dev>
|
||||
Date: Tue, 10 Dec 2009 07:42:14 -0400
|
||||
User-Agent: Thunderbird 2.0.0.22 (Macintosh/20090605)
|
||||
MIME-Version: 1.0
|
||||
From: Cyril <message3from@cyril.dev>
|
||||
To: message3to@cyril.dev
|
||||
CC: message3cc@cyril.dev
|
||||
Subject: Hallo
|
||||
Content-Type: text/plain; charset=us-ascii; format=flowed
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Reply-To: support@inverse.ca
|
||||
|
||||
Hello Jacques,
|
||||
|
||||
Can you read me?
|
||||
|
||||
This message is just a big larger than message1 but smaller than message2
|
||||
--
|
||||
Cyril <cyril@cyril.dev>
|
||||
"""
|
||||
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"""
|
||||
Tue, 17 Dec 2009 07:42:16 -0400"""
|
||||
|
||||
class DAVMailCollectionTest(unittest.TestCase):
|
||||
resource = '/SOGo/dav/%s/Mail/' % username
|
||||
@@ -64,16 +178,16 @@ class DAVMailCollectionTest(unittest.TestCase):
|
||||
username, password)
|
||||
if self.user_email is None:
|
||||
self.user_email = fetchUserEmail(username)
|
||||
if self.user_email.startswith ("mailto:"):
|
||||
if self.user_email.startswith("mailto:"):
|
||||
self.user_email = self.user_email[7:]
|
||||
|
||||
self.resource = '/SOGo/dav/%s/Mail/%s_A_%s/' \
|
||||
% (username,
|
||||
username.replace("@", "_A_").replace (".", "_D_"),
|
||||
mailserver.replace (".", "_D_"))
|
||||
username.replace("@", "_A_").replace(".", "_D_"),
|
||||
mailserver.replace(".", "_D_"))
|
||||
|
||||
## helper methods
|
||||
def _makeCollection (self, name, status = 201):
|
||||
def _makeCollection(self, name, status = 201):
|
||||
url = "%s%s" % (self.resource, name)
|
||||
mkcol = webdavlib.WebDAVMKCOL(url)
|
||||
self.client.execute(mkcol)
|
||||
@@ -81,7 +195,7 @@ class DAVMailCollectionTest(unittest.TestCase):
|
||||
"failure creating collection"
|
||||
"(code = %d)" % mkcol.response["status"])
|
||||
|
||||
def _deleteCollection (self, name, status = 204):
|
||||
def _deleteCollection(self, name, status = 204):
|
||||
url = "%sfolder%s" % (self.resource, name)
|
||||
delete = webdavlib.WebDAVDELETE(url)
|
||||
self.client.execute(delete)
|
||||
@@ -89,16 +203,18 @@ class DAVMailCollectionTest(unittest.TestCase):
|
||||
"failure deleting collection"
|
||||
"(code = %d)" % delete.response["status"])
|
||||
|
||||
def _putMessage(self, client, filename,
|
||||
def _putMessage(self, client, folder, message,
|
||||
exp_status = 201):
|
||||
url = "%s%s" % (self.resource, filename)
|
||||
url = "%sfolder%s" % (self.resource, folder)
|
||||
put = webdavlib.HTTPPUT(url, message)
|
||||
put.content_type = "message/rfc822"
|
||||
client.execute(put)
|
||||
self.assertEquals(put.response["status"], exp_status,
|
||||
"%s: event creation/modification:"
|
||||
" expected status code '%d' (received '%d')"
|
||||
% (filename, exp_status, put.response["status"]))
|
||||
if (exp_status is not None):
|
||||
self.assertEquals(put.response["status"], exp_status,
|
||||
"message creation/modification:"
|
||||
" expected status code '%d' (received '%d')"
|
||||
% (exp_status, put.response["status"]))
|
||||
return put.response["headers"]["location"]
|
||||
|
||||
def _testProperty (self, url, property, expected, isDate = 0):
|
||||
propfind = webdavlib.WebDAVPROPFIND(url, (property, ), 0)
|
||||
@@ -123,13 +239,13 @@ class DAVMailCollectionTest(unittest.TestCase):
|
||||
|
||||
def testMKCOL(self):
|
||||
"""Folder creation"""
|
||||
self._makeCollection ("test-dav-mail-%40-abc")
|
||||
self._deleteCollection ("test-dav-mail-%40-abc")
|
||||
self._makeCollection ("test-dav-mail-@-def")
|
||||
self._deleteCollection ("test-dav-mail-@-def")
|
||||
self._makeCollection ("test-dav-mail-%20-ghi")
|
||||
self._deleteCollection ("test-dav-mail-%20-ghi")
|
||||
self._makeCollection ("test-dav-mail-%25-jkl", 500)
|
||||
self._makeCollection("test-dav-mail-%40-abc")
|
||||
self._deleteCollection("test-dav-mail-%40-abc")
|
||||
self._makeCollection("test-dav-mail-@-def")
|
||||
self._deleteCollection("test-dav-mail-@-def")
|
||||
self._makeCollection("test-dav-mail-%20-ghi")
|
||||
self._deleteCollection("test-dav-mail-%20-ghi")
|
||||
self._makeCollection("test-dav-mail-%25-jkl", 500)
|
||||
|
||||
# Test MOVE
|
||||
# self._makeCollection ("test-dav-mail-movable")
|
||||
@@ -144,42 +260,252 @@ class DAVMailCollectionTest(unittest.TestCase):
|
||||
|
||||
def testPUT(self):
|
||||
"""Message creation"""
|
||||
self._deleteCollection ("test-dav-mail")
|
||||
self._makeCollection ("test-dav-mail")
|
||||
self._deleteCollection("test-dav-mail")
|
||||
self._makeCollection("test-dav-mail")
|
||||
|
||||
# message creation on collection url
|
||||
url = "%s%s" % (self.resource, "foldertest-dav-mail/")
|
||||
put = webdavlib.HTTPPUT (url, message1)
|
||||
put = webdavlib.HTTPPUT(url, message1)
|
||||
put.content_type = "message/rfc822"
|
||||
self.client.execute (put)
|
||||
self.client.execute(put)
|
||||
self.assertEquals(put.response["status"], 201,
|
||||
"failure putting message"
|
||||
"(code = %d)" % put.response["status"])
|
||||
|
||||
itemLocation = put.response["headers"]["location"]
|
||||
get = webdavlib.WebDAVGET (itemLocation)
|
||||
self.client.execute (get)
|
||||
get = webdavlib.WebDAVGET(itemLocation)
|
||||
self.client.execute(get)
|
||||
self.assertEquals(get.response["status"], 200,
|
||||
"failure getting item"
|
||||
"(code = %d)" % get.response["status"])
|
||||
|
||||
# message creation with explicit filename
|
||||
url = "%s%s" % (self.resource, "foldertest-dav-mail/blabla.eml")
|
||||
put = webdavlib.HTTPPUT (url, message1)
|
||||
url = "%s%s" %(self.resource, "foldertest-dav-mail/blabla.eml")
|
||||
put = webdavlib.HTTPPUT(url, message1)
|
||||
put.content_type = "message/rfc822"
|
||||
self.client.execute (put)
|
||||
self.client.execute(put)
|
||||
self.assertEquals(put.response["status"], 201,
|
||||
"failure putting message"
|
||||
"(code = %d)" % put.response["status"])
|
||||
|
||||
itemLocation = put.response["headers"]["location"]
|
||||
get = webdavlib.WebDAVGET (itemLocation)
|
||||
self.client.execute (get)
|
||||
get = webdavlib.WebDAVGET(itemLocation)
|
||||
self.client.execute(get)
|
||||
self.assertEquals(get.response["status"], 200,
|
||||
"failure getting item"
|
||||
"(code = %d)" % get.response["status"])
|
||||
|
||||
self._deleteCollection ("test-dav-mail")
|
||||
self._deleteCollection("test-dav-mail")
|
||||
|
||||
def _testFilters(self, filters):
|
||||
for filter in filters:
|
||||
self._testFilter(filter)
|
||||
|
||||
def _testFilter(self, filter):
|
||||
expected_hrefs = {}
|
||||
expected_count = len(filter[1])
|
||||
for href in filter[1]:
|
||||
expected_hrefs[href] = True
|
||||
|
||||
received_count = 0
|
||||
query = webdavlib.MailDAVMailQuery(self.resource, ["displayname"],
|
||||
filter[0])
|
||||
self.client.execute(query)
|
||||
self.assertEquals(query.response["status"], 207,
|
||||
"filter %s:\n\tunexpected status: %d"
|
||||
% (filter[0], query.response["status"]))
|
||||
query.xpath_namespace = { "D": "DAV:",
|
||||
"I": "urn:inverse:params:xml:ns:inverse-dav" }
|
||||
response_nodes = query.xpath_evaluate("/D:multistatus/D:response")
|
||||
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.assertTrue(expected_hrefs.has_key(href),
|
||||
"filter %s:\n\tunexpected href: %s" % (filter[0], href))
|
||||
|
||||
self.assertEquals(len(filter[1]), received_count,
|
||||
"filter %s:\n\tunexpected amount of refs: %d"
|
||||
% (filter[0], received_count))
|
||||
|
||||
def testREPORTMailQuery(self):
|
||||
"""mail-query"""
|
||||
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
|
||||
|
||||
properties = ["{DAV:}displayname"]
|
||||
|
||||
## 1. test filter: receive-date
|
||||
# SINCE, BEFORE, ON
|
||||
# q = MailDAVMailQuery(self.resource, properties, filters = None)
|
||||
|
||||
filters = (({ "receive-date": { "from": "20091201T000000Z",
|
||||
"to": "20091208T000000Z" } },
|
||||
[]),
|
||||
({ "receive-date": { "from": "20091208T000000Z",
|
||||
"to": "20091213T134300Z" } },
|
||||
[ msg2Loc ]),
|
||||
({ "receive-date": { "from": "20091208T000000Z",
|
||||
"to": "20091216T134300Z" } },
|
||||
[ msg2Loc, msg3Loc ]),
|
||||
({ "receive-date": { "from": "20091216T000000Z",
|
||||
"to": "20091220T134300Z" } },
|
||||
[ msg1Loc ]),
|
||||
({ "receive-date": { "from": "20091220T000000Z",
|
||||
"to": "20091229T134300Z" } },
|
||||
[]))
|
||||
self._testFilters(filters)
|
||||
|
||||
## 1. test filter: date
|
||||
# SENTSINCE, SENTBEFORE, SENTON
|
||||
|
||||
filters = (({ "date": { "from": "20090101T000000Z",
|
||||
"to": "20090201T000000Z" } },
|
||||
[]),
|
||||
({ "date": { "from": "20090912T000000Z",
|
||||
"to": "20090929T134300Z" } },
|
||||
[ msg1Loc ]),
|
||||
({ "date": { "from": "20090929T134300Z",
|
||||
"to": "20091209T000000Z" } },
|
||||
[]),
|
||||
({ "date": { "from": "20090901T134300Z",
|
||||
"to": "20091209T000000Z" } },
|
||||
[ msg1Loc, msg2Loc ]),
|
||||
({ "date": { "from": "20091201T000000Z",
|
||||
"to": "20091211T000000Z" } },
|
||||
[ msg3Loc ]),
|
||||
({ "date": { "from": "20091211T000000Z",
|
||||
"to": "20101211T000000Z" } },
|
||||
[]),
|
||||
({ "date": { "from": "20090101T000000Z",
|
||||
"to": "20100101T000000Z" } },
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]))
|
||||
self._testFilters(filters)
|
||||
|
||||
## 1. test filter: sequence
|
||||
# x:y
|
||||
filters = (({ "sequence": { "from": "1" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "sequence": { "from": "5" }},
|
||||
[]),
|
||||
({ "sequence": { "to": "5" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "sequence": { "from": "1",
|
||||
"to": "2" }},
|
||||
[ msg1Loc, msg2Loc ]))
|
||||
self._testFilters(filters)
|
||||
|
||||
## 1. test filter: uid
|
||||
# UID
|
||||
filters = (({ "uid": { "from": "1" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "uid": { "from": "5" }},
|
||||
[]),
|
||||
({ "uid": { "to": "5" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "uid": { "from": "1",
|
||||
"to": "2" }},
|
||||
[ msg1Loc, msg2Loc ]))
|
||||
self._testFilters(filters)
|
||||
|
||||
## 1. test filter: from
|
||||
# FROM
|
||||
filters = (({ "from": { "match": "message" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "from": { "match": "Cyril" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "from": { "match": "cyril.dev" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "from": { "match": "message1from" }},
|
||||
[ msg1Loc ]),
|
||||
({ "from": { "match": "message2from" }},
|
||||
[ msg2Loc ]),
|
||||
({ "from": { "match": "message3from" }},
|
||||
[ msg3Loc ]))
|
||||
self._testFilters(filters)
|
||||
|
||||
## 1. test filter: to
|
||||
# TO
|
||||
filters = (({ "to": { "match": "message" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "to": { "match": "Cyril" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "to": { "match": "cyril.dev" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "to": { "match": "message1to" }},
|
||||
[ msg1Loc ]),
|
||||
({ "to": { "match": "message2to" }},
|
||||
[ msg2Loc ]),
|
||||
({ "to": { "match": "message3to" }},
|
||||
[ msg3Loc ]))
|
||||
self._testFilters(filters)
|
||||
|
||||
## 1. test filter: cc
|
||||
# CC
|
||||
filters = (({ "cc": { "match": "message" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "cc": { "match": "Cyril" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "cc": { "match": "cyril.dev" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "cc": { "match": "message1cc" }},
|
||||
[ msg1Loc ]),
|
||||
({ "cc": { "match": "message2cc" }},
|
||||
[ msg2Loc ]),
|
||||
({ "cc": { "match": "message3cc" }},
|
||||
[ msg3Loc ]))
|
||||
self._testFilters(filters)
|
||||
|
||||
## 1. test filter: bcc
|
||||
# BCC
|
||||
## TODO
|
||||
|
||||
## 1. test filter: body
|
||||
# BODY
|
||||
filters = (({ "body": { "match": "Hello" }},
|
||||
[ msg1Loc, msg2Loc, msg3Loc ]),
|
||||
({ "body": { "match": "Stuff" }},
|
||||
[ msg2Loc ]),
|
||||
({ "body": { "match": "DOESNOT MATCH" }},
|
||||
[]))
|
||||
self._testFilters(filters)
|
||||
|
||||
## 1. test filter: size
|
||||
# LARGER, SMALLER
|
||||
## 1. test filter: answered
|
||||
# ANSWERED, UNANSWERED
|
||||
## 1. test filter: draft
|
||||
# DRAFT
|
||||
## 1. test filter: flagged
|
||||
# FLAGGED
|
||||
## 1. test filter: recent
|
||||
# RECENT
|
||||
## 1. test filter: seen
|
||||
# SEEN
|
||||
## 1. test filter: deleted
|
||||
# DELETED
|
||||
## 1. test filter: keywords
|
||||
# KEYWORD x
|
||||
|
||||
# 1. test sort: (receive-date) ARRIVAL
|
||||
# 1. test sort: (date) DATE
|
||||
# 1. test sort: CC
|
||||
# 1. test sort: FROM
|
||||
# 1. test sort: SIZE
|
||||
# 1. test sort: SUBJECT
|
||||
# 1. test sort: TO
|
||||
|
||||
self._deleteCollection("test-dav-mail")
|
||||
|
||||
def testPROPFIND(self):
|
||||
"""Message properties"""
|
||||
@@ -201,11 +527,11 @@ class DAVMailCollectionTest(unittest.TestCase):
|
||||
("{urn:schemas:httpmail:}textdescription",
|
||||
"<![CDATA[%s]]>" % message1, 0),
|
||||
("{urn:schemas:httpmail:}unreadcount", None, 0),
|
||||
("{urn:schemas:mailheader:}cc","support@inverse.ca, user10@cyril.dev", 0),
|
||||
("{urn:schemas:mailheader:}date", 1254242534, 1),
|
||||
("{urn:schemas:mailheader:}from", "Cyril <cyril@cyril.dev>", 0),
|
||||
("{urn:schemas:mailheader:}cc","message1cc@cyril.dev, user10@cyril.dev", 0),
|
||||
("{urn:schemas:mailheader:}date", "Tue, 29 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","<4AC1F296.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),
|
||||
|
||||
+62
-27
@@ -22,7 +22,7 @@ class HTTPUnparsedURL:
|
||||
# ((proto)://((username(:(password)?)@)?hostname(:(port))))(path)?
|
||||
# if url_re is None:
|
||||
url_parts = url.split("?")
|
||||
alpha_match = "[a-zA-Z0-9]+"
|
||||
alpha_match = "[a-zA-Z0-9%\._-]+"
|
||||
num_match = "[0-9]+"
|
||||
pattern = ("((%s)://(((%s)(:(%s)?)@)?(%s)(:(%s))))?(/.*)"
|
||||
% (alpha_match, alpha_match, alpha_match,
|
||||
@@ -139,7 +139,15 @@ class WebDAVQuery(HTTPQuery):
|
||||
self.ns_mgr = _WD_XMLNS_MGR()
|
||||
self.top_node = None
|
||||
self.xml_response = None
|
||||
self.xpath_namespace = { "D": "DAV:" }
|
||||
self.xpath_namespace = { "D": xmlns_dav }
|
||||
|
||||
# helper for PROPFIND and REPORT (only)
|
||||
def _initProperties(self, properties):
|
||||
props = _WD_XMLTreeElement("prop")
|
||||
self.top_node.append(props)
|
||||
for prop in properties:
|
||||
prop_tag = self.render_tag(prop)
|
||||
props.append(_WD_XMLTreeElement(prop_tag))
|
||||
|
||||
def render(self):
|
||||
if self.top_node is not None:
|
||||
@@ -199,11 +207,8 @@ class WebDAVPROPFIND(WebDAVQuery):
|
||||
def __init__(self, url, properties, depth = None):
|
||||
WebDAVQuery.__init__(self, url, depth)
|
||||
self.top_node = _WD_XMLTreeElement("propfind")
|
||||
props = _WD_XMLTreeElement("prop")
|
||||
self.top_node.append(props)
|
||||
for prop in properties:
|
||||
prop_tag = self.render_tag(prop)
|
||||
props.append(_WD_XMLTreeElement(prop_tag))
|
||||
if properties is not None and len(properties) > 0:
|
||||
self._initProperties(properties)
|
||||
|
||||
class WebDAVMOVE(WebDAVQuery):
|
||||
method = "MOVE"
|
||||
@@ -262,13 +267,10 @@ class CalDAVPOST(WebDAVQuery):
|
||||
class CalDAVCalendarMultiget(WebDAVREPORT):
|
||||
def __init__(self, url, properties, hrefs):
|
||||
WebDAVQuery.__init__(self, url)
|
||||
multiget_tag = self.ns_mgr.register("calendar-multiget", "urn:ietf:params:xml:ns:caldav")
|
||||
multiget_tag = self.ns_mgr.register("calendar-multiget", xmlns_caldav)
|
||||
self.top_node = _WD_XMLTreeElement(multiget_tag)
|
||||
props = _WD_XMLTreeElement("prop")
|
||||
self.top_node.append(props)
|
||||
for prop in properties:
|
||||
prop_tag = self.render_tag(prop)
|
||||
props.append(_WD_XMLTreeElement(prop_tag))
|
||||
if properties is not None and len(properties) > 0:
|
||||
self._initProperties(properties)
|
||||
|
||||
for href in hrefs:
|
||||
href_node = _WD_XMLTreeElement("href")
|
||||
@@ -278,19 +280,16 @@ class CalDAVCalendarMultiget(WebDAVREPORT):
|
||||
class CalDAVCalendarQuery(WebDAVREPORT):
|
||||
def __init__(self, url, properties, component = None, timerange = None):
|
||||
WebDAVQuery.__init__(self, url)
|
||||
multiget_tag = self.ns_mgr.register("calendar-query", "urn:ietf:params:xml:ns:caldav")
|
||||
multiget_tag = self.ns_mgr.register("calendar-query", xmlns_caldav)
|
||||
self.top_node = _WD_XMLTreeElement(multiget_tag)
|
||||
props = _WD_XMLTreeElement("prop")
|
||||
self.top_node.append(props)
|
||||
for prop in properties:
|
||||
prop_tag = self.render_tag(prop)
|
||||
props.append(_WD_XMLTreeElement(prop_tag))
|
||||
if properties is not None and len(properties) > 0:
|
||||
self._initProperties(properties)
|
||||
|
||||
if component is not None:
|
||||
filter_tag = self.ns_mgr.register("filter",
|
||||
"urn:ietf:params:xml:ns:caldav")
|
||||
xmlns_caldav)
|
||||
compfilter_tag = self.ns_mgr.register("comp-filter",
|
||||
"urn:ietf:params:xml:ns:caldav")
|
||||
xmlns_caldav)
|
||||
filter_node = _WD_XMLTreeElement(filter_tag)
|
||||
cal_filter_node = _WD_XMLTreeElement(compfilter_tag,
|
||||
{ "name": "VCALENDAR" })
|
||||
@@ -312,11 +311,47 @@ class WebDAVSyncQuery(WebDAVREPORT):
|
||||
if token is not None:
|
||||
sync_token.append(_WD_XMLTreeTextNode(token))
|
||||
|
||||
props = _WD_XMLTreeElement("prop")
|
||||
self.top_node.append(props)
|
||||
for prop in properties:
|
||||
prop_tag = self.render_tag(prop)
|
||||
props.append(_WD_XMLTreeElement(prop_tag))
|
||||
if properties is not None and len(properties) > 0:
|
||||
self._initProperties(properties)
|
||||
|
||||
class MailDAVMailQuery(WebDAVREPORT):
|
||||
def __init__(self, url, properties, filters = None, sort = None):
|
||||
WebDAVQuery.__init__(self, url)
|
||||
mailquery_tag = self.ns_mgr.register("mail-query",
|
||||
xmlns_inversedav)
|
||||
self.top_node = _WD_XMLTreeElement(mailquery_tag)
|
||||
if properties is not None and len(properties) > 0:
|
||||
self._initProperties(properties)
|
||||
|
||||
if filters is not None and len(filters) > 0:
|
||||
self._initFilters(filters)
|
||||
|
||||
if sort is not None and len(sort) > 0:
|
||||
self._initSort(sort)
|
||||
|
||||
def _initFilters(self, filters):
|
||||
mailfilter_tag = self.ns_mgr.register("mail-filters",
|
||||
xmlns_inversedav)
|
||||
mailfilter_node = _WD_XMLTreeElement(mailfilter_tag)
|
||||
self.top_node.append(mailfilter_node)
|
||||
for filterk in filters.keys():
|
||||
filter_tag = self.ns_mgr.register(filterk,
|
||||
xmlns_inversedav)
|
||||
filter_node = _WD_XMLTreeElement(filter_tag,
|
||||
filters[filterk])
|
||||
mailfilter_node.append(filter_node)
|
||||
|
||||
def _initSort(self, sort):
|
||||
sort_tag = self.ns_mgr.register("sort", xmlns_inversedav)
|
||||
sort_node = _WD_XMLTreeElement(sort_tag)
|
||||
self.top_node.append(sort_node)
|
||||
sort_subtag = self.ns_mgr.register(sort[0], xmlns_inversedav)
|
||||
if len(sort) > 1:
|
||||
attributes = sort[1]
|
||||
else:
|
||||
attributes = {}
|
||||
sort_subnode = _WD_XMLTreeElement(sort_subtag, attributes)
|
||||
sort_node.append(sort_subnode)
|
||||
|
||||
# private classes to handle XML stuff
|
||||
class _WD_XMLNS_MGR:
|
||||
@@ -339,7 +374,7 @@ class _WD_XMLNS_MGR:
|
||||
return new_nssym
|
||||
|
||||
def register(self, tag, namespace):
|
||||
if namespace != "DAV:":
|
||||
if namespace != xmlns_dav:
|
||||
if self.xmlns.has_key(namespace):
|
||||
key = self.xmlns[namespace]
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user