[evolution-mapi] Bug #623028 - Crash in e_data_book_view_notify_complete



commit e0ed02caaaa420ec329fcfa0c969b8f3e07aef23
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 30 09:34:41 2010 +0200

    Bug #623028 - Crash in e_data_book_view_notify_complete

 src/addressbook/e-book-backend-mapi-gal.c |  366 +++++++++++++----------------
 src/addressbook/e-book-backend-mapi.c     |  307 ++++++++++++++-----------
 2 files changed, 333 insertions(+), 340 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-mapi-gal.c b/src/addressbook/e-book-backend-mapi-gal.c
index fb992eb..e470614 100644
--- a/src/addressbook/e-book-backend-mapi-gal.c
+++ b/src/addressbook/e-book-backend-mapi-gal.c
@@ -42,12 +42,14 @@ struct _EBookBackendMAPIGALPrivate
 	gboolean is_summary_ready;
 	gboolean is_writable;
 	gchar *uri;
-	gchar *book_name;
 
 	GMutex *lock;
 	gchar *summary_file_name;
 	EBookBackendSummary *summary;
 	EBookBackendCache *cache;
+
+	GStaticMutex running_mutex;
+	GHashTable *view_to_closure_hash; /* EDataBookView -> BESearchClosure */
 };
 
 #define SUMMARY_FLUSH_TIMEOUT 5000
@@ -285,6 +287,7 @@ e_book_backend_mapi_gal_authenticate_user (EBookBackend *backend,
 		return;
 
 	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+		g_static_mutex_lock (&priv->running_mutex);
 
 		/* rather reuse already established connection */
 		priv->conn = exchange_mapi_connection_find (priv->profile);
@@ -293,8 +296,11 @@ e_book_backend_mapi_gal_authenticate_user (EBookBackend *backend,
 		else if (!priv->conn)
 			priv->conn = exchange_mapi_connection_new (priv->profile, passwd);
 
-		if (!priv->conn)
-			return e_data_book_respond_authenticate_user (book, opid,GNOME_Evolution_Addressbook_OtherError);
+		if (!priv->conn) {
+			e_data_book_respond_authenticate_user (book, opid,GNOME_Evolution_Addressbook_OtherError);
+			g_static_mutex_unlock (&priv->running_mutex);
+			return;
+		}
 
 		if (priv->cache && priv->is_cache_ready) {
 			printf("FIXME: Should check for an update in the cache\n");
@@ -310,6 +316,7 @@ e_book_backend_mapi_gal_authenticate_user (EBookBackend *backend,
 		}
 		e_book_backend_set_is_writable (backend, FALSE);
 		e_data_book_respond_authenticate_user (book, opid, GNOME_Evolution_Addressbook_Success);
+		g_static_mutex_unlock (&priv->running_mutex);
 		return;
 
 	default :
@@ -383,8 +390,6 @@ e_book_backend_mapi_gal_load_source (EBookBackend *backend,
 {
 	EBookBackendMAPIGALPrivate *priv = ((EBookBackendMAPIGAL *) backend)->priv;
 	const gchar *offline, *tmp;
-	gchar **tokens;
-	gchar *uri = NULL;
 
 	if (enable_debug)
 		printf("MAPI load source\n");
@@ -398,17 +403,7 @@ e_book_backend_mapi_gal_load_source (EBookBackend *backend,
 
 	/* Either we are in Online mode or this is marked for offline */
 
-	priv->uri = g_strdup (e_source_get_uri (source));
-
-	tokens = g_strsplit (priv->uri, ";", 2);
-	if (tokens[0])
-		uri = g_strdup (tokens [0]);
-	priv->book_name  = g_strdup (tokens[1]);
-	if (priv->book_name == NULL) {
-		g_warning ("Bookname is null for %s\n", uri);
-		return GNOME_Evolution_Addressbook_OtherError;
-	}
-	g_strfreev (tokens);
+	priv->uri = e_source_get_uri (source);
 
 	if (priv->mode ==  GNOME_Evolution_Addressbook_MODE_LOCAL &&
 	    !priv->marked_for_offline ) {
@@ -441,7 +436,6 @@ e_book_backend_mapi_gal_load_source (EBookBackend *backend,
 		priv->summary = e_book_backend_summary_new (NULL,SUMMARY_FLUSH_TIMEOUT);
 	}
 
-	g_free (uri);
 	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
 	e_book_backend_set_is_writable (backend, FALSE);
 	if (priv->mode ==  GNOME_Evolution_Addressbook_MODE_LOCAL) {
@@ -501,42 +495,58 @@ e_book_backend_mapi_gal_set_mode (EBookBackend *backend, GNOME_Evolution_Address
 	}
 }
 
-static void
-e_book_backend_mapi_gal_dispose (GObject *object)
+typedef struct {
+	EBookBackendMAPIGAL *bg;
+	EDataBookView *book_view;
+	gboolean stop;
+} BESearchClosure;
+
+static BESearchClosure*
+init_closure (EDataBookView *book_view, EBookBackendMAPIGAL *bg)
 {
-	/* FIXME : provide implmentation */
-	EBookBackendMAPIGALPrivate *priv = ((EBookBackendMAPIGAL *) object)->priv;
+	BESearchClosure *closure;
 
-	if (priv->profile) {
-		g_free (priv->profile);
-		priv->profile = NULL;
-	}
-	if (priv->conn) {
-		g_object_unref (priv->conn);
-		priv->conn = NULL;
-	}
-	if (priv->uri) {
-		g_free (priv->uri);
-		priv->uri = NULL;
-	}
+	g_return_val_if_fail (bg != NULL, NULL);
+	g_return_val_if_fail (bg->priv != NULL, NULL);
+	g_return_val_if_fail (bg->priv->view_to_closure_hash != NULL, NULL);
+	
+	closure = g_new0 (BESearchClosure, 1);
+	closure->bg = bg;
+	closure->book_view = book_view;
+	closure->stop = FALSE;
 
-	if (priv->build_cache_thread) {
-		priv->kill_cache_build = TRUE;
-		g_thread_join (priv->build_cache_thread);
-		priv->build_cache_thread = NULL;
-	}
+	g_hash_table_insert (bg->priv->view_to_closure_hash, g_object_ref (book_view), closure);
+
+	return closure;
 }
 
-typedef struct {
-	EBookBackendMAPIGAL *bg;
-	GThread *thread;
-	EFlag *running;
-} BESearchClosure;
+static void
+destroy_closure (BESearchClosure *closure)
+{
+	g_return_if_fail (closure != NULL);
 
-static BESearchClosure*
-get_closure (EDataBookView *book_view)
+	if (closure->book_view)
+		g_object_unref (closure->book_view);
+	g_free (closure);
+}
+
+static void
+stop_book_view (EDataBookView *book_view, BESearchClosure *closure, EBookBackendMAPIGAL *mapi_backend)
+{
+	g_return_if_fail (closure != NULL);
+
+	closure->stop = TRUE;
+}
+
+static void
+untrack_book_view (EBookBackendMAPIGAL *mapi_backend, EDataBookView *book_view)
 {
-	return g_object_get_data (G_OBJECT (book_view), "closure");
+	g_return_if_fail (mapi_backend != NULL);
+	g_return_if_fail (mapi_backend->priv != NULL);
+	g_return_if_fail (mapi_backend->priv->view_to_closure_hash != NULL);
+	g_return_if_fail (book_view != NULL);
+
+	g_hash_table_remove (mapi_backend->priv->view_to_closure_hash, book_view);
 }
 
 static void
@@ -552,7 +562,7 @@ get_contacts_from_cache (EBookBackendMAPIGAL *ebmapi,
 		gchar *uid;
 		EContact *contact;
 
-                if (!e_flag_is_set (closure->running))
+                if (closure->stop)
                         break;
 
 		uid = g_ptr_array_index (ids, i);
@@ -562,9 +572,6 @@ get_contacts_from_cache (EBookBackendMAPIGAL *ebmapi,
 			g_object_unref (contact);
 		}
 	}
-	if (e_flag_is_set (closure->running))
-		e_data_book_view_notify_complete (book_view,
-						  GNOME_Evolution_Addressbook_Success);
 }
 #if 0
 static gboolean
@@ -605,97 +612,20 @@ build_restriction_emails_contains (struct mapi_SRestriction *res,
 }
 #endif
 
-static gboolean
-build_multiple_restriction_emails_contains (struct mapi_SRestriction *res,
-					    struct mapi_SRestriction_or *or_res,
-					    const gchar *query)
-{
-	gchar *email=NULL, *tmp, *tmp1;
-	//Number of restriction to apply
-	guint res_count = 6;
-
-	/* This currently supports "email foo bar soo" */
-	tmp = strdup (query);
-
-	tmp = strstr (tmp, "email");
-	if (tmp ) {
-		tmp = strchr (tmp, '\"');
-		if (tmp && ++tmp) {
-			tmp = strchr (tmp, '\"');
-			if (tmp && ++tmp) {
-				tmp1 = tmp;
-				tmp1 = strchr (tmp1, '\"');
-				if (tmp1) {
-					*tmp1 = 0;
-					email = tmp;
-				}
-			}
-		}
-	}
-
-	if (email==NULL || !strchr (email, '@'))
-		return FALSE;
-
-	or_res[0].rt = RES_CONTENT;
-	or_res[0].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[0].res.resContent.ulPropTag = PR_EMS_AB_MANAGER_T_UNICODE;
-	or_res[0].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[1].rt = RES_CONTENT;
-	or_res[1].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[1].res.resContent.ulPropTag = PR_DISPLAY_NAME_UNICODE;
-	or_res[1].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[2].rt = RES_CONTENT;
-	or_res[2].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[2].res.resContent.ulPropTag = PR_GIVEN_NAME_UNICODE;
-	or_res[2].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[3].rt = RES_CONTENT;
-	or_res[3].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[3].res.resContent.ulPropTag = PROP_TAG(PT_UNICODE, 0x8084);
-	or_res[3].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[4].rt = RES_CONTENT;
-	or_res[4].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[4].res.resContent.ulPropTag = PROP_TAG(PT_UNICODE, 0x8094);
-	or_res[4].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[5].rt = RES_CONTENT;
-	or_res[5].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[5].res.resContent.ulPropTag = PROP_TAG(PT_UNICODE, 0x80a4);
-	or_res[5].res.resContent.lpProp.value.lpszA = email;
-
-	res = g_new0 (struct mapi_SRestriction, 1);
-
-	res->rt = RES_OR;
-	res->res.resOr.cRes = res_count;
-	res->res.resOr.res = or_res;
-
-	return TRUE;
-}
-
 static void
 book_view_thread (gpointer data)
 {
-	struct mapi_SRestriction res;
-	struct mapi_SRestriction_or *or_res = NULL;
-	EDataBookView *book_view = data;
-	BESearchClosure *closure = get_closure (book_view);
+	BESearchClosure *closure = data;
+	EDataBookView *book_view = closure->book_view;
 	EBookBackendMAPIGAL *backend = closure->bg;
 	EBookBackendMAPIGALPrivate *priv = backend->priv;
 	const gchar *query = NULL;
 	GPtrArray *ids = NULL;
 	GList *contacts = NULL, *temp_list = NULL;
-	//Number of multiple restriction to apply
-	guint res_count = 6;
 
 	if (enable_debug)
 		printf("mapi: book view\n");
 
-	g_object_ref (book_view);
-	e_flag_set (closure->running);
-
 	book_view_notify_status (book_view, _("Searching"));
 	query = e_data_book_view_get_card_query (book_view);
 
@@ -708,13 +638,16 @@ book_view_thread (gpointer data)
 				e_book_backend_notify_auth_required (E_BOOK_BACKEND (backend));
 				e_data_book_view_notify_complete (book_view,
 							GNOME_Evolution_Addressbook_AuthenticationRequired);
-				g_object_unref (book_view);
+				untrack_book_view (backend, book_view);
+				destroy_closure (closure);
 				return;
 			}
 
 			if (priv->marked_for_offline && !priv->is_cache_ready) {
 				/* To translators : Here Evolution MAPI downloads the entries from the GAL server */
 				book_view_notify_status (book_view, _("Downloading GAL entries from serverâ?¦"));
+				untrack_book_view (backend, book_view);
+				destroy_closure (closure);
 				return;
 			}
 
@@ -724,11 +657,10 @@ book_view_thread (gpointer data)
 					if (enable_debug)
 						printf ("reading the contacts from summary \n");
 					ids = e_book_backend_summary_search (priv->summary, query);
-					if (ids && ids->len > 0) {
+					if (ids && ids->len > 0)
 						get_contacts_from_cache (backend, query, ids, book_view, closure);
+					if (ids)
 						g_ptr_array_free (ids, TRUE);
-					}
-					g_object_unref (book_view);
 					break;
 				}
 
@@ -739,7 +671,7 @@ book_view_thread (gpointer data)
 								      query);
 				temp_list = contacts;
 				for (; contacts != NULL; contacts = g_list_next(contacts)) {
-					if (!e_flag_is_set (closure->running)) {
+					if (closure->stop) {
 						for (;contacts != NULL; contacts = g_list_next (contacts))
 							g_object_unref (contacts->data);
 						break;
@@ -748,58 +680,26 @@ book_view_thread (gpointer data)
 									E_CONTACT(contacts->data));
 					g_object_unref (contacts->data);
 				}
-				if (e_flag_is_set (closure->running))
-					e_data_book_view_notify_complete (book_view,
-									  GNOME_Evolution_Addressbook_Success);
 				if (temp_list)
-					 g_list_free (temp_list);
-				g_object_unref (book_view);
+					g_list_free (temp_list);
 				break;
 			}
 
 			if (e_book_backend_summary_is_summary_query (priv->summary, query)) {
-				or_res = g_new (struct mapi_SRestriction_or, res_count);
-
-				if (!build_multiple_restriction_emails_contains (&res, or_res, query)) {
-					e_data_book_view_notify_complete (book_view,
-								  GNOME_Evolution_Addressbook_OtherError);
-					return;
-				}
+				ids = e_book_backend_summary_search (priv->summary, query);
+				if (ids && ids->len > 0)
+					get_contacts_from_cache (backend, query, ids, book_view, closure);
+				if (ids)
+					g_ptr_array_free (ids, TRUE);
+				break;
+			}
 
-			if (e_flag_is_set (closure->running))
-				e_data_book_view_notify_complete (book_view,
-								  GNOME_Evolution_Addressbook_Success);
-			g_object_unref (book_view);
 			break;
-		}
 	}
 
-	if (book_view)
-		e_data_book_view_notify_complete (book_view,
-						  GNOME_Evolution_Addressbook_Success);
-	return;
-}
-
-static void
-closure_destroy (BESearchClosure *closure)
-{
-	e_flag_free (closure->running);
-	g_free (closure);
-}
-
-static BESearchClosure*
-init_closure (EDataBookView *book_view, EBookBackendMAPIGAL *bg)
-{
-	BESearchClosure *closure = g_new (BESearchClosure, 1);
-
-	closure->bg = bg;
-	closure->thread = NULL;
-	closure->running = e_flag_new ();
-
-	g_object_set_data_full (G_OBJECT (book_view), "closure",
-				closure, (GDestroyNotify)closure_destroy);
-
-	return closure;
+	e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_Success);
+	untrack_book_view (backend, book_view);
+	destroy_closure (closure);
 }
 
 static void
@@ -837,12 +737,12 @@ e_book_backend_mapi_gal_start_book_view (EBookBackend  *backend,
 {
 	BESearchClosure *closure = init_closure (book_view, E_BOOK_BACKEND_MAPIGAL (backend));
 
+	g_return_if_fail (closure != NULL);
+
 	if (enable_debug)
 		printf ("mapi: start_book_view...\n");
-	closure->thread = g_thread_create ((GThreadFunc) book_view_thread, book_view, FALSE, NULL);
-	e_flag_wait (closure->running);
 
-	/* at this point we know the book view thread is actually running */
+	g_thread_create ((GThreadFunc) book_view_thread, closure, FALSE, NULL);
 }
 
 static void
@@ -851,7 +751,8 @@ e_book_backend_mapi_gal_stop_book_view (EBookBackend  *backend,
 {
 	if (enable_debug)
 		printf("mapi: stop book view\n");
-	/* FIXME : provide implmentation */
+
+	untrack_book_view (E_BOOK_BACKEND_MAPIGAL (backend), book_view);
 }
 
 static void
@@ -896,13 +797,85 @@ e_book_backend_mapi_gal_remove (EBookBackend *backend, EDataBook *book, guint32
 	e_data_book_respond_remove (book, opid, GNOME_Evolution_Addressbook_PermissionDenied);
 }
 
-static void e_book_backend_mapi_gal_class_init (EBookBackendMAPIGALClass *klass)
+static void
+e_book_backend_mapi_gal_init (EBookBackendMAPIGAL *backend)
+{
+	EBookBackendMAPIGALPrivate *priv;
+
+	priv = g_new0 (EBookBackendMAPIGALPrivate, 1);
+	/* Priv Struct init */
+	backend->priv = priv;
+
+	priv->build_cache_thread = NULL;
+	priv->view_to_closure_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
+	g_static_mutex_init (&priv->running_mutex);
+
+/*	priv->marked_for_offline = FALSE;
+	priv->uri = NULL;
+	priv->cache = NULL;
+	priv->is_summary_ready = FALSE;
+	priv->is_cache_ready = FALSE;
+
+*/	if (g_getenv ("MAPI_DEBUG"))
+		enable_debug = TRUE;
+	else
+		enable_debug = FALSE;
+}
+
+static void
+e_book_backend_mapi_gal_dispose (GObject *object)
+{
+	EBookBackendMAPIGAL *mapi_backend = E_BOOK_BACKEND_MAPIGAL (object);
+	EBookBackendMAPIGALPrivate *priv = mapi_backend->priv;
+
+	if (priv) {
+		if (priv->view_to_closure_hash) {
+			g_hash_table_foreach (priv->view_to_closure_hash, (GHFunc) stop_book_view, mapi_backend);
+			g_hash_table_destroy (priv->view_to_closure_hash);
+			priv->view_to_closure_hash = NULL;
+		}
+
+		if (priv->build_cache_thread) {
+			priv->kill_cache_build = TRUE;
+			g_thread_join (priv->build_cache_thread);
+			priv->build_cache_thread = NULL;
+		}
+
+		#define FREE(x) if (x) { g_free (x); x = NULL; }
+		#define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
+
+		/* this will also ensure any pending authentication
+		   request is finished and it's safe to free memory */
+		g_static_mutex_lock (&priv->running_mutex);
+
+		UNREF (priv->conn);
+		UNREF (priv->cache);
+		UNREF (priv->summary);
+
+		FREE (priv->profile);
+		FREE (priv->uri);
+		FREE (priv->summary_file_name);
+
+		g_static_mutex_unlock (&priv->running_mutex);
+		g_static_mutex_free (&priv->running_mutex);
+
+		FREE (mapi_backend->priv);
+
+		#undef UNREF
+		#undef FREE
+	}
+
+	/* Chain up to parent's dispose() method. */
+	if (G_OBJECT_CLASS (e_book_backend_mapi_gal_parent_class)->dispose)
+		G_OBJECT_CLASS (e_book_backend_mapi_gal_parent_class)->dispose (object);
+}
+
+static void
+e_book_backend_mapi_gal_class_init (EBookBackendMAPIGALClass *klass)
 {
 	GObjectClass  *object_class = G_OBJECT_CLASS (klass);
 	EBookBackendClass *parent_class;
 
-	e_book_backend_mapi_gal_parent_class = g_type_class_peek_parent (klass);
-
 	parent_class = E_BOOK_BACKEND_CLASS (klass);
 
 	/* Set the virtual methods. */
@@ -924,6 +897,7 @@ static void e_book_backend_mapi_gal_class_init (EBookBackendMAPIGALClass *klass)
 	parent_class->cancel_operation		 = e_book_backend_mapi_gal_cancel_operation;
 	parent_class->set_mode                   = e_book_backend_mapi_gal_set_mode;
 	parent_class->remove			 = e_book_backend_mapi_gal_remove;
+
 	object_class->dispose                    = e_book_backend_mapi_gal_dispose;
 }
 
@@ -935,32 +909,10 @@ e_book_backend_mapi_gal_new (void)
 {
 	EBookBackendMAPIGAL *backend;
 
-//	if (enable_debug)
+	if (enable_debug)
 		printf ("\ne_book_backend_mapi_gal_new...\n");
 
 	backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPIGAL, NULL);
 
 	return E_BOOK_BACKEND (backend);
 }
-
-static void	e_book_backend_mapi_gal_init (EBookBackendMAPIGAL *backend)
-{
-	EBookBackendMAPIGALPrivate *priv;
-
-	priv= g_new0 (EBookBackendMAPIGALPrivate, 1);
-	/* Priv Struct init */
-	backend->priv = priv;
-
-	priv->build_cache_thread = NULL;
-
-/*	priv->marked_for_offline = FALSE;
-	priv->uri = NULL;
-	priv->cache = NULL;
-	priv->is_summary_ready = FALSE;
-	priv->is_cache_ready = FALSE;
-
-*/	if (g_getenv ("MAPI_DEBUG"))
-		enable_debug = TRUE;
-	else
-		enable_debug = FALSE;
-}
diff --git a/src/addressbook/e-book-backend-mapi.c b/src/addressbook/e-book-backend-mapi.c
index 78da4fa..b280e16 100644
--- a/src/addressbook/e-book-backend-mapi.c
+++ b/src/addressbook/e-book-backend-mapi.c
@@ -65,18 +65,15 @@ struct _EBookBackendMAPIPrivate
 	gboolean is_summary_ready;
 	gboolean is_writable;
 	gchar *uri;
-	gchar *book_name;
 
-	GMutex *lock;
 	gchar *summary_file_name;
 	EBookBackendSummary *summary;
 	EBookBackendCache *cache;
 
+	GStaticMutex running_mutex;
+	GHashTable *view_to_closure_hash; /* EDataBookView -> BESearchClosure */
 };
 
-#define LOCK() g_mutex_lock (priv->lock)
-#define UNLOCK() g_mutex_unlock (priv->lock)
-
 #define SUMMARY_FLUSH_TIMEOUT 5000
 
 #if 0
@@ -151,16 +148,18 @@ build_restriction_emails_contains (struct mapi_SRestriction *res,
 static gboolean
 build_multiple_restriction_emails_contains (ExchangeMapiConnection *conn, mapi_id_t fid, struct mapi_SRestriction *res,
 					    struct mapi_SRestriction_or *or_res,
-					    const gchar *query)
+					    const gchar *query, gchar **to_free)
 {
 	gchar *email=NULL, *tmp, *tmp1;
 	//Number of restriction to apply
 	guint res_count = 6;
 
+	g_return_val_if_fail (to_free != NULL, FALSE);
+
 	/* This currently supports "email foo bar soo" */
-	tmp = strdup (query);
+	*to_free = strdup (query);
 
-	tmp = strstr (tmp, "email");
+	tmp = strstr (*to_free, "email");
 	if (tmp ) {
 		tmp = strchr (tmp, '\"');
 		if (tmp && ++tmp) {
@@ -176,8 +175,12 @@ build_multiple_restriction_emails_contains (ExchangeMapiConnection *conn, mapi_i
 		}
 	}
 
-	if (email==NULL || !strchr (email, '@'))
+	if (email==NULL || !strchr (email, '@')) {
+		g_free (*to_free);
+		*to_free = NULL;
+
 		return FALSE;
+	}
 
 	or_res[0].rt = RES_CONTENT;
 	or_res[0].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
@@ -251,8 +254,6 @@ e_book_backend_mapi_load_source (EBookBackend *backend,
 {
 	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
 	const gchar *offline, *tmp;
-	gchar **tokens;
-	gchar *uri = NULL;
 
 	if (enable_debug)
 		printf("MAPI load source\n");
@@ -266,17 +267,7 @@ e_book_backend_mapi_load_source (EBookBackend *backend,
 
 	/* Either we are in Online mode or this is marked for offline */
 
-	priv->uri = g_strdup (e_source_get_uri (source));
-
-	tokens = g_strsplit (priv->uri, ";", 2);
-	if (tokens[0])
-		uri = g_strdup (tokens [0]);
-	priv->book_name  = g_strdup (tokens[1]);
-	if (priv->book_name == NULL) {
-		g_warning ("Bookname is null for %s\n", uri);
-		return GNOME_Evolution_Addressbook_OtherError;
-	}
-	g_strfreev (tokens);
+	priv->uri = e_source_get_uri (source);
 
 	if (priv->mode ==  GNOME_Evolution_Addressbook_MODE_LOCAL &&
 	    !priv->marked_for_offline ) {
@@ -305,7 +296,6 @@ e_book_backend_mapi_load_source (EBookBackend *backend,
 		priv->cache = e_book_backend_cache_new (priv->uri);
 	}
 
-	g_free (uri);
 	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
 	e_book_backend_set_is_writable (backend, TRUE);
 	if (priv->mode ==  GNOME_Evolution_Addressbook_MODE_LOCAL) {
@@ -1107,36 +1097,56 @@ e_book_backend_mapi_get_contact_list (EBookBackend *backend,
 
 typedef struct {
 	EBookBackendMAPI *bg;
-	GThread *thread;
-	EFlag *running;
+	EDataBookView *book_view;
+	gboolean stop;
 } BESearchClosure;
 
-static void
-closure_destroy (BESearchClosure *closure)
-{
-	e_flag_free (closure->running);
-	g_free (closure);
-}
-
 static BESearchClosure*
 init_closure (EDataBookView *book_view, EBookBackendMAPI *bg)
 {
-	BESearchClosure *closure = g_new (BESearchClosure, 1);
+	BESearchClosure *closure;
 
+	g_return_val_if_fail (bg != NULL, NULL);
+	g_return_val_if_fail (bg->priv != NULL, NULL);
+	g_return_val_if_fail (bg->priv->view_to_closure_hash != NULL, NULL);
+	
+	closure = g_new0 (BESearchClosure, 1);
 	closure->bg = bg;
-	closure->thread = NULL;
-	closure->running = e_flag_new ();
+	closure->book_view = book_view;
+	closure->stop = FALSE;
 
-	g_object_set_data_full (G_OBJECT (book_view), "closure",
-				closure, (GDestroyNotify)closure_destroy);
+	g_hash_table_insert (bg->priv->view_to_closure_hash, g_object_ref (book_view), closure);
 
 	return closure;
 }
 
-static BESearchClosure*
-get_closure (EDataBookView *book_view)
+static void
+destroy_closure (BESearchClosure *closure)
+{
+	g_return_if_fail (closure != NULL);
+
+	if (closure->book_view)
+		g_object_unref (closure->book_view);
+	g_free (closure);
+}
+
+static void
+stop_book_view (EDataBookView *book_view, BESearchClosure *closure, EBookBackendMAPI *mapi_backend)
+{
+	g_return_if_fail (closure != NULL);
+
+	closure->stop = TRUE;
+}
+
+static void
+untrack_book_view (EBookBackendMAPI *mapi_backend, EDataBookView *book_view)
 {
-	return g_object_get_data (G_OBJECT (book_view), "closure");
+	g_return_if_fail (mapi_backend != NULL);
+	g_return_if_fail (mapi_backend->priv != NULL);
+	g_return_if_fail (mapi_backend->priv->view_to_closure_hash != NULL);
+	g_return_if_fail (book_view != NULL);
+
+	g_hash_table_remove (mapi_backend->priv->view_to_closure_hash, book_view);
 }
 
 static void
@@ -1154,7 +1164,7 @@ get_contacts_from_cache (EBookBackendMAPI *ebmapi,
 		gchar *uid;
 		EContact *contact;
 
-                if (!e_flag_is_set (closure->running))
+                if (closure->stop)
                         break;
 
 		uid = g_ptr_array_index (ids, i);
@@ -1164,25 +1174,20 @@ get_contacts_from_cache (EBookBackendMAPI *ebmapi,
 			g_object_unref (contact);
 		}
 	}
-	if (e_flag_is_set (closure->running))
-		e_data_book_view_notify_complete (book_view,
-						  GNOME_Evolution_Addressbook_Success);
 }
 
 static gboolean
 create_contact_cb (FetchItemsCallbackData *item_data, gpointer data)
 {
-	EDataBookView *book_view = data;
-	BESearchClosure *closure = get_closure (book_view);
+	BESearchClosure *closure = data;
+	EDataBookView *book_view = closure->book_view;
 	EBookBackendMAPI *be = closure->bg;
 	EContact *contact;
 	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) be)->priv;
 	gchar *suid;
 
-	if (!e_flag_is_set (closure->running)) {
-		printf("Might be that the operation is cancelled. Lets ask our parent also to do.\n");
+	if (closure->stop)
 		return FALSE;
-	}
 
 	contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, item_data->properties, NULL);
 	suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
@@ -1206,8 +1211,8 @@ book_view_thread (gpointer data)
 {
 	struct mapi_SRestriction res;
 	struct mapi_SRestriction_or *or_res = NULL;
-	EDataBookView *book_view = data;
-	BESearchClosure *closure = get_closure (book_view);
+	BESearchClosure *closure = data;
+	EDataBookView *book_view = closure->book_view;
 	EBookBackendMAPI *backend = closure->bg;
 	EBookBackendMAPIPrivate *priv = backend->priv;
 	const gchar *query = NULL;
@@ -1228,9 +1233,6 @@ book_view_thread (gpointer data)
 	if (enable_debug)
 		printf("mapi: book view\n");
 
-	g_object_ref (book_view);
-	e_flag_set (closure->running);
-
 	e_data_book_view_notify_status_message (book_view, "Searching...");
 	query = e_data_book_view_get_card_query (book_view);
 
@@ -1240,13 +1242,16 @@ book_view_thread (gpointer data)
 		if (!priv->marked_for_offline) {
 			e_data_book_view_notify_complete (book_view,
 					GNOME_Evolution_Addressbook_OfflineUnavailable);
-			g_object_unref (book_view);
+			untrack_book_view (backend, book_view);
+			destroy_closure (closure);
 			return;
 		}
 		if (!priv->cache) {
 			printf("The cache is not yet built\n");
 			e_data_book_view_notify_complete (book_view,
 					GNOME_Evolution_Addressbook_Success);
+			untrack_book_view (backend, book_view);
+			destroy_closure (closure);
 			return;
 		}
 
@@ -1255,11 +1260,12 @@ book_view_thread (gpointer data)
 			if (enable_debug)
 				printf ("reading the contacts from summary \n");
 			ids = e_book_backend_summary_search (priv->summary, query);
-			if (ids && ids->len > 0) {
+			if (ids && ids->len > 0)
 				get_contacts_from_cache (backend, query, ids, book_view, closure);
+			if (ids)
 				g_ptr_array_free (ids, TRUE);
-			}
-			g_object_unref (book_view);
+			untrack_book_view (backend, book_view);
+			destroy_closure (closure);
 			return;
 		}
 
@@ -1271,7 +1277,7 @@ book_view_thread (gpointer data)
 							      query);
 		temp_list = contacts;
 		for (; contacts != NULL; contacts = g_list_next(contacts)) {
-			if (!e_flag_is_set (closure->running)) {
+			if (closure->stop) {
 				for (;contacts != NULL; contacts = g_list_next (contacts))
 					g_object_unref (contacts->data);
 				break;
@@ -1280,12 +1286,11 @@ book_view_thread (gpointer data)
 							E_CONTACT(contacts->data));
 			g_object_unref (contacts->data);
 		}
-		if (e_flag_is_set (closure->running))
-			e_data_book_view_notify_complete (book_view,
-							  GNOME_Evolution_Addressbook_Success);
+		e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_Success);
 		if (temp_list)
 			 g_list_free (temp_list);
-		g_object_unref (book_view);
+		untrack_book_view (backend, book_view);
+		destroy_closure (closure);
 		return;
 
 	case GNOME_Evolution_Addressbook_MODE_REMOTE:
@@ -1294,7 +1299,8 @@ book_view_thread (gpointer data)
 			e_book_backend_notify_auth_required (E_BOOK_BACKEND (backend));
 			e_data_book_view_notify_complete (book_view,
 						GNOME_Evolution_Addressbook_AuthenticationRequired);
-			g_object_unref (book_view);
+			untrack_book_view (backend, book_view);
+			destroy_closure (closure);
 			return;
 		}
 
@@ -1304,11 +1310,12 @@ book_view_thread (gpointer data)
 				if (enable_debug)
 					printf ("reading the contacts from summary \n");
 				ids = e_book_backend_summary_search (priv->summary, query);
-				if (ids && ids->len > 0) {
+				if (ids && ids->len > 0)
 					get_contacts_from_cache (backend, query, ids, book_view, closure);
+				if (ids)
 					g_ptr_array_free (ids, TRUE);
-				}
-				g_object_unref (book_view);
+				untrack_book_view (backend, book_view);
+				destroy_closure (closure);
 				return;
 			}
 
@@ -1319,7 +1326,7 @@ book_view_thread (gpointer data)
 								      query);
 			temp_list = contacts;
 			for (; contacts != NULL; contacts = g_list_next(contacts)) {
-				if (!e_flag_is_set (closure->running)) {
+				if (closure->stop) {
 					for (;contacts != NULL; contacts = g_list_next (contacts))
 						g_object_unref (contacts->data);
 					break;
@@ -1328,57 +1335,60 @@ book_view_thread (gpointer data)
 								E_CONTACT(contacts->data));
 				g_object_unref (contacts->data);
 			}
-			if (e_flag_is_set (closure->running))
-				e_data_book_view_notify_complete (book_view,
-								  GNOME_Evolution_Addressbook_Success);
+			e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_Success);
 			if (temp_list)
 				 g_list_free (temp_list);
-			g_object_unref (book_view);
+			untrack_book_view (backend, book_view);
+			destroy_closure (closure);
 			return;
 		}
 
 		if (e_book_backend_summary_is_summary_query (priv->summary, query)) {
-			or_res = g_new (struct mapi_SRestriction_or, res_count);
+			/* free when done with or_res, not before */
+			gchar *to_free = NULL;
 
-			if (!build_multiple_restriction_emails_contains (priv->conn, priv->fid, &res, or_res, query)) {
+			or_res = g_new0 (struct mapi_SRestriction_or, res_count);
+
+			if (!build_multiple_restriction_emails_contains (priv->conn, priv->fid, &res, or_res, query, &to_free)) {
 				e_data_book_view_notify_complete (book_view,
 							  GNOME_Evolution_Addressbook_OtherError);
+				g_free (or_res);
+				g_free (to_free);
+				untrack_book_view (backend, book_view);
+				destroy_closure (closure);
 				return;
 			}
 
 			//FIXME: We need to fetch only the query from the server live and not everything.
 			if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, &res, NULL,
 							   is_public ? NULL : mapi_book_utils_get_prop_list, GET_SHORT_SUMMARY,
-							   create_contact_cb, book_view,
+							   create_contact_cb, closure,
 							   options)) {
-			if (e_flag_is_set (closure->running))
-				e_data_book_view_notify_complete (book_view,
-								  GNOME_Evolution_Addressbook_OtherError);
-				g_object_unref (book_view);
+				e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_OtherError);
 
 				if (or_res)
 					g_free(or_res);
+				g_free (to_free);
+				untrack_book_view (backend, book_view);
+				destroy_closure (closure);
 
 				return;
 			}
+
+			g_free (to_free);
 		} else {
 			if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, NULL, NULL,
 							is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
-							create_contact_cb, book_view,
+							create_contact_cb, closure,
 							options)) {
-				if (e_flag_is_set (closure->running))
-					e_data_book_view_notify_complete (book_view,
-									  GNOME_Evolution_Addressbook_OtherError);
-				g_object_unref (book_view);
+				e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_OtherError);
+				untrack_book_view (backend, book_view);
+				destroy_closure (closure);
 				return;
 			}
 		}
 
-		if (e_flag_is_set (closure->running))
-			e_data_book_view_notify_complete (book_view,
-							  GNOME_Evolution_Addressbook_Success);
-		g_object_unref (book_view);
-
+		e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_Success);
 	default:
 		break;
 	}
@@ -1386,7 +1396,8 @@ book_view_thread (gpointer data)
 	if (or_res)
 		g_free(or_res);
 
-	return;
+	untrack_book_view (backend, book_view);
+	destroy_closure (closure);
 }
 
 static void
@@ -1395,12 +1406,12 @@ e_book_backend_mapi_start_book_view (EBookBackend  *backend,
 {
 	BESearchClosure *closure = init_closure (book_view, E_BOOK_BACKEND_MAPI (backend));
 
+	g_return_if_fail (closure != NULL);
+
 	if (enable_debug)
 		printf ("mapi: start_book_view...\n");
-	closure->thread = g_thread_create ((GThreadFunc) book_view_thread, book_view, FALSE, NULL);
-	e_flag_wait (closure->running);
 
-	/* at this point we know the book view thread is actually running */
+	g_thread_create ((GThreadFunc) book_view_thread, closure, FALSE, NULL);
 }
 
 static void
@@ -1409,7 +1420,8 @@ e_book_backend_mapi_stop_book_view (EBookBackend  *backend,
 {
 	if (enable_debug)
 		printf("mapi: stop book view\n");
-	/* FIXME : provide implmentation */
+
+	untrack_book_view (E_BOOK_BACKEND_MAPI (backend), book_view);
 }
 
 static void
@@ -1561,6 +1573,7 @@ e_book_backend_mapi_authenticate_user (EBookBackend *backend,
 		return;
 
 	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+		g_static_mutex_lock (&priv->running_mutex);
 
 		/* rather reuse already established connection */
 		priv->conn = exchange_mapi_connection_find (priv->profile);
@@ -1569,8 +1582,11 @@ e_book_backend_mapi_authenticate_user (EBookBackend *backend,
 		else if (!priv->conn)
 			priv->conn = exchange_mapi_connection_new (priv->profile, passwd);
 
-		if (!priv->conn)
-			return e_data_book_respond_authenticate_user (book, opid,GNOME_Evolution_Addressbook_OtherError);
+		if (!priv->conn) {
+			e_data_book_respond_authenticate_user (book, opid,GNOME_Evolution_Addressbook_OtherError);
+			g_static_mutex_unlock (&priv->running_mutex);
+			return;
+		}
 
 		if (priv->cache && priv->is_cache_ready) {
 			printf("FIXME: Should check for an update in the cache\n");
@@ -1583,6 +1599,7 @@ e_book_backend_mapi_authenticate_user (EBookBackend *backend,
 		}
 		e_book_backend_set_is_writable (backend, TRUE);
 		e_data_book_respond_authenticate_user (book, opid, GNOME_Evolution_Addressbook_Success);
+		g_static_mutex_unlock (&priv->running_mutex);
 		return;
 
 	default :
@@ -1742,24 +1759,71 @@ e_book_backend_mapi_set_mode (EBookBackend *backend, GNOME_Evolution_Addressbook
 }
 
 static void
+e_book_backend_mapi_init (EBookBackendMAPI *backend)
+{
+	EBookBackendMAPIPrivate *priv;
+
+	priv = g_new0 (EBookBackendMAPIPrivate, 1);
+	/* Priv Struct init */
+	backend->priv = priv;
+
+	priv->view_to_closure_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
+	priv->summary = NULL;
+
+	priv->marked_for_offline = FALSE;
+	priv->uri = NULL;
+	priv->cache = NULL;
+	priv->is_summary_ready = FALSE;
+	priv->is_cache_ready = FALSE;
+	g_static_mutex_init (&priv->running_mutex);
+
+	if (g_getenv ("MAPI_DEBUG"))
+		enable_debug = TRUE;
+	else
+		enable_debug = FALSE;
+
+}
+
+static void
 e_book_backend_mapi_dispose (GObject *object)
 {
-	/* FIXME : provide implmentation */
-	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) object)->priv;
+	EBookBackendMAPI *mapi_backend = E_BOOK_BACKEND_MAPI (object);
+	EBookBackendMAPIPrivate *priv = mapi_backend->priv;
+
+	if (priv) {
+		if (priv->view_to_closure_hash) {
+			g_hash_table_foreach (priv->view_to_closure_hash, (GHFunc) stop_book_view, mapi_backend);
+			g_hash_table_destroy (priv->view_to_closure_hash);
+			priv->view_to_closure_hash = NULL;
+		}
 
-	if (priv->profile) {
-		g_free (priv->profile);
-		priv->profile = NULL;
-	}
-	if (priv->conn) {
-		g_object_unref (priv->conn);
-		priv->conn = NULL;
-	}
-	if (priv->uri) {
-		g_free (priv->uri);
-		priv->uri = NULL;
+		#define FREE(x) if (x) { g_free (x); x = NULL; }
+		#define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
+
+		/* this will also ensure any pending authentication
+		   request is finished and it's safe to free memory */
+		g_static_mutex_lock (&priv->running_mutex);
+
+		UNREF (priv->summary);
+		UNREF (priv->cache);
+		UNREF (priv->conn);
+
+		FREE (priv->profile);
+		FREE (priv->uri);
+		FREE (priv->summary_file_name);
+
+		g_static_mutex_unlock (&priv->running_mutex);
+		g_static_mutex_free (&priv->running_mutex);
+
+		FREE (mapi_backend->priv);
+
+		#undef UNREF
+		#undef FREE
 	}
 
+	/* Chain up to parent's dispose() method. */
+	if (G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose)
+		G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose (object);
 }
 
 static void e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
@@ -1767,8 +1831,6 @@ static void e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
 	GObjectClass  *object_class = G_OBJECT_CLASS (klass);
 	EBookBackendClass *parent_class;
 
-	e_book_backend_mapi_parent_class = g_type_class_peek_parent (klass);
-
 	parent_class = E_BOOK_BACKEND_CLASS (klass);
 
 	/* Set the virtual methods. */
@@ -1789,8 +1851,8 @@ static void e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
 	parent_class->cancel_operation           = e_book_backend_mapi_cancel_operation;
 	parent_class->remove                     = e_book_backend_mapi_remove;
 	parent_class->set_mode                   = e_book_backend_mapi_set_mode;
-	object_class->dispose                    = e_book_backend_mapi_dispose;
 
+	object_class->dispose                    = e_book_backend_mapi_dispose;
 }
 
 EBookBackend *e_book_backend_mapi_new (void)
@@ -1800,24 +1862,3 @@ EBookBackend *e_book_backend_mapi_new (void)
 	backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPI, NULL);
 	return E_BOOK_BACKEND (backend);
 }
-
-static void	e_book_backend_mapi_init (EBookBackendMAPI *backend)
-{
-	EBookBackendMAPIPrivate *priv;
-
-	priv= g_new0 (EBookBackendMAPIPrivate, 1);
-	/* Priv Struct init */
-	backend->priv = priv;
-
-	priv->marked_for_offline = FALSE;
-	priv->uri = NULL;
-	priv->cache = NULL;
-	priv->is_summary_ready = FALSE;
-	priv->is_cache_ready = FALSE;
-
-	if (g_getenv ("MAPI_DEBUG"))
-		enable_debug = TRUE;
-	else
-		enable_debug = FALSE;
-
-}



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