[evolution/gnome-2-32] Bug 647698 - Selected calendar doesnt authenticate after offline/online



commit ca0d2d390d80fdc81e08ace8fba6f632d2b3a573
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu Apr 14 08:23:13 2011 -0400

    Bug 647698 - Selected calendar doesnt authenticate after offline/online
    
    When I wrote e_load_cal_source_async() it didn't occur to me that a
    calendar backend may emit "auth-required" after the initial connection
    attempt.  And because I was passing the allocated context data for the
    asynchronous load operation to e_cal_set_auth_func(), meaning the data
    gets freed at the end of the load operation, I was then calling
    e_cal_set_auth_func(cal, NULL, NULL) after the initial authentication
    was complete so that the ECal would not try to access the freed context
    data after the load operation finished.
    
    But that turned out to break the case of switching to offline mode, then
    back to online mode.  Most calendar backends need to re-authenticate when
    they come back online.
    
    This commit instead passes data to the authentication function by way of
    g_object_set_data_full() so that the authentication function can be left
    in place for the duration of the ECal instance.
    
    Note that e_cal_set_auth_func() lacks a GDestroyNotify argument for the
    user data passed to it, which rules out passing any kind of allocated
    data structure.  This is an API design flaw, in my opinion.  But
    g_object_set_data_full() *does* take a GDestroyNotify argument.
    (cherry picked from commit 760c438e670e4ebe01c5431779628ed3a3189b76)

 calendar/common/authentication.c |   56 ++++++++++++++++++++++++++-----------
 1 files changed, 39 insertions(+), 17 deletions(-)
---
diff --git a/calendar/common/authentication.c b/calendar/common/authentication.c
index 286b7d6..ddcc0ff 100644
--- a/calendar/common/authentication.c
+++ b/calendar/common/authentication.c
@@ -131,7 +131,6 @@ typedef struct {
 	icaltimezone *default_zone;
 
 	/* Authentication Details */
-	gchar *auth_uri;
 	gchar *auth_component;
 } LoadContext;
 
@@ -147,7 +146,6 @@ load_cal_source_context_free (LoadContext *context)
 	if (context->cancellable != NULL)
 		g_object_unref (context->cancellable);
 
-	g_free (context->auth_uri);
 	g_free (context->auth_component);
 
 	g_slice_free (LoadContext, context);
@@ -177,28 +175,39 @@ static gchar *
 load_cal_source_authenticate (ECal *cal,
                               const gchar *prompt,
                               const gchar *uri,
-                              LoadContext *context)
+                              gpointer not_used)
 {
+	const gchar *auth_component;
 	const gchar *title;
 	gboolean remember;  /* not used */
+	GtkWindow *parent;
 	gchar *password;
 
+	/* XXX Dig up authentication info embedded in the ECal instance.
+	 * (See load_cal_source_thread() for an explanation of why.) */
+	auth_component = g_object_get_data (G_OBJECT (cal), "auth-component");
+	g_return_val_if_fail (auth_component != NULL, NULL);
+
+	parent = g_object_get_data (G_OBJECT (cal), "parent-window");
+
 	/* Remember the URI so we don't have to reconstruct it if
 	 * authentication fails and we have to forget the password. */
-	g_free (context->auth_uri);
-	context->auth_uri = g_strdup (uri);
+	g_object_set_data_full (
+		G_OBJECT (cal),
+		"auth-uri", g_strdup (uri),
+		(GDestroyNotify) g_free);
 
 	/* XXX Dialog windows should not have titles. */
 	title = "";
 
-	password = e_passwords_get_password (context->auth_component, uri);
+	password = e_passwords_get_password (auth_component, uri);
 
 	if (password == NULL)
 		password = e_passwords_ask_password (
-			title, context->auth_component, uri,
+			title, auth_component, uri,
 			prompt, E_PASSWORDS_REMEMBER_FOREVER |
 			E_PASSWORDS_SECRET | E_PASSWORDS_ONLINE,
-			&remember, context->parent);
+			&remember, parent);
 
 	return password;
 }
@@ -233,20 +242,28 @@ load_cal_source_thread (GSimpleAsyncResult *simple,
 		return;
 	}
 
-	/* XXX Why doesn't EBook have something like this? */
+	/* XXX e_cal_set_auth_func() does not take a GDestroyNotify callback
+	 *     for the 'user_data' argument, which makes the argument rather
+	 *     useless.  So instead, we'll embed the information needed by
+	 *     the authentication callback directly into the ECal instance
+	 *     using g_object_set_data_full(). */
+	g_object_set_data_full (
+		G_OBJECT (cal), "auth-component",
+		g_strdup (context->auth_component),
+		(GDestroyNotify) g_free);
+	if (context->parent != NULL)
+		g_object_set_data_full (
+			G_OBJECT (cal), "parent-window",
+			g_object_ref (context->parent),
+			(GDestroyNotify) g_object_unref);
+
 	e_cal_set_auth_func (
-		cal, (ECalAuthFunc)
-		load_cal_source_authenticate, context);
+		cal, (ECalAuthFunc) load_cal_source_authenticate, NULL);
 
 try_again:
 	if (!e_cal_open (cal, FALSE, &error))
 		goto fail;
 
-	/* We should be authenticated now if we're going to be,
-	 * so remove the authentication callback so it doesn't
-	 * get triggered after we free the load context. */
-	e_cal_set_auth_func (cal, NULL, NULL);
-
 	if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
 		g_simple_async_result_set_from_error (simple, error);
 		g_object_unref (cal);
@@ -265,8 +282,13 @@ fail:
 	if (g_error_matches (
 		error, E_CALENDAR_ERROR,
 		E_CALENDAR_STATUS_AUTHENTICATION_FAILED)) {
+		const gchar *auth_uri;
+
+		/* Retrieve the URI set by the authentication function. */
+		auth_uri = g_object_get_data (G_OBJECT (cal), "auth-uri");
+
 		e_passwords_forget_password (
-			context->auth_component, context->auth_uri);
+			context->auth_component, auth_uri);
 		g_clear_error (&error);
 		goto try_again;
 



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