From a7f12b5face8df8ac85e158316cc8a046bd65b50 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 10 Mar 2017 22:14:13 +0100 Subject: [PATCH 1/6] PROPFIND: only one privilege per privilege element Before: After: --- radicale/xmlutils.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 375117c..153e2c4 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -669,14 +669,16 @@ def _propfind_response(base_prefix, path, item, props, user, write=False, tag.text = _href(base_prefix, ("/%s/" % user) if user else "/") element.append(tag) elif tag == _tag("D", "current-user-privilege-set"): - privilege = ET.Element(_tag("D", "privilege")) + privileges = [("D", "read")] if write: - privilege.append(ET.Element(_tag("D", "all"))) - privilege.append(ET.Element(_tag("D", "write"))) - privilege.append(ET.Element(_tag("D", "write-properties"))) - privilege.append(ET.Element(_tag("D", "write-content"))) - privilege.append(ET.Element(_tag("D", "read"))) - element.append(privilege) + privileges.append(("D", "all")) + privileges.append(("D", "write")) + privileges.append(("D", "write-properties")) + privileges.append(("D", "write-content")) + for ns, privilege_name in privileges: + privilege = ET.Element(_tag("D", "privilege")) + privilege.append(ET.Element(_tag(ns, privilege_name))) + element.append(privilege) elif tag == _tag("D", "supported-report-set"): for report_name in ( "principal-property-search", "sync-collection", From 2f67da5750b6843c38b7c4cf61258bb337ad9975 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 10 Mar 2017 22:16:46 +0100 Subject: [PATCH 2/6] Remove unnecessary conditions --- radicale/xmlutils.py | 47 +++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 153e2c4..d7162f4 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -691,19 +691,15 @@ def _propfind_response(base_prefix, path, item, props, user, write=False, element.append(supported) elif is_collection: if tag == _tag("D", "getcontenttype"): - item_tag = item.get_meta("tag") - if item_tag: - element.text = MIMETYPES[item_tag] + if is_leaf: + element.text = MIMETYPES[item.get_meta("tag")] else: is404 = True elif tag == _tag("D", "resourcetype"): if item.is_principal: tag = ET.Element(_tag("D", "principal")) element.append(tag) - item_tag = item.get_meta("tag") - if is_leaf or item_tag: - # 2nd case happens when the collection is not stored yet, - # but the resource type is guessed + if is_leaf: if item.get_meta("tag") == "VADDRESSBOOK": tag = ET.Element(_tag("CR", "addressbook")) element.append(tag) @@ -829,27 +825,24 @@ def report(base_prefix, path, xml_request, collection): [prop.tag for prop in prop_element] if prop_element is not None else []) - if collection: - if root.tag in ( - _tag("C", "calendar-multiget"), - _tag("CR", "addressbook-multiget")): - # Read rfc4791-7.9 for info - hreferences = set() - for href_element in root.findall(_tag("D", "href")): - href_path = storage.sanitize_path( - unquote(urlparse(href_element.text).path)) - if (href_path + "/").startswith(base_prefix + "/"): - hreferences.add(href_path[len(base_prefix):]) - else: - collection.logger.info( - "Skipping invalid path: %s", href_path) - else: - hreferences = (path,) - filters = ( - root.findall(".//%s" % _tag("C", "filter")) + - root.findall(".//%s" % _tag("CR", "filter"))) + if root.tag in ( + _tag("C", "calendar-multiget"), + _tag("CR", "addressbook-multiget")): + # Read rfc4791-7.9 for info + hreferences = set() + for href_element in root.findall(_tag("D", "href")): + href_path = storage.sanitize_path( + unquote(urlparse(href_element.text).path)) + if (href_path + "/").startswith(base_prefix + "/"): + hreferences.add(href_path[len(base_prefix):]) + else: + collection.logger.info( + "Skipping invalid path: %s", href_path) else: - hreferences = filters = () + hreferences = (path,) + filters = ( + root.findall(".//%s" % _tag("C", "filter")) + + root.findall(".//%s" % _tag("CR", "filter"))) multistatus = ET.Element(_tag("D", "multistatus")) From 53a7e158335ef1eb90800bd22981d65b2f3d0828 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 10 Mar 2017 22:19:10 +0100 Subject: [PATCH 3/6] Return empty result for unsupported report methods --- radicale/xmlutils.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index d7162f4..2a44041 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -820,6 +820,16 @@ def report(base_prefix, path, xml_request, collection): """ root = ET.fromstring(xml_request.encode("utf8")) + if root.tag in ( + _tag("D", "principal-search-property-set"), + _tag("D", "principal-property-search"), + _tag("D", "expand-property")): + # We don't support searching for principals or indirect retrieving of + # properties, just return an empty result. + # InfCloud asks for expand-property reports (even if we don't announce + # support for them) and stops working if an error code is returned. + collection.logger.warning("Unsupported report method: %s", root.tag) + return _pretty_xml(ET.Element(_tag("D", "multistatus"))) prop_element = root.find(_tag("D", "prop")) props = ( [prop.tag for prop in prop_element] From c027b68b4ff9be748b3bf16f29824160ae564679 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 10 Mar 2017 22:20:49 +0100 Subject: [PATCH 4/6] PROPFIND: return all supported report methods addressbook-multiget, addressbook-query, calendar-multiget and calendar-query were missing. sync-collection only works for leaf collections. --- radicale/xmlutils.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 2a44041..119153f 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -680,12 +680,21 @@ def _propfind_response(base_prefix, path, item, props, user, write=False, privilege.append(ET.Element(_tag(ns, privilege_name))) element.append(privilege) elif tag == _tag("D", "supported-report-set"): - for report_name in ( - "principal-property-search", "sync-collection", - "expand-property", "principal-search-property-set"): + reports = [("D", "expand-property"), # not implemented + ("D", "principal-search-property-set"), # not implemented + ("D", "principal-property-search")] # not implemented + if is_collection and is_leaf: + reports.append(("D", "sync-collection")) + if item.get_meta("tag") == "VADDRESSBOOK": + reports.append(("CR", "addressbook-multiget")) + reports.append(("CR", "addressbook-query")) + elif item.get_meta("tag") == "VCALENDAR": + reports.append(("C", "calendar-multiget")) + reports.append(("C", "calendar-query")) + for ns, report_name in reports: supported = ET.Element(_tag("D", "supported-report")) report_tag = ET.Element(_tag("D", "report")) - supported_report_tag = ET.Element(_tag("D", report_name)) + supported_report_tag = ET.Element(_tag(ns, report_name)) report_tag.append(supported_report_tag) supported.append(report_tag) element.append(supported) From a05cca563a67b2c26f1aad107729796da01e6851 Mon Sep 17 00:00:00 2001 From: Unrud Date: Sat, 18 Mar 2017 04:58:55 +0100 Subject: [PATCH 5/6] Stop iterating when a component is found --- radicale/xmlutils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 119153f..f94b5e0 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -180,6 +180,7 @@ def _prop_match(item, filter_): for component in item.components(): if component.name in ("VTODO", "VEVENT", "VJOURNAL"): vobject_item = component + break else: vobject_item = item.item if filter_length == 0: From 4f6d2e8b58238d357a216fc83ac3383b239d1602 Mon Sep 17 00:00:00 2001 From: Unrud Date: Sat, 18 Mar 2017 04:59:27 +0100 Subject: [PATCH 6/6] Only search for filter that are direct children --- radicale/xmlutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index f94b5e0..c7c55c9 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -861,8 +861,8 @@ def report(base_prefix, path, xml_request, collection): else: hreferences = (path,) filters = ( - root.findall(".//%s" % _tag("C", "filter")) + - root.findall(".//%s" % _tag("CR", "filter"))) + root.findall("./%s" % _tag("C", "filter")) + + root.findall("./%s" % _tag("CR", "filter"))) multistatus = ET.Element(_tag("D", "multistatus"))