apple / ccs-caldavclientlibrary Goto Github PK
View Code? Open in Web Editor NEWCalDAV/CardDAV Testing Tool Used by CalendarServer
Home Page: https://www.calendarserver.org
License: Apache License 2.0
CalDAV/CardDAV Testing Tool Used by CalendarServer
Home Page: https://www.calendarserver.org
License: Apache License 2.0
karra.etc@… originally submitted this as ticket:808
Check of None input and do something meaningful
From b53421747d150556a9bf6a6243bb015a1bfbde1d Mon Sep 17 00:00:00 2001
From: Sriram Karra <[email protected]>
Date: Wed, 10 Apr 2013 07:16:00 +0530
Subject: [PATCH] Better input testing in URL:compEqual
---
caldavclientlibrary/protocol/url.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/caldavclientlibrary/protocol/url.py b/caldavclientlibrary/protocol/url.py
index c8e65fe..817466b 100644
--- a/caldavclientlibrary/protocol/url.py
+++ b/caldavclientlibrary/protocol/url.py
@@ -173,6 +173,12 @@ def equalRelative(self, comp):
if comp.server:
return False
+ if not self.path and not comp.path:
+ return True
+
+ if not self.path or not comp.path:
+ return False
+
# Just compare paths, ignore trailing slash
return self.path.rstrip("/") == comp.path.rstrip("/")
--
1.8.1.6
eneas.rotterdam@… originally submitted this as ticket:402
karra.etc@… originally submitted this as ticket:810
This is the first part of the code to add carddav multiGet() support to the client library.
From 72ac60dc32c22b83af6ad57820af960e061cf692 Mon Sep 17 00:00:00 2001
From: Sriram Karra <[email protected]>
Date: Mon, 8 Apr 2013 11:18:24 +0530
Subject: [PATCH] Support for addressbook_multiget
Replicate the caldav/multiget.py functionality for carddav as well. Also
replicate the unit test caldav/tests/test_multiget.py
---
caldavclientlibrary/protocol/carddav/multiget.py | 76 ++++++++++++
.../protocol/carddav/tests/test_multiget.py | 134 +++++++++++++++++++++
2 files changed, 210 insertions(+)
create mode 100644 caldavclientlibrary/protocol/carddav/multiget.py
create mode 100644 caldavclientlibrary/protocol/carddav/tests/test_multiget.py
diff --git a/caldavclientlibrary/protocol/carddav/multiget.py b/caldavclientlibrary/protocol/carddav/multiget.py
new file mode 100644
index 0000000..ddd0170
--- /dev/null
+++ b/caldavclientlibrary/protocol/carddav/multiget.py
@@ -0,0 +1,76 @@
+##
+# Copyright (c) 2007-2013 Apple Inc. All rights reserved.
+# Copyright (c) 2013 Sriram Karra <[email protected]>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from StringIO import StringIO
+from caldavclientlibrary.protocol.carddav.definitions import carddavxml
+from caldavclientlibrary.protocol.http.data.string import RequestDataString
+from caldavclientlibrary.protocol.utils.xmlhelpers import BetterElementTree
+from caldavclientlibrary.protocol.webdav.definitions import davxml
+from caldavclientlibrary.protocol.webdav.report import Report
+from xml.etree.ElementTree import Element
+from xml.etree.ElementTree import SubElement
+
+class Multiget(Report):
+
+ def __init__(self, session, url, hrefs, props=()):
+ super(Multiget, self).__init__(session, url)
+ self.props = props
+ self.hrefs = hrefs
+
+ self.initRequestData()
+
+
+ def initRequestData(self):
+ # Write XML info to a string
+ os = StringIO()
+ self.generateXML(os)
+ self.request_data = RequestDataString(os.getvalue(),
+ "text/xml charset=utf-8")
+
+
+ def generateXML(self, os):
+ ## FIXME: Needs to be replace.
+ # Structure of document is:
+ #
+ # <CardDAV:addressbook-multiget>
+ # <DAV:prop>
+ # <<names of each property as elements>>
+ # </DAV:prop>
+ # <DAV:href>...</DAV:href>
+ # ...
+ # </CardDAV:addresbook-multiget>
+
+ # <CardDAV:addressbook-multiget> element
+ multiget = Element(carddavxml.addressbook_multiget)
+
+ if self.props:
+ # <DAV:prop> element
+ prop = SubElement(multiget, davxml.prop)
+
+ # Now add each property
+ for propname in self.props:
+ # Add property element taking namespace into account
+ SubElement(prop, propname)
+
+ # Now add each href
+ for href in self.hrefs:
+ # Add href elements
+ SubElement(multiget, davxml.href).text = href
+
+ # Now we have the complete document, so write it out (no indentation)
+ xmldoc = BetterElementTree(multiget)
+ xmldoc.writeUTF8(os)
diff --git a/caldavclientlibrary/protocol/carddav/tests/test_multiget.py b/caldavclientlibrary/protocol/carddav/tests/test_multiget.py
new file mode 100644
index 0000000..d575a8e
--- /dev/null
+++ b/caldavclientlibrary/protocol/carddav/tests/test_multiget.py
@@ -0,0 +1,134 @@
+##
+# Copyright (c) 2006-2013 Apple Inc. All rights reserved.
+# Copyright (c) 2013 Sriram Karra <[email protected]>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from caldavclientlibrary.protocol.webdav.session import Session
+from caldavclientlibrary.protocol.carddav.multiget import Multiget
+from StringIO import StringIO
+from caldavclientlibrary.protocol.webdav.definitions import davxml
+import unittest
+
+host = 'www.example.com'
+
+class TestRequest(unittest.TestCase):
+
+
+ def test_Method(self):
+
+ server = Session(host)
+ request = Multiget(server, "/", ())
+ self.assertEqual(request.getMethod(), "REPORT")
+
+
+
+class TestRequestHeaders(unittest.TestCase):
+ pass
+
+
+
+class TestRequestBody(unittest.TestCase):
+
+ def test_GenerateXMLOneHrefOnly(self):
+
+ server = Session(host)
+ request = Multiget(server, "/", ("/a",))
+ os = StringIO()
+ request.generateXML(os)
+ self.assertEqual(os.getvalue(), """<?xml version='1.0' encoding='utf-8'?>
+<ns0:addressbook-multiget xmlns:ns0="urn:ietf:params:xml:ns:carddav">
+ <ns1:href xmlns:ns1="DAV:">/a</ns1:href>
+</ns0:addressbook-multiget>
+""".replace("\n", "\r\n")
+)
+
+
+ def test_GenerateXMLMultipleHrefsOnly(self):
+
+ server = Session(host)
+ request = Multiget(server, "/", ("/a", "/b",))
+ os = StringIO()
+ request.generateXML(os)
+ self.assertEqual(os.getvalue(), """<?xml version='1.0' encoding='utf-8'?>
+<ns0:addressbook-multiget xmlns:ns0="urn:ietf:params:xml:ns:carddav">
+ <ns1:href xmlns:ns1="DAV:">/a</ns1:href>
+ <ns1:href xmlns:ns1="DAV:">/b</ns1:href>
+</ns0:addressbook-multiget>
+""".replace("\n", "\r\n")
+)
+
+
+ def test_GenerateXMLMultipleHrefsOneProperty(self):
+
+ server = Session(host)
+ request = Multiget(server, "/", ("/a", "/b",), (davxml.getetag,))
+ os = StringIO()
+ request.generateXML(os)
+ self.assertEqual(os.getvalue(), """<?xml version='1.0' encoding='utf-8'?>
+<ns0:addressbook-multiget xmlns:ns0="urn:ietf:params:xml:ns:carddav">
+ <ns1:prop xmlns:ns1="DAV:">
+ <ns1:getetag />
+ </ns1:prop>
+ <ns1:href xmlns:ns1="DAV:">/a</ns1:href>
+ <ns1:href xmlns:ns1="DAV:">/b</ns1:href>
+</ns0:addressbook-multiget>
+""".replace("\n", "\r\n")
+)
+
+
+ def test_GenerateXMLMultipleHrefsMultipleProperties(self):
+
+ server = Session(host)
+ request = Multiget(server, "/", ("/a", "/b",), (davxml.getetag, davxml.displayname,))
+ os = StringIO()
+ request.generateXML(os)
+ self.assertEqual(os.getvalue(), """<?xml version='1.0' encoding='utf-8'?>
+<ns0:addressbook-multiget xmlns:ns0="urn:ietf:params:xml:ns:carddav">
+ <ns1:prop xmlns:ns1="DAV:">
+ <ns1:getetag />
+ <ns1:displayname />
+ </ns1:prop>
+ <ns1:href xmlns:ns1="DAV:">/a</ns1:href>
+ <ns1:href xmlns:ns1="DAV:">/b</ns1:href>
+</ns0:addressbook-multiget>
+""".replace("\n", "\r\n")
+)
+
+
+
+class TestResponse(unittest.TestCase):
+ pass
+
+
+
+class TestResponseHeaders(unittest.TestCase):
+ pass
+
+
+
+class TestResponseBody(unittest.TestCase):
+ pass
+
+
+def main (argv=None):
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestRequest)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestRequestBody)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
+if __name__ == '__main__':
+ main()
--
1.8.1.6
mrcastle@… originally submitted this as ticket:828
Hello, I am trying to install the kerberos module on my Windows 7 machine with Python 2.6. I downloaded the install file from pypi and used "gunzip -c kerberos-1.1.1.tar.gz | tar xf - " to extract it. When I run setup.py I get the attached error. I should say that I also tried this on a different Windows 7 machine with minGW and got the same error. I've found examples of people using the kerberos module in Windows so I think it should work. What am I missing? Thanks,
Mike
karra.etc@… originally submitted this as ticket:807
As stated in the summary the patch below defines a new QName. Note that the patch is in the format of a git patch.
From e4ff6916fadcee62c074e0b009ada894576f03c1 Mon Sep 17 00:00:00 2001
From: Sriram Karra <[email protected]>
Date: Sat, 6 Apr 2013 17:37:15 +0530
Subject: [PATCH] New QName for default-addressbook-URL
---
caldavclientlibrary/protocol/carddav/definitions/carddavxml.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/caldavclientlibrary/protocol/carddav/definitions/carddavxml.py b/caldavclientlibrary/protocol/carddav/definitions/carddavxml.py
index 3fd1453..ce255da 100644
--- a/caldavclientlibrary/protocol/carddav/definitions/carddavxml.py
+++ b/caldavclientlibrary/protocol/carddav/definitions/carddavxml.py
@@ -43,3 +43,5 @@
text_match = QName(CardDAVNamespace, "text-match")
addressbook_multiget = QName(CardDAVNamespace, "addressbook-multiget")
+
+def_adbk_url = QName(CardDAVNamespace, "default-addressbook-URL")
--
1.8.1.6
info@… originally submitted this as ticket:458
karra.etc@… originally submitted this as ticket:806
caldavclient library has a multiGet() method for calldav, but not for carddav. The patch below implements this method. Note that this patch is in the git patch format:
From c98176a63e86f2fe6003f1580802404358a209a8 Mon Sep 17 00:00:00 2001
From: Sriram Karra <[email protected]>
Date: Fri, 12 Apr 2013 20:14:37 +0530
Subject: [PATCH] New multiGet() method to fetch multiple carddav documents in
one shot
---
caldavclientlibrary/client/clientsession.py | 31 +++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/caldavclientlibrary/client/clientsession.py b/caldavclientlibrary/client/clientsession.py
index e4c888d..e0b8599 100644
--- a/caldavclientlibrary/client/clientsession.py
+++ b/caldavclientlibrary/client/clientsession.py
@@ -18,6 +18,7 @@
from caldavclientlibrary.protocol.caldav.definitions import headers
from caldavclientlibrary.protocol.caldav.makecalendar import MakeCalendar
from caldavclientlibrary.protocol.carddav.makeaddressbook import MakeAddressBook
+from caldavclientlibrary.protocol.carddav.multiget import Multiget
from caldavclientlibrary.protocol.http.authentication.basic import Basic
from caldavclientlibrary.protocol.http.authentication.digest import Digest
from caldavclientlibrary.protocol.http.util import parseStatusLine
@@ -31,6 +32,7 @@
from caldavclientlibrary.protocol.url import URL
from caldavclientlibrary.protocol.webdav.acl import ACL
from caldavclientlibrary.protocol.webdav.definitions import davxml
+from caldavclientlibrary.protocol.carddav.definitions import carddavxml
from caldavclientlibrary.protocol.webdav.definitions import statuscodes
from caldavclientlibrary.protocol.webdav.delete import Delete
from caldavclientlibrary.protocol.webdav.get import Get
@@ -599,6 +601,35 @@ def queryCollection(self, rurl, timerange, start, end, expand, props=()):
return hrefs
+ ## This works only for carddav multiget at the moment; but there is no
+ ## reason why this cannot be made more generic
+ def multiGet(self, rurl, hrefs, props):
+ """Fetches the specified props for the specified hrefs using a single
+ multoget call. The return value is a dictionary where the keys are the
+ hrefs and the values are PropFindResult objects containign results for
+ the requested props."""
+
+ assert(isinstance(rurl, URL))
+
+ request = Multiget(self, rurl.relativeURL(), hrefs=hrefs, props=props)
+ result = ResponseDataString()
+ request.setOutput(result)
+
+ # Process it
+ self.runSession(request)
+
+ # If it's a 207 we want to parse the XML
+ if request.getStatusCode() == statuscodes.MultiStatus:
+
+ parser = PropFindParser()
+ parser.parseData(result.getData())
+ return parser.getResults()
+
+ else:
+ self.handleHTTPError(request)
+ return None
+
+
def deleteResource(self, rurl):
assert(isinstance(rurl, URL))
--
1.8.1.6
damien@… originally submitted this as ticket:907
Hi,
the implementation of httpshandler.py is very basic: either the default python SSL options are suitable for the connection or the connection fails. For example, there is no way to specify where certificates can be found or that a particular certificate is white-listed (e.g., when self-signed).
mail@… originally submitted this as ticket:323
Since Linux upgrade to Lenny, the command 'cat' of 'CalDAVClientLibrary/runshell.py' returns HTML instead of an ics text if the argument is a directory.
E.g. calling 'cat calendars/users/me/calendar/f0e947e9.ics' works fine, but 'cat calendars/users/me/calendar' returns the same HTML page, as if you use a web browser (<html><head><title>Collection listing for /calendars/users...).
moc@… originally submitted this as ticket:934
rziai@… originally submitted this as ticket:334
CalDAVClientLibrary is the way to go for setting ACLs and various other things but it does not support Kerberos authentication. On the other hand, using Kerberos is the recommended authentication method of CalendarServer. The attached patch adds Kerberos support to the library, using the PyKerberos binding.
naoh123@… originally submitted this as ticket:348
First off, excellent project. It's been exciting following along the past year. I have been running the server on an Ubuntu 8.04 server for sometime, and can connect and manipulate fine using iCal clients; however, I have been unable to get Sunbird clients to cooperate. A little backgound: my setup is stock with the exception of the documentroot directive in caldavd.plist, and my pool of users (accounts.xml). When I add an account (any account) in sunbird I use the prescribed path, http://example.com:8008/calendars/user/jdoe/calendar, after which I am met with the user/pass prompt, credentials are accepted, but no calendars populate. The logs report the following ad nauseum:
2009-09-17 21:47:23-0500 [-] [caldav-8009] [PooledMemCacheProtocol,client] [twistedcaldav.extensions#info] PROPFIND /calendars/users/jdoe/calendar/ HTTP/1.1
2009-09-17 21:47:23-0500 [-] [caldav-8009] [AMP,client] [twistedcaldav.extensions#info] OPTIONS /calendars/users/jdoe/ HTTP/1.1
2009-09-17 21:47:23-0500 [-] [caldav-8009] [AMP,client] [twistedcaldav.extensions#info] HEAD /calendars/users/jdoe/calendar/ HTTP/1.1
2009-09-17 21:47:23-0500 [-] [caldav-8009] [PooledMemCacheProtocol,client] [twistedcaldav.directory.principal#error] No principal found for UID: admin
Any ideas what is going on here? Thanks!
eneas.rotterdam@… originally submitted this as ticket:403
vivien@… originally submitted this as ticket:301
Hi,
Trying to use CalDAVClientLibrary on a Debian Lenny server, I noticed that the CalDAVClient shell did not allow to enter the 'b' letter.
This issue is quite annoying especially when your user id contains a 'b' :)
I found that this issue was reported on the CalendarServer-users mailing list in April 2008 [1]. Unfortunately this bug does not seem to have been fixed as I am running a fresh SVN checkout [2]
A patch [3] was proposed in reply to this email fixing this issue. Applying it solved this 'b' key issue problem.
Thanks, Vivien
karra.etc@… originally submitted this as ticket:809
The code seems to assume that the status returned is an integer when in fact it is a String. We just need to use the appropriate parsing routines to fetch the status code as integer. The attached patch (in git patch format) does that:
From b64512376539c80be67b364bd671e83b9f0af4e1 Mon Sep 17 00:00:00 2001
From: Sriram Karra <[email protected]>
Date: Sat, 6 Apr 2013 17:38:20 +0530
Subject: [PATCH] PropFindResult.status obtained from server is not an integer;
it is a status string that needs parsing.
---
caldavclientlibrary/client/clientsession.py | 7 +++++--
caldavclientlibrary/protocol/webdav/propfindparser.py | 2 +-
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/caldavclientlibrary/client/clientsession.py b/caldavclientlibrary/client/clientsession.py
index bc30e5b..e4c888d 100644
--- a/caldavclientlibrary/client/clientsession.py
+++ b/caldavclientlibrary/client/clientsession.py
@@ -20,6 +20,7 @@
from caldavclientlibrary.protocol.carddav.makeaddressbook import MakeAddressBook
from caldavclientlibrary.protocol.http.authentication.basic import Basic
from caldavclientlibrary.protocol.http.authentication.digest import Digest
+from caldavclientlibrary.protocol.http.util import parseStatusLine
from caldavclientlibrary.protocol.webdav.synccollection import SyncCollection
from caldavclientlibrary.protocol.caldav.query import QueryVEVENTTimeRange
try:
@@ -538,12 +539,14 @@ def syncCollection(self, rurl, synctoken, props=()):
# Look at each propfind result
for item in parser.getResults().itervalues():
+ # item is of type webdav.propfindparser.PropFindResult
# Get child element name (decode URL)
name = URL(url=item.getResource(), decode=True)
- if item.status == 404:
+ status = parseStatusLine(item.status)
+ if status == 404:
removed.add(name)
- elif item.status / 100 != 2:
+ elif status / 100 != 2:
other.add(name)
else:
changed.add(name)
diff --git a/caldavclientlibrary/protocol/webdav/propfindparser.py b/caldavclientlibrary/protocol/webdav/propfindparser.py
index d523997..ef5fe4a 100644
--- a/caldavclientlibrary/protocol/webdav/propfindparser.py
+++ b/caldavclientlibrary/protocol/webdav/propfindparser.py
@@ -29,7 +29,7 @@ class PropFindParser(MultiResponseParser):
class PropFindResult(object):
def __init__(self):
- self.status = 200
+ self.status = "HTTP/1.1 200 OK"
self.textProperties = {}
self.hrefProperties = {}
self.nodeProperties = {}
--
1.8.1.6
rootsphere@… originally submitted this as ticket:485
I found caldavclientlibrary/ui/WebDAVBrowser.nib is not installed by ./run -i. Attached log file ends with
warning: install_data: setup script did not provide a directory for 'caldavclientlibrary/ui/WebDAVBrowser.nib' -- installing right in '../package/System/Library/Frameworks/Python.framework/Versions/2.6' error: can't copy 'caldavclientlibrary/ui/WebDAVBrowser.nib': doesn't exist or not a regular file
I don't know what script warns this line. Please fix this problem. I had compiled calendarserver on my MacPRO: MacOSX 10.6.8 with Xcode.
rhodey@… originally submitted this as ticket:826
Darwin Calendar Server (release tag 5.2) becomes unusable when connection to the memcached server is lost. Darwin Calendar Server should simply query the datastore and directory services without relying on cache while attempting to reconnect with memcached.
antpaz@… originally submitted this as ticket:541
Curl can be used to create a calendar using curl -k -X MKCALENDAR -u usr1 https://localhost:8443/calendars/users/usr1/newcal/
However this is a VEVENT calendar.
To create a VTODO calendar I used curl -k -X MKCALENDAR --data "<C:supported-calendar-component-set xmlns:C='urn:ietf:params:xml:ns:caldav'><C:comp name='VTODO'/></C:supported-calendar-component-set>" -u usr1 https://localhost:8443/calendars/users/usr1/newcal2/
which fails with
<html><head><title>Unsupported Media Type</title></head><body><h1>Unsupported Media Type</h1><p>Non-mkcalendar element in MKCALENDAR request body: {urn:ietf:params:xml:ns:caldav}supported-calendar-component-sets</p></body></html>
I am newbie with DCS then I may be missing something on the above command.
karra.etc@… originally submitted this as ticket:805
To update an existing document on the server an If-Match header needs to be included in the request. There is no way to do this with the existing writeData() method.
The patch below does this:
@@ -692,14 +692,14 @@ def readData(self, rurl):
return dout.getData(), etag
- def writeData(self, rurl, data, contentType):
+ def writeData(self, rurl, data, contentType, etag=None):
assert(isinstance(rurl, URL))
# Create WebDAV PUT
request = Put(self, rurl.relativeURL())
dout = RequestDataString(data, contentType)
- request.setData(dout, None)
+ request.setData(dout, None, etag=etag)
# Process it
self.runSession(request)
mail@… originally submitted this as ticket:268
When using the command line shell to add a read/write proxy the list of proxies isn't updated correctly. Reproduce as follows...
(assuming logged in)
proxies -i
list
add -w
<add a proxy>
list
[ proxy will not be shown in list]
add -w
[ proxy will now be shown ]
q <don't add a proxy, just quit>
list
[ proxy will now be shown in list ]
This works OK when adding a read-only proxy.
sasha@… originally submitted this as ticket:853
As per https://docs.python.org/2/library/commands.html , the module has been deprecated in Python 3. They recommend using subprocess.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.