[evolution-ews/wip/mcrha/soup3] Modify OAL functions



commit e8203acef25d1eb427cd7a882653997415eb95bd
Author: Milan Crha <mcrha redhat com>
Date:   Thu Dec 16 14:05:18 2021 +0100

    Modify OAL functions

 src/EWS/common/e-ews-connection.c | 737 +++++++++++++-------------------------
 src/EWS/common/e-ews-connection.h |   4 +-
 src/EWS/common/e-ews-request.c    |   6 +-
 src/EWS/common/e-soap-request.c   | 157 +++++++-
 src/EWS/common/e-soap-request.h   |  29 ++
 src/EWS/common/e-soap-response.c  |  69 ++--
 src/EWS/common/e-soap-response.h  |   6 +
 7 files changed, 473 insertions(+), 535 deletions(-)
---
diff --git a/src/EWS/common/e-ews-connection.c b/src/EWS/common/e-ews-connection.c
index f5a70f7d..ca442735 100644
--- a/src/EWS/common/e-ews-connection.c
+++ b/src/EWS/common/e-ews-connection.c
@@ -556,22 +556,38 @@ e_ews_connection_send_request_sync (EEwsConnection *cnc,
                }
 
                if (!local_error) {
-                       response = e_soap_response_new ();
+                       ESoapRequestCustomProcessFn custom_process_fn = NULL;
+                       gpointer custom_process_data = NULL;
 
-                       if (!e_soap_response_from_message_sync (response, message, input_stream, cancellable, 
&local_error)) {
-                               g_clear_object (&response);
+                       e_soap_request_get_custom_process_fn (request, &custom_process_fn, 
&custom_process_data);
 
-                               if (!local_error) {
-                                       g_set_error (&local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NORESPONSE,
-                                               _("No response: %s"), soup_message_get_reason_phrase 
(messsage));
-                               }
-                       }
+                       if (custom_process_fn) {
+                               custom_process_fn (request, message, input_stream, custom_process_data, 
&repeat, cancellable, &local_error);
+                       } else {
+                               ESoapResponseProgressFn progress_fn = NULL;
+                               gpointer progress_data = NULL;
+
+                               e_soap_request_get_progress_fn (request, &progress_fn, &progress_data);
+
+                               response = e_soap_response_new ();
 
-                       if (response) {
-                               repeat = e_ews_connection_handle_backoff_policy (cnc, response, cancellable, 
&local_error);
+                               e_soap_response_set_progress_fn (request, progress_fn, progress_data);
 
-                               if (repeat || local_error)
+                               if (!e_soap_response_from_message_sync (response, message, input_stream, 
cancellable, &local_error)) {
                                        g_clear_object (&response);
+
+                                       if (!local_error) {
+                                               g_set_error (&local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NORESPONSE,
+                                                       _("No response: %s"), soup_message_get_reason_phrase 
(messsage));
+                                       }
+                               }
+
+                               if (response) {
+                                       repeat = e_ews_connection_handle_backoff_policy (cnc, response, 
cancellable, &local_error);
+
+                                       if (repeat || local_error)
+                                               g_clear_object (&response);
+                               }
                        }
                }
 
@@ -579,7 +595,7 @@ e_ews_connection_send_request_sync (EEwsConnection *cnc,
                g_clear_object (&message);
        }
 
-       if (local_error) {
+       if (local_error)
                g_propagate_error (error, local_error);
 
        if (response && cnc->priv->version == E_EWS_EXCHANGE_UNKNOWN) {
@@ -2675,14 +2691,12 @@ post_restarted (SoupMessage *msg,
                );
 }
 
-static SoupMessage *
-e_ews_get_msg_for_url (EEwsConnection *cnc,
-                      const gchar *url,
-                       xmlOutputBuffer *buf,
-                       GError **error)
+static ESoapRequest *
+e_ews_create_request_for_url (const gchar *url,
+                             xmlOutputBuffer *buf,
+                             GError **error)
 {
-       SoupMessage *msg;
-       CamelEwsSettings *settings;
+       ESoapRequest *request;
 
        if (url == NULL) {
                g_set_error_literal (
@@ -2691,37 +2705,28 @@ e_ews_get_msg_for_url (EEwsConnection *cnc,
                return NULL;
        }
 
-       msg = soup_message_new (buf != NULL ? "POST" : "GET", url);
-       if (!msg) {
+       request = e_soap_request_new (buf ? SOUP_METHOD_POST : SOUP_METHOD_GET, uri, FALSE, NULL, NULL, NULL);
+       if (!request) {
                g_set_error (
                        error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
                        _("URL ā€œ%sā€ is not valid"), url);
                return NULL;
        }
 
-       if (cnc->priv->source)
-               e_soup_ssl_trust_connect (request, cnc->priv->source);
-
-       settings = e_ews_connection_ref_settings (cnc);
-       e_ews_connection_utils_set_user_agent_header (request, settings);
-       g_clear_object (&settings);
-
-       if (buf != NULL) {
-               soup_message_set_request (
-                       msg, "text/xml; charset=utf-8", SOUP_MEMORY_COPY,
-                       (gchar *)
+       if (buf) {
+               e_soap_request_set_custom_body (request, "text/xml; charset=utf-8",
                        #ifdef LIBXML2_NEW_BUFFER
                        xmlOutputBufferGetContent (buf), xmlOutputBufferGetSize (buf)
                        #else
                        buf->buffer->content, buf->buffer->use
                        #endif
                        );
-               g_signal_connect (
-                       msg, "restarted",
-                       G_CALLBACK (post_restarted), buf);
+       } else {
+               /* No body set for the GET request */
+               e_soap_request_set_custom_body (request, "", NULL, 0);
        }
 
-       return msg;
+       return request;
 }
 
 static void
@@ -2917,11 +2922,11 @@ e_ews_discover_prepare_messages_and_send (GSimpleAsyncResult *simple,
        }
 
        /* Passing a NULL URL string returns NULL. */
-       ad->msgs[0] = e_ews_get_msg_for_url (ad->cnc, url1, ad->buf, &local_error);
-       ad->msgs[1] = e_ews_get_msg_for_url (ad->cnc, url2, ad->buf, local_error ? NULL : &local_error);
-       ad->msgs[2] = e_ews_get_msg_for_url (ad->cnc, url3, ad->buf, local_error ? NULL : &local_error);
-       ad->msgs[3] = e_ews_get_msg_for_url (ad->cnc, url4, ad->buf, local_error ? NULL : &local_error);
-       ad->msgs[4] = e_ews_get_msg_for_url (ad->cnc, url5, ad->buf, local_error ? NULL : &local_error);
+       ad->msgs[0] = e_ews_create_request_for_url (url1, ad->buf, &local_error);
+       ad->msgs[1] = e_ews_create_request_for_url (url2, ad->buf, local_error ? NULL : &local_error);
+       ad->msgs[2] = e_ews_create_request_for_url (url3, ad->buf, local_error ? NULL : &local_error);
+       ad->msgs[3] = e_ews_create_request_for_url (url4, ad->buf, local_error ? NULL : &local_error);
+       ad->msgs[4] = e_ews_create_request_for_url (url5, ad->buf, local_error ? NULL : &local_error);
 
        if (!is_outlook && *domain && (ad->msgs[0] || ad->msgs[1] || ad->msgs[2] || ad->msgs[3] || 
ad->msgs[4])) {
                gchar *tmp;
@@ -2929,7 +2934,7 @@ e_ews_discover_prepare_messages_and_send (GSimpleAsyncResult *simple,
                tmp = g_strdup_printf ("http%s://%s/", use_secure ? "s" : "", domain);
 
                /* Fake SoupMessage, for the autodiscovery with SRV record help */
-               ad->msgs[5] = e_ews_get_msg_for_url (ad->cnc, tmp, ad->buf, local_error ? NULL : 
&local_error);
+               ad->msgs[5] = e_ews_create_request_for_url (tmp, ad->buf, local_error ? NULL : &local_error);
 
                if (ad->msgs[5]) {
                        g_resolver_lookup_service_async (g_resolver_get_default (), "autodiscover", "tcp", 
domain, ad->cancellable,
@@ -3123,49 +3128,28 @@ e_ews_autodiscover_ws_url_finish (CamelEwsSettings *settings,
        return TRUE;
 }
 
-struct _oal_req_data {
-       EEwsConnection *cnc;
-       SoupMessage *soup_message;
-       gchar *oal_id;
-       gchar *oal_element;
+typedef struct _OalRequestData {
+       const gchar *oal_id;
+       const gchar *oal_element;
 
-       GSList *oals;
-       GSList *elements;
+       GSList *oals; /* EwsOAL * */
+       GSList *elements; /* EwsOALDetails */
        gchar *etag;
-
-       GCancellable *cancellable;
-       gulong cancel_id;
-
-       /* for dowloading oal file */
-       gchar *cache_filename;
-       GError *error;
-       ESoapResponseProgressFn progress_fn;
-       gpointer progress_data;
-       gsize response_size;
-       gsize received_size;
-};
+} OalRequestData;
 
 static void
-oal_req_data_free (struct _oal_req_data *data)
+oal_request_data_init (OalRequestData *req_data)
 {
-       /* The SoupMessage is owned by the SoupSession. */
-       g_object_unref (data->cnc);
-
-       g_free (data->oal_id);
-       g_free (data->oal_element);
-       g_free (data->etag);
-
-       g_slist_free_full (data->oals, (GDestroyNotify) ews_oal_free);
-       g_slist_free_full (data->elements, (GDestroyNotify) ews_oal_details_free);
-
-       if (data->cancellable != NULL) {
-               g_cancellable_disconnect (data->cancellable, data->cancel_id);
-               g_object_unref (data->cancellable);
-       }
+       memset (req_data, 0, sizeof (OalRequestData));
+}
 
-       g_free (data->cache_filename);
+static void
+oal_request_data_clear (OalRequestData *req_data)
+{
+       g_free (req_data->etag);
 
-       g_slice_free (struct _oal_req_data, data);
+       g_slist_free_full (req_data->oals, (GDestroyNotify) ews_oal_free);
+       g_slist_free_full (req_data->elements, (GDestroyNotify) ews_oal_details_free);
 }
 
 static gchar *
@@ -3245,114 +3229,77 @@ parse_oal_full_details (xmlNode *node,
 
 /* this is run in cnc->priv->soup_thread */
 static void
-oal_response_cb (SoupSession *soup_session,
-                 SoupMessage *soup_message,
-                 gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-       struct _oal_req_data *data;
+e_ews_process_oal_data_response (ESoupaRequest *request,
+                                SoupMessage *message,
+                                GInputStream *input_stream,
+                                gpointer user_data,
+                                gboolean *out_repeat,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       OalRequestData *req_data = user_data;
+       ESoapResponse *response;
+       ESoapResponseProgressFn progress_fn = NULL;
+       gpointer progress_data = NULL;
        const gchar *etag;
        xmlDoc *doc;
-       xmlNode *node;
 
-       simple = G_SIMPLE_ASYNC_RESULT (user_data);
-       data = g_simple_async_result_get_op_res_gpointer (simple);
+       e_soap_request_get_progress_fn (request, &progress_fn, &progress_data);
 
-       ews_connection_check_ssl_error (data->cnc, soup_message);
+       response = e_soap_response_new ();
 
-       if (ews_connection_credentials_failed (data->cnc, soup_message, simple)) {
-               goto exit;
-       } else if (soup_message->status_code != SOUP_STATUS_OK) {
-               if (soup_message->status_code == SOUP_STATUS_UNAUTHORIZED &&
-                   soup_message_get_response_headers (soup_message)) {
-                       const gchar *diagnostics;
-
-                       diagnostics = soup_message_headers_get_list (soup_message_get_response_headers 
(soup_message), "X-MS-DIAGNOSTICS");
-                       if (diagnostics && strstr (diagnostics, "invalid_grant")) {
-                               g_simple_async_result_set_error (
-                                       simple,
-                                       EWS_CONNECTION_ERROR,
-                                       EWS_CONNECTION_ERROR_ACCESSDENIED,
-                                       "%s", diagnostics);
-                               goto exit;
-                       } else if (diagnostics && *diagnostics) {
-                               g_simple_async_result_set_error (
-                                       simple,
-                                       EWS_CONNECTION_ERROR,
-                                       EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED,
-                                       "%s", diagnostics);
-                               goto exit;
-                       }
-               }
-               g_simple_async_result_set_error (
-                       simple, E_SOUP_SESSION_ERROR,
-                       soup_message->status_code,
-                       "%d %s",
-                       soup_message->status_code,
-                       soup_message->reason_phrase);
-               goto exit;
+       e_soap_response_set_progress_fn (request, progress_fn, progress_data);
+
+       doc = e_soap_response_xmldoc_from_message_sync (response, message, input_stream, cancellable, error);
+
+       g_clear_object (&response);
+
+       if (!doc) {
+               if (error && !*error)
+                       g_set_error_literal (error, EWS_CONNECTION_ERROR, -1, _("Failed to parse oab XML"));
+               return;
        }
 
        etag = soup_message_headers_get_one (soup_message_get_response_headers (soup_message), "ETag");
        if (etag)
-               data->etag = g_strdup (etag);
-
-       doc = xmlReadMemory (
-               soup_message->response_body->data,
-               soup_message->response_body->length,
-               "oab.xml", NULL, 0);
-       if (doc == NULL) {
-               g_simple_async_result_set_error (
-                       simple, EWS_CONNECTION_ERROR, -1,
-                       "%s", _("Failed to parse oab XML"));
-               goto exit;
-       }
+               req_data->etag = g_strdup (etag);
 
        node = xmlDocGetRootElement (doc);
-       if (strcmp ((gchar *) node->name, "OAB") != 0) {
-               g_simple_async_result_set_error (
-                       simple, EWS_CONNECTION_ERROR, -1,
-                       "%s", _("Failed to find <OAB> element\n"));
-               goto exit_doc;
-       }
+       if (strcmp ((gchar *) node->name, "OAB") == 0) {
+               xmlNode *node;
 
-       for (node = node->children; node; node = node->next) {
-               if (node->type == XML_ELEMENT_NODE && strcmp ((gchar *) node->name, "OAL") == 0) {
-                       if (data->oal_id == NULL) {
-                               EwsOAL *oal = g_new0 (EwsOAL, 1);
+               for (node = node->children; node; node = node->next) {
+                       if (node->type == XML_ELEMENT_NODE && strcmp ((gchar *) node->name, "OAL") == 0) {
+                               if (req_data->oal_id == NULL) {
+                                       EwsOAL *oal = g_new0 (EwsOAL, 1);
 
-                               oal->id = get_property (node, "id");
-                               oal->dn = get_property (node, "dn");
-                               oal->name = get_property (node, "name");
+                                       oal->id = get_property (node, "id");
+                                       oal->dn = get_property (node, "dn");
+                                       oal->name = get_property (node, "name");
 
-                               data->oals = g_slist_prepend (data->oals, oal);
-                       } else {
-                               gchar *id = get_property (node, "id");
+                                       req_data->oals = g_slist_prepend (req_data->oals, oal);
+                               } else {
+                                       gchar *id = get_property (node, "id");
+
+                                       if (strcmp (id, req_data->oal_id) == 0) {
+                                               /* parse details of full_details file */
+                                               req_data->elements = parse_oal_full_details (node, 
req_data->oal_element);
 
-                               if (strcmp (id, data->oal_id) == 0) {
-                                       /* parse details of full_details file */
-                                       data->elements = parse_oal_full_details (node, data->oal_element);
+                                               g_free (id);
+                                               break;
+                                       }
 
                                        g_free (id);
-                                       break;
                                }
-
-                               g_free (id);
                        }
                }
-       }
 
-       data->oals = g_slist_reverse (data->oals);
+               req_data->oals = g_slist_reverse (req_data->oals);
+       } else {
+               g_set_error_literal (error, EWS_CONNECTION_ERROR, -1, _("Failed to find <OAB> element\n"));
+       }
 
- exit_doc:
        xmlFreeDoc (doc);
- exit:
-       g_simple_async_result_complete_in_idle (simple);
-       /* This is run in cnc->priv->soup_thread, and the cnc is held by simple, thus
-        * for cases when the complete_in_idle is finished before the unref call, when
-        * the cnc will be left with the last reference and thus cannot join the soup_thread
-        * while still in it, the unref is done in a dedicated thread. */
-       e_ews_connection_utils_unref_in_thread (simple);
 }
 
 static void
@@ -3364,109 +3311,43 @@ ews_cancel_msg (GCancellable *cancellable,
 
 gboolean
 e_ews_connection_get_oal_list_sync (EEwsConnection *cnc,
-                                    GSList **oals,
+                                    GSList **out_oals,
                                     GCancellable *cancellable,
                                     GError **error)
 {
        ESoapRequest *request;
        ESoapResponse *response;
-       gboolean success;
+       OalRequestData req_data;
+       GError *local_error = NULL;
 
        g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (out_oals != NULL, FALSE);
 
-       closure = e_async_closure_new ();
+       *out_oals = NULL;
 
-       e_ews_connection_get_oal_list (
-               cnc, cancellable, e_async_closure_callback, closure);
+       request = e_ews_create_request_for_url (cnc->priv->uri, NULL, error);
 
-       result = e_async_closure_wait (closure);
+       if (!request)
+               return FALSE;
 
-       success = e_ews_connection_get_oal_list_finish (
-               cnc, result, oals, error);
+       oal_request_data_init (&req_data);
 
-       response = e_ews_connection_send_request_sync (cnc, request, cancellable, error);
-
-       if (!response) {
-               g_clear_object (&request);
-               return FALSE;
-       }
+       e_soap_request_set_custom_process_fn (request, e_ews_process_oal_data_response, &req_data);
 
-       success = e_ews_process__response (cnc, response, , error);
+       response = e_ews_connection_send_request_sync (cnc, request, cancellable, &local_error);
+       g_warn_if_fail (response == NULL);
 
        g_clear_object (&request);
        g_clear_object (&response);
 
-       return success;
-}
-
-void
-e_ews_connection_get_oal_list (EEwsConnection *cnc,
-                               GCancellable *cancellable,
-                               GAsyncReadyCallback callback,
-                               gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-       SoupMessage *soup_message;
-       struct _oal_req_data *data;
-       GError *error = NULL;
-
-       g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
+       if (!local_error)
+               *out_oals = g_steal_pointer (&req_data.oals);
 
-       soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->uri, NULL, &error);
+       oal_req_data_clear (&req_data);
 
-       simple = g_simple_async_result_new (
-               G_OBJECT (cnc), callback, user_data,
-               e_ews_connection_get_oal_list);
-
-       if (!soup_message) {
+       if (local_error) {
                g_propagate_error (error, local_error);
-               g_simple_async_result_complete_in_idle (simple);
-               return;
-       }
-
-       data = g_slice_new0 (struct _oal_req_data);
-       data->cnc = g_object_ref (cnc);
-       data->soup_message = soup_message;  /* the session owns this */
-
-       if (G_IS_CANCELLABLE (cancellable)) {
-               data->cancellable = g_object_ref (cancellable);
-               data->cancel_id = g_cancellable_connect (
-                       data->cancellable,
-                       G_CALLBACK (ews_cancel_msg),
-                       data, (GDestroyNotify) NULL);
-       }
-
-       g_simple_async_result_set_op_res_gpointer (
-               simple, data, (GDestroyNotify) oal_req_data_free);
-
-       ews_connection_schedule_queue_message (cnc, soup_message, oal_response_cb, simple);
-}
-
-gboolean
-e_ews_connection_get_oal_list_finish (EEwsConnection *cnc,
-                                      GAsyncResult *result,
-                                      GSList **oals,
-                                      GError **error)
-{
-       GSimpleAsyncResult *simple;
-       struct _oal_req_data *data;
-
-       g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
-
-       g_return_val_if_fail (
-               g_simple_async_result_is_valid (
-               result, G_OBJECT (cnc), e_ews_connection_get_oal_list),
-               FALSE);
-
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-       data = g_simple_async_result_get_op_res_gpointer (simple);
-
-       if (g_simple_async_result_propagate_error (simple, error))
                return FALSE;
-
-       if (oals != NULL) {
-               *oals = data->oals;
-               data->oals = NULL;
        }
 
        return TRUE;
@@ -3484,184 +3365,63 @@ e_ews_connection_get_oal_detail_sync (EEwsConnection *cnc,
 {
        ESoapRequest *request;
        ESoapResponse *response;
-       gboolean success;
+       OalRequestData req_data;
+       gchar *tmp_oal_id = NULL;
+       GError *local_error = NULL;
 
        g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (oal_id, FALSE);
 
-       closure = e_async_closure_new ();
-
-       e_ews_connection_get_oal_detail (
-               cnc, oal_id, oal_element, old_etag,
-               cancellable, e_async_closure_callback, closure);
+       if (out_elements)
+               *out_elements = NULL;
+       if (out_etag)
+               *out_etag = NULL;
 
-       result = e_async_closure_wait (closure);
+       request = e_ews_create_request_for_url (cnc->priv->uri, NULL, error);
 
-       success = e_ews_connection_get_oal_detail_finish (
-               cnc, result, elements, etag, error);
-
-       response = e_ews_connection_send_request_sync (cnc, request, cancellable, error);
-
-       if (!response) {
-               g_clear_object (&request);
+       if (!request)
                return FALSE;
-       }
-
-       success = e_ews_process__response (cnc, response, , error);
-
-       g_clear_object (&request);
-       g_clear_object (&response);
-
-       return success;
-}
-
-void
-e_ews_connection_get_oal_detail (EEwsConnection *cnc,
-                                 const gchar *oal_id,
-                                 const gchar *oal_element,
-                                const gchar *etag,
-                                 GCancellable *cancellable,
-                                 GAsyncReadyCallback callback,
-                                 gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-       SoupMessage *soup_message;
-       struct _oal_req_data *data;
-       gchar *sep;
-       GError *error = NULL;
-
-       g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
-
-       soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->uri, NULL, &error);
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (cnc), callback, user_data,
-               e_ews_connection_get_oal_detail);
-
-       if (!soup_message) {
-               g_propagate_error (error, local_error);
-               g_simple_async_result_complete_in_idle (simple);
-               return;
-       }
-
-       if (etag && *etag)
-               soup_message_headers_replace (soup_message_get_request_headers (soup_message),
-                                             "If-None-Match", etag);
-
-       data = g_slice_new0 (struct _oal_req_data);
-       data->cnc = g_object_ref (cnc);
-       data->soup_message = soup_message;  /* the session owns this */
-       data->oal_id = g_strdup (oal_id);
-       data->oal_element = g_strdup (oal_element);
 
        /* oal_id can be of form "GUID:name", but here is compared only GUID */
-       sep = strchr (data->oal_id, ':');
-       if (sep)
-               *sep = '\0';
+       if (strchr (oal_id, ':')) {
+               gchar *sep;
 
-       if (G_IS_CANCELLABLE (cancellable)) {
-               data->cancellable = g_object_ref (cancellable);
-               data->cancel_id = g_cancellable_connect (
-                       data->cancellable,
-                       G_CALLBACK (ews_cancel_msg),
-                       data, (GDestroyNotify) NULL);
+               tmp_oal_id = g_strdup (oal_id);
+               sep = strchr (tmp_oal_id, ':');
+               if (sep)
+                       *sep = '\0';
        }
 
-       g_simple_async_result_set_op_res_gpointer (
-               simple, data, (GDestroyNotify) oal_req_data_free);
-
-       ews_connection_schedule_queue_message (cnc, soup_message, oal_response_cb, simple);
-}
+       oal_request_data_init (&req_data);
 
-gboolean
-e_ews_connection_get_oal_detail_finish (EEwsConnection *cnc,
-                                        GAsyncResult *result,
-                                        GSList **elements,
-                                       gchar **etag,
-                                        GError **error)
-{
-       GSimpleAsyncResult *simple;
-       struct _oal_req_data *data;
+       req_data.oal_id = tmp_oal_id ? tmp_oal_id : oal_id;
+       req_data.oal_element = oal_element;
 
-       g_return_val_if_fail (cnc != NULL, FALSE);
-       g_return_val_if_fail (
-               g_simple_async_result_is_valid (
-               result, G_OBJECT (cnc), e_ews_connection_get_oal_detail),
-               FALSE);
+       e_soap_request_set_custom_process_fn (request, e_ews_process_oal_data_response, &req_data);
+       e_soap_request_set_etag (request, old_etag);
 
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-       data = g_simple_async_result_get_op_res_gpointer (simple);
+       response = e_ews_connection_send_request_sync (cnc, request, cancellable, &local_error);
+       g_warn_if_fail (response == NULL);
 
-       if (g_simple_async_result_propagate_error (simple, error))
-               return FALSE;
+       g_clear_object (&request);
+       g_clear_object (&response);
+       g_free (tmp_oal_id);
 
-       if (elements != NULL) {
-               *elements = data->elements;
-               data->elements = NULL;
-       }
-       if (etag != NULL) {
-               *etag = data->etag;
-               data->etag = NULL;
+       if (!local_error) {
+               if (out_elements)
+                       *out_elements = g_steal_pointer (&req_data.elements);
+               if (out_etag)
+                       *out_etag = g_steal_pointer (&req_data.etag);
        }
 
-       return TRUE;
+       oal_req_data_clear (&req_data);
 
-}
-
-static void
-oal_download_response_cb (SoupSession *soup_session,
-                          SoupMessage *soup_message,
-                          gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-       struct _oal_req_data *data;
-
-       simple = G_SIMPLE_ASYNC_RESULT (user_data);
-       data = g_simple_async_result_get_op_res_gpointer (simple);
-
-       ews_connection_check_ssl_error (data->cnc, soup_message);
-
-       if (ews_connection_credentials_failed (data->cnc, soup_message, simple)) {
-               g_unlink (data->cache_filename);
-       } else if (soup_message->status_code != SOUP_STATUS_OK) {
-               g_simple_async_result_set_error (
-                       simple, E_SOUP_SESSION_ERROR,
-                       soup_message->status_code,
-                       "%d %s",
-                       soup_message->status_code,
-                       soup_message->reason_phrase);
-               g_unlink (data->cache_filename);
-
-       } else if (data->error != NULL) {
-               g_simple_async_result_take_error (simple, data->error);
-               data->error = NULL;
-               g_unlink (data->cache_filename);
+       if (local_error) {
+               g_propagate_error (error, local_error);
+               return FALSE;
        }
 
-       g_simple_async_result_complete_in_idle (simple);
-       e_ews_connection_utils_unref_in_thread (simple);
-}
-
-static void
-ews_soup_got_headers (SoupMessage *msg,
-                      gpointer user_data)
-{
-       struct _oal_req_data *data = (struct _oal_req_data *) user_data;
-       const gchar *size;
-
-       size = soup_message_headers_get_one (soup_message_get_response_headers (request), "Content-Length");
-
-       if (size)
-               data->response_size = strtol (size, NULL, 10);
-}
-
-static void
-ews_soup_restarted (SoupMessage *msg,
-                    gpointer user_data)
-{
-       struct _oal_req_data *data = (struct _oal_req_data *) user_data;
-
-       data->response_size = 0;
-       data->received_size = 0;
+       return TRUE;
 }
 
 static void
@@ -3697,6 +3457,66 @@ ews_soup_got_chunk (SoupMessage *msg,
        }
 }
 
+typedef struct _DownloadOalData {
+       const gchar *cache_filename;
+       gint fd;
+} DownloadOalData;
+
+#define BUFFER_SIZE 16384
+
+static void
+e_ews_process_download_oal_file_response (ESoupaRequest *request,
+                                         SoupMessage *message,
+                                         GInputStream *input_stream,
+                                         gpointer user_data,
+                                         gboolean *out_repeat,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       DownloadOalData *dod = user_data;
+       ESoapResponseProgressFn progress_fn = NULL;
+       gpointer progress_data = NULL;
+       const gchar *size;
+       gpointer buffer;
+       gsize response_size = 0;
+       gsize response_received = 0;
+       gsize progress_percent = 0;
+       gsize nread = 0;
+
+       g_return_if_fail (dod != NULL);
+       g_return_if_fail (dod->fd != -1);
+
+       e_soap_request_get_progress_fn (request, &progress_fn, &progress_data);
+
+       size = soup_message_headers_get_one (soup_message_get_response_headers (soup_msg), "Content-Length");
+
+       if (size)
+               response_size = g_ascii_strtoll (size, NULL, 10);
+
+       buffer = g_malloc (BUFFER_SIZE);
+
+       while (success = g_input_stream_read_all (input_stream, buffer, BUFFER_SIZE, &nread, cancellable, 
error),
+              success && nread > 0) {
+               response_received += nread;
+
+               if (response_size && progress_fn) {
+                       gint pc = response_received * 100 / response_size;
+                       if (progress_percent != pc) {
+                               progress_percent = pc;
+                               progress_fn (progress_data, progress_percent);
+                       }
+               }
+
+               if (write (dod->fd, (const gchar *) buffer, nread) != nread) {
+                       g_set_error (error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_UNKNOWN,
+                               "Failed to write streaming data to file '%s': %s", dod->cache_filename, 
g_strerror (errno));
+                       break;
+               }
+       }
+
+       g_free (buffer);
+}
+
 gboolean
 e_ews_connection_download_oal_file_sync (EEwsConnection *cnc,
                                          const gchar *cache_filename,
@@ -3707,113 +3527,46 @@ e_ews_connection_download_oal_file_sync (EEwsConnection *cnc,
 {
        ESoapRequest *request;
        ESoapResponse *response;
-       gboolean success;
+       DownloadOalData dod;
+       GError *local_error = NULL;
 
        g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
 
-       closure = e_async_closure_new ();
+       request = e_ews_create_request_for_url (cnc->priv->uri, NULL, error);
 
-       e_ews_connection_download_oal_file (
-               cnc, cache_filename,
-               progress_fn, progress_data, cancellable,
-               e_async_closure_callback, closure);
-
-       result = e_async_closure_wait (closure);
-
-       success = e_ews_connection_download_oal_file_finish (
-               cnc, result, error);
+       if (!request)
+               return FALSE;
 
-       response = e_ews_connection_send_request_sync (cnc, request, cancellable, error);
+       /* Prepare the file */
+       g_unlink (cache_filename);
 
-       if (!response) {
+       dod.cache_filename = cache_filename;
+       dod.fd = g_open (data->cache_filename, O_RDONLY | O_WRONLY | O_APPEND | O_CREAT, 0600);
+       if (dod.fd == -1) {
+               g_set_error (error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_UNKNOWN,
+                       "Failed to open the cache file '%s': %s", cache_filename, g_strerror (errno));
                g_clear_object (&request);
+
                return FALSE;
        }
 
-       success = e_ews_process__response (cnc, response, , error);
+       e_soap_request_set_progress_fn (request, progress_fn, progress_data);
 
-       g_clear_object (&request);
-       g_clear_object (&response);
+       e_soap_request_set_custom_process_fn (request, e_ews_process_download_oal_file_response, &dod);
 
-       return success;
-}
+       response = e_ews_connection_send_request_sync (cnc, request, cancellable, &local_error);
+       g_warn_if_fail (response == NULL);
 
-void
-e_ews_connection_download_oal_file (EEwsConnection *cnc,
-                                    const gchar *cache_filename,
-                                    ESoapResponseProgressFn progress_fn,
-                                    gpointer progress_data,
-                                    GCancellable *cancellable,
-                                    GAsyncReadyCallback callback,
-                                    gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-       SoupMessage *soup_message;
-       struct _oal_req_data *data;
-       GError *error = NULL;
-
-       g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
-
-       soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->uri, NULL, &error);
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (cnc), callback, user_data,
-               e_ews_connection_download_oal_file);
+       g_clear_object (&request);
+       g_clear_object (&response);
+       close (dod.fd);
 
-       if (!soup_message) {
+       if (local_error) {
                g_propagate_error (error, local_error);
-               g_simple_async_result_complete_in_idle (simple);
-               return;
-       }
-
-       data = g_slice_new0 (struct _oal_req_data);
-       data->cnc = g_object_ref (cnc);
-       data->soup_message = soup_message;  /* the session owns this */
-       data->cache_filename = g_strdup (cache_filename);
-       data->progress_fn = progress_fn;
-       data->progress_data = progress_data;
-
-       if (G_IS_CANCELLABLE (cancellable)) {
-               data->cancellable = g_object_ref (cancellable);
-               data->cancel_id = g_cancellable_connect (
-                       data->cancellable,
-                       G_CALLBACK (ews_cancel_msg),
-                       data, (GDestroyNotify) NULL);
+               return FALSE;
        }
 
-       g_simple_async_result_set_op_res_gpointer (
-               simple, data, (GDestroyNotify) oal_req_data_free);
-
-       g_signal_connect (
-               soup_message, "got-headers",
-               G_CALLBACK (ews_soup_got_headers), data);
-       g_signal_connect (
-               soup_message, "got-chunk",
-               G_CALLBACK (ews_soup_got_chunk), data);
-       g_signal_connect (
-               soup_message, "restarted",
-               G_CALLBACK (ews_soup_restarted), data);
-
-       ews_connection_schedule_queue_message (cnc, soup_message, oal_download_response_cb, simple);
-}
-
-gboolean
-e_ews_connection_download_oal_file_finish (EEwsConnection *cnc,
-                                           GAsyncResult *result,
-                                           GError **error)
-{
-       GSimpleAsyncResult *simple;
-
-       g_return_val_if_fail (cnc != NULL, FALSE);
-       g_return_val_if_fail (
-               g_simple_async_result_is_valid (
-               result, G_OBJECT (cnc),
-               e_ews_connection_download_oal_file), FALSE);
-
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-
-       /* Assume success unless a GError is set. */
-       return !g_simple_async_result_propagate_error (simple, error);
+       return TRUE;
 }
 
 const gchar *
diff --git a/src/EWS/common/e-ews-connection.h b/src/EWS/common/e-ews-connection.h
index 6776a0e6..7380e046 100644
--- a/src/EWS/common/e-ews-connection.h
+++ b/src/EWS/common/e-ews-connection.h
@@ -728,7 +728,7 @@ gboolean    e_ews_connection_get_attachments_sync
                                                 GError **error);
 gboolean       e_ews_connection_get_oal_list_sync
                                                (EEwsConnection *cnc,
-                                                GSList **out_oals,
+                                                GSList **out_oals, /* EwsOAL * */
                                                 GCancellable *cancellable,
                                                 GError **error);
 gboolean       e_ews_connection_get_oal_detail_sync
@@ -736,7 +736,7 @@ gboolean    e_ews_connection_get_oal_detail_sync
                                                 const gchar *oal_id,
                                                 const gchar *oal_element,
                                                 const gchar *old_etag,
-                                                GSList **out_elements,
+                                                GSList **out_elements, /* EwsOALDetails * */
                                                 gchar **out_etag,
                                                 GCancellable *cancellable,
                                                 GError **error);
diff --git a/src/EWS/common/e-ews-request.c b/src/EWS/common/e-ews-request.c
index ffa20d05..26dcfb30 100644
--- a/src/EWS/common/e-ews-request.c
+++ b/src/EWS/common/e-ews-request.c
@@ -57,15 +57,13 @@ e_ews_request_new_with_header (CamelEwsSettings *settings,
                                const gchar *attribute_value,
                               EEwsServerVersion server_version,
                                EEwsServerVersion minimum_version,
-                              gboolean force_minimum_version,
-                              gboolean standard_handlers)
+                              gboolean force_minimum_version)
 {
        ESoapRequest *req;
        const gchar *server_ver;
        EEwsServerVersion version;
 
-       req = e_soap_request_new (
-               SOUP_METHOD_POST, uri, FALSE, NULL, NULL, NULL, standard_handlers);
+       req = e_soap_request_new (SOUP_METHOD_POST, uri, FALSE, NULL, NULL, NULL);
        if (req == NULL) {
                g_warning ("%s: Could not build SOAP message for uri '%s'", G_STRFUNC, uri);
                return NULL;
diff --git a/src/EWS/common/e-soap-request.c b/src/EWS/common/e-soap-request.c
index 6e55ac76..9acda9dd 100644
--- a/src/EWS/common/e-soap-request.c
+++ b/src/EWS/common/e-soap-request.c
@@ -23,6 +23,18 @@ struct _ESoapRequestPrivate {
        gchar *method;
        GUri *uri;
 
+       ESoapResponseProgressFn progress_fn;
+       gpointer progress_data;
+
+       ESoapRequestCustomProcessFn custom_process_fn;
+       gpointer custom_process_data;
+
+       gchar *custom_body_content_type;
+       gpointer custom_body_data;
+       gssize custom_body_data_len;
+
+       gchar *etag;
+
        gchar *certificate_pem;
        GTlsCertificateFlags certificate_errors;
 
@@ -47,6 +59,9 @@ soap_request_finalize (GObject *object)
 
        g_clear_pointer (&req->priv->method, g_free);
        g_clear_pointer (&req->priv->uri, g_uri_unref);
+       g_clear_pointer (&req->priv->custom_body_content_type, g_free);
+       g_clear_pointer (&req->priv->custom_body_data, g_free);
+       g_clear_pointer (&req->priv->etag, g_free);
        g_clear_pointer (&req->priv->certificate_pem, g_free);
 
        g_clear_pointer (&req->priv->doc, xmlFreeDoc);
@@ -854,6 +869,30 @@ e_soap_request_get_xml_doc (ESoapRequest *req)
        return req->priv->doc;
 }
 
+void
+e_soap_request_set_progress_fn (ESoapRequest *req,
+                               ESoapResponseProgressFn fn,
+                               gpointer user_data)
+{
+       g_return_if_fail (E_IS_SOAP_REQUEST (req));
+
+       req->priv->progress_fn = fn;
+       req->priv->progress_data = user_data;
+}
+
+void
+e_soap_request_get_progress_fn (ESoapRequest *req,
+                               ESoapResponseProgressFn *out_fn,
+                               gpointer *out_user_data)
+{
+       g_return_if_fail (E_IS_SOAP_REQUEST (req));
+       g_return_if_fail (out_fn != NULL);
+       g_return_if_fail (out_user_data != NULL);
+
+       *out_fn = req->priv->progress_fn;
+       *out_user_data = req->priv->progress_data;
+}
+
 /**
  * e_soap_request_persist:
  * @req: the #ESoapRequest.
@@ -863,6 +902,9 @@ e_soap_request_get_xml_doc (ESoapRequest *req)
  *
  * Writes the serialized XML tree to the #SoupMessage's buffer.
  *
+ * When a custom body was set with e_soap_request_set_custom_body(), then that body
+ * is used instead.
+ *
  * Returns: (nullable) (transfer full): a #SoupMessage containing the SOAP request
  *    as its request body, or %NULL on error.
  */
@@ -873,30 +915,105 @@ e_soap_request_persist (ESoapRequest *req,
                        GError **error)
 {
        SoupMessage *message;
-       xmlChar *body;
-       gint len;
 
-       g_return_if_fail (E_IS_SOAP_REQUEST (req));
+       g_return_val_if_fail (E_IS_SOAP_REQUEST (req), NULL);
 
        message = e_soup_session_new_message_from_uri (soup_session, req->priv->method, req->priv->uri, 
error);
 
        if (!message)
                return NULL;
 
-       xmlDocDumpMemory (req->priv->doc, &body, &len);
-
-       e_soup_session_util_set_message_request_body_from_data (message, FALSE,
-               "text/xml; charset=utf-8", body, len, (GDestroyNotify) xmlFree);
+       if (req->priv->custom_body_content_type) {
+               /* Can use empty string as content_type to indicate no body to be set */
+               if (*req->priv->custom_body_content_type && req->priv->custom_body_data) {
+                       e_soup_session_util_set_message_request_body_from_data (message, TRUE,
+                               req->priv->custom_body_content_type,
+                               req->priv->custom_body_data,
+                               req->priv->custom_body_data_len, NULL);
+               }
+       } else {
+               xmlChar *body;
+               gint len;
+
+               xmlDocDumpMemory (req->priv->doc, &body, &len);
+
+               e_soup_session_util_set_message_request_body_from_data (message, FALSE,
+                       "text/xml; charset=utf-8", body, len, (GDestroyNotify) xmlFree);
+       }
 
        e_ews_connection_utils_set_user_agent_header (message, settings);
 
-       soup_message_headers_replace (
-               soup_message_get_request_headers (message),
-               "Connection", "Keep-Alive");
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Connection", "Keep-Alive");
+
+       if (req->priv->etag && *req->priv->etag)
+               soup_message_headers_replace (soup_message_get_request_headers (soup_message), 
"If-None-Match", req->priv->etag);
 
        return message;
 }
 
+/**
+ * e_soap_request_set_custom_body:
+ * @req: the #ESoapRequest.
+ * @content_type: (optional): content type of the custom body
+ * @body: (optional): the custom message body, or %NULL; ignored when @content_type is %NULL
+ * @body_len: length of the @body; ignored when @content_type is %NULL
+ *
+ * Stores custom body for the request, to be used instead of the SOAP @req content.
+ * The @content_type can be %NULL to unset the custom body, or an empty string to indicate
+ * no body should be set. The @body and @body_len parameters are ignored in these cases,
+ * otherwise they are required.
+ *
+ * This function exists only to make internal API simpler.
+ **/
+void
+e_soap_request_set_custom_body (ESoapRequest *req,
+                               const gchar *content_type,
+                               gconstpointer body,
+                               gsize body_len)
+{
+       g_return_val_if_fail (E_IS_SOAP_REQUEST (req), NULL);
+
+       if (content_type && *content_type)
+               g_return_val_if_fail (body != NULL, NULL);
+
+       g_clear_pointer (&req->priv->custom_body_content_type, g_free);
+       g_clear_pointer (&req->priv->custom_body_data, g_free);
+       req->priv->custom_body_data_len = 0;
+
+       if (content_type) {
+               req->priv->custom_body_content_type = g_strdup (req->priv->custom_body_content_type);
+
+               if (*content_type) {
+                       req->priv->custom_body_data = g_memdup2 (body, body_len);
+                       req->priv->custom_body_data_len = body_len;
+               }
+       }
+}
+
+void
+e_soap_request_set_custom_process_fn (ESoapRequest *req,
+                                     ESoapRequestCustomProcessFn fn,
+                                     gpointer user_data)
+{
+       g_return_if_fail (E_IS_SOAP_REQUEST (req));
+
+       req->priv->custom_process_fn = fn;
+       req->priv->custom_process_data = user_data;
+}
+
+void
+e_soap_request_get_custom_process_fn (ESoapRequest *req,
+                                     ESoapRequestCustomProcessFn *out_fn,
+                                     gpointer *out_user_data)
+{
+       g_return_if_fail (E_IS_SOAP_REQUEST (req));
+       g_return_if_fail (out_fn != NULL);
+       g_return_if_fail (out_user_data != NULL);
+
+       *out_fn = req->priv->custom_process_fn;
+       *out_user_data = req->priv->custom_process_data;
+}
+
 /**
  * e_soap_request_take_tls_error_details:
  * @req: an #ESoapRequest
@@ -952,3 +1069,23 @@ e_soap_request_get_tls_error_details (ESoapRequest *req,
 
        return TRUE;
 }
+
+void
+e_soap_request_set_etag (ESoapRequest *req,
+                        const gchar *etag)
+{
+       g_return_if_fail (E_IS_SOAP_REQUEST (req));
+
+       if (g_strcmp0 (req->priv->etag, etag) != 0) {
+               g_clear_pointer (&req->priv->etag, g_free);
+               req->priv->etag = g_strdup ((etag && *etag) ? etag : NULL);
+       }
+}
+
+const gchar *
+e_soap_request_get_etag (ESoapRequest *req)
+{
+       g_return_val_if_fail (E_IS_SOAP_REQUEST (req), NULL);
+
+       return req->priv->etag;
+}
diff --git a/src/EWS/common/e-soap-request.h b/src/EWS/common/e-soap-request.h
index d716f1a0..e3ac9894 100644
--- a/src/EWS/common/e-soap-request.h
+++ b/src/EWS/common/e-soap-request.h
@@ -35,6 +35,14 @@
 
 G_BEGIN_DECLS
 
+typedef gboolean (* ESoapRequestCustomProcessFn) (ESoupaRequest *request,
+                                                 SoupMessage *message,
+                                                 GInputStream *input_stream,
+                                                 gpointer user_data,
+                                                 gboolean *out_repeat,
+                                                 GCancellable *cancellable,
+                                                 GError **error);
+
 typedef struct _ESoapRequest ESoapRequest;
 typedef struct _ESoapRequestClass ESoapRequestClass;
 typedef struct _ESoapRequestPrivate ESoapRequestPrivate;
@@ -128,10 +136,28 @@ const gchar *     e_soap_request_get_namespace_prefix
                                                (ESoapRequest *req,
                                                 const gchar *ns_uri);
 xmlDocPtr      e_soap_request_get_xml_doc      (ESoapRequest *req);
+void           e_soap_request_set_progress_fn  (ESoapRequest *req,
+                                                ESoapResponseProgressFn fn,
+                                                gpointer user_data);
+void           e_soap_request_get_progress_fn  (ESoapRequest *req,
+                                                ESoapResponseProgressFn *out_fn,
+                                                gpointer *out_user_data);
 SoupMessage *  e_soap_request_persist          (ESoapRequest *req,
                                                 ESoupSession *soup_session,
                                                 CamelEwsSettings *settings,
                                                 GError **error);
+void           e_soap_request_set_custom_body  (ESoapRequest *req,
+                                                const gchar *content_type,
+                                                gconstpointer body,
+                                                gssize body_len);
+void           e_soap_request_set_custom_process_fn
+                                               (ESoapRequest *req,
+                                                ESoapRequestCustomProcessFn fn,
+                                                gpointer user_data);
+void           e_soap_request_get_custom_process_fn
+                                               (ESoapRequest *req,
+                                                ESoapRequestCustomProcessFn *out_fn,
+                                                gpointer *out_user_data);
 void           e_soap_request_take_tls_error_details
                                                (ESoapRequest *req,
                                                 gchar *certificate_pem,
@@ -140,6 +166,9 @@ gboolean    e_soap_request_get_tls_error_details
                                                (ESoapRequest *req,
                                                 const gchar **out_certificate_pem,
                                                 GTlsCertificateFlags *out_certificate_errors);
+void           e_soap_request_set_etag         (ESoapRequest *req,
+                                                const gchar *etag);
+const gchar *  e_soap_request_get_etag         (ESoapRequest *req);
 
 G_END_DECLS
 
diff --git a/src/EWS/common/e-soap-response.c b/src/EWS/common/e-soap-response.c
index 911fe6a5..609d36bb 100644
--- a/src/EWS/common/e-soap-response.c
+++ b/src/EWS/common/e-soap-response.c
@@ -33,9 +33,6 @@ struct _ESoapResponsePrivate {
        gint steal_fd;
 
        /* Progress callbacks */
-       gsize response_size;
-       gsize response_received;
-       gsize progress_percent;
        ESoapProgressFn progress_fn;
        gpointer progress_data;
 };
@@ -378,26 +375,26 @@ soap_sax_characters (gpointer _ctxt,
 
 #define BUFFER_SIZE 16384
 
-gboolean
-e_soap_response_from_message_sync (ESoapResponse *response,
-                                  SoupMessage *msg,
-                                  GInputStream *response_data,
-                                  GCancellable *cancellable,
-                                  GError **error)
+xmlDoc *
+e_soap_response_xmldoc_from_message_sync (ESoapResponse *response,
+                                         SoupMessage *msg,
+                                         GInputStream *response_data,
+                                         GCancellable *cancellable,
+                                         GError **error)
 {
        const gchar *size;
+       xmlDoc xmldoc = NULL;
        gboolean success;
        gpointer buffer;
+       gsize response_size = 0;
+       gsize response_received = 0;
+       gsize progress_percent = 0;
        gsize nread = 0;
 
        g_return_val_if_fail (E_IS_SOAP_RESPONSE (response), FALSE);
        g_return_val_if_fail (SOAP_IS_MESSAGE (msg), FALSE);
        g_return_val_if_fail (G_IS_INPUT_STREAM (response_data), FALSE);
 
-       response->priv->response_size = 0;
-       response->priv->response_received = 0;
-       response->priv->progress_percent = 0;
-
        /* Discard the existing context, if there is one, and start again */
        if (response->priv->ctxt) {
                if (response->priv->ctxt->myDoc)
@@ -414,19 +411,19 @@ e_soap_response_from_message_sync (ESoapResponse *response,
        size = soup_message_headers_get_one (soup_message_get_response_headers (soup_msg), "Content-Length");
 
        if (size)
-               req->priv->response_size = g_ascii_strtoll (size, NULL, 10);
+               response_size = g_ascii_strtoll (size, NULL, 10);
 
        buffer = g_malloc (BUFFER_SIZE);
 
        while (success = g_input_stream_read_all (input_stream, buffer, BUFFER_SIZE, &nread, cancellable, 
error),
               success && nread > 0) {
-               response->priv->response_received += nread;
+               response_received += nread;
 
-               if (response->priv->response_size && response->priv->progress_fn) {
-                       gint pc = response->priv->response_received * 100 / response->priv->response_size;
-                       if (response->priv->progress_percent != pc) {
-                               response->priv->progress_percent = pc;
-                               response->priv->progress_fn (response->priv->progress_data, 
response->priv->progress_percent);
+               if (response_size && response->priv->progress_fn) {
+                       gint pc = response_received * 100 / response_size;
+                       if (progress_percent != pc) {
+                               progress_percent = pc;
+                               response->priv->progress_fn (response->priv->progress_data, progress_percent);
                        }
                }
 
@@ -453,13 +450,6 @@ e_soap_response_from_message_sync (ESoapResponse *response,
 
                        xmlFreeParserCtxt (response->priv->ctxt);
                        response->priv->ctxt = NULL;
-
-                       if (xmldoc) {
-                               success = e_soap_response_from_xmldoc (response, xmldoc);
-                               if (!success)
-                                       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, 
"Received invalid SOAP response");
-                       } else
-                               succeess = FALSE;
                } else {
                        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "No data read");
                        success = FALSE;
@@ -478,6 +468,31 @@ e_soap_response_from_message_sync (ESoapResponse *response,
                response->priv->steal_fd = -1;
        }
 
+       return xmldoc;
+}
+
+gboolean
+e_soap_response_from_message_sync (ESoapResponse *response,
+                                  SoupMessage *msg,
+                                  GInputStream *response_data,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       xmlDoc *xmldoc;
+       gboolean successs = FALSE;
+
+       g_return_val_if_fail (E_IS_SOAP_RESPONSE (response), FALSE);
+       g_return_val_if_fail (SOAP_IS_MESSAGE (msg), FALSE);
+       g_return_val_if_fail (G_IS_INPUT_STREAM (response_data), FALSE);
+
+       xmldoc = e_soap_response_xmldoc_from_message_sync (response, msg, response_data, cancellable, error);
+
+       if (xmldoc) {
+               success = e_soap_response_from_xmldoc (response, xmldoc);
+               if (!success)
+                       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Received invalid 
SOAP response");
+       }
+
        return success;
 }
 
diff --git a/src/EWS/common/e-soap-response.h b/src/EWS/common/e-soap-response.h
index 6849a962..122067f4 100644
--- a/src/EWS/common/e-soap-response.h
+++ b/src/EWS/common/e-soap-response.h
@@ -64,6 +64,12 @@ gboolean     e_soap_response_from_message_sync
                                                 GInputStream *response_data,
                                                 GCancellable *cancellable,
                                                 GError **error);
+xmlDoc *       e_soap_response_xmldoc_from_message_sync
+                                               (ESoapResponse *response,
+                                                SoupMessage *msg,
+                                                GInputStream *response_data,
+                                                GCancellable *cancellable,
+                                                GError **error);
 /* used only with e_soap_response_from_message_sync() */
 void           e_soap_response_store_node_data (ESoapResponse *response,
                                                 const gchar *nodename,


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