From: Matthew Barnes Date: Mon, 27 Aug 2012 15:44:46 +0000 (-0400) Subject: ESourceWebdav: Add "resource-query" property. X-Git-Tag: upstream/3.7.4~508 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=44d5f2152663d0854dec4b2ee1e73ddd99e93a41;p=platform%2Fupstream%2Fevolution-data-server.git ESourceWebdav: Add "resource-query" property. Retain the query portion of a WebDAV URI, and update migration to preserve it from the old XML-based ESource URIs. Also reimplement the "soup-uri" property. Using bi-directional property bindings from one property to many properties results in feedback loops. Instead, listen for "notify" signals from URI component properties and emit a "notify::soup-uri" signal, but don't actually update the internal SoupURI until a copy is requested. This makes Facebook birthday calendars work again, which has the form: webcal://www.facebook.com/ical/b.php?uid=<>&key=<> --- diff --git a/docs/reference/libedataserver/libedataserver-sections.txt b/docs/reference/libedataserver/libedataserver-sections.txt index a7af852..54f9b28 100644 --- a/docs/reference/libedataserver/libedataserver-sections.txt +++ b/docs/reference/libedataserver/libedataserver-sections.txt @@ -991,6 +991,9 @@ e_source_webdav_set_ignore_invalid_cert e_source_webdav_get_resource_path e_source_webdav_dup_resource_path e_source_webdav_set_resource_path +e_source_webdav_get_resource_query +e_source_webdav_dup_resource_query +e_source_webdav_set_resource_query e_source_webdav_dup_soup_uri e_source_webdav_set_soup_uri e_source_webdav_get_avoid_ifmatch diff --git a/libedataserver/e-source-webdav.c b/libedataserver/e-source-webdav.c index 2a2a017..c624e1b 100644 --- a/libedataserver/e-source-webdav.c +++ b/libedataserver/e-source-webdav.c @@ -59,10 +59,11 @@ struct _ESourceWebdavPrivate { gchar *display_name; gchar *email_address; gchar *resource_path; + gchar *resource_query; gboolean avoid_ifmatch; gboolean calendar_auto_schedule; gboolean ignore_invalid_cert; - SoupURI *uri; + SoupURI *soup_uri; }; enum { @@ -73,6 +74,7 @@ enum { PROP_EMAIL_ADDRESS, PROP_IGNORE_INVALID_CERT, PROP_RESOURCE_PATH, + PROP_RESOURCE_QUERY, PROP_SOUP_URI }; @@ -81,210 +83,142 @@ G_DEFINE_TYPE ( e_source_webdav, E_TYPE_SOURCE_EXTENSION) -static gboolean -source_webdav_host_to_soup_uri (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) +static void +source_webdav_notify_cb (GObject *object, + GParamSpec *pspec, + ESourceWebdav *extension) { - GObject *target; - SoupURI *soup_uri; - const gchar *host; - - host = g_value_get_string (source_value); - - target = g_binding_get_target (binding); - g_return_val_if_fail (E_IS_SOURCE_WEBDAV (target), FALSE); - - soup_uri = e_source_webdav_dup_soup_uri (E_SOURCE_WEBDAV (target)); - soup_uri_set_host (soup_uri, host); - g_value_take_boxed (target_value, soup_uri); - - return TRUE; + g_object_notify (G_OBJECT (extension), "soup-uri"); } static gboolean -source_webdav_soup_uri_to_host (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) +source_webdav_user_to_method (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) { - SoupURI *soup_uri; + const gchar *user; - soup_uri = g_value_get_boxed (source_value); - g_value_set_string (target_value, soup_uri->host); + user = g_value_get_string (source_value); + if (user == NULL || *user == '\0') + g_value_set_string (target_value, "none"); + else + g_value_set_string (target_value, "plain/password"); return TRUE; } -static gboolean -source_webdav_path_to_soup_uri (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) +static void +source_webdav_update_properties_from_soup_uri (ESourceWebdav *webdav_extension) { - GObject *target; + ESource *source; + ESourceExtension *extension; SoupURI *soup_uri; - const gchar *path; + const gchar *extension_name; - path = g_value_get_string (source_value); + /* Do not use e_source_webdav_dup_soup_uri() here. That + * builds the URI from properties we haven't yet updated. */ + g_mutex_lock (webdav_extension->priv->property_lock); + soup_uri = soup_uri_copy (webdav_extension->priv->soup_uri); + g_mutex_unlock (webdav_extension->priv->property_lock); - /* soup_uri_set_path() warns on NULL. */ - if (path == NULL) - path = ""; + extension = E_SOURCE_EXTENSION (webdav_extension); + source = e_source_extension_get_source (extension); - target = g_binding_get_target (binding); - g_return_val_if_fail (E_IS_SOURCE_WEBDAV (target), FALSE); + g_object_set ( + extension, + "resource-path", soup_uri->path, + "resource-query", soup_uri->query, + NULL); - soup_uri = e_source_webdav_dup_soup_uri (E_SOURCE_WEBDAV (target)); - soup_uri_set_path (soup_uri, path); - g_value_take_boxed (target_value, soup_uri); + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + extension = e_source_get_extension (source, extension_name); - return TRUE; -} + g_object_set ( + extension, + "host", soup_uri->host, + "port", soup_uri->port, + "user", soup_uri->user, + NULL); -static gboolean -source_webdav_soup_uri_to_path (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - SoupURI *soup_uri; + extension_name = E_SOURCE_EXTENSION_SECURITY; + extension = e_source_get_extension (source, extension_name); - soup_uri = g_value_get_boxed (source_value); - g_value_set_string (target_value, soup_uri->path); + g_object_set ( + extension, + "secure", (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS), + NULL); - return TRUE; + soup_uri_free (soup_uri); } -static gboolean -source_webdav_port_to_soup_uri (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) +static void +source_webdav_update_soup_uri_from_properties (ESourceWebdav *webdav_extension) { - GObject *target; + ESource *source; + ESourceExtension *extension; SoupURI *soup_uri; + const gchar *extension_name; + gchar *user; + gchar *host; + gchar *path; + gchar *query; guint port; + gboolean secure; - port = g_value_get_uint (source_value); - - target = g_binding_get_target (binding); - g_return_val_if_fail (E_IS_SOURCE_WEBDAV (target), FALSE); - - soup_uri = e_source_webdav_dup_soup_uri (E_SOURCE_WEBDAV (target)); - soup_uri_set_port (soup_uri, port); - g_value_take_boxed (target_value, soup_uri); + extension = E_SOURCE_EXTENSION (webdav_extension); + source = e_source_extension_get_source (extension); - return TRUE; -} + g_object_get ( + extension, + "resource-path", &path, + "resource-query", &query, + NULL); -static gboolean -source_webdav_soup_uri_to_port (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - SoupURI *soup_uri; + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + extension = e_source_get_extension (source, extension_name); - soup_uri = g_value_get_boxed (source_value); - g_value_set_uint (target_value, soup_uri->port); + g_object_get ( + extension, + "user", &user, + "host", &host, + "port", &port, + NULL); - return TRUE; -} + extension_name = E_SOURCE_EXTENSION_SECURITY; + extension = e_source_get_extension (source, extension_name); -static gboolean -source_webdav_secure_to_soup_uri (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - GObject *target; - SoupURI *soup_uri; - gboolean secure; + g_object_get ( + extension, + "secure", &secure, + NULL); - secure = g_value_get_boolean (source_value); + g_mutex_lock (webdav_extension->priv->property_lock); - target = g_binding_get_target (binding); - g_return_val_if_fail (E_IS_SOURCE_WEBDAV (target), FALSE); + soup_uri = webdav_extension->priv->soup_uri; - soup_uri = e_source_webdav_dup_soup_uri (E_SOURCE_WEBDAV (target)); - if (secure) + /* Try not to disturb the scheme, in case it's "webcal" or some + * other non-standard value. But if we have to change it, do it. */ + if (secure && soup_uri->scheme != SOUP_URI_SCHEME_HTTPS) soup_uri_set_scheme (soup_uri, SOUP_URI_SCHEME_HTTPS); - else + if (!secure && soup_uri->scheme == SOUP_URI_SCHEME_HTTPS) soup_uri_set_scheme (soup_uri, SOUP_URI_SCHEME_HTTP); - g_value_take_boxed (target_value, soup_uri); - - return TRUE; -} - -static gboolean -source_webdav_soup_uri_to_secure (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - SoupURI *soup_uri; - gboolean secure; - soup_uri = g_value_get_boxed (source_value); - secure = (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS); - g_value_set_boolean (target_value, secure); - - return TRUE; -} - -static gboolean -source_webdav_user_to_soup_uri (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - GObject *target; - SoupURI *soup_uri; - const gchar *user; - - user = g_value_get_string (source_value); - - target = g_binding_get_target (binding); - g_return_val_if_fail (E_IS_SOURCE_WEBDAV (target), FALSE); - - soup_uri = e_source_webdav_dup_soup_uri (E_SOURCE_WEBDAV (target)); soup_uri_set_user (soup_uri, user); - g_value_take_boxed (target_value, soup_uri); - - return TRUE; -} + soup_uri_set_host (soup_uri, host); + soup_uri_set_port (soup_uri, port); -static gboolean -source_webdav_soup_uri_to_user (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - SoupURI *soup_uri; + /* SoupURI doesn't like NULL paths. */ + soup_uri_set_path (soup_uri, (path != NULL) ? path : ""); - soup_uri = g_value_get_boxed (source_value); - g_value_set_string (target_value, soup_uri->user); + soup_uri_set_query (soup_uri, query); - return TRUE; -} + g_mutex_unlock (webdav_extension->priv->property_lock); -static gboolean -source_webdav_user_to_method (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - const gchar *user; - - user = g_value_get_string (source_value); - if (user == NULL || *user == '\0') - g_value_set_string (target_value, "none"); - else - g_value_set_string (target_value, "plain/password"); - - return TRUE; + g_free (user); + g_free (host); + g_free (path); + g_free (query); } static void @@ -330,6 +264,12 @@ source_webdav_set_property (GObject *object, g_value_get_string (value)); return; + case PROP_RESOURCE_QUERY: + e_source_webdav_set_resource_query ( + E_SOURCE_WEBDAV (object), + g_value_get_string (value)); + return; + case PROP_SOUP_URI: e_source_webdav_set_soup_uri ( E_SOURCE_WEBDAV (object), @@ -389,6 +329,13 @@ source_webdav_get_property (GObject *object, E_SOURCE_WEBDAV (object))); return; + case PROP_RESOURCE_QUERY: + g_value_take_string ( + value, + e_source_webdav_dup_resource_query ( + E_SOURCE_WEBDAV (object))); + return; + case PROP_SOUP_URI: g_value_take_boxed ( value, @@ -412,8 +359,9 @@ source_webdav_finalize (GObject *object) g_free (priv->display_name); g_free (priv->email_address); g_free (priv->resource_path); + g_free (priv->resource_query); - soup_uri_free (priv->uri); + soup_uri_free (priv->soup_uri); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_source_webdav_parent_class)->finalize (object); @@ -423,76 +371,59 @@ static void source_webdav_constructed (GObject *object) { ESource *source; - ESourceExtension *this_extension; - ESourceExtension *other_extension; + ESourceExtension *extension; const gchar *extension_name; /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_source_webdav_parent_class)->constructed (object); - this_extension = E_SOURCE_EXTENSION (object); - source = e_source_extension_get_source (this_extension); + /* XXX I *think* we don't need to worry about disconnecting the + * signals. ESourceExtensions are only added, never removed, + * and they all finalize with their ESource. At least that's + * how it's supposed to work if everyone follows the rules. */ - g_object_bind_property_full ( - this_extension, "resource-path", - this_extension, "soup-uri", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE, - source_webdav_path_to_soup_uri, - source_webdav_soup_uri_to_path, - NULL, (GDestroyNotify) NULL); + extension = E_SOURCE_EXTENSION (object); + source = e_source_extension_get_source (extension); + + g_signal_connect ( + extension, "notify::resource-path", + G_CALLBACK (source_webdav_notify_cb), object); - /* Bind to properties of other extensions for convenience. */ + g_signal_connect ( + extension, "notify::resource-query", + G_CALLBACK (source_webdav_notify_cb), object); extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; - other_extension = e_source_get_extension (source, extension_name); + extension = e_source_get_extension (source, extension_name); - g_object_bind_property_full ( - other_extension, "host", - this_extension, "soup-uri", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE, - source_webdav_host_to_soup_uri, - source_webdav_soup_uri_to_host, - NULL, (GDestroyNotify) NULL); + g_signal_connect ( + extension, "notify::host", + G_CALLBACK (source_webdav_notify_cb), object); - g_object_bind_property_full ( - other_extension, "port", - this_extension, "soup-uri", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE, - source_webdav_port_to_soup_uri, - source_webdav_soup_uri_to_port, - NULL, (GDestroyNotify) NULL); + g_signal_connect ( + extension, "notify::port", + G_CALLBACK (source_webdav_notify_cb), object); - g_object_bind_property_full ( - other_extension, "user", - this_extension, "soup-uri", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE, - source_webdav_user_to_soup_uri, - source_webdav_soup_uri_to_user, - NULL, (GDestroyNotify) NULL); + g_signal_connect ( + extension, "notify::user", + G_CALLBACK (source_webdav_notify_cb), object); + /* This updates the authentication method + * based on whether a user name was given. */ g_object_bind_property_full ( - other_extension, "user", - other_extension, "method", + extension, "user", + extension, "method", G_BINDING_SYNC_CREATE, source_webdav_user_to_method, NULL, NULL, (GDestroyNotify) NULL); extension_name = E_SOURCE_EXTENSION_SECURITY; - other_extension = e_source_get_extension (source, extension_name); + extension = e_source_get_extension (source, extension_name); - g_object_bind_property_full ( - other_extension, "secure", - this_extension, "soup-uri", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE, - source_webdav_secure_to_soup_uri, - source_webdav_soup_uri_to_secure, - NULL, (GDestroyNotify) NULL); + g_signal_connect ( + extension, "notify::secure", + G_CALLBACK (source_webdav_notify_cb), object); } static void @@ -587,6 +518,18 @@ e_source_webdav_class_init (ESourceWebdavClass *class) g_object_class_install_property ( object_class, + PROP_RESOURCE_QUERY, + g_param_spec_string ( + "resource-query", + "Resource Query", + "Query to access a WebDAV resource", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + E_SOURCE_PARAM_SETTING)); + + g_object_class_install_property ( + object_class, PROP_SOUP_URI, g_param_spec_boxed ( "soup-uri", @@ -603,9 +546,9 @@ e_source_webdav_init (ESourceWebdav *extension) extension->priv->property_lock = g_mutex_new (); /* Initialize this enough for SOUP_URI_IS_VALID() to pass. */ - extension->priv->uri = soup_uri_new (NULL); - extension->priv->uri->scheme = SOUP_URI_SCHEME_HTTP; - extension->priv->uri->path = g_strdup (""); + extension->priv->soup_uri = soup_uri_new (NULL); + extension->priv->soup_uri->scheme = SOUP_URI_SCHEME_HTTP; + extension->priv->soup_uri->path = g_strdup (""); } /** @@ -1014,6 +957,100 @@ e_source_webdav_set_resource_path (ESourceWebdav *extension, } /** + * e_source_webdav_get_resource_query: + * @extension: an #ESourceWebdav + * + * Returns the URI query required to access a resource on a WebDAV server. + * + * This is typically used when the #ESourceWebdav:resource-path points not + * to the resource itself but to a web program that generates the resource + * content on-the-fly. The #ESourceWebdav:resource-query holds the input + * values for the program. + * + * Returns: the query to access a WebDAV resource + * + * Since: 3.6 + **/ +const gchar * +e_source_webdav_get_resource_query (ESourceWebdav *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL); + + return extension->priv->resource_query; +} + +/** + * e_source_webdav_dup_resource_query: + * @extension: an #ESourceWebdav + * + * Thread-safe variation of e_source_webdav_get_resource_query(). + * Use this function when accessing @extension from multiple threads. + * + * The returned string should be freed with g_free() when no longer needed. + * + * Returns: the newly-allocated copy of #ESourceWebdav:resource-query + * + * Since: 3.6 + **/ +gchar * +e_source_webdav_dup_resource_query (ESourceWebdav *extension) +{ + const gchar *protected; + gchar *duplicate; + + g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL); + + g_mutex_lock (extension->priv->property_lock); + + protected = e_source_webdav_get_resource_query (extension); + duplicate = g_strdup (protected); + + g_mutex_unlock (extension->priv->property_lock); + + return duplicate; +} + +/** + * e_source_webdav_set_resource_query: + * @extension: an #ESourceWebdav + * @resource_query: (allow-none): the query to access a WebDAV resource, + * or %NULL + * + * Sets the URI query required to access a resource on a WebDAV server. + * + * This is typically used when the #ESourceWebdav:resource-path points not + * to the resource itself but to a web program that generates the resource + * content on-the-fly. The #ESourceWebdav:resource-query holds the input + * values for the program. + * + * The internal copy of @resource_query is automatically stripped of leading + * and trailing whitespace. If the resulting string is empty, %NULL is set + * instead. + * + * Since: 3.6 + **/ +void +e_source_webdav_set_resource_query (ESourceWebdav *extension, + const gchar *resource_query) +{ + g_return_if_fail (E_IS_SOURCE_WEBDAV (extension)); + + g_mutex_lock (extension->priv->property_lock); + + if (g_strcmp0 (extension->priv->resource_query, resource_query) == 0) { + g_mutex_unlock (extension->priv->property_lock); + return; + } + + g_free (extension->priv->resource_query); + extension->priv->resource_query = e_util_strdup_strip (resource_query); + + g_mutex_unlock (extension->priv->property_lock); + + g_object_notify (G_OBJECT (extension), "resource-query"); +} + +/** * e_source_webdav_dup_soup_uri: * @extension: an #ESourceWebdav * @@ -1033,9 +1070,12 @@ e_source_webdav_dup_soup_uri (ESourceWebdav *extension) g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL); + /* Keep this outside of the property lock. */ + source_webdav_update_soup_uri_from_properties (extension); + g_mutex_lock (extension->priv->property_lock); - duplicate = soup_uri_copy (extension->priv->uri); + duplicate = soup_uri_copy (extension->priv->soup_uri); g_mutex_unlock (extension->priv->property_lock); @@ -1045,34 +1085,35 @@ e_source_webdav_dup_soup_uri (ESourceWebdav *extension) /** * e_source_webdav_set_soup_uri: * @extension: an #ESourceWebdav - * @uri: a #SoupURI + * @soup_uri: a #SoupURI * * This is a convenience function which propagates the components of * @uri to the #ESourceAuthentication extension, the #ESourceSecurity - * extension, and @extension itself. (The "query" and "fragment" - * components of @uri are ignored.) + * extension, and @extension itself. (The "fragment" component of + * @uri is ignored.) * * Since: 3.6 **/ void e_source_webdav_set_soup_uri (ESourceWebdav *extension, - SoupURI *uri) + SoupURI *soup_uri) { g_return_if_fail (E_IS_SOURCE_WEBDAV (extension)); - g_return_if_fail (SOUP_URI_IS_VALID (uri)); + g_return_if_fail (SOUP_URI_IS_VALID (soup_uri)); g_mutex_lock (extension->priv->property_lock); - if (extension->priv->uri && soup_uri_equal (extension->priv->uri, uri)) { - g_mutex_unlock (extension->priv->property_lock); - return; - } + /* Do not test for URI equality because our + * internal SoupURI might not be up-to-date. */ - soup_uri_free (extension->priv->uri); - extension->priv->uri = soup_uri_copy (uri); + soup_uri_free (extension->priv->soup_uri); + extension->priv->soup_uri = soup_uri_copy (soup_uri); g_mutex_unlock (extension->priv->property_lock); + g_object_freeze_notify (G_OBJECT (extension)); + source_webdav_update_properties_from_soup_uri (extension); g_object_notify (G_OBJECT (extension), "soup-uri"); + g_object_thaw_notify (G_OBJECT (extension)); } diff --git a/libedataserver/e-source-webdav.h b/libedataserver/e-source-webdav.h index 1e69471..797d238 100644 --- a/libedataserver/e-source-webdav.h +++ b/libedataserver/e-source-webdav.h @@ -115,9 +115,16 @@ gchar * e_source_webdav_dup_resource_path void e_source_webdav_set_resource_path (ESourceWebdav *extension, const gchar *resource_path); +const gchar * e_source_webdav_get_resource_query + (ESourceWebdav *extension); +gchar * e_source_webdav_dup_resource_query + (ESourceWebdav *extension); +void e_source_webdav_set_resource_query + (ESourceWebdav *extension, + const gchar *resource_query); SoupURI * e_source_webdav_dup_soup_uri (ESourceWebdav *extension); void e_source_webdav_set_soup_uri (ESourceWebdav *extension, - SoupURI *uri); + SoupURI *soup_uri); G_END_DECLS diff --git a/services/evolution-source-registry/evolution-source-registry-migrate-sources.c b/services/evolution-source-registry/evolution-source-registry-migrate-sources.c index cabc692..99f8025 100644 --- a/services/evolution-source-registry/evolution-source-registry-migrate-sources.c +++ b/services/evolution-source-registry/evolution-source-registry-migrate-sources.c @@ -2254,6 +2254,12 @@ migrate_parse_caldav_source (ParseData *parse_data) E_SOURCE_EXTENSION_WEBDAV_BACKEND, "ResourcePath", parse_data->soup_uri->path); + if (parse_data->soup_uri->query != NULL) + g_key_file_set_string ( + parse_data->key_file, + E_SOURCE_EXTENSION_WEBDAV_BACKEND, + "ResourceQuery", parse_data->soup_uri->query); + parse_data->property_func = migrate_parse_caldav_property; } @@ -2502,6 +2508,12 @@ migrate_parse_webcal_source (ParseData *parse_data) E_SOURCE_EXTENSION_WEBDAV_BACKEND, "ResourcePath", parse_data->soup_uri->path); + if (parse_data->soup_uri->query != NULL) + g_key_file_set_string ( + parse_data->key_file, + E_SOURCE_EXTENSION_WEBDAV_BACKEND, + "ResourceQuery", parse_data->soup_uri->query); + /* Webcal Backend has no special properties to parse. */ } @@ -2546,6 +2558,12 @@ migrate_parse_webdav_source (ParseData *parse_data) E_SOURCE_EXTENSION_WEBDAV_BACKEND, "ResourcePath", parse_data->soup_uri->path); + if (parse_data->soup_uri->query != NULL) + g_key_file_set_string ( + parse_data->key_file, + E_SOURCE_EXTENSION_WEBDAV_BACKEND, + "ResourceQuery", parse_data->soup_uri->query); + parse_data->property_func = migrate_parse_webdav_property; }