[evolution-kolab/ek-wip-porting: 6/6] E<Cal|Book>BackendKolab: avoid a race condition (fixes #672614)



commit 47a2bdec7d362fbe12ae7efdf6365b10f94cfab2
Author: Christian Hilberg <hilberg kernelconcepts de>
Date:   Thu Mar 22 11:55:30 2012 +0100

    E<Cal|Book>BackendKolab: avoid a race condition (fixes #672614)
    
    * the hash table of KolabMailAccess instances is shared
      by all Kolab backend instances of the same type
      (calendar/address book)
    * access to this data structure is concurrent when
      opening calendars or address books, so we must
      serialize access to it by using a lock

 src/addressbook/e-book-backend-kolab.c |  217 +++++++++++++++-----------------
 src/calendar/e-cal-backend-kolab.c     |  199 +++++++++++++++--------------
 2 files changed, 204 insertions(+), 212 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-kolab.c b/src/addressbook/e-book-backend-kolab.c
index 2ec0f50..a852fe7 100644
--- a/src/addressbook/e-book-backend-kolab.c
+++ b/src/addressbook/e-book-backend-kolab.c
@@ -51,6 +51,7 @@
 /* table of KolabMailAccess objects */
 
 static GHashTable *koma_objects = NULL;
+static GMutex *koma_objects_lock = NULL;
 
 /*----------------------------------------------------------------------------*/
 
@@ -61,7 +62,6 @@ struct _EBookBackendKolabPrivate
 	EBookBackendCache *book_cache;
 	KolabMailAccess *book_koma;
 	gchar *book_uri;
-	GHashTable *koma_table;
 	GHashTable *active_book_views;
 	gboolean auth_received;
 	GError *mode_switch_err;
@@ -206,7 +206,7 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 {
 	EBookBackendKolab *self = NULL;
 	EBookBackendKolabPrivate *priv = NULL;
-	ESource *source = NULL;
+	ESource *esource = NULL;
 	CamelURL *c_url = NULL;
 	KolabSettingsHandler *ksettings = NULL;
 	KolabMailAccess *tmp_koma = NULL;
@@ -216,8 +216,9 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 	gchar *username = NULL;
 	gchar *user_at_server = NULL;
 	gchar *tmp_key = NULL;
-	const gchar *sync_prop = NULL;
+	const gchar *prop_str = NULL;
 	gboolean online = FALSE;
+	gboolean auth_required = FALSE;
 	gboolean ok = FALSE;
 	GError *tmp_err = NULL;
 
@@ -230,47 +231,31 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 	self = E_BOOK_BACKEND_KOLAB (backend);
 	priv = E_BOOK_BACKEND_KOLAB_PRIVATE (self);
 
-	kolab_util_glib_init ();
-	kolab_util_http_init ();
-	/* libcamel
-	 * Curl init may configure the underlying SSL lib,
-	 * but as far as SSL goes, we want Camel to rule here
-	 * TODO check whether Camel session needs to be initialized before or after libcurl.
+	g_mutex_lock (koma_objects_lock);
+
+	/* to trigger eds to pass along username and password, set the property
+	 * "auth" to "true" in the source setting:
+	 * <property name="auth" value="true"/>
+	 * <property name="username" value="..."/>
 	 */
-	ok = kolab_util_camel_init (&tmp_err);
-	if (! ok) {
-		kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
 
-	source = e_backend_get_source (E_BACKEND (backend));
-	if (! E_IS_SOURCE (source)) {
-		/* FIXME is this E_DATA_BOOK_STATUS_NO_SUCH_BOOK ? */
+	esource = e_backend_get_source (E_BACKEND (backend));
+	if (! E_IS_SOURCE (esource)) {
 		/* FIXME mark this as a translatable string */
 		tmp_err = e_data_book_create_error (E_DATA_BOOK_STATUS_OTHER_ERROR,
 		                                    "Could not get ESource for backend");
-		g_propagate_error (error, tmp_err);
-		return;
+		goto exit;
 	}
 
-	priv->book_uri = e_source_get_uri (source);
-	g_debug ("%s()[%u] uri = %s",
-	         __func__, __LINE__, priv->book_uri);
-
+	priv->book_uri = e_source_get_uri (esource);
 	c_url = camel_url_new (priv->book_uri, &tmp_err);
-	if (c_url == NULL) {
-		kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (c_url == NULL)
+		goto exit;
+
 	servername = g_strdup (c_url->host);
 	username = g_strdup (c_url->user);
-	camel_url_free (c_url);
-	g_debug ("%s()[%u] servername = %s",
-	         __func__, __LINE__, servername);
-	g_debug ("%s()[%u]   username = %s",
-	         __func__, __LINE__, username);
+	g_debug ("%s()[%u] servername = %s", __func__, __LINE__, servername);
+	g_debug ("%s()[%u]   username = %s", __func__, __LINE__, username);
 
 	/* Initialize backend cache */
 	if (priv->book_cache != NULL) {
@@ -281,19 +266,18 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 	g_debug (" + Book cache cleaning %s.", ok ? "was successful" : "FAILED");
 
 	/* Prepare data from sync strategy property */
-	sync_prop = e_source_get_property (source, KOLAB_SYNC_STRATEGY_PROP);
-	sync_value = kolab_util_misc_sync_value_from_property (sync_prop);
+	prop_str = e_source_get_property (esource, KOLAB_SYNC_STRATEGY_PROP);
+	sync_value = kolab_util_misc_sync_value_from_property (prop_str);
 	sourcename = kolab_util_backend_get_relative_path_from_uri (priv->book_uri);
 
 	/* Check whether we have a KolabMailAccess (KoMA) instance already */
-
 	user_at_server = g_strdup_printf ("%s %s",
 	                                  username, servername);
-
-	ok = g_hash_table_lookup_extended (priv->koma_table,
+	ok = g_hash_table_lookup_extended (koma_objects,
 	                                   user_at_server,
 	                                   (gpointer *) &tmp_key,
 	                                   (gpointer *) &tmp_koma);
+
 	if (ok) {
 		gchar *passwd = NULL;
 
@@ -302,9 +286,6 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 		 */
 		g_object_ref (tmp_koma);
 		priv->book_koma = tmp_koma;
-		g_free (servername);
-		g_free (username);
-		g_free (user_at_server);
 		ksettings = kolab_mail_access_get_settings_handler (priv->book_koma);
 		kolab_util_backend_prepare_settings (ksettings,
 		                                     NULL,
@@ -313,7 +294,6 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 		                                     NULL,
 		                                     sourcename,
 		                                     &sync_value);
-
 		/* We may find that we do not yet have a password set.
 		 * In case we're requested to go online, we will need
 		 * one, so we need to get authentication data first.
@@ -321,10 +301,9 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 		passwd = g_strdup (kolab_settings_handler_get_char_field (ksettings,
 		                                                          KOLAB_SETTINGS_HANDLER_CHAR_FIELD_KOLAB_USER_PASSWORD,
 		                                                          NULL));
-		g_object_unref (ksettings);
 		if (passwd == NULL) {
-			e_book_backend_notify_auth_required (E_BOOK_BACKEND (self), TRUE, NULL);
-			return;
+			auth_required = TRUE;
+			goto exit;
 		}
 		g_free (passwd);
 
@@ -332,85 +311,64 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 		                                                  online,
 		                                                  cancellable,
 		                                                  &tmp_err);
-		if (tmp_err != NULL) {
-			kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-			g_error_free (tmp_err);
-			return;
-		}
-		ok = book_backend_kolab_notify_opened (self, &tmp_err);
-		if (! ok) {
-			kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-			g_error_free (tmp_err);
-		}
-		return;
+		goto exit;
 	}
 
 	/* Nope, we need to setup a new KoMA instance and a settings handler */
 
+	/* init subsystems (these are no-ops if already called before) */
+	kolab_util_glib_init ();
+	kolab_util_http_init ();
+	/* libcamel
+	 * Curl init may configure the underlying SSL lib,
+	 * but as far as SSL goes, we want Camel to rule here
+	 * TODO check whether Camel session needs to be initialized before or after libcurl.
+	 */
+	ok = kolab_util_camel_init (&tmp_err);
+	if (! ok)
+		goto exit;
+
 	/* Configure settings handler */
 	ksettings = KOLAB_SETTINGS_HANDLER (g_object_new (KOLAB_TYPE_SETTINGS_HANDLER, NULL));
 	ok = kolab_settings_handler_configure (ksettings,
 	                                       KOLAB_FOLDER_CONTEXT_CONTACT,
 	                                       &tmp_err);
-	if (! ok) {
-		g_free (servername);
-		g_free (username);
-		g_free (user_at_server);
-		g_object_unref (ksettings);
-		kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (! ok)
+		goto exit;
 
 	ok = kolab_settings_handler_bringup (ksettings, &tmp_err);
-	if (! ok) {
-		g_free (servername);
-		g_free (username);
-		g_free (user_at_server);
-		g_object_unref (ksettings);
-		kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (! ok)
+		goto exit;
 
 	kolab_util_backend_prepare_settings (ksettings,
-	                                     source,
+	                                     esource,
 	                                     servername,
 	                                     username,
 	                                     NULL,
 	                                     sourcename,
 	                                     &sync_value);
 
-	g_free (servername);
-	g_free (username);
-	g_free (sourcename);
-
+	/* create new KolabMailAccess instance */
 	priv->book_koma = KOLAB_MAIL_ACCESS (g_object_new (KOLAB_TYPE_MAIL_ACCESS, NULL));
 	g_object_add_toggle_ref (G_OBJECT (priv->book_koma),
 	                         kolab_util_backend_koma_table_cleanup_cb,
-	                         priv->koma_table);
-	g_hash_table_insert (priv->koma_table,
+	                         koma_objects);
+	g_hash_table_insert (koma_objects,
 	                     user_at_server,
 	                     priv->book_koma);
 
+	/* configure and bring up KolabMailAccess instance */
 	ok = kolab_mail_access_configure (priv->book_koma,
 	                                  ksettings,
 	                                  &tmp_err);
-	g_object_unref (ksettings);
-	if (! ok) {
-		kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (! ok)
+		goto exit;
 
 	ok = kolab_mail_access_bringup (priv->book_koma,
 	                                cancellable,
 	                                &tmp_err);
-	if (! ok) {
-		kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (! ok)
+		goto exit;
 
 	/* If we are here (just created a fresh KolabMailAccess),
 	 * we did not yet receive authentication data. Though we
@@ -419,24 +377,43 @@ e_book_backend_kolab_open (EBookBackendSync *backend,
 	 * (password in our case) anyway, so we can just request
 	 * it once the book gets opened.
 	 */
-	e_book_backend_notify_auth_required (E_BOOK_BACKEND (self), TRUE, NULL);
+	auth_required = TRUE;
 
-	/* FIXME may need to move the notifications to authenticate_user() */
-#if 0
-	/* e_book_backend_kolab_set_mode (backend, priv->book_mode); */
-	tmp_mode = kolab_mail_access_get_opmode (priv->book_koma, &tmp_err);
+ exit:
+
+	if (ksettings != NULL)
+		g_object_unref (ksettings);
+
+	g_mutex_unlock (koma_objects_lock);
+
+	if (c_url != NULL)
+		camel_url_free (c_url);
+	if (servername != NULL)
+		g_free (servername);
+	if (username != NULL)
+		g_free (username);
+	if (user_at_server != NULL)
+		g_free (user_at_server);
+
+	/* do we have an error set? if so, propagate and return */
 	if (tmp_err != NULL) {
 		kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
 		g_error_free (tmp_err);
 		return;
 	}
 
-	e_book_backend_set_is_loaded (bbackend, TRUE);
-	e_book_backend_notify_connection_status (bbackend,
-	                                         tmp_mode = KOLAB_MAIL_ACCESS_OPMODE_ONLINE ? TRUE : FALSE);
-	e_book_backend_set_is_writable (bbackend, TRUE);
-	e_book_backend_notify_writable (bbackend, TRUE);
-#endif
+	/* do we need authentication data? if so, notify and return */
+	if (auth_required) {
+		e_book_backend_notify_auth_required (E_BOOK_BACKEND (self), TRUE, NULL);
+		return;
+	}
+
+	/* all good, notify that we're open for business */
+	ok = book_backend_kolab_notify_opened (self, &tmp_err);
+	if (! ok) {
+		kolab_util_contact_err_to_edb_err (error, tmp_err, __func__, __LINE__);
+		g_error_free (tmp_err);
+	}
 }
 
 static void
@@ -1192,16 +1169,30 @@ e_book_backend_kolab_init (EBookBackendKolab *backend)
 {
 	EBookBackendKolabPrivate *priv = E_BOOK_BACKEND_KOLAB_PRIVATE (backend);
 
-	g_debug ("%s()[%u] called.", __func__, __LINE__);
-
+	/* We're inside a thread, and each of our siblings
+	 * (other configured ECalBackendKolab instances) is
+	 * so as well. Depending on how the threads are
+	 * started, checking for lock existence (and creating
+	 * one if it is not) in *this* place can still be
+	 * racy. Let's hope the threads are started one
+	 * at a time, in which case this solution will work.
+	 * The whole handling of living KolabMailAccess
+	 * instances would better be moved to a separate
+	 * library...
+	 *
+	 */
+	if (koma_objects_lock == NULL)
+		koma_objects_lock = g_mutex_new ();
+	g_mutex_lock (koma_objects_lock);
 	if (koma_objects == NULL)
-		koma_objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-	else
-		g_hash_table_ref (koma_objects);
+		koma_objects = g_hash_table_new_full (g_direct_hash,
+		                                      g_direct_equal,
+		                                      g_free,
+		                                      g_object_unref);
+	g_mutex_unlock (koma_objects_lock);
 
-	priv->koma_table = koma_objects;
+	g_debug ("%s()[%u] called.", __func__, __LINE__);
 
-	/* priv->book_mode = E_DATA_BOOK_MODE_LOCAL; */ /* Start in local mode for now. */
 	priv->book_cache = NULL;
 	priv->book_uri = NULL;
 	priv->book_koma = NULL;
@@ -1237,10 +1228,6 @@ e_book_backend_kolab_dispose (GObject *object)
 		g_object_unref (priv->book_koma);
 		priv->book_koma = NULL;
 	}
-	if (priv->koma_table != NULL) {
-		g_hash_table_unref (koma_objects);
-		priv->koma_table = NULL;
-	}
 #endif
 	if (priv->book_cache != NULL) {
 		(void) e_file_cache_remove (E_FILE_CACHE (priv->book_cache));
diff --git a/src/calendar/e-cal-backend-kolab.c b/src/calendar/e-cal-backend-kolab.c
index 85d5056..173c020 100644
--- a/src/calendar/e-cal-backend-kolab.c
+++ b/src/calendar/e-cal-backend-kolab.c
@@ -51,6 +51,7 @@
 /* table of KolabMailAccess objects */
 
 static GHashTable *koma_objects = NULL;
+static GMutex *koma_objects_lock = NULL;
 
 /*----------------------------------------------------------------------------*/
 /* forward declarations */
@@ -88,7 +89,6 @@ typedef struct {
 /* Private part of the ECalBackendKolab structure */
 typedef struct _ECalBackendKolabPrivate ECalBackendKolabPrivate;
 struct _ECalBackendKolabPrivate {
-	GHashTable *koma_table;
 	CalMode cal_mode;
 	KolabMailAccess *cal_koma;
 	ECalBackendCache *cal_cache;
@@ -248,6 +248,7 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 	gchar *tmp_key = NULL;
 	const gchar *prop_str = NULL;
 	gboolean online = FALSE;
+	gboolean auth_required = FALSE;
 	gboolean ok = FALSE;
 	GError *tmp_err = NULL;
 
@@ -260,6 +261,8 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 	self = E_CAL_BACKEND_KOLAB (backend);
 	priv = E_CAL_BACKEND_KOLAB_PRIVATE (self);
 
+	g_mutex_lock (koma_objects_lock);
+
 	/* to trigger eds to pass along username and password, set the property
 	 * "auth" to "true" in the source setting:
 	 * <property name="auth" value="true"/>
@@ -279,23 +282,11 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 		priv->source_type = E_CAL_SOURCE_TYPE_JOURNAL;
 		break;
 	default:
-		/* FIXME */
-		g_error ("%s()[%u]: Unknown Type used in e-cal-backend-kolab initialization!",
-		         __func__, __LINE__);
-	}
-
-	kolab_util_glib_init ();
-	kolab_util_http_init ();
-	/* libcamel
-	 * Curl init may configure the underlying SSL lib,
-	 * but as far as SSL goes, we want Camel to rule here
-	 * TODO check whether Camel session needs to be initialized before or after libcurl.
-	 */
-	ok = kolab_util_camel_init (&tmp_err);
-	if (! ok) {
-		kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
+		g_set_error (&tmp_err,
+		             KOLAB_BACKEND_ERROR,
+		             KOLAB_BACKEND_ERROR_GENERIC,
+		             "Unknown type used in e-cal-backend-kolab initialization");
+		goto exit;
 	}
 
 	esource = e_backend_get_source (E_BACKEND (backend));
@@ -303,25 +294,18 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 		/* FIXME mark this as a translatable string */
 		tmp_err = e_data_cal_create_error (OtherError,
 		                                   "Could not get ESource for backend");
-		g_propagate_error (error, tmp_err);
-		return;
+		goto exit;
 	}
 
 	priv->cal_uri = e_source_get_uri (esource);
-
 	c_url = camel_url_new (priv->cal_uri, &tmp_err);
-	if (c_url == NULL) {
-		kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (c_url == NULL)
+		goto exit;
+
 	servername = g_strdup (c_url->host);
 	username = g_strdup (c_url->user);
-	camel_url_free (c_url);
-	g_debug ("%s()[%u] servername = %s",
-	         __func__, __LINE__, servername);
-	g_debug ("%s()[%u]   username = %s",
-	         __func__, __LINE__, username);
+	g_debug ("%s()[%u] servername = %s", __func__, __LINE__, servername);
+	g_debug ("%s()[%u]   username = %s", __func__, __LINE__, username);
 
 	/* Initialize backend cache */
 	if (priv->cal_cache != NULL) {
@@ -337,14 +321,13 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 	sourcename = kolab_util_backend_get_relative_path_from_uri (priv->cal_uri);
 
 	/* Check whether we have a KolabMailAccess (KoMA) instance already */
-
 	user_at_server = g_strdup_printf ("%s %s",
 	                                  username, servername);
-
-	ok = g_hash_table_lookup_extended (priv->koma_table,
+	ok = g_hash_table_lookup_extended (koma_objects,
 	                                   user_at_server,
 	                                   (gpointer *) &tmp_key,
 	                                   (gpointer *) &tmp_koma);
+
 	if (ok) {
 		gchar *passwd = NULL;
 
@@ -353,9 +336,6 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 		 */
 		g_object_ref (tmp_koma);
 		priv->cal_koma = tmp_koma;
-		g_free (servername);
-		g_free (username);
-		g_free (user_at_server);
 		ksettings = kolab_mail_access_get_settings_handler (priv->cal_koma);
 		kolab_util_backend_prepare_settings (ksettings,
 		                                     NULL,
@@ -371,10 +351,9 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 		passwd = g_strdup (kolab_settings_handler_get_char_field (ksettings,
 		                                                          KOLAB_SETTINGS_HANDLER_CHAR_FIELD_KOLAB_USER_PASSWORD,
 		                                                          NULL));
-		g_object_unref (ksettings);
 		if (passwd == NULL) {
-			e_cal_backend_notify_auth_required (E_CAL_BACKEND (self), TRUE, NULL);
-			return;
+			auth_required = TRUE;
+			goto exit;
 		}
 		g_free (passwd);
 
@@ -382,46 +361,34 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 		                                                  online,
 		                                                  cancellable,
 		                                                  &tmp_err);
-		if (tmp_err != NULL) {
-			kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-			g_error_free (tmp_err);
-			return;
-		}
-		ok = cal_backend_kolab_notify_opened (self, &tmp_err);
-		if (! ok) {
-			kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-			g_error_free (tmp_err);
-		}
-		return;
+		goto exit;
 	}
 
 	/* Nope, we need to setup a new KoMA instance and a settings handler */
 
+	/* init subsystems (these are no-ops if already called before) */
+	kolab_util_glib_init ();
+	kolab_util_http_init ();
+	/* libcamel
+	 * Curl init may configure the underlying SSL lib,
+	 * but as far as SSL goes, we want Camel to rule here
+	 * TODO check whether Camel session needs to be initialized before or after libcurl.
+	 */
+	ok = kolab_util_camel_init (&tmp_err);
+	if (! ok)
+		goto exit;
+
 	/* Configure settings handler */
 	ksettings = KOLAB_SETTINGS_HANDLER (g_object_new (KOLAB_TYPE_SETTINGS_HANDLER, NULL));
 	ok = kolab_settings_handler_configure (ksettings,
 	                                       KOLAB_FOLDER_CONTEXT_CALENDAR,
 	                                       &tmp_err);
-	if (! ok) {
-		g_free (servername);
-		g_free (username);
-		g_free (user_at_server);
-		g_object_unref (ksettings);
-		kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (! ok)
+		goto exit;
 
 	ok = kolab_settings_handler_bringup (ksettings, &tmp_err);
-	if (! ok) {
-		g_free (servername);
-		g_free (username);
-		g_free (user_at_server);
-		g_object_unref (ksettings);
-		kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (! ok)
+		goto exit;
 
 	kolab_util_backend_prepare_settings (ksettings,
 	                                     esource,
@@ -431,36 +398,27 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 	                                     sourcename,
 	                                     &sync_value);
 
-	g_free (servername);
-	g_free (username);
-	g_free (sourcename);
-
+	/* create new KolabMailAccess instance */
 	priv->cal_koma = KOLAB_MAIL_ACCESS (g_object_new (KOLAB_TYPE_MAIL_ACCESS, NULL));
 	g_object_add_toggle_ref (G_OBJECT (priv->cal_koma),
 	                         kolab_util_backend_koma_table_cleanup_cb,
-	                         priv->koma_table);
-	g_hash_table_insert (priv->koma_table,
+	                         koma_objects);
+	g_hash_table_insert (koma_objects,
 	                     user_at_server,
 	                     priv->cal_koma);
 
+	/* configure and bring up KolabMailAccess instance */
 	ok = kolab_mail_access_configure (priv->cal_koma,
 	                                  ksettings,
 	                                  &tmp_err);
-	g_object_unref (ksettings);
-	if (! ok) {
-		kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (! ok)
+		goto exit;
 
 	ok = kolab_mail_access_bringup (priv->cal_koma,
 	                                cancellable,
 	                                &tmp_err);
-	if (! ok) {
-		kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
-		g_error_free (tmp_err);
-		return;
-	}
+	if (! ok)
+		goto exit;
 
 	/* TODO this is sort of hackish, we cannot be sure that
 	 *      'user server' is truly the Kolab email address
@@ -475,7 +433,43 @@ e_cal_backend_kolab_open (ECalBackendSync *backend,
 	 * (password in our case) anyway, so we can just request
 	 * it once the book gets opened.
 	 */
-	e_cal_backend_notify_auth_required (E_CAL_BACKEND (self), TRUE, NULL);
+	auth_required = TRUE;
+
+ exit:
+
+	if (ksettings != NULL)
+		g_object_unref (ksettings);
+
+	g_mutex_unlock (koma_objects_lock);
+
+	if (c_url != NULL)
+		camel_url_free (c_url);
+	if (servername != NULL)
+		g_free (servername);
+	if (username != NULL)
+		g_free (username);
+	if (user_at_server != NULL)
+		g_free (user_at_server);
+
+	/* do we have an error set? if so, propagate and return */
+	if (tmp_err != NULL) {
+		kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
+		g_error_free (tmp_err);
+		return;
+	}
+
+	/* do we need authentication data? if so, notify and return */
+	if (auth_required) {
+		e_cal_backend_notify_auth_required (E_CAL_BACKEND (self), TRUE, NULL);
+		return;
+	}
+
+	/* all good, notify that we're open for business */
+	ok = cal_backend_kolab_notify_opened (self, &tmp_err);
+	if (! ok) {
+		kolab_util_calendar_err_to_edb_err (error, tmp_err, __func__, __LINE__);
+		g_error_free (tmp_err);
+	}
 }
 
 static void
@@ -1887,14 +1881,29 @@ e_cal_backend_kolab_init (ECalBackendKolab *backend)
 	ECalBackendKolab *self = E_CAL_BACKEND_KOLAB (backend);
 	ECalBackendKolabPrivate *priv = E_CAL_BACKEND_KOLAB_PRIVATE (self);
 
-	g_debug ("%s()[%u] called.", __func__, __LINE__);
-
+	/* We're inside a thread, and each of our siblings
+	 * (other configured ECalBackendKolab instances) is
+	 * so as well. Depending on how the threads are
+	 * started, checking for lock existence (and creating
+	 * one if it is not) in *this* place can still be
+	 * racy. Let's hope the threads are started one
+	 * at a time, in which case this solution will work.
+	 * The whole handling of living KolabMailAccess
+	 * instances would better be moved to a separate
+	 * library...
+	 *
+	 */
+	if (koma_objects_lock == NULL)
+		koma_objects_lock = g_mutex_new ();
+	g_mutex_lock (koma_objects_lock);
 	if (koma_objects == NULL)
-		koma_objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-	else
-		g_hash_table_ref (koma_objects);
+		koma_objects = g_hash_table_new_full (g_direct_hash,
+		                                      g_direct_equal,
+		                                      g_free,
+		                                      g_object_unref);
+	g_mutex_unlock (koma_objects_lock);
 
-	priv->koma_table = koma_objects;
+	g_debug ("%s()[%u] called.", __func__, __LINE__);
 
 	priv->cal_mode = 0;
 	priv->cal_koma = NULL;
@@ -1926,10 +1935,6 @@ e_cal_backend_kolab_dispose (GObject *object)
 			g_object_unref (priv->cal_koma);
 			priv->cal_koma = NULL;
 		}
-		if (priv->koma_table != NULL) {
-			g_hash_table_unref (priv->koma_table);
-			priv->koma_table = NULL;
-		}
 #endif
 	if (priv->default_zone != NULL) {
 		g_object_unref (priv->default_zone);



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