[evolution-kolab/ek-wip-porting] CamelKolabIMAPXConnManager: implemented our own "get_connection" path



commit 61dc29bd277f51a7f5d0f773aff7ca01b891f7b2
Author: Christian Hilberg <hilberg kernelconcepts de>
Date:   Wed Mar 7 16:28:29 2012 +0100

    CamelKolabIMAPXConnManager: implemented our own "get_connection" path
    
    * same as in the parent, we need to implement our own
      code path for getting a connection here
    * otherwise we will not get a CamelKolabIMAPXServer
      when requesting a new server connection, but it's
      parent type
    * moreover, the locking mechanisms will fail since
      they will try to get a connection lock on the
      wrong object

 src/camel/camel-kolab-imapx-conn-manager.c |  155 ++++++++++++++++++++++++----
 src/camel/camel-kolab-imapx-conn-manager.h |    1 -
 2 files changed, 135 insertions(+), 21 deletions(-)
---
diff --git a/src/camel/camel-kolab-imapx-conn-manager.c b/src/camel/camel-kolab-imapx-conn-manager.c
index b9ce755..b2b1c37 100644
--- a/src/camel/camel-kolab-imapx-conn-manager.c
+++ b/src/camel/camel-kolab-imapx-conn-manager.c
@@ -29,15 +29,15 @@
 #include <config.h>
 #endif
 
+#include "camel-kolab-imapx-server.h"
+
 #include "camel-kolab-imapx-conn-manager.h"
 
-/*----------------------------------------------------------------------------*/
+#include <camel/providers/imapx/camel-imapx-conn-manager-defs.h>
+#include <camel/providers/imapx/camel-imapx-conn-manager-friend.h>
+#include <camel/providers/imapx/camel-imapx-extd-conn-manager-friend.h>
 
-/* dupe of enum in camel/providers/imapx/camel-imapx-conn-manager.c */
-enum {
-	PROP_0,
-	PROP_STORE
-};
+/*----------------------------------------------------------------------------*/
 
 G_DEFINE_TYPE (CamelKolabIMAPXConnManager, camel_kolab_imapx_conn_manager, CAMEL_TYPE_IMAPX_EXTD_CONN_MANAGER)
 
@@ -67,6 +67,116 @@ camel_kolab_imapx_conn_manager_finalize (GObject *object)
 }
 
 /*----------------------------------------------------------------------------*/
+/* local statics */
+
+static void
+kolab_imapx_conn_manager_conn_shutdown (CamelIMAPXServer *is,
+                                        CamelIMAPXConnManager *con_man)
+{
+	g_assert (CAMEL_IS_IMAPX_EXTD_SERVER (is));
+	g_assert (CAMEL_IS_IMAPX_EXTD_CONN_MANAGER (con_man));
+
+	camel_imapx_extd_conn_manager_conn_shutdown (is, con_man);
+}
+
+static void
+kolab_imapx_conn_manager_conn_update_select (CamelIMAPXServer *is,
+                                             const gchar *selected_folder,
+                                             CamelIMAPXConnManager *con_man)
+{
+	g_assert (CAMEL_IS_IMAPX_EXTD_SERVER (is));
+	g_assert (selected_folder != NULL);
+	g_assert (CAMEL_IS_IMAPX_EXTD_CONN_MANAGER (con_man));
+
+	camel_imapx_extd_conn_manager_conn_update_select (is,
+	                                                  selected_folder,
+	                                                  con_man);
+}
+
+static CamelIMAPXServer*
+kolab_imapx_conn_manager_new_connection_unlocked (CamelIMAPXConnManager *con_man,
+                                                  const gchar *folder_name,
+                                                  GCancellable *cancellable,
+                                                  GError **error)
+{
+	/* modified dupe of imapx_conn_manager_get_connection() */
+
+	CamelKolabIMAPXServer *ks = NULL;
+	CamelIMAPXServer *is = NULL;
+	CamelIMAPXStore *imapx_store = NULL;
+	CamelStore *store = con_man->priv->store;
+	CamelService *service = NULL;
+	struct _ConnectionInfo *cinfo = NULL;
+	gboolean success = FALSE;
+
+	g_assert (CAMEL_IS_KOLAB_IMAPX_CONN_MANAGER (con_man));
+	/* folder_name may be NULL */
+	/* cancellable may be NULL */
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	/* Caller must be holding CON_WRITE_LOCK. */
+
+	service = CAMEL_SERVICE (store);
+
+	imapx_store = CAMEL_IMAPX_STORE (store);
+
+	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
+
+	/* Check if we got cancelled while we were waiting. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error))
+		goto exit;
+
+	ks = camel_kolab_imapx_server_new (CAMEL_KOLAB_IMAPX_STORE (store));
+	is = CAMEL_IMAPX_SERVER (ks);
+
+	/* XXX As part of the connect operation the CamelIMAPXServer will
+	 *     have to call camel_session_authenticate_sync(), but it has
+	 *     no way to pass itself through in that call so the service
+	 *     knows which CamelIMAPXServer is trying to authenticate.
+	 *
+	 *     IMAPX is the only provider that does multiple connections
+	 *     like this, so I didn't want to pollute the CamelSession and
+	 *     CamelService authentication APIs with an extra argument.
+	 *     Instead we do this little hack so the service knows which
+	 *     CamelIMAPXServer to act on in its authenticate_sync() method.
+	 *
+	 *     Because we're holding the CAMEL_SERVICE_REC_CONNECT_LOCK
+	 *     we should not have multiple IMAPX connections trying to
+	 *     authenticate at once, so this should be thread-safe.
+	 */
+	imapx_store->authenticating_server = g_object_ref (is);
+	success = camel_imapx_extd_server_connect (is, cancellable, error);
+	g_object_unref (imapx_store->authenticating_server);
+	imapx_store->authenticating_server = NULL;
+
+	if (!success) {
+		g_object_unref (ks);
+		is = NULL;
+		goto exit;
+	}
+
+	g_signal_connect (ks, "shutdown",
+	                  G_CALLBACK (kolab_imapx_conn_manager_conn_shutdown), con_man);
+	g_signal_connect (ks, "select_changed",
+	                  G_CALLBACK (kolab_imapx_conn_manager_conn_update_select), con_man);
+
+	cinfo = camel_imapx_conn_manager_connection_info_new (is);
+
+	if (folder_name != NULL)
+		camel_imapx_conn_manager_connection_info_insert_folder_name (cinfo, folder_name);
+
+	/* Takes ownership of the ConnectionInfo. */
+	con_man->priv->connections = g_list_prepend (con_man->priv->connections, cinfo);
+
+	c(is->tagprefix, "Created new connection for %s and total connections %d \n", folder_name, g_list_length (con_man->priv->connections));
+
+ exit:
+	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
+
+	return is;
+}
+
+/*----------------------------------------------------------------------------*/
 /* class functions */
 
 static CamelStore*
@@ -88,27 +198,32 @@ kolab_imapx_conn_manager_get_connection (CamelIMAPXConnManager *self,
                                          GCancellable *cancellable,
                                          GError **err)
 {
-	CamelIMAPXServer *server = NULL;
-	GError *tmp_err = NULL;
+	/* modified dupe of function in parent class */
 
-	g_assert (CAMEL_IS_KOLAB_IMAPX_CONN_MANAGER (self));
-	g_assert (foldername != NULL);
+	CamelIMAPXServer *is = NULL;
+
+	g_return_val_if_fail (CAMEL_IS_KOLAB_IMAPX_CONN_MANAGER (self), NULL);
+	/* foldername may be NULL */
 	/* cancellable may be NULL */
 	g_return_val_if_fail (err == NULL || *err == NULL, NULL);
 
-	server = camel_imapx_extd_conn_manager_get_connection (self,
-	                                                       foldername,
-	                                                       cancellable,
-	                                                       &tmp_err);
-	if (server == NULL) {
-		if (tmp_err != NULL)
-			g_propagate_error (err, tmp_err);
-		return NULL;
+	/* Hold the writer lock while we requisition a CamelIMAPXServer
+	 * to prevent other threads from adding or removing connections. */
+	CON_WRITE_LOCK (self);
+
+	/* Check if we got cancelled while waiting for the lock. */
+	if (!g_cancellable_set_error_if_cancelled (cancellable, err)) {
+		is = camel_imapx_conn_manager_find_connection_unlocked (self, foldername);
+		if (is == NULL)
+			is = kolab_imapx_conn_manager_new_connection_unlocked (self,
+			                                                       foldername,
+			                                                       cancellable,
+			                                                       err);
 	}
 
-	g_assert (CAMEL_IS_KOLAB_IMAPX_SERVER (server));
+	CON_WRITE_UNLOCK (self);
 
-	return server;
+	return is;
 }
 
 static void
diff --git a/src/camel/camel-kolab-imapx-conn-manager.h b/src/camel/camel-kolab-imapx-conn-manager.h
index fd0b2a4..ba38737 100644
--- a/src/camel/camel-kolab-imapx-conn-manager.h
+++ b/src/camel/camel-kolab-imapx-conn-manager.h
@@ -36,7 +36,6 @@
 
 #include <camel/providers/imapx/camel-imapx-extd-conn-manager.h>
 
-#include "camel-kolab-imapx-server.h"
 #include "camel-kolab-imapx-store.h"
 
 /*----------------------------------------------------------------------------*/



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