[evolution-ews/gnome-3-20] Bug 763719 - Reconnect or use its own connection for message send
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews/gnome-3-20] Bug 763719 - Reconnect or use its own connection for message send
- Date: Wed, 23 Mar 2016 14:49:59 +0000 (UTC)
commit 439a8b78351f7be2e867096cc64a518bf0f74780
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]