[evolution-data-server/gnome-3-34] I#145 - WebDAV: Not every 403/Forbidden means wrong credentials



commit 95435817f6d5da565d242dab766ef06a2960c7f0
Author: Milan Crha <mcrha redhat com>
Date:   Mon Sep 9 11:54:41 2019 +0200

    I#145 - WebDAV: Not every 403/Forbidden means wrong credentials
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/issues/145

 .../backends/carddav/e-book-backend-carddav.c      |  22 +-
 .../backends/caldav/e-cal-backend-caldav.c         |  22 +-
 src/libedataserver/e-webdav-session.c              | 231 +++++++++++++++------
 src/libedataserver/e-webdav-session.h              |   3 +
 4 files changed, 213 insertions(+), 65 deletions(-)
---
diff --git a/src/addressbook/backends/carddav/e-book-backend-carddav.c 
b/src/addressbook/backends/carddav/e-book-backend-carddav.c
index 3509229ea..979899a1e 100644
--- a/src/addressbook/backends/carddav/e-book-backend-carddav.c
+++ b/src/addressbook/backends/carddav/e-book-backend-carddav.c
@@ -616,17 +616,33 @@ ebb_carddav_check_credentials_error (EBookBackendCardDAV *bbdav,
                op_error->code = E_CLIENT_ERROR_TLS_NOT_AVAILABLE;
        } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
                   g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
+               gboolean was_forbidden = g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN);
+
                op_error->domain = E_CLIENT_ERROR;
                op_error->code = E_CLIENT_ERROR_AUTHENTICATION_REQUIRED;
 
                if (webdav) {
                        ENamedParameters *credentials;
+                       gboolean empty_credentials;
 
                        credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (webdav));
-                       if (credentials && e_named_parameters_count (credentials) > 0)
-                               op_error->code = E_CLIENT_ERROR_AUTHENTICATION_FAILED;
-
+                       empty_credentials = !credentials || !e_named_parameters_count (credentials);
                        e_named_parameters_free (credentials);
+
+                       if (!empty_credentials) {
+                               if (was_forbidden) {
+                                       if (e_webdav_session_get_last_dav_error_is_permission (webdav)) {
+                                               op_error->code = E_CLIENT_ERROR_PERMISSION_DENIED;
+                                               g_free (op_error->message);
+                                               op_error->message = g_strdup (e_client_error_to_string 
(op_error->code));
+                                       } else {
+                                               /* To avoid credentials prompt */
+                                               op_error->code = E_CLIENT_ERROR_OTHER_ERROR;
+                                       }
+                               } else {
+                                       op_error->code = E_CLIENT_ERROR_AUTHENTICATION_FAILED;
+                               }
+                       }
                }
        }
 }
diff --git a/src/calendar/backends/caldav/e-cal-backend-caldav.c 
b/src/calendar/backends/caldav/e-cal-backend-caldav.c
index 6628d60dd..aabd3cd2d 100644
--- a/src/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/src/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -727,17 +727,33 @@ ecb_caldav_check_credentials_error (ECalBackendCalDAV *cbdav,
                op_error->code = E_CLIENT_ERROR_TLS_NOT_AVAILABLE;
        } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
                   g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
+               gboolean was_forbidden = g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN);
+
                op_error->domain = E_CLIENT_ERROR;
                op_error->code = E_CLIENT_ERROR_AUTHENTICATION_REQUIRED;
 
                if (webdav) {
                        ENamedParameters *credentials;
+                       gboolean empty_credentials;
 
                        credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (webdav));
-                       if (credentials && e_named_parameters_count (credentials) > 0)
-                               op_error->code = E_CLIENT_ERROR_AUTHENTICATION_FAILED;
-
+                       empty_credentials = !credentials || !e_named_parameters_count (credentials);
                        e_named_parameters_free (credentials);
+
+                       if (!empty_credentials) {
+                               if (was_forbidden) {
+                                       if (e_webdav_session_get_last_dav_error_is_permission (webdav)) {
+                                               op_error->code = E_CLIENT_ERROR_PERMISSION_DENIED;
+                                               g_free (op_error->message);
+                                               op_error->message = g_strdup (e_client_error_to_string 
(op_error->code));
+                                       } else {
+                                               /* To avoid credentials prompt */
+                                               op_error->code = E_CLIENT_ERROR_OTHER_ERROR;
+                                       }
+                               } else {
+                                       op_error->code = E_CLIENT_ERROR_AUTHENTICATION_FAILED;
+                               }
+                       }
                }
        }
 }
diff --git a/src/libedataserver/e-webdav-session.c b/src/libedataserver/e-webdav-session.c
index 721eff64e..de0cc29ed 100644
--- a/src/libedataserver/e-webdav-session.c
+++ b/src/libedataserver/e-webdav-session.c
@@ -42,7 +42,7 @@
 #define BUFFER_SIZE 16384
 
 struct _EWebDAVSessionPrivate {
-       gboolean dummy;
+       gchar *last_dav_error_code;
 };
 
 G_DEFINE_TYPE (EWebDAVSession, e_webdav_session, E_TYPE_SOUP_SESSION)
@@ -595,10 +595,26 @@ e_webdav_access_control_entry_get_privileges (EWebDAVAccessControlEntry *ace)
        return ace->privileges;
 }
 
+static void
+e_webdav_session_finalize (GObject *object)
+{
+       EWebDAVSession *webdav = E_WEBDAV_SESSION (object);
+
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_webdav_session_parent_class)->finalize (object);
+}
+
 static void
 e_webdav_session_class_init (EWebDAVSessionClass *klass)
 {
+       GObjectClass *object_class;
+
        g_type_class_add_private (klass, sizeof (EWebDAVSessionPrivate));
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->finalize = e_webdav_session_finalize;
 }
 
 static void
@@ -630,6 +646,48 @@ e_webdav_session_new (ESource *source)
                NULL);
 }
 
+/**
+ * e_webdav_session_get_last_dav_error_code:
+ * @webdav: an #EWebDAVSession
+ *
+ * Returns last DAV error code as returned by the server. Each recognized code
+ * is enclosed in "[]" in the returned string, to be able to distinguish between
+ * them, in case the server returned multiple codes.
+ *
+ * The string is valid until the next request is executed.
+ *
+ * Returns: (transfer none): a DAV error from the last request, or %NULL, when
+ *    no error had been recognized.
+ *
+ * Since: 3.34.1
+ **/
+const gchar *
+e_webdav_session_get_last_dav_error_code (EWebDAVSession *webdav)
+{
+       g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), NULL);
+
+       return webdav->priv->last_dav_error_code;
+}
+
+/**
+ * e_webdav_session_get_last_dav_error_is_permission:
+ * @webdav: an #EWebDAVSession
+ *
+ * Returns: whether the last recognized DAV error code contains an error
+ *    which means that user doesn't have permission for the operation. If there
+ *    is no DAV error stored, then returns %FALSE.
+ *
+ * Since: 3.34.1
+ **/
+gboolean
+e_webdav_session_get_last_dav_error_is_permission (EWebDAVSession *webdav)
+{
+       g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
+
+       return webdav->priv->last_dav_error_code &&
+               strstr (webdav->priv->last_dav_error_code, "[need-privileges]");
+}
+
 /**
  * e_webdav_session_new_request:
  * @webdav: an #EWebDAVSession
@@ -736,7 +794,8 @@ static gboolean
 e_webdav_session_extract_dav_error (EWebDAVSession *webdav,
                                    xmlXPathContextPtr xpath_ctx,
                                    const gchar *xpath_prefix,
-                                   gchar **out_detail_text)
+                                   gchar **out_detail_text,
+                                   gboolean can_change_last_dav_error_code)
 {
        xmlXPathObjectPtr xpath_obj;
        gchar *detail_text;
@@ -764,11 +823,17 @@ e_webdav_session_extract_dav_error (EWebDAVSession *webdav,
 
                        for (node = xpath_obj->nodesetval->nodeTab[0]->children; node; node = node->next) {
                                if (node->type == XML_ELEMENT_NODE &&
-                                   node->name && *(node->name))
+                                   node->name && *(node->name)) {
                                        g_string_append_printf (text, "[%s]", (const gchar *) node->name);
+                               }
                        }
 
                        if (text->len > 0) {
+                               if (can_change_last_dav_error_code) {
+                                       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+                                       webdav->priv->last_dav_error_code = g_strdup (text->str);
+                               }
+
                                if (detail_text) {
                                        g_strstrip (detail_text);
                                        if (*detail_text)
@@ -790,41 +855,14 @@ e_webdav_session_extract_dav_error (EWebDAVSession *webdav,
        return detail_text != NULL;
 }
 
-/**
- * e_webdav_session_replace_with_detailed_error:
- * @webdav: an #EWebDAVSession
- * @request: a #SoupRequestHTTP
- * @response_data: (nullable): received response data, or %NULL
- * @ignore_multistatus: whether to ignore multistatus responses
- * @prefix: (nullable): error message prefix, used when replacing, or %NULL
- * @inout_error: (inout) (nullable) (transfer full): a #GError variable to replace content to, or %NULL
- *
- * Tries to read detailed error information from @response_data,
- * if not provided, then from @request's response_body. If the detailed
- * error cannot be found, then does nothing, otherwise frees the content
- * of @inout_error, if any, and then populates it with an error message
- * prefixed with @prefix.
- *
- * The @prefix might be of form "Failed to something", because the resulting
- * error message will be:
- * "Failed to something: HTTP error code XXX (reason_phrase): detailed_error".
- * When @prefix is %NULL, the error message will be:
- * "Failed with HTTP error code XXX (reason phrase): detailed_error".
- *
- * As the caller might not be interested in errors, also the @inout_error
- * can be %NULL, in which case the function does nothing.
- *
- * Returns: Whether any detailed error had been recognized.
- *
- * Since: 3.26
- **/
-gboolean
-e_webdav_session_replace_with_detailed_error (EWebDAVSession *webdav,
-                                             SoupRequestHTTP *request,
-                                             const GByteArray *response_data,
-                                             gboolean ignore_multistatus,
-                                             const gchar *prefix,
-                                             GError **inout_error)
+static gboolean
+e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
+                                                      SoupRequestHTTP *request,
+                                                      const GByteArray *response_data,
+                                                      gboolean ignore_multistatus,
+                                                      const gchar *prefix,
+                                                      GError **inout_error,
+                                                      gboolean can_change_last_dav_error_code)
 {
        SoupMessage *message;
        GByteArray byte_array = { 0 };
@@ -896,7 +934,7 @@ e_webdav_session_replace_with_detailed_error (EWebDAVSession *webdav,
                                NULL);
 
                        if (xpath_ctx &&
-                           e_webdav_session_extract_dav_error (webdav, xpath_ctx, "", &detail_text)) {
+                           e_webdav_session_extract_dav_error (webdav, xpath_ctx, "", &detail_text, 
can_change_last_dav_error_code)) {
                                /* do nothing, detail_text is set */
                        } else if (xpath_ctx) {
                                const gchar *path_prefix = NULL;
@@ -920,9 +958,9 @@ e_webdav_session_replace_with_detailed_error (EWebDAVSession *webdav,
                                                detail_text = e_xml_xpath_eval_as_string (xpath_ctx, 
"%s/D:responsedescription", path_prefix);
 
                                                if (!detail_text)
-                                                       e_webdav_session_extract_dav_error (webdav, 
xpath_ctx, path_prefix, &detail_text);
+                                                       e_webdav_session_extract_dav_error (webdav, 
xpath_ctx, path_prefix, &detail_text, can_change_last_dav_error_code);
                                        } else {
-                                               e_webdav_session_extract_dav_error (webdav, xpath_ctx, 
path_prefix, &detail_text);
+                                               e_webdav_session_extract_dav_error (webdav, xpath_ctx, 
path_prefix, &detail_text, can_change_last_dav_error_code);
                                        }
 
                                        g_free (status);
@@ -1016,6 +1054,45 @@ e_webdav_session_replace_with_detailed_error (EWebDAVSession *webdav,
        return error_set;
 }
 
+/**
+ * e_webdav_session_replace_with_detailed_error:
+ * @webdav: an #EWebDAVSession
+ * @request: a #SoupRequestHTTP
+ * @response_data: (nullable): received response data, or %NULL
+ * @ignore_multistatus: whether to ignore multistatus responses
+ * @prefix: (nullable): error message prefix, used when replacing, or %NULL
+ * @inout_error: (inout) (nullable) (transfer full): a #GError variable to replace content to, or %NULL
+ *
+ * Tries to read detailed error information from @response_data,
+ * if not provided, then from @request's response_body. If the detailed
+ * error cannot be found, then does nothing, otherwise frees the content
+ * of @inout_error, if any, and then populates it with an error message
+ * prefixed with @prefix.
+ *
+ * The @prefix might be of form "Failed to something", because the resulting
+ * error message will be:
+ * "Failed to something: HTTP error code XXX (reason_phrase): detailed_error".
+ * When @prefix is %NULL, the error message will be:
+ * "Failed with HTTP error code XXX (reason phrase): detailed_error".
+ *
+ * As the caller might not be interested in errors, also the @inout_error
+ * can be %NULL, in which case the function does nothing.
+ *
+ * Returns: Whether any detailed error had been recognized.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_webdav_session_replace_with_detailed_error (EWebDAVSession *webdav,
+                                             SoupRequestHTTP *request,
+                                             const GByteArray *response_data,
+                                             gboolean ignore_multistatus,
+                                             const gchar *prefix,
+                                             GError **inout_error)
+{
+       return e_webdav_session_replace_with_detailed_error_internal (webdav, request, response_data, 
ignore_multistatus, prefix, inout_error, FALSE);
+}
+
 /**
  * e_webdav_session_ensure_full_uri:
  * @webdav: an #EWebDAVSession
@@ -1160,6 +1237,8 @@ e_webdav_session_options_sync (EWebDAVSession *webdav,
        *out_capabilities = NULL;
        *out_allows = NULL;
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_OPTIONS, uri, error);
        if (!request)
                return FALSE;
@@ -1239,6 +1318,8 @@ e_webdav_session_post_with_content_type_sync (EWebDAVSession *webdav,
        if (data_length == (gsize) -1)
                data_length = strlen (data);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_POST, uri, error);
        if (!request)
                return FALSE;
@@ -1256,7 +1337,7 @@ e_webdav_session_post_with_content_type_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, TRUE, _("Failed to 
post data"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, TRUE, 
_("Failed to post data"), error, TRUE) &&
                bytes != NULL;
 
        if (success) {
@@ -1368,6 +1449,8 @@ e_webdav_session_propfind_sync (EWebDAVSession *webdav,
                g_return_val_if_fail (E_IS_XML_DOCUMENT (xml), FALSE);
        g_return_val_if_fail (func != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_PROPFIND, uri, error);
        if (!request)
                return FALSE;
@@ -1402,7 +1485,7 @@ e_webdav_session_propfind_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, TRUE, _("Failed to 
get properties"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, TRUE, 
_("Failed to get properties"), error, TRUE) &&
                bytes != NULL;
 
        if (success)
@@ -1449,6 +1532,8 @@ e_webdav_session_proppatch_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
        g_return_val_if_fail (E_IS_XML_DOCUMENT (xml), FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_PROPPATCH, uri, error);
        if (!request)
                return FALSE;
@@ -1476,7 +1561,7 @@ e_webdav_session_proppatch_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
update properties"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to update properties"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -1550,6 +1635,8 @@ e_webdav_session_report_sync (EWebDAVSession *webdav,
        if (out_content)
                *out_content = NULL;
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, "REPORT", uri, error);
        if (!request)
                return FALSE;
@@ -1580,7 +1667,7 @@ e_webdav_session_report_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, TRUE, _("Failed to 
issue REPORT"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, TRUE, 
_("Failed to issue REPORT"), error, TRUE) &&
                bytes != NULL;
 
        if (success && func && message->status_code == SOUP_STATUS_MULTI_STATUS)
@@ -1633,13 +1720,15 @@ e_webdav_session_mkcol_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
        g_return_val_if_fail (uri != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_MKCOL, uri, error);
        if (!request)
                return FALSE;
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
create collection"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to create collection"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -1687,6 +1776,8 @@ e_webdav_session_mkcol_addressbook_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
        g_return_val_if_fail (uri != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_MKCOL, uri, error);
        if (!request)
                return FALSE;
@@ -1742,7 +1833,7 @@ e_webdav_session_mkcol_addressbook_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
create address book"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to create address book"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -1796,6 +1887,8 @@ e_webdav_session_mkcalendar_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
        g_return_val_if_fail (uri != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, "MKCALENDAR", uri, error);
        if (!request)
                return FALSE;
@@ -1902,7 +1995,7 @@ e_webdav_session_mkcalendar_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
create calendar"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to create calendar"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -1995,6 +2088,8 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (uri != NULL, FALSE);
        g_return_val_if_fail (G_IS_OUTPUT_STREAM (out_stream), FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_GET, uri, error);
        if (!request)
                return FALSE;
@@ -2034,7 +2129,7 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
                                tmp_bytes.data = buffer;
                                tmp_bytes.len = nread;
 
-                               success = !e_webdav_session_replace_with_detailed_error (webdav, request, 
&tmp_bytes, FALSE, _("Failed to read resource"), error);
+                               success = !e_webdav_session_replace_with_detailed_error_internal (webdav, 
request, &tmp_bytes, FALSE, _("Failed to read resource"), error, TRUE);
                                if (!success)
                                        break;
                        }
@@ -2045,7 +2140,7 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
                }
 
                if (success && first_chunk) {
-                       success = !e_webdav_session_replace_with_detailed_error (webdav, request, NULL, 
FALSE, _("Failed to read resource"), error);
+                       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, 
NULL, FALSE, _("Failed to read resource"), error, TRUE);
                } else if (success && !first_chunk && log_level == SOUP_LOGGER_LOG_BODY) {
                        fprintf (stdout, "\n");
                        fflush (stdout);
@@ -2294,6 +2389,8 @@ e_webdav_session_put_sync (EWebDAVSession *webdav,
        if (out_etag)
                *out_etag = NULL;
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_PUT, uri, error);
        if (!request)
                return FALSE;
@@ -2357,7 +2454,7 @@ e_webdav_session_put_sync (EWebDAVSession *webdav,
        g_signal_handler_disconnect (message, wrote_headers_id);
        g_signal_handler_disconnect (message, wrote_chunk_id);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
put data"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to put data"), error, TRUE) &&
                bytes != NULL;
 
        if (cwd.wrote_any && cwd.log_level == SOUP_LOGGER_LOG_BODY) {
@@ -2459,6 +2556,8 @@ e_webdav_session_put_data_sync (EWebDAVSession *webdav,
        if (out_etag)
                *out_etag = NULL;
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_PUT, uri, error);
        if (!request)
                return FALSE;
@@ -2501,7 +2600,7 @@ e_webdav_session_put_data_sync (EWebDAVSession *webdav,
 
        ret_bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, ret_bytes, FALSE, _("Failed 
to put data"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, ret_bytes, FALSE, 
_("Failed to put data"), error, TRUE) &&
                ret_bytes != NULL;
 
        if (success) {
@@ -2567,6 +2666,8 @@ e_webdav_session_delete_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
        g_return_val_if_fail (uri != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_DELETE, uri, error);
        if (!request)
                return FALSE;
@@ -2601,7 +2702,7 @@ e_webdav_session_delete_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
delete resource"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to delete resource"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -2650,6 +2751,8 @@ e_webdav_session_copy_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (destination_uri != NULL, FALSE);
        g_return_val_if_fail (depth != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_COPY, source_uri, error);
        if (!request)
                return FALSE;
@@ -2668,7 +2771,7 @@ e_webdav_session_copy_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
copy resource"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to copy resource"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -2712,6 +2815,8 @@ e_webdav_session_move_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (source_uri != NULL, FALSE);
        g_return_val_if_fail (destination_uri != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_MOVE, source_uri, error);
        if (!request)
                return FALSE;
@@ -2730,7 +2835,7 @@ e_webdav_session_move_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
move resource"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to move resource"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -2790,6 +2895,8 @@ e_webdav_session_lock_sync (EWebDAVSession *webdav,
 
        *out_lock_token = NULL;
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_LOCK, uri, error);
        if (!request)
                return FALSE;
@@ -2835,7 +2942,7 @@ e_webdav_session_lock_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
lock resource"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to lock resource"), error, TRUE) &&
                bytes != NULL;
 
        if (success && out_xml_response) {
@@ -2919,6 +3026,8 @@ e_webdav_session_refresh_lock_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
        g_return_val_if_fail (lock_token != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_LOCK, uri, error);
        if (!request)
                return FALSE;
@@ -2943,7 +3052,7 @@ e_webdav_session_refresh_lock_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
refresh lock"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to refresh lock"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -2986,6 +3095,8 @@ e_webdav_session_unlock_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
        g_return_val_if_fail (lock_token != NULL, FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, SOUP_METHOD_UNLOCK, uri, error);
        if (!request)
                return FALSE;
@@ -3002,7 +3113,7 @@ e_webdav_session_unlock_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, FALSE, _("Failed to 
unlock"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to unlock"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
@@ -4093,6 +4204,8 @@ e_webdav_session_acl_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
        g_return_val_if_fail (E_IS_XML_DOCUMENT (xml), FALSE);
 
+       g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
+
        request = e_webdav_session_new_request (webdav, "ACL", uri, error);
        if (!request)
                return FALSE;
@@ -4120,7 +4233,7 @@ e_webdav_session_acl_sync (EWebDAVSession *webdav,
 
        bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error (webdav, request, bytes, TRUE, _("Failed to 
get access control list"), error) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, TRUE, 
_("Failed to get access control list"), error, TRUE) &&
                bytes != NULL;
 
        if (bytes)
diff --git a/src/libedataserver/e-webdav-session.h b/src/libedataserver/e-webdav-session.h
index a542d0d77..0345e437e 100644
--- a/src/libedataserver/e-webdav-session.h
+++ b/src/libedataserver/e-webdav-session.h
@@ -338,6 +338,9 @@ struct _EWebDAVSessionClass {
 GType          e_webdav_session_get_type               (void) G_GNUC_CONST;
 
 EWebDAVSession *e_webdav_session_new                   (ESource *source);
+const gchar *  e_webdav_session_get_last_dav_error_code(EWebDAVSession *webdav);
+gboolean       e_webdav_session_get_last_dav_error_is_permission
+                                                       (EWebDAVSession *webdav);
 SoupRequestHTTP *
                e_webdav_session_new_request            (EWebDAVSession *webdav,
                                                         const gchar *method,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]