From 8f911909496d37ff5c0c65102beeb2b4b4c2e71e Mon Sep 17 00:00:00 2001 From: Unrud Date: Mon, 1 Aug 2016 20:42:03 +0200 Subject: [PATCH 1/5] Remove duplicate code --- radicale/xmlutils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index b57f08d..5991508 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -590,14 +590,11 @@ def _propfind_response(path, item, props, user, write=False): is404 = False if tag == _tag("D", "getetag"): element.text = item.etag - elif tag == _tag("D", "principal-URL"): - tag = ET.Element(_tag("D", "href")) - tag.text = _href(collection, path) - element.append(tag) elif tag == _tag("D", "getlastmodified"): element.text = item.last_modified elif tag in (_tag("D", "principal-collection-set"), _tag("C", "calendar-user-address-set"), + _tag("D", "principal-URL"), _tag("CR", "addressbook-home-set"), _tag("C", "calendar-home-set")): tag = ET.Element(_tag("D", "href")) From 7aa481aaa1a0da238fc4d7f7753226d75695efe5 Mon Sep 17 00:00:00 2001 From: Unrud Date: Mon, 1 Aug 2016 20:44:04 +0200 Subject: [PATCH 2/5] Return / for principal-collection-set From RFC3744: This protected property of a resource contains a set of URLs that identify the root collections that contain the principals that are available on the server that implements this resource. --- radicale/xmlutils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 5991508..14dfc46 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -592,8 +592,11 @@ def _propfind_response(path, item, props, user, write=False): element.text = item.etag elif tag == _tag("D", "getlastmodified"): element.text = item.last_modified - elif tag in (_tag("D", "principal-collection-set"), - _tag("C", "calendar-user-address-set"), + elif tag == _tag("D", "principal-collection-set"): + tag = ET.Element(_tag("D", "href")) + tag.text = _href(collection, "/") + element.append(tag) + elif tag in (_tag("C", "calendar-user-address-set"), _tag("D", "principal-URL"), _tag("CR", "addressbook-home-set"), _tag("C", "calendar-home-set")): From 03cbcee5cd9ecd4966c0f5ddd36facd358f5d6a9 Mon Sep 17 00:00:00 2001 From: Unrud Date: Mon, 1 Aug 2016 20:46:57 +0200 Subject: [PATCH 3/5] / is not a principal --- radicale/storage.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/radicale/storage.py b/radicale/storage.py index 446d7bb..a878306 100644 --- a/radicale/storage.py +++ b/radicale/storage.py @@ -355,25 +355,27 @@ class Collection(BaseCollection): # path should already be sanitized sane_path = sanitize_path(path).strip("/") attributes = sane_path.split("/") - if not attributes: - return + if not attributes[0]: + attributes.pop() # Try to guess if the path leads to a collection or an item folder = os.path.expanduser( cls.configuration.get("storage", "filesystem_folder")) if not os.path.isdir(path_to_filesystem(folder, sane_path)): # path is not a collection - if os.path.isfile(path_to_filesystem(folder, sane_path)): + if attributes and os.path.isfile(path_to_filesystem(folder, + sane_path)): # path is an item attributes.pop() - elif os.path.isdir(path_to_filesystem(folder, *attributes[:-1])): + elif attributes and os.path.isdir(path_to_filesystem( + folder, *attributes[:-1])): # path parent is a collection attributes.pop() # TODO: else: return? path = "/".join(attributes) - principal = len(attributes) <= 1 + principal = len(attributes) == 1 collection = cls(path, principal) yield collection if depth != "0": From d5008672c5129c6c8b07018449af55daf7c99944 Mon Sep 17 00:00:00 2001 From: Unrud Date: Mon, 1 Aug 2016 20:48:57 +0200 Subject: [PATCH 4/5] Principal associated properties only on principal collections This misguides DAVdroid into creating new calendars and addressbooks in / --- radicale/xmlutils.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 14dfc46..b1dc2bf 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -596,10 +596,11 @@ def _propfind_response(path, item, props, user, write=False): tag = ET.Element(_tag("D", "href")) tag.text = _href(collection, "/") element.append(tag) - elif tag in (_tag("C", "calendar-user-address-set"), - _tag("D", "principal-URL"), - _tag("CR", "addressbook-home-set"), - _tag("C", "calendar-home-set")): + elif (tag in (_tag("C", "calendar-user-address-set"), + _tag("D", "principal-URL"), + _tag("CR", "addressbook-home-set"), + _tag("C", "calendar-home-set")) and + collection.is_principal): tag = ET.Element(_tag("D", "href")) tag.text = _href(collection, path) element.append(tag) From 81b04890f1157922005aa1d4139bfab9a7d3a5df Mon Sep 17 00:00:00 2001 From: Unrud Date: Mon, 1 Aug 2016 20:51:27 +0200 Subject: [PATCH 5/5] Create principal collection automatically --- radicale/__init__.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/radicale/__init__.py b/radicale/__init__.py index 9331821..bc28e62 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -302,6 +302,23 @@ class Application: is_authenticated = self.is_authenticated(user, password) is_valid_user = is_authenticated or not user + # Create principal collection + if user and is_authenticated: + principal_path = "/%s/" % user + if self.authorized(user, self.Collection(principal_path, True), + "w"): + with self.Collection.acquire_lock("r"): + principal = next(self.Collection.discover(principal_path), + None) + if not principal or principal.path != principal_path.strip("/"): + with self.Collection.acquire_lock("w"): + # the collection might exist by now + principal = next(self.Collection.discover( + principal_path), None) + if (not principal or + principal.path != principal_path.strip("/")): + self.Collection.create_collection(principal_path) + # Get content content_length = int(environ.get("CONTENT_LENGTH") or 0) if content_length: