[evolution-ews] Bug 784058 - Ignores Exchange backoff response



commit a05d03daac06dfbeb0b8fea4ae8169dc0ac7ec5f
Author: Milan Crha <mcrha redhat com>
Date:   Mon Jul 10 14:31:06 2017 +0200

    Bug 784058 - Ignores Exchange backoff response

 src/server/e-ews-connection.c |  121 +++++++++++++++++++++++++++++++++++++++--
 1 files changed, 116 insertions(+), 5 deletions(-)
---
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index 0c15ec5..a5f7371 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -700,10 +700,13 @@ ews_active_job_done (EEwsConnection *cnc,
        if (ews_node->cancellable)
                g_object_unref (ews_node->cancellable);
 
-       /* the 'simple' holds reference on 'cnc' and this function
-        * is called in a dedicated thread, which 'cnc' joins on dispose,
-        * thus to avoid race condition, unref the object in its own thread */
-       e_ews_connection_utils_unref_in_thread (ews_node->simple);
+       if (ews_node->simple) {
+               /* the 'simple' holds reference on 'cnc' and this function
+                * is called in a dedicated thread, which 'cnc' joins on dispose,
+                * thus to avoid race condition, unref the object in its own thread */
+               e_ews_connection_utils_unref_in_thread (ews_node->simple);
+       }
+
        g_free (ews_node);
 }
 
@@ -782,7 +785,9 @@ ews_response_cb (SoupSession *session,
 {
        EwsNode *enode = (EwsNode *) data;
        ESoapResponse *response;
+       ESoapParameter *param;
        gint log_level;
+       gint wait_ms = 0;
 
        if (g_cancellable_is_cancelled (enode->cancellable))
                goto exit;
@@ -831,13 +836,119 @@ ews_response_cb (SoupSession *session,
                e_soap_response_dump_response (response, stdout);
        }
 
+       param = e_soap_response_get_first_parameter_by_name (response, "detail", NULL);
+       if (param)
+               param = e_soap_parameter_get_first_child_by_name (param, "ResponseCode");
+       if (param) {
+               gchar *value;
+
+               value = e_soap_parameter_get_string_value (param);
+               if (value && ews_get_error_code (value) == EWS_CONNECTION_ERROR_SERVERBUSY) {
+                       param = e_soap_response_get_first_parameter_by_name (response, "detail", NULL);
+                       if (param)
+                               param = e_soap_parameter_get_first_child_by_name (param, "MessageXml");
+                       if (param) {
+                               param = e_soap_parameter_get_first_child_by_name (param, "Value");
+                               if (param) {
+                                       g_free (value);
+
+                                       value = e_soap_parameter_get_property (param, "Name");
+                                       if (g_strcmp0 (value, "BackOffMilliseconds") == 0) {
+                                               wait_ms = e_soap_parameter_get_int_value (param);
+                                       }
+                               }
+                       }
+               }
+
+               g_free (value);
+       }
+
+       if (wait_ms > 0) {
+               GCancellable *cancellable = enode->cancellable;
+               EFlag *flag;
+
+               if (cancellable)
+                       g_object_ref (cancellable);
+               g_object_ref (msg);
+
+               flag = e_flag_new ();
+               while (wait_ms > 0 && !g_cancellable_is_cancelled (cancellable) && msg->status_code != 
SOUP_STATUS_CANCELLED) {
+                       gint64 now = g_get_monotonic_time ();
+                       gint left_minutes, left_seconds;
+
+                       left_minutes = wait_ms / 60000;
+                       left_seconds = (wait_ms / 1000) % 60;
+
+                       if (left_minutes > 0) {
+                               camel_operation_push_message (cancellable,
+                                       g_dngettext (GETTEXT_PACKAGE,
+                                               "Exchange server is busy, waiting to retry (%d:%02d minute)",
+                                               "Exchange server is busy, waiting to retry (%d:%02d 
minutes)", left_minutes),
+                                       left_minutes, left_seconds);
+                       } else {
+                               camel_operation_push_message (cancellable,
+                                       g_dngettext (GETTEXT_PACKAGE,
+                                               "Exchange server is busy, waiting to retry (%d second)",
+                                               "Exchange server is busy, waiting to retry (%d seconds)", 
left_seconds),
+                                       left_seconds);
+                       }
+
+                       e_flag_wait_until (flag, now + (G_TIME_SPAN_MILLISECOND * (wait_ms > 1000 ? 1000 : 
wait_ms)));
+
+                       now = g_get_monotonic_time () - now;
+                       now = now / G_TIME_SPAN_MILLISECOND;
+
+                       if (now >= wait_ms)
+                               wait_ms = 0;
+                       wait_ms -= now;
+
+                       camel_operation_pop_message (cancellable);
+               }
+
+               e_flag_free (flag);
+
+               g_object_unref (response);
+
+               if (g_cancellable_is_cancelled (cancellable) ||
+                   msg->status_code == SOUP_STATUS_CANCELLED) {
+                       g_clear_object (&cancellable);
+                       g_object_unref (msg);
+               } else {
+                       EwsNode *new_node;
+
+                       new_node = ews_node_new ();
+                       new_node->msg = E_SOAP_MESSAGE (msg); /* takes ownership */
+                       new_node->pri = enode->pri;
+                       new_node->cb = enode->cb;
+                       new_node->cnc = enode->cnc;
+                       new_node->simple = enode->simple;
+
+                       enode->simple = NULL;
+
+                       QUEUE_LOCK (enode->cnc);
+                       enode->cnc->priv->jobs = g_slist_prepend (enode->cnc->priv->jobs, new_node);
+                       QUEUE_UNLOCK (enode->cnc);
+
+                       if (cancellable) {
+                               new_node->cancellable = g_object_ref (cancellable);
+                               new_node->cancel_handler_id = g_cancellable_connect (
+                                       cancellable, G_CALLBACK (ews_cancel_request), new_node, NULL);
+                       }
+
+                       g_clear_object (&cancellable);
+               }
+
+               goto exit;
+       }
+
        if (enode->cb != NULL)
                enode->cb (response, enode->simple);
 
        g_object_unref (response);
 
 exit:
-       g_simple_async_result_complete_in_idle (enode->simple);
+       if (enode->simple)
+               g_simple_async_result_complete_in_idle (enode->simple);
 
        ews_active_job_done (enode->cnc, enode);
 }


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