From b8bcf65785e79c58b218d1c6106ae9e572ed6772 Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Wed, 8 Jun 2011 07:43:40 +0200 Subject: [PATCH 1/5] Restore the Lightning + anonymous calendars support --- radicale/ical.py | 4 +--- radicale/xmlutils.py | 9 +++++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/radicale/ical.py b/radicale/ical.py index 96ead4f..d0eca6b 100644 --- a/radicale/ical.py +++ b/radicale/ical.py @@ -194,7 +194,7 @@ class Calendar(object): path = "/".join(attributes[:min(len(attributes), 2)]) path = path.replace("/", os.sep) abs_path = os.path.join(FOLDER, path) - if os.path.isdir(abs_path) or len(attributes) == 1: + if os.path.isdir(abs_path): if depth == "0": result.append(cls(path, principal=True)) else: @@ -297,8 +297,6 @@ class Calendar(object): def write(self, headers=None, items=None): """Write calendar with given parameters.""" - if self.is_principal: - return headers = headers or self.headers or ( Header("PRODID:-//Radicale//NONSGML Radicale Server//EN"), Header("VERSION:2.0")) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index f02175b..66b69b4 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -264,9 +264,11 @@ def _propfind_response(path, item, props, user): if tag == _tag("D", "getcontenttype"): element.text = "text/calendar" elif tag == _tag("D", "resourcetype"): - if not item.is_principal: - tag = ET.Element(_tag("C", "calendar")) + if item.is_principal: + tag = ET.Element(_tag("D", "principal")) element.append(tag) + tag = ET.Element(_tag("C", "calendar")) + element.append(tag) tag = ET.Element(_tag("D", "collection")) element.append(tag) elif tag == _tag("D", "owner") and item.owner_url: @@ -284,6 +286,9 @@ def _propfind_response(path, item, props, user): # Not for calendars elif tag == _tag("D", "getcontenttype"): element.text = "text/calendar; component=%s" % item.tag.lower() + elif tag == _tag("D", "resourcetype"): + # resourcetype must be returned empty for non-collection elements + pass else: is404 = True From de0643e741a86a572c2833f89546c10be313591d Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Thu, 16 Jun 2011 07:49:47 +0200 Subject: [PATCH 2/5] Fix propfind paths --- radicale/__init__.py | 3 +-- radicale/xmlutils.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/radicale/__init__.py b/radicale/__init__.py index 3215af7..6bbdc5a 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -143,8 +143,7 @@ class Application(object): @staticmethod def sanitize_uri(uri): """Clean URI: unquote and remove /../ to prevent access to other data.""" - uri = posixpath.normpath(urllib.unquote(uri)) - return uri + return posixpath.normpath(urllib.unquote(uri)) def __call__(self, environ, start_response): """Manage a request.""" diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 66b69b4..25a3cd4 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -201,7 +201,7 @@ def _propfind_response(path, item, props, user): response = ET.Element(_tag("D", "response")) href = ET.Element(_tag("D", "href")) - href.text = item.url if is_calendar else path + item.name + href.text = item.url if is_calendar else "%s/%s" % (path, item.name) response.append(href) propstat404 = ET.Element(_tag("D", "propstat")) From af10a2f1c42c03ba51bcf4f5bba5aee92211ddfa Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Thu, 16 Jun 2011 07:54:15 +0200 Subject: [PATCH 3/5] Fix URLs in report requests --- radicale/xmlutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 25a3cd4..074bd62 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -430,7 +430,7 @@ def report(path, xml_request, calendar): multistatus.append(response) href = ET.Element(_tag("D", "href")) - href.text = path + item.name + href.text = "%s/%s" % (path, item.name) response.append(href) propstat = ET.Element(_tag("D", "propstat")) From 1d67706b562208d64a6f0cee2a03f488af17b24c Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Thu, 16 Jun 2011 10:39:36 +0200 Subject: [PATCH 4/5] Clean the calendar paths --- radicale/ical.py | 17 ++++++++++------- radicale/xmlutils.py | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/radicale/ical.py b/radicale/ical.py index 233b448..56a79bb 100644 --- a/radicale/ical.py +++ b/radicale/ical.py @@ -163,7 +163,12 @@ class Calendar(object): tag = "VCALENDAR" def __init__(self, path, principal=False): - """Initialize the calendar with ``cal`` and ``user`` parameters.""" + """Initialize the calendar. + + ``path`` must be the normalized relative path of the calendar, using + the slash as the folder delimiter, with no leading nor trailing slash. + + """ self.encoding = "utf-8" split_path = path.split("/") self.owner = split_path[0] if len(split_path) > 1 else None @@ -193,8 +198,7 @@ class Calendar(object): result = [] path = "/".join(attributes[:min(len(attributes), 2)]) - path = path.replace("/", os.sep) - abs_path = os.path.join(FOLDER, path) + abs_path = os.path.join(FOLDER, path.replace("/", os.sep)) if os.path.isdir(abs_path): if depth == "0": result.append(cls(path, principal=True)) @@ -203,9 +207,8 @@ class Calendar(object): result.append(cls(path, principal=True)) try: for filename in next(os.walk(abs_path))[2]: - file_path = os.path.join(path, filename) if cls.is_vcalendar(os.path.join(abs_path, filename)): - result.append(cls(file_path)) + result.append(cls(os.path.join(path, filename))) except StopIteration: # directory does not exist yet pass @@ -413,11 +416,11 @@ class Calendar(object): def owner_url(self): """Get the calendar URL according to its owner.""" if self.owner: - return ('/%s/' % self.owner).replace('//', '/') + return "/%s/" % self.owner else: return None @property def url(self): """Get the standard calendar URL.""" - return ('/%s/' % self.local_path).replace('//', '/') + return "/%s/" % self.local_path diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 074bd62..b5d28bc 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -201,7 +201,7 @@ def _propfind_response(path, item, props, user): response = ET.Element(_tag("D", "response")) href = ET.Element(_tag("D", "href")) - href.text = item.url if is_calendar else "%s/%s" % (path, item.name) + href.text = item.local_path if is_calendar else "%s/%s" % (path, item.name) response.append(href) propstat404 = ET.Element(_tag("D", "propstat")) From 21d435b560b17ea312aa6665338b037d96f93ccf Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Thu, 16 Jun 2011 10:40:30 +0200 Subject: [PATCH 5/5] Minor typo fixes --- radicale/__init__.py | 4 ++-- radicale/ical.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/radicale/__init__.py b/radicale/__init__.py index 6bbdc5a..42d0936 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -166,8 +166,8 @@ class Application(object): content = None # Find calendar(s) - items = ical.Calendar.from_path(environ["PATH_INFO"], - environ.get("HTTP_DEPTH", "0")) + items = ical.Calendar.from_path( + environ["PATH_INFO"], environ.get("HTTP_DEPTH", "0")) # Get function corresponding to method function = getattr(self, environ["REQUEST_METHOD"].lower()) diff --git a/radicale/ical.py b/radicale/ical.py index 56a79bb..393956d 100644 --- a/radicale/ical.py +++ b/radicale/ical.py @@ -210,7 +210,7 @@ class Calendar(object): if cls.is_vcalendar(os.path.join(abs_path, filename)): result.append(cls(os.path.join(path, filename))) except StopIteration: - # directory does not exist yet + # Directory does not exist yet pass else: calendar = cls(path)