[evolution-data-server] I#223 - WebDAV: Inefficient processing of returned XML data
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] I#223 - WebDAV: Inefficient processing of returned XML data
- Date: Mon, 22 Jun 2020 20:15:38 +0000 (UTC)
commit ecb1470c68341b18bbd7146039e8345d308ffc0b
Author: Milan Crha <mcrha redhat com>
Date: Mon Jun 22 22:15:01 2020 +0200
I#223 - WebDAV: Inefficient processing of returned XML data
Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/223
CMakeLists.txt | 2 +-
.../backends/carddav/e-book-backend-carddav.c | 73 +-
.../backends/caldav/e-cal-backend-caldav.c | 228 +++---
.../webdav-notes/e-cal-backend-webdav-notes.c | 17 +-
src/libedataserver/e-webdav-discover.c | 291 ++++---
src/libedataserver/e-webdav-session.c | 897 +++++++++------------
src/libedataserver/e-webdav-session.h | 12 +-
src/libedataserver/e-xml-utils.c | 366 +++++++++
src/libedataserver/e-xml-utils.h | 28 +
9 files changed, 1083 insertions(+), 831 deletions(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a3ba458f2..73bda6d85 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,7 +56,7 @@ set(LIBEBACKEND_CURRENT 10)
set(LIBEBACKEND_REVISION 0)
set(LIBEBACKEND_AGE 0)
-set(LIBEDATASERVER_CURRENT 24)
+set(LIBEDATASERVER_CURRENT 25)
set(LIBEDATASERVER_REVISION 0)
set(LIBEDATASERVER_AGE 0)
diff --git a/src/addressbook/backends/carddav/e-book-backend-carddav.c
b/src/addressbook/backends/carddav/e-book-backend-carddav.c
index d3a33097f..d60507d4a 100644
--- a/src/addressbook/backends/carddav/e-book-backend-carddav.c
+++ b/src/addressbook/backends/carddav/e-book-backend-carddav.c
@@ -389,8 +389,7 @@ ebb_carddav_update_nfo_with_contact (EBookMetaBackendInfo *nfo,
static gboolean
ebb_carddav_multiget_response_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -400,27 +399,33 @@ ebb_carddav_multiget_response_cb (EWebDAVSession *webdav,
g_return_val_if_fail (from_link != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx, "C", E_WEBDAV_NS_CARDDAV, NULL);
- } else if (status_code == SOUP_STATUS_OK) {
- gchar *address_data, *etag;
+ if (status_code == SOUP_STATUS_OK) {
+ const xmlChar *address_data, *etag;
+ xmlNodePtr address_data_node = NULL, etag_node = NULL;
g_return_val_if_fail (href != NULL, FALSE);
- address_data = e_xml_xpath_eval_as_string (xpath_ctx, "%s/C:address-data", xpath_prop_prefix);
- etag = e_webdav_session_util_maybe_dequote (e_xml_xpath_eval_as_string (xpath_ctx,
"%s/D:getetag", xpath_prop_prefix));
+ e_xml_find_children_nodes (prop_node, 2,
+ E_WEBDAV_NS_CARDDAV, "address-data", &address_data_node,
+ E_WEBDAV_NS_DAV, "getetag", &etag_node);
+
+ address_data = e_xml_get_node_text (address_data_node);
+ etag = e_xml_get_node_text (etag_node);
if (address_data) {
EContact *contact;
- contact = e_contact_new_from_vcard (address_data);
+ contact = e_contact_new_from_vcard ((const gchar *) address_data);
if (contact) {
const gchar *uid;
uid = e_contact_get_const (contact, E_CONTACT_UID);
if (uid) {
+ gchar *dequoted_etag;
GSList *link;
+ dequoted_etag = e_webdav_session_util_maybe_dequote (g_strdup ((const
gchar *) etag));
+
for (link = *from_link; link; link = g_slist_next (link)) {
EBookMetaBackendInfo *nfo = link->data;
@@ -433,19 +438,18 @@ ebb_carddav_multiget_response_cb (EWebDAVSession *webdav,
if (link == *from_link)
*from_link = g_slist_next (*from_link);
- ebb_carddav_update_nfo_with_contact (nfo, contact,
etag);
+ ebb_carddav_update_nfo_with_contact (nfo, contact,
dequoted_etag);
break;
}
}
+
+ g_free (dequoted_etag);
}
g_object_unref (contact);
}
}
-
- g_free (address_data);
- g_free (etag);
} else if (status_code == SOUP_STATUS_NOT_FOUND) {
GSList *link;
@@ -548,8 +552,7 @@ ebb_carddav_multiget_from_sets_sync (EBookBackendCardDAV *bbdav,
static gboolean
ebb_carddav_get_contact_items_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -557,11 +560,10 @@ ebb_carddav_get_contact_items_cb (EWebDAVSession *webdav,
{
GHashTable *known_items = user_data; /* gchar *href ~> EBookMetaBackendInfo * */
- g_return_val_if_fail (xpath_ctx != NULL, FALSE);
+ g_return_val_if_fail (prop_node != NULL, FALSE);
g_return_val_if_fail (known_items != NULL, FALSE);
- if (xpath_prop_prefix &&
- status_code == SOUP_STATUS_OK) {
+ if (status_code == SOUP_STATUS_OK) {
EBookMetaBackendInfo *nfo;
gchar *etag;
@@ -573,7 +575,7 @@ ebb_carddav_get_contact_items_cb (EWebDAVSession *webdav,
return TRUE;
}
- etag = e_webdav_session_util_maybe_dequote (e_xml_xpath_eval_as_string (xpath_ctx,
"%s/D:getetag", xpath_prop_prefix));
+ etag = e_webdav_session_util_maybe_dequote (g_strdup ((const gchar *)
e_xml_find_child_and_get_text (prop_node, E_WEBDAV_NS_DAV, "getetag")));
/* Return 'TRUE' to not stop on faulty data from the server */
g_return_val_if_fail (etag != NULL, TRUE);
@@ -802,8 +804,7 @@ ebb_carddav_get_changes_sync (EBookMetaBackend *meta_backend,
static gboolean
ebb_carddav_extract_existing_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -813,38 +814,42 @@ ebb_carddav_extract_existing_cb (EWebDAVSession *webdav,
g_return_val_if_fail (out_existing_objects != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx, "C", E_WEBDAV_NS_CARDDAV, NULL);
- } else if (status_code == SOUP_STATUS_OK) {
- gchar *etag;
- gchar *address_data;
+ if (status_code == SOUP_STATUS_OK) {
+ const xmlChar *address_data, *etag;
+ xmlNodePtr address_data_node = NULL, etag_node = NULL;
g_return_val_if_fail (href != NULL, FALSE);
- etag = e_xml_xpath_eval_as_string (xpath_ctx, "%s/D:getetag", xpath_prop_prefix);
- address_data = e_xml_xpath_eval_as_string (xpath_ctx, "%s/C:address-data", xpath_prop_prefix);
+ e_xml_find_children_nodes (prop_node, 2,
+ E_WEBDAV_NS_CARDDAV, "address-data", &address_data_node,
+ E_WEBDAV_NS_DAV, "getetag", &etag_node);
+
+ address_data = e_xml_get_node_text (address_data_node);
+ etag = e_xml_get_node_text (etag_node);
if (address_data) {
EContact *contact;
- contact = e_contact_new_from_vcard (address_data);
+ contact = e_contact_new_from_vcard ((const gchar *) address_data);
if (contact) {
const gchar *uid;
uid = e_contact_get_const (contact, E_CONTACT_UID);
if (uid) {
- etag = e_webdav_session_util_maybe_dequote (etag);
+ gchar *dequoted_etag;
+
+ dequoted_etag = e_webdav_session_util_maybe_dequote (g_strdup ((const
gchar *) etag));
+
*out_existing_objects = g_slist_prepend (*out_existing_objects,
- e_book_meta_backend_info_new (uid, etag, NULL, href));
+ e_book_meta_backend_info_new (uid, dequoted_etag, NULL,
href));
+
+ g_free (dequoted_etag);
}
g_object_unref (contact);
}
}
-
- g_free (address_data);
- g_free (etag);
}
return TRUE;
diff --git a/src/calendar/backends/caldav/e-cal-backend-caldav.c
b/src/calendar/backends/caldav/e-cal-backend-caldav.c
index f316426d6..11af2d87d 100644
--- a/src/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/src/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -416,8 +416,7 @@ typedef struct _MultigetData {
static gboolean
ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -428,27 +427,33 @@ ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
g_return_val_if_fail (md != NULL, FALSE);
g_return_val_if_fail (md->from_link != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx, "C", E_WEBDAV_NS_CALDAV, NULL);
- } else if (status_code == SOUP_STATUS_OK) {
- gchar *calendar_data, *etag;
+ if (status_code == SOUP_STATUS_OK) {
+ const xmlChar *calendar_data, *etag;
+ xmlNodePtr calendar_data_node = NULL, etag_node = NULL;
g_return_val_if_fail (href != NULL, FALSE);
- calendar_data = e_xml_xpath_eval_as_string (xpath_ctx, "%s/C:calendar-data",
xpath_prop_prefix);
- etag = e_webdav_session_util_maybe_dequote (e_xml_xpath_eval_as_string (xpath_ctx,
"%s/D:getetag", xpath_prop_prefix));
+ e_xml_find_children_nodes (prop_node, 2,
+ E_WEBDAV_NS_CALDAV, "calendar-data", &calendar_data_node,
+ E_WEBDAV_NS_DAV, "getetag", &etag_node);
+
+ calendar_data = e_xml_get_node_text (calendar_data_node);
+ etag = e_xml_get_node_text (etag_node);
if (calendar_data) {
ICalComponent *vcalendar;
- vcalendar = i_cal_component_new_from_string (calendar_data);
+ vcalendar = i_cal_component_new_from_string ((const gchar *) calendar_data);
if (vcalendar) {
const gchar *uid;
uid = ecb_caldav_get_vcalendar_uid (vcalendar);
if (uid) {
+ gchar *dequoted_etag;
GSList *link;
+ dequoted_etag = e_webdav_session_util_maybe_dequote (g_strdup ((const
gchar *) etag));
+
for (link = md->from_link; link; link = g_slist_next (link)) {
ECalMetaBackendInfo *nfo = link->data;
@@ -461,19 +466,18 @@ ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
if (link == md->from_link)
md->from_link = g_slist_next (md->from_link);
- ecb_caldav_update_nfo_with_vcalendar (nfo, vcalendar,
etag);
+ ecb_caldav_update_nfo_with_vcalendar (nfo, vcalendar,
dequoted_etag);
break;
}
}
+
+ g_free (dequoted_etag);
}
g_object_unref (vcalendar);
}
}
-
- g_free (calendar_data);
- g_free (etag);
} else if (status_code == SOUP_STATUS_NOT_FOUND) {
GSList *link;
@@ -688,43 +692,40 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
static gboolean
ecb_caldav_get_calendar_items_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
gpointer user_data)
{
GHashTable *known_items = user_data; /* gchar *href ~> ECalMetaBackendInfo * */
+ ECalMetaBackendInfo *nfo;
+ gchar *etag;
- g_return_val_if_fail (xpath_ctx != NULL, FALSE);
+ g_return_val_if_fail (prop_node != NULL, FALSE);
g_return_val_if_fail (known_items != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx, "C", E_WEBDAV_NS_CALDAV, NULL);
- } else if (status_code == SOUP_STATUS_OK) {
- ECalMetaBackendInfo *nfo;
- gchar *etag;
+ if (status_code != SOUP_STATUS_OK)
+ return TRUE;
- g_return_val_if_fail (href != NULL, FALSE);
+ g_return_val_if_fail (href != NULL, FALSE);
- /* Skip collection resource, if returned by the server (like iCloud.com does) */
- if (g_str_has_suffix (href, "/") ||
- (request_uri && request_uri->path && g_str_has_suffix (href, request_uri->path)))
- return TRUE;
+ /* Skip collection resource, if returned by the server (like iCloud.com does) */
+ if (g_str_has_suffix (href, "/") ||
+ (request_uri && request_uri->path && g_str_has_suffix (href, request_uri->path)))
+ return TRUE;
- etag = e_webdav_session_util_maybe_dequote (e_xml_xpath_eval_as_string (xpath_ctx,
"%s/D:getetag", xpath_prop_prefix));
- /* Return 'TRUE' to not stop on faulty data from the server */
- g_return_val_if_fail (etag != NULL, TRUE);
+ etag = e_webdav_session_util_maybe_dequote (g_strdup ((const gchar *) e_xml_find_child_and_get_text
(prop_node, E_WEBDAV_NS_DAV, "getetag")));
+ /* Return 'TRUE' to not stop on faulty data from the server */
+ g_return_val_if_fail (etag != NULL, TRUE);
- /* UID is unknown at this moment */
- nfo = e_cal_meta_backend_info_new ("", etag, NULL, href);
+ /* UID is unknown at this moment */
+ nfo = e_cal_meta_backend_info_new ("", etag, NULL, href);
- g_free (etag);
- g_return_val_if_fail (nfo != NULL, FALSE);
+ g_free (etag);
+ g_return_val_if_fail (nfo != NULL, FALSE);
- g_hash_table_insert (known_items, g_strdup (href), nfo);
- }
+ g_hash_table_insert (known_items, g_strdup (href), nfo);
return TRUE;
}
@@ -1030,8 +1031,7 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
static gboolean
ecb_caldav_extract_existing_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -1041,38 +1041,42 @@ ecb_caldav_extract_existing_cb (EWebDAVSession *webdav,
g_return_val_if_fail (out_existing_objects != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx, "C", E_WEBDAV_NS_CALDAV, NULL);
- } else if (status_code == SOUP_STATUS_OK) {
- gchar *etag;
- gchar *calendar_data;
+ if (status_code == SOUP_STATUS_OK) {
+ const xmlChar *calendar_data, *etag;
+ xmlNodePtr calendar_data_node = NULL, etag_node = NULL;
g_return_val_if_fail (href != NULL, FALSE);
- etag = e_xml_xpath_eval_as_string (xpath_ctx, "%s/D:getetag", xpath_prop_prefix);
- calendar_data = e_xml_xpath_eval_as_string (xpath_ctx, "%s/C:calendar-data",
xpath_prop_prefix);
+ e_xml_find_children_nodes (prop_node, 2,
+ E_WEBDAV_NS_CALDAV, "calendar-data", &calendar_data_node,
+ E_WEBDAV_NS_DAV, "getetag", &etag_node);
+
+ calendar_data = e_xml_get_node_text (calendar_data_node);
+ etag = e_xml_get_node_text (etag_node);
if (calendar_data) {
ICalComponent *vcalendar;
- vcalendar = i_cal_component_new_from_string (calendar_data);
+ vcalendar = i_cal_component_new_from_string ((const gchar *) calendar_data);
if (vcalendar) {
const gchar *uid;
uid = ecb_caldav_get_vcalendar_uid (vcalendar);
if (uid) {
- etag = e_webdav_session_util_maybe_dequote (etag);
+ gchar *dequoted_etag;
+
+ dequoted_etag = e_webdav_session_util_maybe_dequote (g_strdup ((const
gchar *) etag));
+
*out_existing_objects = g_slist_prepend (*out_existing_objects,
- e_cal_meta_backend_info_new (uid, etag, NULL, href));
+ e_cal_meta_backend_info_new (uid, dequoted_etag, NULL, href));
+
+ g_free (dequoted_etag);
}
g_object_unref (vcalendar);
}
}
-
- g_free (calendar_data);
- g_free (etag);
}
return TRUE;
@@ -1643,10 +1647,41 @@ ecb_caldav_get_ssl_error_details (ECalMetaBackend *meta_backend,
return res;
}
+static gboolean
+ecb_caldav_dup_href_node_value (EWebDAVSession *webdav,
+ const SoupURI *request_uri,
+ xmlNodePtr from_node,
+ const gchar *parent_ns_href,
+ const gchar *parent_name,
+ gchar **out_href)
+{
+ xmlNodePtr node;
+
+ g_return_val_if_fail (out_href != NULL, FALSE);
+
+ if (!from_node)
+ return FALSE;
+
+ node = e_xml_find_in_hierarchy (from_node, parent_ns_href, parent_name, E_WEBDAV_NS_DAV, "href",
NULL, NULL);
+
+ if (node) {
+ const xmlChar *href;
+
+ href = e_xml_get_node_text (node);
+
+ if (href && *href) {
+ *out_href = e_webdav_session_ensure_full_uri (webdav, request_uri, (const gchar *)
href);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
static gboolean
ecb_caldav_propfind_get_owner_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -1654,17 +1689,11 @@ ecb_caldav_propfind_get_owner_cb (EWebDAVSession *webdav,
{
gchar **out_owner_href = user_data;
+ g_return_val_if_fail (prop_node != NULL, FALSE);
g_return_val_if_fail (out_owner_href != NULL, FALSE);
- if (xpath_prop_prefix &&
- status_code == SOUP_STATUS_OK) {
- gchar *tmp = e_xml_xpath_eval_as_string (xpath_ctx, "%s/D:owner/D:href", xpath_prop_prefix);
-
- if (tmp && *tmp)
- *out_owner_href = e_webdav_session_ensure_full_uri (webdav, request_uri, tmp);
-
- g_free (tmp);
-
+ if (status_code == SOUP_STATUS_OK &&
+ ecb_caldav_dup_href_node_value (webdav, request_uri, prop_node, E_WEBDAV_NS_DAV, "owner",
out_owner_href)) {
return FALSE;
}
@@ -1673,8 +1702,7 @@ ecb_caldav_propfind_get_owner_cb (EWebDAVSession *webdav,
static gboolean
ecb_caldav_propfind_get_schedule_outbox_url_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -1684,16 +1712,8 @@ ecb_caldav_propfind_get_schedule_outbox_url_cb (EWebDAVSession *webdav,
g_return_val_if_fail (out_schedule_outbox_url != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx, "C", E_WEBDAV_NS_CALDAV, NULL);
- } else if (status_code == SOUP_STATUS_OK) {
- gchar *tmp = e_xml_xpath_eval_as_string (xpath_ctx, "%s/C:schedule-outbox-URL/D:href",
xpath_prop_prefix);
-
- if (tmp && *tmp)
- *out_schedule_outbox_url = e_webdav_session_ensure_full_uri (webdav, request_uri,
tmp);
-
- g_free (tmp);
-
+ if (status_code == SOUP_STATUS_OK &&
+ ecb_caldav_dup_href_node_value (webdav, request_uri, prop_node, E_WEBDAV_NS_CALDAV,
"schedule-outbox-URL", out_schedule_outbox_url)) {
return FALSE;
}
@@ -1981,7 +2001,7 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
response) {
/* parse returned xml */
xmlDocPtr doc;
- xmlXPathContextPtr xpath_ctx = NULL;
+ xmlNodePtr schedule_response = NULL;
doc = e_xml_parse_data (response->data, response->len);
@@ -1989,56 +2009,44 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
g_set_error_literal (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
_("Failed to parse response data"));
} else {
- xpath_ctx = e_xml_new_xpath_context_with_namespaces (doc,
- "D", E_WEBDAV_NS_DAV,
- "C", E_WEBDAV_NS_CALDAV,
- NULL);
+ schedule_response = e_xml_find_sibling (xmlDocGetRootElement (doc),
E_WEBDAV_NS_CALDAV, "schedule-response");
}
- if (xpath_ctx) {
- xmlXPathObjectPtr xpath_obj_response;
+ if (schedule_response) {
+ xmlNodePtr response_node;
- xpath_obj_response = e_xml_xpath_eval (xpath_ctx, "/C:schedule-response/C:response");
+ for (response_node = e_xml_find_child (schedule_response, E_WEBDAV_NS_CALDAV,
"response");
+ response_node && !g_cancellable_is_cancelled (cancellable);
+ response_node = e_xml_find_next_sibling (response_node, E_WEBDAV_NS_CALDAV,
"response")) {
+ const xmlChar *calendar_data;
- if (xpath_obj_response) {
- gint response_index, response_length;
+ calendar_data = e_xml_find_child_and_get_text (response_node,
E_WEBDAV_NS_CALDAV, "calendar-data");
- response_length = xmlXPathNodeSetGetLength (xpath_obj_response->nodesetval);
+ if (calendar_data && *calendar_data) {
+ GSList *objects = NULL;
- for (response_index = 0; response_index < response_length; response_index++) {
- gchar *tmp;
+ icomp = i_cal_parser_parse_string ((const gchar *) calendar_data);
- tmp = e_xml_xpath_eval_as_string
(xpath_ctx,"/C:schedule-response/C:response[%d]/C:calendar-data", response_index + 1);
- if (tmp && *tmp) {
- GSList *objects = NULL;
+ if (icomp)
+ ecb_caldav_extract_objects (icomp, I_CAL_VFREEBUSY_COMPONENT,
&objects, &local_error);
- icomp = i_cal_parser_parse_string (tmp);
- if (icomp)
- ecb_caldav_extract_objects (icomp,
I_CAL_VFREEBUSY_COMPONENT, &objects, &local_error);
- if (icomp && !local_error) {
- for (link = objects; link; link = g_slist_next
(link)) {
- gchar *obj_str =
i_cal_component_as_ical_string (link->data);
+ if (icomp && !local_error) {
+ for (link = objects; link; link = g_slist_next (link)) {
+ gchar *obj_str = i_cal_component_as_ical_string
(link->data);
- if (obj_str && *obj_str)
- *out_freebusy = g_slist_prepend
(*out_freebusy, obj_str);
- else
- g_free (obj_str);
- }
+ if (obj_str && *obj_str)
+ *out_freebusy = g_slist_prepend
(*out_freebusy, obj_str);
+ else
+ g_free (obj_str);
}
-
- g_slist_free_full (objects, g_object_unref);
-
- g_clear_object (&icomp);
- g_clear_error (&local_error);
}
- g_free (tmp);
- }
+ g_slist_free_full (objects, g_object_unref);
- xmlXPathFreeObject (xpath_obj_response);
+ g_clear_object (&icomp);
+ g_clear_error (&local_error);
+ }
}
-
- xmlXPathFreeContext (xpath_ctx);
}
if (doc)
diff --git a/src/calendar/backends/webdav-notes/e-cal-backend-webdav-notes.c
b/src/calendar/backends/webdav-notes/e-cal-backend-webdav-notes.c
index dd9e05eaa..b397fadac 100644
--- a/src/calendar/backends/webdav-notes/e-cal-backend-webdav-notes.c
+++ b/src/calendar/backends/webdav-notes/e-cal-backend-webdav-notes.c
@@ -356,29 +356,22 @@ ecb_webdav_notes_check_credentials_error (ECalBackendWebDAVNotes *cbnotes,
static gboolean
ecb_webdav_notes_getetag_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
gpointer user_data)
{
- if (!xpath_prop_prefix)
- return TRUE;
-
if (status_code == SOUP_STATUS_OK) {
gchar **out_etag = user_data;
- gchar *etag;
+ const xmlChar *etag;
g_return_val_if_fail (out_etag != NULL, FALSE);
- etag = e_xml_xpath_eval_as_string (xpath_ctx, "%s/D:getetag", xpath_prop_prefix);
+ etag = e_xml_find_child_and_get_text (prop_node, E_WEBDAV_NS_DAV, "getetag");
- if (etag && *etag) {
- *out_etag = e_webdav_session_util_maybe_dequote (etag);
- } else {
- g_free (etag);
- }
+ if (etag && *etag)
+ *out_etag = e_webdav_session_util_maybe_dequote (g_strdup ((const gchar *) etag));
}
return FALSE;
diff --git a/src/libedataserver/e-webdav-discover.c b/src/libedataserver/e-webdav-discover.c
index 204923f3a..9f822e079 100644
--- a/src/libedataserver/e-webdav-discover.c
+++ b/src/libedataserver/e-webdav-discover.c
@@ -110,215 +110,196 @@ e_webdav_discover_propfind_uri_sync (EWebDAVSession *webdav,
static gboolean
e_webdav_discover_traverse_propfind_response_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
gpointer user_data)
{
WebDAVDiscoverData *wdd = user_data;
+ xmlNodePtr set_node, node;
+ const xmlChar *href_value;
+ gboolean is_calendar, is_addressbook;
g_return_val_if_fail (wdd != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx,
- "C", E_WEBDAV_NS_CALDAV,
- "A", E_WEBDAV_NS_CARDDAV,
- NULL);
- } else if (status_code == SOUP_STATUS_OK) {
- xmlXPathObjectPtr xpath_obj;
- gchar *principal_href, *full_href;
- gboolean is_calendar, is_addressbook;
-
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s/A:addressbook-home-set/D:href",
xpath_prop_prefix);
- if (xpath_obj) {
- gint ii, length;
-
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
-
- for (ii = 0; ii < length && !g_cancellable_is_cancelled (wdd->cancellable); ii++) {
- gchar *home_set_href;
-
- full_href = NULL;
-
- home_set_href = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/A:addressbook-home-set/D:href[%d]", xpath_prop_prefix, ii + 1);
- if (home_set_href && *home_set_href) {
- GSList *resources = NULL;
- GError *local_error = NULL;
-
- full_href = e_webdav_session_ensure_full_uri (webdav, request_uri,
home_set_href);
- if (full_href && *full_href && GPOINTER_TO_INT (g_hash_table_contains
(wdd->covered_hrefs, full_href)) != 2 &&
- e_webdav_session_list_sync (webdav, full_href,
E_WEBDAV_DEPTH_THIS_AND_CHILDREN,
- E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME |
E_WEBDAV_LIST_DESCRIPTION |
- E_WEBDAV_LIST_COLOR | E_WEBDAV_LIST_ONLY_ADDRESSBOOK |
E_WEBDAV_LIST_ALL,
- &resources, wdd->cancellable, &local_error)) {
- e_webdav_discover_split_resources (wdd, resources);
- g_slist_free_full (resources, e_webdav_resource_free);
- }
+ if (status_code != SOUP_STATUS_OK)
+ return TRUE;
- if (full_href && *full_href)
- g_hash_table_insert (wdd->covered_hrefs, g_strdup
(full_href), GINT_TO_POINTER (2));
+ set_node = e_xml_find_child (prop_node, E_WEBDAV_NS_CARDDAV, "addressbook-home-set");
- if (local_error && wdd->error && !*wdd->error)
- g_propagate_error (wdd->error, local_error);
- else
- g_clear_error (&local_error);
- }
+ for (node = e_xml_find_child (set_node, E_WEBDAV_NS_DAV, "href");
+ node && !g_cancellable_is_cancelled (wdd->cancellable);
+ node = e_xml_find_next_sibling (node, E_WEBDAV_NS_DAV, "href")) {
+ const xmlChar *home_set_href;
+
+ home_set_href = e_xml_get_node_text (node);
+
+ if (home_set_href && *home_set_href) {
+ GSList *resources = NULL;
+ GError *local_error = NULL;
+ gchar *full_href;
+
+ full_href = e_webdav_session_ensure_full_uri (webdav, request_uri, (const gchar *)
home_set_href);
- g_free (home_set_href);
- g_free (full_href);
+ if (full_href && *full_href && GPOINTER_TO_INT (g_hash_table_contains
(wdd->covered_hrefs, full_href)) != 2 &&
+ e_webdav_session_list_sync (webdav, full_href, E_WEBDAV_DEPTH_THIS_AND_CHILDREN,
+ E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME |
E_WEBDAV_LIST_DESCRIPTION |
+ E_WEBDAV_LIST_COLOR | E_WEBDAV_LIST_ONLY_ADDRESSBOOK | E_WEBDAV_LIST_ALL,
+ &resources, wdd->cancellable, &local_error)) {
+ e_webdav_discover_split_resources (wdd, resources);
+ g_slist_free_full (resources, e_webdav_resource_free);
}
- xmlXPathFreeObject (xpath_obj);
- }
+ if (full_href && *full_href)
+ g_hash_table_insert (wdd->covered_hrefs, g_strdup (full_href),
GINT_TO_POINTER (2));
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s/C:calendar-home-set/D:href", xpath_prop_prefix);
- if (xpath_obj) {
- gint ii, length;
+ if (local_error && wdd->error && !*wdd->error)
+ g_propagate_error (wdd->error, local_error);
+ else
+ g_clear_error (&local_error);
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
+ g_free (full_href);
+ }
+ }
- for (ii = 0; ii < length && !g_cancellable_is_cancelled (wdd->cancellable); ii++) {
- gchar *home_set_href, *full_href = NULL;
+ set_node = e_xml_find_child (prop_node, E_WEBDAV_NS_CALDAV, "calendar-home-set");
- home_set_href = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/C:calendar-home-set/D:href[%d]", xpath_prop_prefix, ii + 1);
- if (home_set_href && *home_set_href) {
- GSList *resources = NULL;
- GError *local_error = NULL;
+ for (node = e_xml_find_child (set_node, E_WEBDAV_NS_DAV, "href");
+ node && !g_cancellable_is_cancelled (wdd->cancellable);
+ node = e_xml_find_next_sibling (node, E_WEBDAV_NS_DAV, "href")) {
+ const xmlChar *home_set_href;
- full_href = e_webdav_session_ensure_full_uri (webdav, request_uri,
home_set_href);
- if (full_href && *full_href && GPOINTER_TO_INT (g_hash_table_contains
(wdd->covered_hrefs, full_href)) != 2 &&
- e_webdav_session_list_sync (webdav, full_href,
E_WEBDAV_DEPTH_THIS_AND_CHILDREN,
- E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME |
E_WEBDAV_LIST_DESCRIPTION |
- E_WEBDAV_LIST_COLOR | E_WEBDAV_LIST_ONLY_CALENDAR |
E_WEBDAV_LIST_ALL,
- &resources, wdd->cancellable, &local_error)) {
- e_webdav_discover_split_resources (wdd, resources);
- g_slist_free_full (resources, e_webdav_resource_free);
- }
+ home_set_href = e_xml_get_node_text (node);
- if (full_href && *full_href)
- g_hash_table_insert (wdd->covered_hrefs, g_strdup
(full_href), GINT_TO_POINTER (2));
+ if (home_set_href && *home_set_href) {
+ GSList *resources = NULL;
+ GError *local_error = NULL;
+ gchar *full_href;
- if (local_error && wdd->error && !*wdd->error)
- g_propagate_error (wdd->error, local_error);
- else
- g_clear_error (&local_error);
- }
+ full_href = e_webdav_session_ensure_full_uri (webdav, request_uri, (const gchar *)
home_set_href);
- g_free (home_set_href);
- g_free (full_href);
+ if (full_href && *full_href && GPOINTER_TO_INT (g_hash_table_contains
(wdd->covered_hrefs, full_href)) != 2 &&
+ e_webdav_session_list_sync (webdav, full_href, E_WEBDAV_DEPTH_THIS_AND_CHILDREN,
+ E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME |
E_WEBDAV_LIST_DESCRIPTION |
+ E_WEBDAV_LIST_COLOR | E_WEBDAV_LIST_ONLY_CALENDAR | E_WEBDAV_LIST_ALL,
+ &resources, wdd->cancellable, &local_error)) {
+ e_webdav_discover_split_resources (wdd, resources);
+ g_slist_free_full (resources, e_webdav_resource_free);
}
- xmlXPathFreeObject (xpath_obj);
+ if (full_href && *full_href)
+ g_hash_table_insert (wdd->covered_hrefs, g_strdup (full_href),
GINT_TO_POINTER (2));
+
+ if (local_error && wdd->error && !*wdd->error)
+ g_propagate_error (wdd->error, local_error);
+ else
+ g_clear_error (&local_error);
+
+ g_free (full_href);
}
+ }
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s/C:calendar-user-address-set/D:href",
xpath_prop_prefix);
- if (xpath_obj) {
- gint ii, length;
+ if (wdd->out_calendar_user_addresses) {
+ set_node = e_xml_find_child (prop_node, E_WEBDAV_NS_CALDAV, "calendar-user-address-set");
- if (wdd->out_calendar_user_addresses)
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
- else
- length = 0;
+ for (node = e_xml_find_child (set_node, E_WEBDAV_NS_DAV, "href");
+ node && !g_cancellable_is_cancelled (wdd->cancellable);
+ node = e_xml_find_next_sibling (node, E_WEBDAV_NS_DAV, "href")) {
+ const xmlChar *address_href;
- for (ii = 0; ii < length; ii++) {
- gchar *address_href;
+ address_href = e_xml_get_node_text (node);
- address_href = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/C:calendar-user-address-set/D:href[%d]", xpath_prop_prefix, ii + 1);
- if (address_href && g_ascii_strncasecmp (address_href, "mailto:", 7) == 0) {
- /* Skip the "mailto:" prefix */
- const gchar *address = address_href + 7;
+ if (address_href && g_ascii_strncasecmp ((const gchar *) address_href, "mailto:", 7)
== 0) {
+ /* Skip the "mailto:" prefix */
+ const gchar *address = (const gchar *) (address_href + 7);
- /* Avoid duplicates and empty values */
- if (*address &&
- !g_slist_find_custom (*wdd->out_calendar_user_addresses, address,
(GCompareFunc) g_ascii_strcasecmp)) {
- *wdd->out_calendar_user_addresses = g_slist_prepend (
- *wdd->out_calendar_user_addresses, g_strdup
(address));
- }
+ /* Avoid duplicates and empty values */
+ if (*address &&
+ !g_slist_find_custom (*wdd->out_calendar_user_addresses, address,
(GCompareFunc) g_ascii_strcasecmp)) {
+ *wdd->out_calendar_user_addresses = g_slist_prepend (
+ *wdd->out_calendar_user_addresses, g_strdup (address));
}
-
- g_free (address_href);
}
-
- xmlXPathFreeObject (xpath_obj);
}
+ }
- principal_href = e_xml_xpath_eval_as_string (xpath_ctx, "%s/D:current-user-principal/D:href",
xpath_prop_prefix);
- if (principal_href && *principal_href && !g_cancellable_is_cancelled (wdd->cancellable)) {
- full_href = e_webdav_session_ensure_full_uri (webdav, request_uri, principal_href);
+ node = e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_DAV, "current-user-principal",
E_WEBDAV_NS_DAV, "href", NULL, NULL);
+ href_value = e_xml_get_node_text (node);
- if (full_href && *full_href)
- e_webdav_discover_propfind_uri_sync (webdav, wdd, full_href, TRUE);
+ if (href_value && *href_value && !g_cancellable_is_cancelled (wdd->cancellable)) {
+ gchar *full_href;
- g_free (full_href);
- g_free (principal_href);
+ full_href = e_webdav_session_ensure_full_uri (webdav, request_uri, (const gchar *)
href_value);
- return TRUE;
- }
+ if (full_href && *full_href)
+ e_webdav_discover_propfind_uri_sync (webdav, wdd, full_href, TRUE);
- g_free (principal_href);
+ g_free (full_href);
- principal_href = e_xml_xpath_eval_as_string (xpath_ctx, "%s/D:principal-URL/D:href",
xpath_prop_prefix);
- if (principal_href && *principal_href && !g_cancellable_is_cancelled (wdd->cancellable)) {
- full_href = e_webdav_session_ensure_full_uri (webdav, request_uri, principal_href);
+ return TRUE;
+ }
- if (full_href && *full_href)
- e_webdav_discover_propfind_uri_sync (webdav, wdd, full_href, TRUE);
+ node = e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_DAV, "principal-URL", E_WEBDAV_NS_DAV, "href",
NULL, NULL);
+ href_value = e_xml_get_node_text (node);
- g_free (full_href);
- g_free (principal_href);
+ if (href_value && *href_value && !g_cancellable_is_cancelled (wdd->cancellable)) {
+ gchar *full_href;
- return TRUE;
- }
+ full_href = e_webdav_session_ensure_full_uri (webdav, request_uri, (const gchar *)
href_value);
- g_free (principal_href);
+ if (full_href && *full_href)
+ e_webdav_discover_propfind_uri_sync (webdav, wdd, full_href, TRUE);
- is_calendar = e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/C:calendar",
xpath_prop_prefix);
- is_addressbook = e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/A:addressbook",
xpath_prop_prefix);
+ g_free (full_href);
- if (is_calendar || is_addressbook) {
- GSList *resources = NULL;
- GError *local_error = NULL;
+ return TRUE;
+ }
- if (GPOINTER_TO_INT (g_hash_table_contains (wdd->covered_hrefs, href)) != 2 &&
- !g_cancellable_is_cancelled (wdd->cancellable) &&
- e_webdav_session_list_sync (webdav, href, E_WEBDAV_DEPTH_THIS,
- E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME |
E_WEBDAV_LIST_DESCRIPTION | E_WEBDAV_LIST_COLOR |
- (is_calendar ? E_WEBDAV_LIST_ONLY_CALENDAR : 0) | (is_addressbook ?
E_WEBDAV_LIST_ONLY_ADDRESSBOOK : 0) | E_WEBDAV_LIST_ALL,
- &resources, wdd->cancellable, &local_error)) {
- e_webdav_discover_split_resources (wdd, resources);
- g_slist_free_full (resources, e_webdav_resource_free);
- }
+ node = e_xml_find_child (prop_node, E_WEBDAV_NS_DAV, "resourcetype");
+ is_calendar = e_xml_find_child (node, E_WEBDAV_NS_CALDAV, "calendar") != NULL;
+ is_addressbook = e_xml_find_child (node, E_WEBDAV_NS_CARDDAV, "addressbook") != NULL;
- g_hash_table_insert (wdd->covered_hrefs, g_strdup (href), GINT_TO_POINTER (2));
+ if (is_calendar || is_addressbook) {
+ GSList *resources = NULL;
+ GError *local_error = NULL;
- if (local_error && wdd->error && !*wdd->error)
- g_propagate_error (wdd->error, local_error);
- else
- g_clear_error (&local_error);
+ if (GPOINTER_TO_INT (g_hash_table_contains (wdd->covered_hrefs, href)) != 2 &&
+ !g_cancellable_is_cancelled (wdd->cancellable) &&
+ e_webdav_session_list_sync (webdav, href, E_WEBDAV_DEPTH_THIS,
+ E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME | E_WEBDAV_LIST_DESCRIPTION |
E_WEBDAV_LIST_COLOR |
+ (is_calendar ? E_WEBDAV_LIST_ONLY_CALENDAR : 0) | (is_addressbook ?
E_WEBDAV_LIST_ONLY_ADDRESSBOOK : 0) | E_WEBDAV_LIST_ALL,
+ &resources, wdd->cancellable, &local_error)) {
+ e_webdav_discover_split_resources (wdd, resources);
+ g_slist_free_full (resources, e_webdav_resource_free);
}
- if (((wdd->only_supports & (~CUSTOM_SUPPORTS_FLAGS)) == E_WEBDAV_DISCOVER_SUPPORTS_NONE ||
- (wdd->only_supports & E_WEBDAV_DISCOVER_SUPPORTS_WEBDAV_NOTES) != 0) &&
- (g_str_has_suffix (href, "/Notes") ||
- g_str_has_suffix (href, "/Notes/")) &&
- !e_webdav_discovery_already_discovered (href, wdd->calendars) &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/D:collection", xpath_prop_prefix))
{
- GSList *resources = NULL;
+ g_hash_table_insert (wdd->covered_hrefs, g_strdup (href), GINT_TO_POINTER (2));
- resources = g_slist_prepend (NULL,
- e_webdav_resource_new (E_WEBDAV_RESOURCE_KIND_WEBDAV_NOTES,
- E_WEBDAV_RESOURCE_SUPPORTS_WEBDAV_NOTES, href, NULL,
- _("Notes"),
- NULL, 0, 0, 0, NULL, NULL));
+ if (local_error && wdd->error && !*wdd->error)
+ g_propagate_error (wdd->error, local_error);
+ else
+ g_clear_error (&local_error);
+ }
- e_webdav_discover_split_resources (wdd, resources);
+ if (((wdd->only_supports & (~CUSTOM_SUPPORTS_FLAGS)) == E_WEBDAV_DISCOVER_SUPPORTS_NONE ||
+ (wdd->only_supports & E_WEBDAV_DISCOVER_SUPPORTS_WEBDAV_NOTES) != 0) &&
+ (g_str_has_suffix (href, "/Notes") || g_str_has_suffix (href, "/Notes/")) &&
+ !e_webdav_discovery_already_discovered (href, wdd->calendars) &&
+ e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_DAV, "resourcetype", E_WEBDAV_NS_DAV,
"collection", NULL, NULL)) {
+ GSList *resources = NULL;
- g_slist_free_full (resources, e_webdav_resource_free);
+ resources = g_slist_prepend (NULL,
+ e_webdav_resource_new (E_WEBDAV_RESOURCE_KIND_WEBDAV_NOTES,
+ E_WEBDAV_RESOURCE_SUPPORTS_WEBDAV_NOTES, href, NULL,
+ _("Notes"),
+ NULL, 0, 0, 0, NULL, NULL));
- g_hash_table_insert (wdd->covered_hrefs, g_strdup (href), GINT_TO_POINTER (2));
- }
+ e_webdav_discover_split_resources (wdd, resources);
+
+ g_slist_free_full (resources, e_webdav_resource_free);
+
+ g_hash_table_insert (wdd->covered_hrefs, g_strdup (href), GINT_TO_POINTER (2));
}
return TRUE;
diff --git a/src/libedataserver/e-webdav-session.c b/src/libedataserver/e-webdav-session.c
index 50b747f7d..a8d07b9ed 100644
--- a/src/libedataserver/e-webdav-session.c
+++ b/src/libedataserver/e-webdav-session.c
@@ -752,8 +752,7 @@ e_webdav_session_new_request (EWebDAVSession *webdav,
static gboolean
e_webdav_session_extract_propstat_error_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -763,26 +762,31 @@ e_webdav_session_extract_propstat_error_cb (EWebDAVSession *webdav,
g_return_val_if_fail (error != NULL, FALSE);
- if (!xpath_prop_prefix)
- return TRUE;
-
if (status_code != SOUP_STATUS_OK && (
status_code != SOUP_STATUS_FAILED_DEPENDENCY ||
!*error)) {
- gchar *description;
+ xmlNodePtr parent;
+ const xmlChar *description = NULL;
- description = e_xml_xpath_eval_as_string (xpath_ctx, "%s/../D:responsedescription",
xpath_prop_prefix);
- if (!description || !*description) {
- g_free (description);
+ parent = prop_node->parent;
+ if (parent) {
+ description = e_xml_find_child_and_get_text (parent, E_WEBDAV_NS_DAV,
"responsedescription");
- description = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/../../D:responsedescription", xpath_prop_prefix);
+ if (!description || !*description) {
+ description = NULL;
+ parent = parent->parent;
+ if (parent) {
+ description = e_xml_find_child_and_get_text (parent, E_WEBDAV_NS_DAV,
"responsedescription");
+
+ if (!description || !*description)
+ description = NULL;
+ }
+ }
}
g_clear_error (error);
g_set_error_literal (error, SOUP_HTTP_ERROR, status_code,
- e_soup_session_util_status_to_string (status_code, description));
-
- g_free (description);
+ e_soup_session_util_status_to_string (status_code, (const gchar *) description));
}
return TRUE;
@@ -1413,13 +1417,7 @@ e_webdav_session_post_sync (EWebDAVSession *webdav,
*
* Issues PROPFIND request on the provided @uri, or, in case it's %NULL, on the URI
* defined in associated #ESource. On success, calls @func for each returned
- * DAV:propstat. The provided XPath context has registered %E_WEBDAV_NS_DAV namespace
- * with prefix "D". It doesn't have any other namespace registered.
- *
- * The @func is called always at least once, with %NULL xpath_prop_prefix, which
- * is meant to let the caller setup the xpath_ctx, like to register its own namespaces
- * to it with e_xml_xpath_context_register_namespaces(). All other invocations of @func
- * will have xpath_prop_prefix non-%NULL.
+ * DAV:propstat.
*
* The @xml can be %NULL, in which case the server should behave like DAV:allprop request.
*
@@ -1586,15 +1584,11 @@ e_webdav_session_proppatch_sync (EWebDAVSession *webdav,
*
* Issues REPORT request on the provided @uri, or, in case it's %NULL, on the URI
* defined in associated #ESource. On success, calls @func for each returned
- * DAV:propstat. The provided XPath context has registered %E_WEBDAV_NS_DAV namespace
- * with prefix "D". It doesn't have any other namespace registered.
+ * DAV:propstat.
*
* The report can result in a multistatus response, but also to raw data. In case
* the @func is provided and the result is a multistatus response, then it is traversed
- * using this @func. The @func is called always at least once, with %NULL xpath_prop_prefix,
- * which is meant to let the caller setup the xpath_ctx, like to register its own namespaces
- * to it with e_xml_xpath_context_register_namespaces(). All other invocations of @func
- * will have xpath_prop_prefix non-%NULL.
+ * using this @func.
*
* The optional @out_content_type can be used to get content type of the response.
* Free it with g_free(), when no longer needed.
@@ -3128,20 +3122,22 @@ e_webdav_session_traverse_propstat_response (EWebDAVSession *webdav,
const SoupMessage *message,
const GByteArray *xml_data,
gboolean require_multistatus,
- const gchar *additional_ns_prefix,
- const gchar *additional_ns,
- const gchar *propstat_path_prefix,
+ const gchar *top_path_ns_href1,
+ const gchar *top_path_name1,
+ const gchar *top_path_ns_href2,
+ const gchar *top_path_name2,
EWebDAVPropstatTraverseFunc func,
gpointer func_user_data,
GError **error)
{
SoupURI *request_uri = NULL;
xmlDocPtr doc;
- xmlXPathContextPtr xpath_ctx;
+ xmlNodePtr top_node, node;
+ gboolean do_stop = FALSE;
g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
g_return_val_if_fail (xml_data != NULL, FALSE);
- g_return_val_if_fail (propstat_path_prefix != NULL, FALSE);
+ g_return_val_if_fail (top_path_name1 != NULL, FALSE);
g_return_val_if_fail (func != NULL, FALSE);
if (message) {
@@ -3182,75 +3178,81 @@ e_webdav_session_traverse_propstat_response (EWebDAVSession *webdav,
return FALSE;
}
- xpath_ctx = e_xml_new_xpath_context_with_namespaces (doc,
- "D", E_WEBDAV_NS_DAV,
- additional_ns_prefix, additional_ns,
- NULL);
+ top_node = xmlDocGetRootElement (doc);
- if (xpath_ctx &&
- func (webdav, xpath_ctx, NULL, request_uri, NULL, SOUP_STATUS_NONE, func_user_data)) {
- xmlXPathObjectPtr xpath_obj_response;
+ if (!top_node) {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+ _("XML data does not have root node"));
- xpath_obj_response = e_xml_xpath_eval (xpath_ctx, "%s", propstat_path_prefix);
+ xmlFreeDoc (doc);
- if (xpath_obj_response) {
- gboolean do_stop = FALSE;
- gint response_index, response_length;
+ return FALSE;
+ }
- response_length = xmlXPathNodeSetGetLength (xpath_obj_response->nodesetval);
+ top_node = e_xml_find_sibling (top_node, top_path_ns_href1, top_path_name1);
- for (response_index = 0; response_index < response_length && !do_stop;
response_index++) {
- xmlXPathObjectPtr xpath_obj_propstat;
+ if (top_path_name2)
+ top_node = e_xml_find_child (top_node, top_path_ns_href2, top_path_name2);
- xpath_obj_propstat = e_xml_xpath_eval (xpath_ctx,
- "%s[%d]/D:propstat",
- propstat_path_prefix, response_index + 1);
+ if (!top_node) {
+ gchar *tmp;
- if (xpath_obj_propstat) {
- gchar *href;
- gint propstat_index, propstat_length;
+ tmp = g_strconcat (
+ top_path_ns_href1 ? top_path_ns_href1 : "",
+ top_path_ns_href1 ? ":" : "",
+ top_path_name1,
+ top_path_name2 ? "/" : "",
+ (top_path_name2 && top_path_ns_href2) ? top_path_ns_href2 : "",
+ (top_path_name2 && top_path_ns_href2) ? ":" : "",
+ top_path_name2 ? top_path_name2 : "",
+ NULL);
- href = e_xml_xpath_eval_as_string (xpath_ctx, "%s[%d]/D:href",
propstat_path_prefix, response_index + 1);
- if (href) {
- gchar *full_uri;
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+ _("XML data doesn't have required structure (%s)"), tmp);
- full_uri = e_webdav_session_ensure_full_uri (webdav,
request_uri, href);
- if (full_uri) {
- g_free (href);
- href = full_uri;
- }
- }
+ xmlFreeDoc (doc);
+ g_free (tmp);
- propstat_length = xmlXPathNodeSetGetLength
(xpath_obj_propstat->nodesetval);
+ return FALSE;
+ }
- for (propstat_index = 0; propstat_index < propstat_length &&
!do_stop; propstat_index++) {
- gchar *status, *propstat_prefix;
- guint status_code;
+ for (node = top_node; node && !do_stop; node = xmlNextElementSibling (node)) {
+ xmlNodePtr href_node = NULL, propstat_node = NULL;
+ xmlNodePtr status_node = NULL, prop_node = NULL;
+ const xmlChar *href_content, *status_content;
+ guint status_code;
+ gchar *full_uri;
- propstat_prefix = g_strdup_printf
("%s[%d]/D:propstat[%d]/D:prop",
- propstat_path_prefix, response_index + 1,
propstat_index + 1);
+ e_xml_find_children_nodes (node, 2,
+ E_WEBDAV_NS_DAV, "href", &href_node,
+ E_WEBDAV_NS_DAV, "propstat", &propstat_node);
- status = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/../D:status", propstat_prefix);
- if (!status || !soup_headers_parse_status_line (status, NULL,
&status_code, NULL))
- status_code = 0;
- g_free (status);
+ if (!href_node || !propstat_node)
+ continue;
- do_stop = !func (webdav, xpath_ctx, propstat_prefix,
request_uri, href, status_code, func_user_data);
+ href_content = e_xml_get_node_text (href_node);
+ g_warn_if_fail (href_content != NULL);
- g_free (propstat_prefix);
- }
+ if (!href_content)
+ continue;
- xmlXPathFreeObject (xpath_obj_propstat);
- g_free (href);
- }
- }
+ full_uri = e_webdav_session_ensure_full_uri (webdav, request_uri, (const gchar *)
href_content);
- xmlXPathFreeObject (xpath_obj_response);
- }
+ e_xml_find_children_nodes (propstat_node, 2,
+ E_WEBDAV_NS_DAV, "status", &status_node,
+ E_WEBDAV_NS_DAV, "prop", &prop_node);
+
+ status_content = e_xml_get_node_text (status_node);
+
+ if (!status_content || !soup_headers_parse_status_line ((const gchar *) status_content, NULL,
&status_code, NULL))
+ status_code = 0;
+
+ if (prop_node && prop_node->children)
+ do_stop = !func (webdav, prop_node, request_uri, full_uri ? full_uri : (const gchar
*) href_content, status_code, func_user_data);
+
+ g_free (full_uri);
}
- if (xpath_ctx)
- xmlXPathFreeContext (xpath_ctx);
xmlFreeDoc (doc);
return TRUE;
@@ -3266,17 +3268,10 @@ e_webdav_session_traverse_propstat_response (EWebDAVSession *webdav,
* @error: return location for a #GError, or %NULL
*
* Traverses a DAV:multistatus response and calls @func for each returned DAV:propstat.
- * The provided XPath context has registered %E_WEBDAV_NS_DAV namespace with prefix "D".
- * It doesn't have any other namespace registered.
*
* The @message, if provided, is used to verify that the response is a multi-status
* and that the Content-Type is properly set. It's used to get a request URI as well.
*
- * The @func is called always at least once, with %NULL xpath_prop_prefix, which
- * is meant to let the caller setup the xpath_ctx, like to register its own namespaces
- * to it with e_xml_xpath_context_register_namespaces(). All other invocations of @func
- * will have xpath_prop_prefix non-%NULL.
- *
* Returns: Whether succeeded.
*
* Since: 3.26
@@ -3294,7 +3289,8 @@ e_webdav_session_traverse_multistatus_response (EWebDAVSession *webdav,
g_return_val_if_fail (func != NULL, FALSE);
return e_webdav_session_traverse_propstat_response (webdav, message, xml_data, TRUE,
- NULL, NULL, "/D:multistatus/D:response",
+ E_WEBDAV_NS_DAV, "multistatus",
+ E_WEBDAV_NS_DAV, "response",
func, func_user_data, error);
}
@@ -3308,17 +3304,10 @@ e_webdav_session_traverse_multistatus_response (EWebDAVSession *webdav,
* @error: return location for a #GError, or %NULL
*
* Traverses a DAV:mkcol-response response and calls @func for each returned DAV:propstat.
- * The provided XPath context has registered %E_WEBDAV_NS_DAV namespace with prefix "D".
- * It doesn't have any other namespace registered.
*
* The @message, if provided, is used to verify that the response is an XML Content-Type.
* It's used to get the request URI as well.
*
- * The @func is called always at least once, with %NULL xpath_prop_prefix, which
- * is meant to let the caller setup the xpath_ctx, like to register its own namespaces
- * to it with e_xml_xpath_context_register_namespaces(). All other invocations of @func
- * will have xpath_prop_prefix non-%NULL.
- *
* Returns: Whether succeeded.
*
* Since: 3.26
@@ -3336,7 +3325,8 @@ e_webdav_session_traverse_mkcol_response (EWebDAVSession *webdav,
g_return_val_if_fail (func != NULL, FALSE);
return e_webdav_session_traverse_propstat_response (webdav, message, xml_data, FALSE,
- NULL, NULL, "/D:mkcol-response",
+ E_WEBDAV_NS_DAV, "mkcol-response",
+ NULL, NULL,
func, func_user_data, error);
}
@@ -3350,17 +3340,10 @@ e_webdav_session_traverse_mkcol_response (EWebDAVSession *webdav,
* @error: return location for a #GError, or %NULL
*
* Traverses a CALDAV:mkcalendar-response response and calls @func for each returned DAV:propstat.
- * The provided XPath context has registered %E_WEBDAV_NS_DAV namespace with prefix "D" and
- * %E_WEBDAV_NS_CALDAV namespace with prefix "C". It doesn't have any other namespace registered.
*
* The @message, if provided, is used to verify that the response is an XML Content-Type.
* It's used to get the request URI as well.
*
- * The @func is called always at least once, with %NULL xpath_prop_prefix, which
- * is meant to let the caller setup the xpath_ctx, like to register its own namespaces
- * to it with e_xml_xpath_context_register_namespaces(). All other invocations of @func
- * will have xpath_prop_prefix non-%NULL.
- *
* Returns: Whether succeeded.
*
* Since: 3.26
@@ -3378,40 +3361,29 @@ e_webdav_session_traverse_mkcalendar_response (EWebDAVSession *webdav,
g_return_val_if_fail (func != NULL, FALSE);
return e_webdav_session_traverse_propstat_response (webdav, message, xml_data, FALSE,
- "C", E_WEBDAV_NS_CALDAV, "/C:mkcalendar-response",
+ E_WEBDAV_NS_CALDAV, "mkcalendar-response",
+ NULL, NULL,
func, func_user_data, error);
}
static gboolean
e_webdav_session_getctag_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
gpointer user_data)
{
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx,
- "CS", E_WEBDAV_NS_CALENDARSERVER,
- NULL);
-
- return TRUE;
- }
-
if (status_code == SOUP_STATUS_OK) {
+ const xmlChar *ctag_content;
gchar **out_ctag = user_data;
- gchar *ctag;
g_return_val_if_fail (out_ctag != NULL, FALSE);
- ctag = e_xml_xpath_eval_as_string (xpath_ctx, "%s/CS:getctag", xpath_prop_prefix);
+ ctag_content = e_xml_find_child_and_get_text (prop_node, E_WEBDAV_NS_CALENDARSERVER,
"getctag");
- if (ctag && *ctag) {
- *out_ctag = e_webdav_session_util_maybe_dequote (ctag);
- } else {
- g_free (ctag);
- }
+ if (ctag_content && *ctag_content)
+ *out_ctag = e_webdav_session_util_maybe_dequote (g_strdup ((const gchar *)
ctag_content));
}
return FALSE;
@@ -3470,79 +3442,79 @@ e_webdav_session_getctag_sync (EWebDAVSession *webdav,
}
static EWebDAVResourceKind
-e_webdav_session_extract_kind (xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix)
+e_webdav_session_extract_kind (xmlNodePtr parent_node)
{
- g_return_val_if_fail (xpath_ctx != NULL, E_WEBDAV_RESOURCE_KIND_UNKNOWN);
- g_return_val_if_fail (xpath_prop_prefix != NULL, E_WEBDAV_RESOURCE_KIND_UNKNOWN);
+ xmlNodePtr resourcetype;
+
+ g_return_val_if_fail (parent_node != NULL, E_WEBDAV_RESOURCE_KIND_UNKNOWN);
+
+ resourcetype = e_xml_find_child (parent_node, E_WEBDAV_NS_DAV, "resourcetype");
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/A:addressbook", xpath_prop_prefix))
+ if (e_xml_find_child (resourcetype, E_WEBDAV_NS_CARDDAV, "addressbook"))
return E_WEBDAV_RESOURCE_KIND_ADDRESSBOOK;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/C:calendar", xpath_prop_prefix))
+ if (e_xml_find_child (resourcetype, E_WEBDAV_NS_CALDAV, "calendar"))
return E_WEBDAV_RESOURCE_KIND_CALENDAR;
/* These are subscribed iCalendar files, aka 'On The Web' calendars */
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/D:collection", xpath_prop_prefix) &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/CS:subscribed", xpath_prop_prefix) &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/CS:source/D:href", xpath_prop_prefix))
+ if (e_xml_find_child (resourcetype, E_WEBDAV_NS_DAV, "collection") &&
+ e_xml_find_child (resourcetype, E_WEBDAV_NS_CALENDARSERVER, "subscribed") &&
+ e_xml_find_in_hierarchy (parent_node, E_WEBDAV_NS_CALENDARSERVER, "source", E_WEBDAV_NS_DAV,
"href", NULL, NULL))
return E_WEBDAV_RESOURCE_KIND_SUBSCRIBED_ICALENDAR;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/D:principal", xpath_prop_prefix))
+ if (e_xml_find_child (resourcetype, E_WEBDAV_NS_DAV, "principal"))
return E_WEBDAV_RESOURCE_KIND_PRINCIPAL;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/D:collection", xpath_prop_prefix))
+ if (e_xml_find_child (resourcetype, E_WEBDAV_NS_DAV, "collection"))
return E_WEBDAV_RESOURCE_KIND_COLLECTION;
return E_WEBDAV_RESOURCE_KIND_RESOURCE;
}
static guint32
-e_webdav_session_extract_supports (xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix)
+e_webdav_session_extract_supports (xmlNodePtr prop_node)
{
+ xmlNodePtr calendar_components;
guint32 supports = E_WEBDAV_RESOURCE_SUPPORTS_NONE;
- g_return_val_if_fail (xpath_ctx != NULL, E_WEBDAV_RESOURCE_SUPPORTS_NONE);
- g_return_val_if_fail (xpath_prop_prefix != NULL, E_WEBDAV_RESOURCE_SUPPORTS_NONE);
+ g_return_val_if_fail (prop_node != NULL, E_WEBDAV_RESOURCE_SUPPORTS_NONE);
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:resourcetype/A:addressbook", xpath_prop_prefix))
+ if (e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_DAV, "resourcetype", E_WEBDAV_NS_CARDDAV,
"addressbook", NULL, NULL))
supports = supports | E_WEBDAV_RESOURCE_SUPPORTS_CONTACTS;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/C:supported-calendar-component-set", xpath_prop_prefix)) {
- xmlXPathObjectPtr xpath_obj;
+ calendar_components = e_xml_find_child (prop_node, E_WEBDAV_NS_CALDAV,
"supported-calendar-component-set");
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s/C:supported-calendar-component-set/C:comp",
xpath_prop_prefix);
- if (xpath_obj) {
- gint ii, length;
+ if (calendar_components) {
+ xmlNodePtr node;
+ gint found_comps = 0;
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
+ for (node = calendar_components->children; node; node = xmlNextElementSibling (node)) {
+ if (e_xml_is_element_name (node, E_WEBDAV_NS_CALDAV, "comp")) {
+ xmlChar *name;
- for (ii = 0; ii < length; ii++) {
- gchar *name;
+ found_comps++;
- name = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/C:supported-calendar-component-set/C:comp[%d]/@name",
- xpath_prop_prefix, ii + 1);
+ name = xmlGetProp (node, (const xmlChar *) "name");
if (!name)
continue;
- if (g_ascii_strcasecmp (name, "VEVENT") == 0)
+ if (g_ascii_strcasecmp ((const gchar *) name, "VEVENT") == 0)
supports |= E_WEBDAV_RESOURCE_SUPPORTS_EVENTS;
- else if (g_ascii_strcasecmp (name, "VJOURNAL") == 0)
+ else if (g_ascii_strcasecmp ((const gchar *) name, "VJOURNAL") == 0)
supports |= E_WEBDAV_RESOURCE_SUPPORTS_MEMOS;
- else if (g_ascii_strcasecmp (name, "VTODO") == 0)
+ else if (g_ascii_strcasecmp ((const gchar *) name, "VTODO") == 0)
supports |= E_WEBDAV_RESOURCE_SUPPORTS_TASKS;
- else if (g_ascii_strcasecmp (name, "VFREEBUSY") == 0)
+ else if (g_ascii_strcasecmp ((const gchar *) name, "VFREEBUSY") == 0)
supports |= E_WEBDAV_RESOURCE_SUPPORTS_FREEBUSY;
- else if (g_ascii_strcasecmp (name, "VTIMEZONE") == 0)
+ else if (g_ascii_strcasecmp ((const gchar *) name, "VTIMEZONE") == 0)
supports |= E_WEBDAV_RESOURCE_SUPPORTS_TIMEZONE;
- g_free (name);
+ xmlFree (name);
}
+ }
- xmlXPathFreeObject (xpath_obj);
- } else {
+ if (!found_comps) {
/* If the property is not present, assume all component
* types are supported. (RFC 4791, Section 5.2.3) */
supports = supports |
@@ -3558,20 +3530,30 @@ e_webdav_session_extract_supports (xmlXPathContextPtr xpath_ctx,
}
static gchar *
-e_webdav_session_extract_nonempty (xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
- const gchar *prop,
- const gchar *alternative_prop)
+e_webdav_session_extract_nonempty (xmlNodePtr parent,
+ const gchar *prop_ns_href,
+ const gchar *prop_name,
+ const gchar *alternative_prop_ns_href,
+ const gchar *alternative_prop_name)
{
- gchar *value;
+ const xmlChar *x_value;
+ gchar *value = NULL;
- g_return_val_if_fail (xpath_ctx != NULL, NULL);
- g_return_val_if_fail (xpath_prop_prefix != NULL, NULL);
- g_return_val_if_fail (prop != NULL, NULL);
+ g_return_val_if_fail (parent != NULL, NULL);
+ g_return_val_if_fail (prop_name != NULL, NULL);
+
+ x_value = e_xml_find_child_and_get_text (parent, prop_ns_href, prop_name);
+
+ if (x_value && *x_value)
+ value = g_strdup ((const gchar *) x_value);
+
+ if (!value && alternative_prop_name) {
+ x_value = e_xml_find_child_and_get_text (parent, alternative_prop_ns_href,
alternative_prop_name);
+
+ if (x_value && *x_value)
+ value = g_strdup ((const gchar *) x_value);
+ }
- value = e_xml_xpath_eval_as_string (xpath_ctx, "%s/%s", xpath_prop_prefix, prop);
- if (!value && alternative_prop)
- value = e_xml_xpath_eval_as_string (xpath_ctx, "%s/%s", xpath_prop_prefix, alternative_prop);
if (!value)
return NULL;
@@ -3584,16 +3566,14 @@ e_webdav_session_extract_nonempty (xmlXPathContextPtr xpath_ctx,
}
static gsize
-e_webdav_session_extract_content_length (xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix)
+e_webdav_session_extract_content_length (xmlNodePtr parent)
{
gchar *value;
gsize length;
- g_return_val_if_fail (xpath_ctx != NULL, 0);
- g_return_val_if_fail (xpath_prop_prefix != NULL, 0);
+ g_return_val_if_fail (parent != NULL, 0);
- value = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix, "D:getcontentlength", NULL);
+ value = e_webdav_session_extract_nonempty (parent, E_WEBDAV_NS_DAV, "getcontentlength", NULL, NULL);
if (!value)
return 0;
@@ -3605,18 +3585,18 @@ e_webdav_session_extract_content_length (xmlXPathContextPtr xpath_ctx,
}
static glong
-e_webdav_session_extract_datetime (xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+e_webdav_session_extract_datetime (xmlNodePtr parent,
+ const gchar *ns_href,
const gchar *prop,
gboolean is_iso_property)
{
gchar *value;
GTimeVal tv;
- g_return_val_if_fail (xpath_ctx != NULL, -1);
- g_return_val_if_fail (xpath_prop_prefix != NULL, -1);
+ g_return_val_if_fail (parent != NULL, -1);
+ g_return_val_if_fail (prop != NULL, -1);
- value = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix, prop, NULL);
+ value = e_webdav_session_extract_nonempty (parent, ns_href, prop, NULL, NULL);
if (!value)
return -1;
@@ -3633,8 +3613,7 @@ e_webdav_session_extract_datetime (xmlXPathContextPtr xpath_ctx,
static gboolean
e_webdav_session_list_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -3645,17 +3624,6 @@ e_webdav_session_list_cb (EWebDAVSession *webdav,
g_return_val_if_fail (out_resources != NULL, FALSE);
g_return_val_if_fail (request_uri != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx,
- "CS", E_WEBDAV_NS_CALENDARSERVER,
- "C", E_WEBDAV_NS_CALDAV,
- "A", E_WEBDAV_NS_CARDDAV,
- "IC", E_WEBDAV_NS_ICAL,
- NULL);
-
- return TRUE;
- }
-
if (status_code == SOUP_STATUS_OK) {
EWebDAVResource *resource;
EWebDAVResourceKind kind;
@@ -3670,26 +3638,38 @@ e_webdav_session_list_cb (EWebDAVSession *webdav,
gchar *color;
gchar *source_href = NULL;
- kind = e_webdav_session_extract_kind (xpath_ctx, xpath_prop_prefix);
+ kind = e_webdav_session_extract_kind (prop_node);
if (kind == E_WEBDAV_RESOURCE_KIND_UNKNOWN)
return TRUE;
if (kind == E_WEBDAV_RESOURCE_KIND_SUBSCRIBED_ICALENDAR) {
- source_href = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix,
"CS:source/D:href", NULL);
+ xmlNodePtr source_href_node;
+ const xmlChar *x_source_href = NULL;
+
+
+ source_href_node = e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_CALENDARSERVER,
"source", E_WEBDAV_NS_DAV, "href", NULL, NULL);
+
+ if (!source_href_node)
+ return TRUE;
+
+ x_source_href = e_xml_get_node_text (source_href_node);
- if (!source_href)
+ if (!x_source_href || !*x_source_href)
return TRUE;
+
+ source_href = e_webdav_session_util_maybe_dequote (g_strdup ((const gchar *)
x_source_href));
}
- supports = e_webdav_session_extract_supports (xpath_ctx, xpath_prop_prefix);
- etag = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix, "D:getetag",
"CS:getctag");
- display_name = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix,
"D:displayname", NULL);
- content_type = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix,
"D:getcontenttype", NULL);
- content_length = e_webdav_session_extract_content_length (xpath_ctx, xpath_prop_prefix);
- creation_date = e_webdav_session_extract_datetime (xpath_ctx, xpath_prop_prefix,
"D:creationdate", TRUE);
- last_modified = e_webdav_session_extract_datetime (xpath_ctx, xpath_prop_prefix,
"D:getlastmodified", FALSE);
- description = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix,
"C:calendar-description", "A:addressbook-description");
- color = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix, "IC:calendar-color",
NULL);
+ supports = e_webdav_session_extract_supports (prop_node);
+ etag = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_DAV, "getetag",
E_WEBDAV_NS_CALENDARSERVER, "getctag");
+ display_name = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_DAV, "displayname",
NULL, NULL);
+ content_type = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_DAV,
"getcontenttype", NULL, NULL);
+ content_length = e_webdav_session_extract_content_length (prop_node);
+ creation_date = e_webdav_session_extract_datetime (prop_node, E_WEBDAV_NS_DAV,
"creationdate", TRUE);
+ last_modified = e_webdav_session_extract_datetime (prop_node, E_WEBDAV_NS_DAV,
"getlastmodified", FALSE);
+ description = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_CALDAV,
"calendar-description",
+ E_WEBDAV_NS_CARDDAV, "addressbook-description");
+ color = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_ICAL, "calendar-color",
NULL, NULL);
resource = e_webdav_resource_new (kind, supports,
source_href ? source_href : href,
@@ -4061,81 +4041,53 @@ e_webdav_session_lock_resource_sync (EWebDAVSession *webdav,
}
static void
-e_webdav_session_traverse_privilege_level (xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prefix,
+e_webdav_session_traverse_privilege_level (xmlNodePtr parent_node,
GNode *parent)
{
- xmlXPathObjectPtr xpath_obj;
+ xmlNodePtr node;
- g_return_if_fail (xpath_ctx != NULL);
- g_return_if_fail (xpath_prefix != NULL);
+ g_return_if_fail (parent_node != NULL);
g_return_if_fail (parent != NULL);
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s/D:supported-privilege", xpath_prefix);
-
- if (xpath_obj) {
- gint ii, length;
-
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
-
- for (ii = 0; ii < length; ii++) {
- xmlXPathObjectPtr xpath_obj_privilege;
- gchar *prefix;
-
- prefix = g_strdup_printf ("%s/D:supported-privilege[%d]", xpath_prefix, ii + 1);
- xpath_obj_privilege = e_xml_xpath_eval (xpath_ctx, "%s/D:privilege", prefix);
-
- if (xpath_obj_privilege &&
- xpath_obj_privilege->type == XPATH_NODESET &&
- xpath_obj_privilege->nodesetval &&
- xpath_obj_privilege->nodesetval->nodeNr == 1 &&
- xpath_obj_privilege->nodesetval->nodeTab &&
- xpath_obj_privilege->nodesetval->nodeTab[0] &&
- xpath_obj_privilege->nodesetval->nodeTab[0]->children) {
- xmlNodePtr node;
-
- for (node = xpath_obj_privilege->nodesetval->nodeTab[0]->children; node; node
= node->next) {
- if (node->type == XML_ELEMENT_NODE &&
- node->name && *(node->name) &&
- node->ns && node->ns->href && *(node->ns->href)) {
- GNode *child;
- gchar *description;
- EWebDAVPrivilegeKind kind = E_WEBDAV_PRIVILEGE_KIND_COMMON;
- EWebDAVPrivilegeHint hint = E_WEBDAV_PRIVILEGE_HINT_UNKNOWN;
- EWebDAVPrivilege *privilege;
-
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:abstract",
prefix))
- kind = E_WEBDAV_PRIVILEGE_KIND_ABSTRACT;
- else if (e_xml_xpath_eval_exists (xpath_ctx,
"%s/D:aggregate", prefix))
- kind = E_WEBDAV_PRIVILEGE_KIND_AGGREGATE;
-
- description = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/D:description", prefix);
- privilege = e_webdav_privilege_new ((const gchar *)
node->ns->href, (const gchar *) node->name, description, kind, hint);
- child = g_node_new (privilege);
- g_node_append (parent, child);
-
- g_free (description);
-
- if (e_xml_xpath_eval_exists (xpath_ctx,
"%s/D:supported-privilege", prefix))
- e_webdav_session_traverse_privilege_level (xpath_ctx,
prefix, child);
- }
- }
- }
-
- if (xpath_obj_privilege)
- xmlXPathFreeObject (xpath_obj_privilege);
-
- g_free (prefix);
+ for (node = e_xml_find_child (parent_node, E_WEBDAV_NS_DAV, "supported-privilege");
+ node;
+ node = e_xml_find_next_sibling (node, E_WEBDAV_NS_DAV, "supported-privilege")) {
+ xmlNodePtr privilege_node;
+
+ privilege_node = e_xml_find_child (node, E_WEBDAV_NS_DAV, "privilege");
+
+ if (privilege_node) {
+ GNode *child;
+ const xmlChar *description;
+ EWebDAVPrivilegeKind kind = E_WEBDAV_PRIVILEGE_KIND_COMMON;
+ EWebDAVPrivilegeHint hint = E_WEBDAV_PRIVILEGE_HINT_UNKNOWN;
+ EWebDAVPrivilege *privilege;
+
+ if (e_xml_find_child (privilege_node, E_WEBDAV_NS_DAV, "abstract"))
+ kind = E_WEBDAV_PRIVILEGE_KIND_ABSTRACT;
+ else if (e_xml_find_child (privilege_node, E_WEBDAV_NS_DAV, "aggregate"))
+ kind = E_WEBDAV_PRIVILEGE_KIND_AGGREGATE;
+
+ description = e_xml_find_child_and_get_text (privilege_node, E_WEBDAV_NS_DAV,
"description");
+ privilege = e_webdav_privilege_new ((const gchar *) ((privilege_node->ns &&
privilege_node->ns->href) ? privilege_node->ns->href : NULL),
+ (const gchar *) privilege_node->name,
+ (const gchar *) description,
+ kind,
+ hint);
+ child = g_node_new (privilege);
+ g_node_append (parent, child);
+
+ privilege_node = e_xml_find_child (privilege_node, E_WEBDAV_NS_DAV,
"supported-privilege");
+
+ if (privilege_node)
+ e_webdav_session_traverse_privilege_level (privilege_node, child);
}
-
- xmlXPathFreeObject (xpath_obj);
}
}
static gboolean
e_webdav_session_supported_privilege_set_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -4145,23 +4097,15 @@ e_webdav_session_supported_privilege_set_cb (EWebDAVSession *webdav,
g_return_val_if_fail (out_privileges != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx,
- "C", E_WEBDAV_NS_CALDAV,
- NULL);
- } else if (status_code == SOUP_STATUS_OK &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/D:supported-privilege-set/D:supported-privilege",
xpath_prop_prefix)) {
+ if (status_code == SOUP_STATUS_OK &&
+ e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_DAV, "supported-privilege-set", E_WEBDAV_NS_DAV,
"supported-privilege", NULL, NULL)) {
GNode *root;
- gchar *prefix;
- prefix = g_strconcat (xpath_prop_prefix, "/D:supported-privilege-set", NULL);
root = g_node_new (NULL);
- e_webdav_session_traverse_privilege_level (xpath_ctx, prefix, root);
+ e_webdav_session_traverse_privilege_level (prop_node, root);
*out_privileges = root;
-
- g_free (prefix);
}
return TRUE;
@@ -4290,19 +4234,13 @@ e_webdav_session_get_supported_privilege_set_sync (EWebDAVSession *webdav,
}
static void
-e_webdav_session_extract_privilege_simple (xmlXPathObjectPtr xpath_obj_privilege,
+e_webdav_session_extract_privilege_simple (xmlNodePtr privilege_node,
GSList **out_privileges)
{
- if (xpath_obj_privilege &&
- xpath_obj_privilege->type == XPATH_NODESET &&
- xpath_obj_privilege->nodesetval &&
- xpath_obj_privilege->nodesetval->nodeNr == 1 &&
- xpath_obj_privilege->nodesetval->nodeTab &&
- xpath_obj_privilege->nodesetval->nodeTab[0] &&
- xpath_obj_privilege->nodesetval->nodeTab[0]->children) {
+ if (privilege_node) {
xmlNodePtr node;
- for (node = xpath_obj_privilege->nodesetval->nodeTab[0]->children; node; node = node->next) {
+ for (node = privilege_node->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE &&
node->name && *(node->name) &&
node->ns && node->ns->href && *(node->ns->href)) {
@@ -4325,8 +4263,7 @@ typedef struct _PrivilegeSetData {
static gboolean
e_webdav_session_current_user_privilege_set_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
@@ -4334,43 +4271,25 @@ e_webdav_session_current_user_privilege_set_cb (EWebDAVSession *webdav,
{
PrivilegeSetData *psd = user_data;
- g_return_val_if_fail (xpath_ctx != NULL, FALSE);
+ g_return_val_if_fail (prop_node != NULL, FALSE);
g_return_val_if_fail (psd != NULL, FALSE);
- if (!xpath_prop_prefix) {
- e_xml_xpath_context_register_namespaces (xpath_ctx,
- "C", E_WEBDAV_NS_CALDAV,
- NULL);
- } else if (status_code == SOUP_STATUS_OK &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/D:current-user-privilege-set/D:privilege",
xpath_prop_prefix)) {
- xmlXPathObjectPtr xpath_obj;
-
- psd->any_found = TRUE;
-
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s/D:current-user-privilege-set/D:privilege",
xpath_prop_prefix);
-
- if (xpath_obj) {
- gint ii, length;
-
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
+ if (status_code == SOUP_STATUS_OK) {
+ xmlNodePtr privilege_set_node;
- for (ii = 0; ii < length; ii++) {
- xmlXPathObjectPtr xpath_obj_privilege;
+ privilege_set_node = e_xml_find_child (prop_node, E_WEBDAV_NS_DAV,
"current-user-privilege-set");
- xpath_obj_privilege = e_xml_xpath_eval (xpath_ctx,
"%s/D:current-user-privilege-set/D:privilege[%d]", xpath_prop_prefix, ii + 1);
+ if (privilege_set_node) {
+ xmlNodePtr privilege_node;
- if (xpath_obj_privilege) {
- e_webdav_session_extract_privilege_simple (xpath_obj_privilege,
psd->out_privileges);
+ psd->any_found = TRUE;
- xmlXPathFreeObject (xpath_obj_privilege);
- }
+ for (privilege_node = e_xml_find_child (privilege_set_node, E_WEBDAV_NS_DAV,
"privilege");
+ privilege_node;
+ privilege_node = e_xml_find_next_sibling (privilege_node, E_WEBDAV_NS_DAV,
"privilege")) {
+ e_webdav_session_extract_privilege_simple (privilege_node,
psd->out_privileges);
}
-
- xmlXPathFreeObject (xpath_obj);
}
- } else if (status_code == SOUP_STATUS_OK &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/D:current-user-privilege-set", xpath_prop_prefix))
{
- psd->any_found = TRUE;
}
return TRUE;
@@ -4436,14 +4355,33 @@ e_webdav_session_get_current_user_privilege_set_sync (EWebDAVSession *webdav,
return success;
}
+static gboolean
+e_webdav_session_has_one_children (xmlNodePtr parent_node)
+{
+ xmlNodePtr node;
+ gint subelements = 0;
+
+ if (!parent_node)
+ return FALSE;
+
+ for (node = parent_node->children; node && subelements <= 1; node = node->next) {
+ if (node->type == XML_ELEMENT_NODE)
+ subelements++;
+ }
+
+ return subelements == 1;
+}
+
static EWebDAVACEPrincipalKind
-e_webdav_session_extract_acl_principal (xmlXPathContextPtr xpath_ctx,
- const gchar *principal_prefix,
+e_webdav_session_extract_acl_principal (xmlNodePtr principal_node,
gchar **out_principal_href,
GSList **out_principal_hrefs)
{
- g_return_val_if_fail (xpath_ctx != NULL, E_WEBDAV_ACE_PRINCIPAL_UNKNOWN);
- g_return_val_if_fail (principal_prefix != NULL, E_WEBDAV_ACE_PRINCIPAL_UNKNOWN);
+ xmlNodePtr node;
+
+ if (!principal_node)
+ return E_WEBDAV_ACE_PRINCIPAL_UNKNOWN;
+
g_return_val_if_fail (out_principal_href != NULL || out_principal_hrefs != NULL,
E_WEBDAV_ACE_PRINCIPAL_UNKNOWN);
if (out_principal_href)
@@ -4452,33 +4390,22 @@ e_webdav_session_extract_acl_principal (xmlXPathContextPtr xpath_ctx,
if (out_principal_hrefs)
*out_principal_hrefs = NULL;
- if (!e_xml_xpath_eval_exists (xpath_ctx, "%s", principal_prefix))
- return E_WEBDAV_ACE_PRINCIPAL_UNKNOWN;
-
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:href", principal_prefix)) {
- if (out_principal_href) {
- *out_principal_href = e_xml_xpath_eval_as_string (xpath_ctx, "%s/D:href",
principal_prefix);
- } else {
- xmlXPathObjectPtr xpath_obj;
-
- *out_principal_hrefs = NULL;
+ node = e_xml_find_child (principal_node, E_WEBDAV_NS_DAV, "href");
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s/D:href", principal_prefix);
-
- if (xpath_obj) {
- gint ii, length;
+ if (node) {
+ const xmlChar *href;
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
+ href = e_xml_get_node_text (node);
- for (ii = 0; ii < length; ii++) {
- gchar *href;
+ if (out_principal_href) {
+ *out_principal_href = (href && *href) ? g_strdup ((const gchar *) href) : NULL;
+ } else {
+ for (; node; node = e_xml_find_next_sibling (node, E_WEBDAV_NS_DAV, "href")) {
- href = e_xml_xpath_eval_as_string (xpath_ctx, "%s/D:href[%d]",
principal_prefix, ii + 1);
- if (href)
- *out_principal_hrefs = g_slist_prepend (*out_principal_hrefs,
href);
- }
+ href = e_xml_get_node_text (node);
- xmlXPathFreeObject (xpath_obj);
+ if (href && *href)
+ *out_principal_hrefs = g_slist_prepend (*out_principal_hrefs,
g_strdup ((const gchar *) href));
}
*out_principal_hrefs = g_slist_reverse (*out_principal_hrefs);
@@ -4487,51 +4414,31 @@ e_webdav_session_extract_acl_principal (xmlXPathContextPtr xpath_ctx,
return E_WEBDAV_ACE_PRINCIPAL_HREF;
}
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:all", principal_prefix))
+ if (e_xml_find_child (principal_node, E_WEBDAV_NS_DAV, "all"))
return E_WEBDAV_ACE_PRINCIPAL_ALL;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:authenticated", principal_prefix))
+ if (e_xml_find_child (principal_node, E_WEBDAV_NS_DAV, "authenticated"))
return E_WEBDAV_ACE_PRINCIPAL_AUTHENTICATED;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:unauthenticated", principal_prefix))
+ if (e_xml_find_child (principal_node, E_WEBDAV_NS_DAV, "unauthenticated"))
return E_WEBDAV_ACE_PRINCIPAL_UNAUTHENTICATED;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:self", principal_prefix))
+ if (e_xml_find_child (principal_node, E_WEBDAV_NS_DAV, "self"))
return E_WEBDAV_ACE_PRINCIPAL_SELF;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:property", principal_prefix)) {
+ node = e_xml_find_child (principal_node, E_WEBDAV_NS_DAV, "property");
+
+ if (node) {
/* No details read about what properties */
EWebDAVACEPrincipalKind kind = E_WEBDAV_ACE_PRINCIPAL_PROPERTY;
/* Special-case owner */
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:property/D:owner", principal_prefix)) {
- xmlXPathObjectPtr xpath_obj_property;
-
- xpath_obj_property = e_xml_xpath_eval (xpath_ctx, "%s/D:property", principal_prefix);
-
+ if (e_xml_find_child (node, E_WEBDAV_NS_DAV, "owner")) {
/* DAV:owner is the only child and there is only one DAV:property child of the
DAV:principal */
- if (xpath_obj_property &&
- xpath_obj_property->type == XPATH_NODESET &&
- xmlXPathNodeSetGetLength (xpath_obj_property->nodesetval) == 1 &&
- xpath_obj_property->nodesetval &&
- xpath_obj_property->nodesetval->nodeNr == 1 &&
- xpath_obj_property->nodesetval->nodeTab &&
- xpath_obj_property->nodesetval->nodeTab[0] &&
- xpath_obj_property->nodesetval->nodeTab[0]->children) {
- xmlNodePtr node;
- gint subelements = 0;
-
- for (node = xpath_obj_property->nodesetval->nodeTab[0]->children; node &&
subelements <= 1; node = node->next) {
- if (node->type == XML_ELEMENT_NODE)
- subelements++;
- }
-
- if (subelements == 1)
- kind = E_WEBDAV_ACE_PRINCIPAL_OWNER;
+ if (e_webdav_session_has_one_children (node) &&
+ e_webdav_session_has_one_children (principal_node)) {
+ kind = E_WEBDAV_ACE_PRINCIPAL_OWNER;
}
-
- if (xpath_obj_property)
- xmlXPathFreeObject (xpath_obj_property);
}
return kind;
@@ -4542,116 +4449,88 @@ e_webdav_session_extract_acl_principal (xmlXPathContextPtr xpath_ctx,
static gboolean
e_webdav_session_acl_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
gpointer user_data)
{
GSList **out_entries = user_data;
+ xmlNodePtr acl_node, ace_node;
- g_return_val_if_fail (xpath_ctx != NULL, FALSE);
+ g_return_val_if_fail (prop_node != NULL, FALSE);
g_return_val_if_fail (out_entries != NULL, FALSE);
- if (!xpath_prop_prefix) {
- } else if (status_code == SOUP_STATUS_OK &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/D:acl/D:ace", xpath_prop_prefix)) {
- xmlXPathObjectPtr xpath_obj_ace;
+ if (status_code != SOUP_STATUS_OK)
+ return TRUE;
- xpath_obj_ace = e_xml_xpath_eval (xpath_ctx, "%s/D:acl/D:ace", xpath_prop_prefix);
- if (xpath_obj_ace) {
- gint ii, length;
+ acl_node = e_xml_find_child (prop_node, E_WEBDAV_NS_DAV, "acl");
- length = xmlXPathNodeSetGetLength (xpath_obj_ace->nodesetval);
+ if (acl_node) {
+ for (ace_node = e_xml_find_child (acl_node, E_WEBDAV_NS_DAV, "ace");
+ ace_node;
+ ace_node = e_xml_find_next_sibling (ace_node, E_WEBDAV_NS_DAV, "ace")) {
+ EWebDAVACEPrincipalKind principal_kind = E_WEBDAV_ACE_PRINCIPAL_UNKNOWN;
+ xmlNodePtr node;
+ gchar *principal_href = NULL;
+ guint32 flags = E_WEBDAV_ACE_FLAG_UNKNOWN;
+ gchar *inherited_href = NULL;
- for (ii = 0; ii < length; ii++) {
- EWebDAVACEPrincipalKind principal_kind = E_WEBDAV_ACE_PRINCIPAL_UNKNOWN;
- xmlXPathObjectPtr xpath_obj = NULL;
- gchar *principal_href = NULL;
- guint32 flags = E_WEBDAV_ACE_FLAG_UNKNOWN;
- gchar *inherited_href = NULL;
- gchar *privilege_prefix = NULL;
- gchar *ace_prefix;
+ node = e_xml_find_child (ace_node, E_WEBDAV_NS_DAV, "invert");
- ace_prefix = g_strdup_printf ("%s/D:acl/D:ace[%d]", xpath_prop_prefix, ii +
1);
+ if (node) {
+ flags |= E_WEBDAV_ACE_FLAG_INVERT;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:invert", ace_prefix)) {
- gchar *prefix;
+ principal_kind = e_webdav_session_extract_acl_principal (e_xml_find_child
(node, E_WEBDAV_NS_DAV, "principal"), &principal_href, NULL);
+ } else {
+ principal_kind = e_webdav_session_extract_acl_principal (e_xml_find_child
(ace_node, E_WEBDAV_NS_DAV, "principal"), &principal_href, NULL);
+ }
- flags |= E_WEBDAV_ACE_FLAG_INVERT;
+ if (principal_kind == E_WEBDAV_ACE_PRINCIPAL_UNKNOWN)
+ continue;
- prefix = g_strdup_printf ("%s/D:invert/D:principal", ace_prefix);
- principal_kind = e_webdav_session_extract_acl_principal (xpath_ctx,
prefix, &principal_href, NULL);
- g_free (prefix);
- } else {
- gchar *prefix;
+ if (e_xml_find_child (ace_node, E_WEBDAV_NS_DAV, "protected"))
+ flags |= E_WEBDAV_ACE_FLAG_PROTECTED;
- prefix = g_strdup_printf ("%s/D:principal", ace_prefix);
- principal_kind = e_webdav_session_extract_acl_principal (xpath_ctx,
prefix, &principal_href, NULL);
- g_free (prefix);
- }
+ node = e_xml_find_in_hierarchy (ace_node, E_WEBDAV_NS_DAV, "inherited",
E_WEBDAV_NS_DAV, "href", NULL, NULL);
- if (principal_kind == E_WEBDAV_ACE_PRINCIPAL_UNKNOWN) {
- g_free (ace_prefix);
- continue;
- }
+ if (node) {
+ flags |= E_WEBDAV_ACE_FLAG_INHERITED;
+ inherited_href = g_strdup ((const gchar *) e_xml_get_node_text (node));
+ }
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:protected", ace_prefix))
- flags |= E_WEBDAV_ACE_FLAG_PROTECTED;
+ node = e_xml_find_child (ace_node, E_WEBDAV_NS_DAV, "grant");
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:inherited/D:href", ace_prefix))
{
- flags |= E_WEBDAV_ACE_FLAG_INHERITED;
- inherited_href = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/D:inherited/D:href", ace_prefix);
- }
+ if (node) {
+ flags |= E_WEBDAV_ACE_FLAG_GRANT;
+ } else {
+ node = e_xml_find_child (ace_node, E_WEBDAV_NS_DAV, "deny");
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:grant", ace_prefix)) {
- privilege_prefix = g_strdup_printf ("%s/D:grant/D:privilege",
ace_prefix);
- flags |= E_WEBDAV_ACE_FLAG_GRANT;
- } else if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:deny", ace_prefix)) {
- privilege_prefix = g_strdup_printf ("%s/D:deny/D:privilege",
ace_prefix);
+ if (node)
flags |= E_WEBDAV_ACE_FLAG_DENY;
- }
-
- if (privilege_prefix)
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s", privilege_prefix);
-
- if (xpath_obj) {
- EWebDAVAccessControlEntry *ace;
- gint ii, length;
-
- ace = e_webdav_access_control_entry_new (principal_kind,
principal_href, flags, inherited_href);
- if (ace) {
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
-
- for (ii = 0; ii < length; ii++) {
- xmlXPathObjectPtr xpath_obj_privilege;
-
- xpath_obj_privilege = e_xml_xpath_eval (xpath_ctx,
"%s[%d]", privilege_prefix, ii + 1);
-
- if (xpath_obj_privilege) {
- e_webdav_session_extract_privilege_simple
(xpath_obj_privilege, &ace->privileges);
+ }
- xmlXPathFreeObject (xpath_obj_privilege);
- }
- }
+ if (node) {
+ EWebDAVAccessControlEntry *ace;
- ace->privileges = g_slist_reverse (ace->privileges);
+ ace = e_webdav_access_control_entry_new (principal_kind, principal_href,
flags, inherited_href);
- *out_entries = g_slist_prepend (*out_entries, ace);
+ if (ace) {
+ for (node = e_xml_find_child (node, E_WEBDAV_NS_DAV, "privilege");
+ node;
+ node = e_xml_find_next_sibling (node, E_WEBDAV_NS_DAV,
"privilege")) {
+ e_webdav_session_extract_privilege_simple (node,
&ace->privileges);
}
- xmlXPathFreeObject (xpath_obj);
- }
+ ace->privileges = g_slist_reverse (ace->privileges);
- g_free (principal_href);
- g_free (inherited_href);
- g_free (privilege_prefix);
- g_free (ace_prefix);
+ *out_entries = g_slist_prepend (*out_entries, ace);
+ }
}
- xmlXPathFreeObject (xpath_obj_ace);
+ g_free (principal_href);
+ g_free (inherited_href);
}
}
@@ -4720,38 +4599,40 @@ typedef struct _ACLRestrictionsData {
static gboolean
e_webdav_session_acl_restrictions_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
gpointer user_data)
{
ACLRestrictionsData *ard = user_data;
+ xmlNodePtr acl_restrictions_node;
- g_return_val_if_fail (xpath_ctx != NULL, FALSE);
+ g_return_val_if_fail (prop_node != NULL, FALSE);
g_return_val_if_fail (ard != NULL, FALSE);
- if (!xpath_prop_prefix) {
- } else if (status_code == SOUP_STATUS_OK &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/D:acl-restrictions", xpath_prop_prefix)) {
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:acl-restrictions/D:grant-only",
xpath_prop_prefix))
+ if (status_code != SOUP_STATUS_OK)
+ return TRUE;
+
+ acl_restrictions_node = e_xml_find_child (prop_node, E_WEBDAV_NS_DAV, "acl-restrictions");
+
+ if (acl_restrictions_node) {
+ xmlNodePtr required_principal;
+
+ if (e_xml_find_child (acl_restrictions_node, E_WEBDAV_NS_DAV, "grant-only"))
*ard->out_restrictions |= E_WEBDAV_ACL_RESTRICTION_GRANT_ONLY;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:acl-restrictions/D:no-invert",
xpath_prop_prefix))
+ if (e_xml_find_child (acl_restrictions_node, E_WEBDAV_NS_DAV, "no-invert"))
*ard->out_restrictions |= E_WEBDAV_ACL_RESTRICTION_NO_INVERT;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:acl-restrictions/D:deny-before-grant",
xpath_prop_prefix))
+ if (e_xml_find_child (acl_restrictions_node, E_WEBDAV_NS_DAV, "deny-before-grant"))
*ard->out_restrictions |= E_WEBDAV_ACL_RESTRICTION_DENY_BEFORE_GRANT;
- if (e_xml_xpath_eval_exists (xpath_ctx, "%s/D:acl-restrictions/D:required-principal",
xpath_prop_prefix)) {
- gchar *prefix;
+ required_principal = e_xml_find_child (acl_restrictions_node, E_WEBDAV_NS_DAV,
"required-principal");
+ if (required_principal) {
*ard->out_restrictions |= E_WEBDAV_ACL_RESTRICTION_REQUIRED_PRINCIPAL;
-
- prefix = g_strdup_printf ("%s/D:acl-restrictions/D:required-principal",
xpath_prop_prefix);
- *ard->out_principal_kind = e_webdav_session_extract_acl_principal (xpath_ctx, prefix,
NULL, ard->out_principal_hrefs);
- g_free (prefix);
+ *ard->out_principal_kind = e_webdav_session_extract_acl_principal
(required_principal, NULL, ard->out_principal_hrefs);
}
}
@@ -4825,39 +4706,35 @@ e_webdav_session_get_acl_restrictions_sync (EWebDAVSession *webdav,
static gboolean
e_webdav_session_principal_collection_set_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
gpointer user_data)
{
GSList **out_principal_hrefs = user_data;
+ xmlNodePtr principal_collection_set;
- g_return_val_if_fail (xpath_ctx != NULL, FALSE);
+ g_return_val_if_fail (prop_node != NULL, FALSE);
g_return_val_if_fail (out_principal_hrefs != NULL, FALSE);
- if (!xpath_prop_prefix) {
- } else if (status_code == SOUP_STATUS_OK &&
- e_xml_xpath_eval_exists (xpath_ctx, "%s/D:principal-collection-set", xpath_prop_prefix)) {
- xmlXPathObjectPtr xpath_obj;
-
- xpath_obj = e_xml_xpath_eval (xpath_ctx, "%s/D:principal-collection-set/D:href",
xpath_prop_prefix);
+ if (status_code != SOUP_STATUS_OK)
+ return TRUE;
- if (xpath_obj) {
- gint ii, length;
+ principal_collection_set = e_xml_find_child (prop_node, E_WEBDAV_NS_DAV, "principal-collection-set");
- length = xmlXPathNodeSetGetLength (xpath_obj->nodesetval);
+ if (principal_collection_set) {
+ xmlNodePtr node;
- for (ii = 0; ii < length; ii++) {
- gchar *got_href;
+ for (node = e_xml_find_child (principal_collection_set, E_WEBDAV_NS_DAV, "href");
+ node;
+ node = e_xml_find_next_sibling (node, E_WEBDAV_NS_DAV, "href")) {
+ const xmlChar *got_href;
- got_href = e_xml_xpath_eval_as_string (xpath_ctx,
"%s/D:principal-collection-set/D:href[%d]", xpath_prop_prefix, ii + 1);
- if (got_href)
- *out_principal_hrefs = g_slist_prepend (*out_principal_hrefs,
got_href);
- }
+ got_href = e_xml_get_node_text (node);
- xmlXPathFreeObject (xpath_obj);
+ if (got_href && *got_href)
+ *out_principal_hrefs = g_slist_prepend (*out_principal_hrefs, g_strdup
((const gchar *) got_href));
}
}
@@ -5091,40 +4968,38 @@ e_webdav_session_set_acl_sync (EWebDAVSession *webdav,
static gboolean
e_webdav_session_principal_property_search_cb (EWebDAVSession *webdav,
- xmlXPathContextPtr xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
gpointer user_data)
{
GSList **out_principals = user_data;
+ EWebDAVResource *resource;
+ gchar *display_name;
g_return_val_if_fail (out_principals != NULL, FALSE);
- if (!xpath_prop_prefix) {
- } else if (status_code == SOUP_STATUS_OK) {
- EWebDAVResource *resource;
- gchar *display_name;
-
- display_name = e_webdav_session_extract_nonempty (xpath_ctx, xpath_prop_prefix,
"D:displayname", NULL);
-
- resource = e_webdav_resource_new (
- E_WEBDAV_RESOURCE_KIND_PRINCIPAL,
- 0, /* supports */
- href,
- NULL, /* etag */
- NULL, /* display_name */
- NULL, /* content_type */
- 0, /* content_length */
- 0, /* creation_date */
- 0, /* last_modified */
- NULL, /* description */
- NULL); /* color */
- resource->display_name = display_name;
+ if (status_code != SOUP_STATUS_OK)
+ return TRUE;
- *out_principals = g_slist_prepend (*out_principals, resource);
- }
+ display_name = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_DAV, "displayname", NULL,
NULL);
+
+ resource = e_webdav_resource_new (
+ E_WEBDAV_RESOURCE_KIND_PRINCIPAL,
+ 0, /* supports */
+ href,
+ NULL, /* etag */
+ NULL, /* display_name */
+ NULL, /* content_type */
+ 0, /* content_length */
+ 0, /* creation_date */
+ 0, /* last_modified */
+ NULL, /* description */
+ NULL); /* color */
+ resource->display_name = display_name;
+
+ *out_principals = g_slist_prepend (*out_principals, resource);
return TRUE;
}
diff --git a/src/libedataserver/e-webdav-session.h b/src/libedataserver/e-webdav-session.h
index 418d30c0c..c45d3c70c 100644
--- a/src/libedataserver/e-webdav-session.h
+++ b/src/libedataserver/e-webdav-session.h
@@ -154,8 +154,7 @@ typedef enum {
/**
* EWebDAVPropstatTraverseFunc:
* @webdav: an #EWebDAVSession
- * @xpath_ctx: an #xmlXPathContextPtr
- * @xpath_prop_prefix: (nullable): an XPath prefix for the current prop element, without trailing forward
slash
+ * @prop_node: an #xmlNodePtr
* @request_uri: a #SoupURI, containing the request URI, maybe redirected by the server
* @href: (nullable): a full URI to which the property belongs, or %NULL, when not found
* @status_code: an HTTP status code for this property
@@ -165,18 +164,15 @@ typedef enum {
* e_webdav_session_report_sync() and other XML response with DAV:propstat
* elements traversal functions.
*
- * The @xpath_prop_prefix can be %NULL only once, for the first time,
- * which is meant to let the caller setup the @xpath_ctx, like to register
- * its own namespaces to it with e_xml_xpath_context_register_namespaces().
- * All other invocations of the function will have @xpath_prop_prefix non-%NULL.
+ * The @prop_node points to the actual property (prop) node and it can be examined
+ * with e_xml_find_child(), e_xml_find_children_nodes() and other provided XML helper functions.
*
* Returns: %TRUE to continue traversal of the returned response, %FALSE otherwise.
*
* Since: 3.26
**/
typedef gboolean (* EWebDAVPropstatTraverseFunc) (EWebDAVSession *webdav,
- xmlXPathContext *xpath_ctx,
- const gchar *xpath_prop_prefix,
+ xmlNodePtr prop_node,
const SoupURI *request_uri,
const gchar *href,
guint status_code,
diff --git a/src/libedataserver/e-xml-utils.c b/src/libedataserver/e-xml-utils.c
index 4d58142dd..0c50144f9 100644
--- a/src/libedataserver/e-xml-utils.c
+++ b/src/libedataserver/e-xml-utils.c
@@ -470,3 +470,369 @@ e_xml_xpath_eval_exists (xmlXPathContext *xpath_ctx,
return TRUE;
}
+
+/**
+ * e_xml_is_element_name: (skip)
+ * @node: (nullable): an #xmlNodePtr
+ * @ns_href: (nullable): a namespace href the node should have set, or %NULL for none namespace
+ * @name: an element name to search for
+ *
+ * Returns: Whether the @node is an element node of name @name and with a namespace href set to @ns_href
+ *
+ * Since: 3.38
+ **/
+gboolean
+e_xml_is_element_name (xmlNodePtr node,
+ const gchar *ns_href,
+ const gchar *name)
+{
+ if (!node || node->type != XML_ELEMENT_NODE)
+ return FALSE;
+
+ if (g_strcmp0 ((const gchar *) node->name, name) == 0) {
+ if (!ns_href) {
+ if (!node->ns)
+ return TRUE;
+ } else if (node->ns) {
+ xmlNsPtr nsPtr = xmlSearchNsByHref (node->doc, node, (const xmlChar *) ns_href);
+
+ if (nsPtr && node->ns == nsPtr)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ * e_xml_find_sibling: (skip)
+ * @sibling: (nullable): an #xmlNodePtr, where to start searching
+ * @ns_href: (nullable): a namespace href the node should have set, or %NULL for none namespace
+ * @name: an element name to search for
+ *
+ * Searches the sibling nodes of the @sibling for an element named @name in namespace @ns_href.
+ * It checks the @sibling itself too, but it doesn't check the previous siblings of the @sibling.
+ *
+ * Returns: (transfer none) (nullable): an #xmlNodePtr of the given name, or %NULL, if not found
+ * It also returns %NULL, when the @sibling is %NULL.
+ *
+ * See: e_xml_find_next_sibling(), e_xml_find_child()
+ *
+ * Since: 3.38
+ **/
+xmlNodePtr
+e_xml_find_sibling (xmlNodePtr sibling,
+ const gchar *ns_href,
+ const gchar *name)
+{
+ xmlNodePtr node;
+
+ for (node = sibling; node; node = xmlNextElementSibling (node)) {
+ if (e_xml_is_element_name (node, ns_href, name))
+ break;
+ }
+
+ return node;
+}
+
+/**
+ * e_xml_find_next_sibling: (skip)
+ * @sibling: (nullable): an #xmlNodePtr, where to search from
+ * @ns_href: (nullable): a namespace href the node should have set, or %NULL for none namespace
+ * @name: an element name to search for
+ *
+ * Searches for the next sibling node of the @sibling for an element named @name in namespace @ns_href.
+ * Unlike e_xml_find_sibling(), it skips the @sibling itself.
+ *
+ * Returns: (transfer none) (nullable): an #xmlNodePtr of the given name, or %NULL, if not found
+ * It also returns %NULL, when the @sibling is %NULL.
+ *
+ * See: e_xml_find_sibling(), e_xml_find_child()
+ *
+ * Since: 3.38
+ **/
+xmlNodePtr
+e_xml_find_next_sibling (xmlNodePtr sibling,
+ const gchar *ns_href,
+ const gchar *name)
+{
+ if (!sibling)
+ return NULL;
+
+ return e_xml_find_sibling (sibling->next, ns_href, name);
+}
+
+/**
+ * e_xml_find_child: (skip)
+ * @parent: (nullable): an #xmlNodePtr, parent of which immediate children to search
+ * @ns_href: (nullable): a namespace href the node should have set, or %NULL for none namespace
+ * @name: an element name to search for
+ *
+ * Searches the children nodes of the @parent for an element named @name in namespace @ns_href.
+ *
+ * Returns: (transfer none) (nullable): an #xmlNodePtr of the given name, or %NULL, if not found.
+ * It also returns %NULL, when the @parent is %NULL.
+ *
+ * See: e_xml_find_sibling(), e_xml_find_children_nodes()
+ *
+ * Since: 3.38
+ **/
+xmlNodePtr
+e_xml_find_child (xmlNodePtr parent,
+ const gchar *ns_href,
+ const gchar *name)
+{
+ if (!parent)
+ return NULL;
+
+ return e_xml_find_sibling (parent->children, ns_href, name);
+}
+
+/**
+ * e_xml_dup_node_content: (skip)
+ * @node: (nullable): an #xmlNodePtr
+ *
+ * Duplicates content of the @node. If the @node is %NULL, then the
+ * function does nothing and returns also %NULL.
+ *
+ * Unlike e_xml_get_node_text(), this includes also any element sub-structure
+ * of the @node, if any such exists.
+ *
+ * Returns: (transfer full) (nullable): the @node content as #xmlChar string,
+ * or %NULL, when the content could not be read or was not set. Free
+ * the non-%NULL value with xmlFree(), when no longer needed.
+ *
+ * See: e_xml_find_child_and_dup_content(), e_xml_get_node_text()
+ *
+ * Since: 3.38
+ **/
+xmlChar *
+e_xml_dup_node_content (const xmlNodePtr node)
+{
+ if (!node)
+ return NULL;
+
+ return xmlNodeGetContent (node);
+}
+
+/**
+ * e_xml_find_child_and_dup_content: (skip)
+ * @parent: (nullable): an #xmlNodePtr, parent of which immediate children to search
+ * @ns_href: (nullable): a namespace href the node should have set, or %NULL for none namespace
+ * @name: an element name to search for
+ *
+ * Searches the children nodes of the @parent for an element named @name in namespace @ns_href
+ * and returns its content. This combines e_xml_find_child() and e_xml_dup_node_content() calls.
+ *
+ * Returns: (transfer full) (nullable): the found node content as #xmlChar string,
+ * or %NULL, when the node could not be found or the content could not be read
+ * or was not set. Free the non-%NULL value with xmlFree(), when no longer needed.
+ *
+ * See: e_xml_find_child_and_get_text()
+ *
+ * Since: 3.38
+ **/
+xmlChar *
+e_xml_find_child_and_dup_content (xmlNodePtr parent,
+ const gchar *ns_href,
+ const gchar *name)
+{
+ xmlNodePtr tmp;
+
+ tmp = e_xml_find_child (parent, ns_href, name);
+
+ if (!tmp)
+ return NULL;
+
+ return e_xml_dup_node_content (tmp);
+}
+
+/**
+ * e_xml_get_node_text: (skip)
+ * @node: (nullable): an #xmlNodePtr
+ *
+ * Retrieves content of the @node. If the @node is %NULL, then the
+ * function does nothing and returns also %NULL.
+ *
+ * This is similar to e_xml_dup_node_content(), except it does not
+ * allocate new memory for the string. It also doesn't traverse
+ * the element structure, is returns the first text node's value
+ * only. It can be used to avoid unnecessary allocations, when
+ * reading element values with a single text node as a child.
+ *
+ * Returns: (transfer none) (nullable): The @node content, or %NULL.
+ *
+ * See: e_xml_dup_node_content()
+ *
+ * Since: 3.38
+ **/
+const xmlChar *
+e_xml_get_node_text (const xmlNodePtr node)
+{
+ xmlNodePtr child;
+
+ if (!node)
+ return NULL;
+
+ if (node->type == XML_TEXT_NODE)
+ return node->content;
+
+ for (child = node->children; child; child = child->next) {
+ if (child->type == XML_TEXT_NODE)
+ return child->content;
+ }
+
+ return NULL;
+}
+
+/**
+ * e_xml_find_child_and_get_text: (skip)
+ * @parent: (nullable): an #xmlNodePtr, parent of which immediate children to search
+ * @ns_href: (nullable): a namespace href the node should have set, or %NULL for none namespace
+ * @name: an element name to search for
+ *
+ * Searches the children nodes of the @parent for an element named @name in namespace @ns_href
+ * and returns its text content.
+ *
+ * It combines e_xml_find_child() and e_xml_get_node_text() calls.
+ *
+ * Returns: (transfer none) (nullable): the found node text as #xmlChar string,
+ * or %NULL, when the node could not be found or the content could not be read
+ * or was not set.
+ *
+ * See: e_xml_find_child_and_dup_content(), e_xml_find_children_nodes()
+ *
+ * Since: 3.38
+ **/
+const xmlChar *
+e_xml_find_child_and_get_text (xmlNodePtr parent,
+ const gchar *ns_href,
+ const gchar *name)
+{
+ xmlNodePtr tmp;
+
+ tmp = e_xml_find_child (parent, ns_href, name);
+
+ if (!tmp)
+ return NULL;
+
+ return e_xml_get_node_text (tmp);
+}
+
+/**
+ * e_xml_find_children_nodes: (skip)
+ * @parent: an #xmlNodePtr, whose children to search
+ * @count: how many nodes will be read
+ * @...: triple of arguments describing the nodes and their out variable
+ *
+ * Retrieve multiple nodes in one go, in an efficient way. It can be
+ * quicker than traversing the children of the @parent @count times
+ * in certain circumstances.
+ *
+ * The variable parameters expect triple of:
+ * const gchar *ns_href;
+ * const gchar *name;
+ * xmlNodePtr *out_node;
+ * where the ns_href is a namespace href the node should have set,
+ * or %NULL for none namespace; the name is an element name to search for.
+ * The names should not be included more than once.
+ *
+ * Since: 3.38
+ **/
+void
+e_xml_find_children_nodes (xmlNodePtr parent,
+ guint count,
+ ...)
+{
+ struct _data {
+ const gchar *ns_href;
+ const gchar *name;
+ xmlNodePtr *out_node;
+ } *data;
+ va_list args;
+ xmlNodePtr node;
+ guint ii;
+
+ g_return_if_fail (count > 0);
+
+ data = g_alloca (sizeof (struct _data) * count);
+
+ va_start (args, count);
+
+ for (ii = 0; ii < count; ii++) {
+ data[ii].ns_href = va_arg (args, const gchar *);
+ data[ii].name = va_arg (args, const gchar *);
+ data[ii].out_node = va_arg (args, xmlNodePtr *);
+
+ *(data[ii].out_node) = NULL;
+ }
+
+ va_end (args);
+
+ for (node = parent->children; node; node = count ? xmlNextElementSibling (node) : NULL) {
+ for (ii = 0; ii < count; ii++) {
+ if (e_xml_is_element_name (node, data[ii].ns_href, data[ii].name)) {
+ *(data[ii].out_node) = node;
+ count--;
+
+ if (ii < count)
+ data[ii] = data[count];
+
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * e_xml_find_in_hierarchy: (skip)
+ * @parent: (nullable): an #xmlNodePtr, or %NULL, in which case function does nothing and just returns %NULL
+ * @child_ns_href: (nullable): a namespace href the node should have set, or %NULL for none namespace
+ * @child_name: an element name to search for
+ * @...: a two-%NULL-terminated pair of hierarchy children
+ *
+ * Checks whether the @parent has a hierarchy of children described by pair
+ * of 'ns_href' and 'name'.
+ *
+ * Note: It requires two %NULL-s at the end of the arguments, because the `ns_href' can
+ * be %NULL, thus it could not distinguish between no namespace href and the end of
+ * the hierarchy children, thus it stops only on the 'name' being %NULL.
+ *
+ * Returns: (transfer none) (nullable): an #xmlNodePtr referencing the node in the hierarchy
+ * of the children of the @parent, or %NULL, when no such found.
+ *
+ * Since: 3.38
+ **/
+xmlNodePtr
+e_xml_find_in_hierarchy (xmlNodePtr parent,
+ const gchar *child_ns_href,
+ const gchar *child_name,
+ ...)
+{
+ xmlNodePtr node;
+ va_list va;
+
+ if (!parent)
+ return NULL;
+
+ node = e_xml_find_child (parent, child_ns_href, child_name);
+
+ if (!node)
+ return NULL;
+
+ va_start (va, child_name);
+
+ while (node) {
+ child_ns_href = va_arg (va, const gchar *);
+ child_name = va_arg (va, const gchar *);
+
+ if (!child_name)
+ break;
+
+ node = e_xml_find_child (node, child_ns_href, child_name);
+ }
+
+ va_end (va);
+
+ return child_name ? NULL : node;
+}
diff --git a/src/libedataserver/e-xml-utils.h b/src/libedataserver/e-xml-utils.h
index 41bb70abc..d063ac0c3 100644
--- a/src/libedataserver/e-xml-utils.h
+++ b/src/libedataserver/e-xml-utils.h
@@ -59,6 +59,34 @@ gboolean e_xml_xpath_eval_exists (xmlXPathContext *xpath_ctx,
const gchar *format,
...) G_GNUC_PRINTF (2, 3);
+gboolean e_xml_is_element_name (xmlNodePtr node,
+ const gchar *ns_href,
+ const gchar *name);
+xmlNodePtr e_xml_find_sibling (xmlNodePtr sibling,
+ const gchar *ns_href,
+ const gchar *name);
+xmlNodePtr e_xml_find_next_sibling (xmlNodePtr sibling,
+ const gchar *ns_href,
+ const gchar *name);
+xmlNodePtr e_xml_find_child (xmlNodePtr parent,
+ const gchar *ns_href,
+ const gchar *name);
+xmlChar * e_xml_dup_node_content (const xmlNodePtr node);
+xmlChar * e_xml_find_child_and_dup_content(xmlNodePtr parent,
+ const gchar *ns_href,
+ const gchar *name);
+const xmlChar * e_xml_get_node_text (const xmlNodePtr node);
+const xmlChar * e_xml_find_child_and_get_text (xmlNodePtr parent,
+ const gchar *ns_href,
+ const gchar *name);
+void e_xml_find_children_nodes (xmlNodePtr parent,
+ guint count,
+ ...);
+xmlNodePtr e_xml_find_in_hierarchy (xmlNodePtr parent,
+ const gchar *child_ns_href,
+ const gchar *child_name,
+ ...) G_GNUC_NULL_TERMINATED; /* requires two NULL-s at the
end of the arguments */
+
G_END_DECLS
#endif /* E_XML_UTILS_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]