[evolution-ews] Bug 763719 - Reconnect or use its own connection for message send



commit c08df7e678fba79ab9c8139a5f0ed20de1eaff28
Author: Milan Crha <mcrha redhat com>
Date:   Wed Mar 23 15:46:43 2016 +0100

    Bug 763719 - Reconnect or use its own connection for message send

 src/camel/camel-ews-transport.c |  204 ++++++++++++++++++++++++++++++++++++++-
 src/camel/camel-ews-transport.h |    4 +-
 2 files changed, 202 insertions(+), 6 deletions(-)
---
diff --git a/src/camel/camel-ews-transport.c b/src/camel/camel-ews-transport.c
index 4c39003..bd8274b 100644
--- a/src/camel/camel-ews-transport.c
+++ b/src/camel/camel-ews-transport.c
@@ -44,6 +44,12 @@
 
 G_DEFINE_TYPE (CamelEwsTransport, camel_ews_transport, CAMEL_TYPE_TRANSPORT)
 
+struct _CamelEwsTransportPrivate
+{
+       GMutex connection_lock;
+       EEwsConnection *connection;
+};
+
 static gboolean
 ews_transport_can_server_side_sent_folder (CamelService *service,
                                           EwsFolderId **folder_id,
@@ -133,16 +139,164 @@ ews_transport_can_server_side_sent_folder (CamelService *service,
        return is_server_side;
 }
 
+static EEwsConnection *
+ews_transport_ref_connection (CamelEwsTransport *ews_transport)
+{
+       EEwsConnection *connection = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_EWS_TRANSPORT (ews_transport), NULL);
+
+       g_mutex_lock (&ews_transport->priv->connection_lock);
+
+       if (ews_transport->priv->connection)
+               connection = g_object_ref (ews_transport->priv->connection);
+
+       g_mutex_unlock (&ews_transport->priv->connection_lock);
+
+       return connection;
+}
+
 static gboolean
 ews_transport_connect_sync (CamelService *service,
-                            GCancellable *cancellable,
-                            GError **error)
+                           GCancellable *cancellable,
+                           GError **error)
 {
+       EEwsConnection *connection;
+       CamelSession *session;
+       CamelSettings *settings;
+       gchar *auth_mech;
+       gboolean success;
+
        /* Chain up to parent's method. */
        if (!CAMEL_SERVICE_CLASS (camel_ews_transport_parent_class)->connect_sync (service, cancellable, 
error))
                return FALSE;
 
-       return TRUE;
+       if (camel_service_get_connection_status (service) == CAMEL_SERVICE_DISCONNECTED)
+               return FALSE;
+
+       connection = ews_transport_ref_connection (CAMEL_EWS_TRANSPORT (service));
+       if (connection) {
+               g_object_unref (connection);
+               return TRUE;
+       }
+
+       session = camel_service_ref_session (service);
+       settings = camel_service_ref_settings (service);
+
+       /* Try running an operation that requires authentication
+        * to make sure we have valid credentials available. */
+       auth_mech = camel_network_settings_dup_auth_mechanism (CAMEL_NETWORK_SETTINGS (settings));
+
+       success = camel_session_authenticate_sync (session, service,
+                          auth_mech ? auth_mech : "NTLM", cancellable, error);
+
+       g_free (auth_mech);
+
+       g_object_unref (session);
+       g_object_unref (settings);
+
+       return success;
+}
+
+static gboolean
+ews_transport_disconnect_sync (CamelService *service,
+                              gboolean clean,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       CamelEwsTransport *ews_transport = CAMEL_EWS_TRANSPORT (service);
+
+       g_mutex_lock (&ews_transport->priv->connection_lock);
+       g_clear_object (&ews_transport->priv->connection);
+       g_mutex_unlock (&ews_transport->priv->connection_lock);
+
+       return CAMEL_SERVICE_CLASS (camel_ews_transport_parent_class)->disconnect_sync (service, clean, 
cancellable, error);
+}
+
+static CamelAuthenticationResult
+ews_transport_authenticate_sync (CamelService *service,
+                                const gchar *mechanism,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       CamelAuthenticationResult result;
+       CamelEwsTransport *ews_transport;
+       CamelSettings *settings;
+       CamelEwsSettings *ews_settings;
+       EEwsConnection *connection;
+       const gchar *password;
+       gchar *hosturl, *new_sync_state = NULL;
+       GSList *folders_created = NULL;
+       GSList *folders_updated = NULL;
+       GSList *folders_deleted = NULL;
+       gboolean includes_last_folder = FALSE;
+       GError *local_error = NULL;
+
+       ews_transport = CAMEL_EWS_TRANSPORT (service);
+
+       password = camel_service_get_password (service);
+
+       settings = camel_service_ref_settings (service);
+
+       ews_settings = CAMEL_EWS_SETTINGS (settings);
+       hosturl = camel_ews_settings_dup_hosturl (ews_settings);
+
+       connection = e_ews_connection_new (hosturl, ews_settings);
+       e_ews_connection_set_password (connection, password);
+
+       g_free (hosturl);
+
+       g_object_unref (settings);
+
+       e_binding_bind_property (
+               service, "proxy-resolver",
+               connection, "proxy-resolver",
+               G_BINDING_SYNC_CREATE);
+
+       /* XXX We need to run some operation that requires authentication
+        *     but does not change any server-side state, so we can check
+        *     the error status and determine if our password is valid.
+        *     David suggested e_ews_connection_sync_folder_hierarchy(),
+        *     since we have to do that eventually anyway. */
+
+       e_ews_connection_sync_folder_hierarchy_sync (connection, EWS_PRIORITY_MEDIUM, NULL,
+               &new_sync_state, &includes_last_folder, &folders_created, &folders_updated, &folders_deleted,
+               cancellable, &local_error);
+
+       g_slist_free_full (folders_created, g_object_unref);
+       g_slist_free_full (folders_updated, g_object_unref);
+       g_slist_free_full (folders_deleted, g_free);
+       g_free (new_sync_state);
+
+       if (g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_UNAVAILABLE)) {
+               local_error->domain = CAMEL_SERVICE_ERROR;
+               local_error->code = CAMEL_SERVICE_ERROR_UNAVAILABLE;
+       }
+
+       if (!local_error) {
+               g_mutex_lock (&ews_transport->priv->connection_lock);
+               g_clear_object (&ews_transport->priv->connection);
+               ews_transport->priv->connection = g_object_ref (connection);
+               g_mutex_unlock (&ews_transport->priv->connection_lock);
+       } else {
+               g_mutex_lock (&ews_transport->priv->connection_lock);
+               g_clear_object (&ews_transport->priv->connection);
+               g_mutex_unlock (&ews_transport->priv->connection_lock);
+       }
+
+       if (!local_error) {
+               result = CAMEL_AUTHENTICATION_ACCEPTED;
+       } else if (g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED)) {
+               g_clear_error (&local_error);
+               result = CAMEL_AUTHENTICATION_REJECTED;
+       } else {
+               g_propagate_error (error, local_error);
+               result = CAMEL_AUTHENTICATION_ERROR;
+       }
+
+       g_object_unref (connection);
+
+       return result;
 }
 
 static gchar *
@@ -251,7 +405,7 @@ ews_send_to_sync (CamelTransport *transport,
                }
        }
 
-       cnc = e_ews_connection_find (host_url, user);
+       cnc = ews_transport_ref_connection (CAMEL_EWS_TRANSPORT (service));
        if (!cnc) {
                g_set_error (
                        error, CAMEL_SERVICE_ERROR,
@@ -281,15 +435,52 @@ exit:
 }
 
 static void
+ews_transport_dispose (GObject *object)
+{
+       CamelEwsTransport *ews_transport;
+
+       ews_transport = CAMEL_EWS_TRANSPORT (object);
+
+       g_mutex_lock (&ews_transport->priv->connection_lock);
+       g_clear_object (&ews_transport->priv->connection);
+       g_mutex_unlock (&ews_transport->priv->connection_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_ews_transport_parent_class)->dispose (object);
+}
+
+static void
+ews_transport_finalize (GObject *object)
+{
+       CamelEwsTransport *ews_transport;
+
+       ews_transport = CAMEL_EWS_TRANSPORT (object);
+
+       g_mutex_clear (&ews_transport->priv->connection_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (camel_ews_transport_parent_class)->finalize (object);
+}
+
+static void
 camel_ews_transport_class_init (CamelEwsTransportClass *class)
 {
+       GObjectClass *object_class;
        CamelServiceClass *service_class;
        CamelTransportClass *transport_class;
 
+       g_type_class_add_private (class, sizeof (CamelEwsTransportPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = ews_transport_dispose;
+       object_class->finalize = ews_transport_finalize;
+
        service_class = CAMEL_SERVICE_CLASS (class);
        service_class->settings_type = CAMEL_TYPE_EWS_SETTINGS;
-       service_class->connect_sync = ews_transport_connect_sync;
        service_class->get_name = ews_transport_get_name;
+       service_class->connect_sync = ews_transport_connect_sync;
+       service_class->disconnect_sync = ews_transport_disconnect_sync;
+       service_class->authenticate_sync = ews_transport_authenticate_sync;
 
        transport_class = CAMEL_TRANSPORT_CLASS (class);
        transport_class->send_to_sync = ews_send_to_sync;
@@ -298,4 +489,7 @@ camel_ews_transport_class_init (CamelEwsTransportClass *class)
 static void
 camel_ews_transport_init (CamelEwsTransport *ews_transport)
 {
+       ews_transport->priv = G_TYPE_INSTANCE_GET_PRIVATE (ews_transport, CAMEL_TYPE_EWS_TRANSPORT, 
CamelEwsTransportPrivate);
+
+       g_mutex_init (&ews_transport->priv->connection_lock);
 }
diff --git a/src/camel/camel-ews-transport.h b/src/camel/camel-ews-transport.h
index 62479d8..4984297 100644
--- a/src/camel/camel-ews-transport.h
+++ b/src/camel/camel-ews-transport.h
@@ -49,10 +49,12 @@ G_BEGIN_DECLS
 
 typedef struct _CamelEwsTransport CamelEwsTransport;
 typedef struct _CamelEwsTransportClass CamelEwsTransportClass;
+typedef struct _CamelEwsTransportPrivate CamelEwsTransportPrivate;
 
 struct _CamelEwsTransport {
        CamelTransport parent;
-       gboolean connected;
+
+       CamelEwsTransportPrivate *priv;
 };
 
 struct _CamelEwsTransportClass {


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