[evolution-mapi] Bug #668637 - May not be able to create books/calendars in offline



commit 987221e3f08cda8920e4d12f49d97a01b05d4eac
Author: Milan Crha <mcrha redhat com>
Date:   Fri Jan 27 18:03:28 2012 +0100

    Bug #668637 - May not be able to create books/calendars in offline

 .../e-mapi-account-listener.c                      |    2 +-
 .../e-mapi-account-settings.c                      |  148 ++-
 src/account-setup-eplugin/e-mapi-account-setup.c   |  969 +++++++++++++++-----
 src/account-setup-eplugin/e-mapi-account-setup.h   |    8 +
 4 files changed, 831 insertions(+), 296 deletions(-)
---
diff --git a/src/account-setup-eplugin/e-mapi-account-listener.c b/src/account-setup-eplugin/e-mapi-account-listener.c
index c043885..3768069 100644
--- a/src/account-setup-eplugin/e-mapi-account-listener.c
+++ b/src/account-setup-eplugin/e-mapi-account-listener.c
@@ -949,7 +949,7 @@ update_account_sources_async (gpointer worker_data, gboolean cancelled, gpointer
 		csd->profile_name = g_strdup (profile);
 		csd->account = g_object_ref (account);
 
-		g_timeout_add_seconds (1, check_for_account_conn_cb, csd);
+		g_timeout_add_seconds (5, check_for_account_conn_cb, csd);
 	}
 
 	camel_url_free (url);
diff --git a/src/account-setup-eplugin/e-mapi-account-settings.c b/src/account-setup-eplugin/e-mapi-account-settings.c
index 6aa4a85..235d436 100644
--- a/src/account-setup-eplugin/e-mapi-account-settings.c
+++ b/src/account-setup-eplugin/e-mapi-account-settings.c
@@ -48,6 +48,7 @@
 #include <mail/em-folder-tree.h>
 
 #include "e-mapi-account-listener.h"
+#include "e-mapi-account-setup.h"
 #include "e-mapi-subscribe-foreign-folder.h"
 #include "e-mapi-edit-folder-permissions.h"
 
@@ -68,26 +69,35 @@ typedef struct
 	GtkGrid *spinner_grid;
 
 	gchar *profile;
+	gchar *username;
+	gchar *host;
 
 	GSList *folder_list;
-	EMapiConnection *conn;
+	GCancellable *cancellable;
+	GError *error;
 } FolderSizeDialogData;
 
 static gboolean
-fill_folder_size_dialog_cb (gpointer data)
+mapi_settings_get_folder_size_idle (gpointer user_data)
 {
 	GtkWidget *widget;
 	GtkCellRenderer *renderer;
 	GtkListStore *store;
 	GtkTreeIter iter;
 	GtkBox *content_area;
-	FolderSizeDialogData *dialog_data = (FolderSizeDialogData *)data;
+	FolderSizeDialogData *fsd = user_data;
+
+	g_return_val_if_fail (fsd != NULL, FALSE);
+
+	if (g_cancellable_is_cancelled (fsd->cancellable))
+		goto cleanup;
 
 	/* Hide progress bar. Set status*/
-	gtk_widget_destroy (GTK_WIDGET (dialog_data->spinner_grid));
+	gtk_widget_destroy (GTK_WIDGET (fsd->spinner_grid));
 
-	if (dialog_data->folder_list) {
+	if (fsd->folder_list) {
 		GtkWidget *scrolledwindow, *tree_view;
+		GSList *fiter;
 
 		scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
 		gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
@@ -109,8 +119,8 @@ fill_folder_size_dialog_cb (gpointer data)
 		gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (store));
 
 		/* Populate model with data */
-		while (dialog_data->folder_list) {
-			EMapiFolder *folder = (EMapiFolder *) dialog_data->folder_list->data;
+		for (fiter = fsd->folder_list; fiter;  fiter = fiter->next) {
+			EMapiFolder *folder = fiter->data;
 			gchar *folder_size = g_format_size_for_display (folder->size);
 
 			gtk_list_store_append (store, &iter);
@@ -118,12 +128,16 @@ fill_folder_size_dialog_cb (gpointer data)
 					    COL_FOLDERSIZE_NAME, folder->folder_name,
 					    COL_FOLDERSIZE_SIZE, folder_size,
 					    -1);
-			dialog_data->folder_list = g_slist_next (dialog_data->folder_list);
+
 			g_free (folder_size);
 		}
 
 		gtk_container_add (GTK_CONTAINER (scrolledwindow), tree_view);
 		widget = scrolledwindow;
+	} else if (fsd->error) {
+		gchar *msg = g_strconcat (_("Unable to retrieve folder size information"), "\n", fsd->error->message, NULL);
+		widget = gtk_label_new (msg);
+		g_free (msg);
 	} else {
 		widget = gtk_label_new (_("Unable to retrieve folder size information"));
 	}
@@ -131,91 +145,117 @@ fill_folder_size_dialog_cb (gpointer data)
 	gtk_widget_show_all (widget);
 
 	/* Pack into content_area */
-	content_area = GTK_BOX (gtk_dialog_get_content_area (dialog_data->dialog));
+	content_area = GTK_BOX (gtk_dialog_get_content_area (fsd->dialog));
 	gtk_box_pack_start (content_area, widget, TRUE, TRUE, 6);
 
-	if (dialog_data->conn)
-		g_object_unref (dialog_data->conn);
+ cleanup:
+	e_mapi_folder_free_list (fsd->folder_list);
+	g_free (fsd->profile);
+	g_free (fsd->username);
+	g_free (fsd->host);
+	g_object_unref (fsd->cancellable);
+	g_clear_error (&fsd->error);
+	g_free (fsd);
 
 	return FALSE;
 }
 
 static gpointer
-mapi_settings_get_folder_size (gpointer data)
+mapi_settings_get_folder_size_thread (gpointer user_data)
 {
-	FolderSizeDialogData *dialog_data = (FolderSizeDialogData *)data;
+	FolderSizeDialogData *fsd = user_data;
+	EMapiConnection *conn;
+
+	g_return_val_if_fail (fsd != NULL, NULL);
+
+	fsd->folder_list = NULL;
+	conn = e_mapi_account_open_connection_for (GTK_WINDOW (fsd->dialog),
+		fsd->profile,
+		fsd->username,
+		fsd->host,
+		fsd->cancellable,
+		&fsd->error);
+
+	if (conn && e_mapi_connection_connected (conn)) {
+		fsd->folder_list = NULL;
+		e_mapi_connection_get_folders_list (conn,
+			&fsd->folder_list,
+			NULL, NULL,
+			fsd->cancellable, &fsd->error);
+	}
 
-	dialog_data->folder_list = NULL;
-	dialog_data->conn = e_mapi_connection_find (dialog_data->profile);
-	if (dialog_data->conn && e_mapi_connection_connected (dialog_data->conn))
-		dialog_data->folder_list = e_mapi_connection_peek_folders_list (dialog_data->conn);
+	if (conn)
+		g_object_unref (conn);
 
-	g_timeout_add (100, fill_folder_size_dialog_cb, dialog_data);
+	g_idle_add (mapi_settings_get_folder_size_idle, fsd);
 
 	return NULL;
 }
 
 static void
-mapi_settings_run_folder_size_dialog (const gchar *profile, gpointer data)
+mapi_settings_run_folder_size_dialog (CamelMapiSettings *mapi_settings)
 {
 	GtkBox *content_area;
-	GtkWidget *spinner, *alignment;
+	GtkWidget *spinner, *alignment, *dialog;
 	GtkWidget *spinner_label;
-	FolderSizeDialogData *dialog_data;
+	GCancellable *cancellable;
+	FolderSizeDialogData *fsd;
 
-	dialog_data = g_new0 (FolderSizeDialogData, 1);
+	g_return_if_fail (mapi_settings != NULL);
 
-	dialog_data->dialog = (GtkDialog *)gtk_dialog_new_with_buttons (_("Folder Size"), NULL,
-							   GTK_DIALOG_DESTROY_WITH_PARENT,
-							   GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT,
-							   NULL);
+	dialog = gtk_dialog_new_with_buttons (_("Folder Size"), NULL,
+		GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT,
+		NULL);
 
-	gtk_window_set_default_size (GTK_WINDOW (dialog_data->dialog), 250, 300);
+	fsd = g_new0 (FolderSizeDialogData, 1);
+	fsd->dialog = GTK_DIALOG (dialog);
 
-	content_area = GTK_BOX (gtk_dialog_get_content_area (dialog_data->dialog));
+	gtk_window_set_default_size (GTK_WINDOW (fsd->dialog), 250, 300);
+
+	content_area = GTK_BOX (gtk_dialog_get_content_area (fsd->dialog));
 
 	spinner = gtk_spinner_new ();
 	gtk_spinner_start (GTK_SPINNER (spinner));
 	spinner_label = gtk_label_new (_("Fetching folder listâ"));
 
-	dialog_data->spinner_grid = GTK_GRID (gtk_grid_new ());
-	gtk_grid_set_column_spacing (dialog_data->spinner_grid, 6);
-	gtk_grid_set_column_homogeneous (dialog_data->spinner_grid, FALSE);
-	gtk_orientable_set_orientation (GTK_ORIENTABLE (dialog_data->spinner_grid), GTK_ORIENTATION_HORIZONTAL);
+	fsd->spinner_grid = GTK_GRID (gtk_grid_new ());
+	gtk_grid_set_column_spacing (fsd->spinner_grid, 6);
+	gtk_grid_set_column_homogeneous (fsd->spinner_grid, FALSE);
+	gtk_orientable_set_orientation (GTK_ORIENTABLE (fsd->spinner_grid), GTK_ORIENTATION_HORIZONTAL);
 
 	alignment = gtk_alignment_new (1.0, 0.5, 0.0, 1.0);
 	gtk_container_add (GTK_CONTAINER (alignment), spinner);
 	gtk_misc_set_alignment (GTK_MISC (spinner_label), 0.0, 0.5);
 
-	gtk_container_add (GTK_CONTAINER (dialog_data->spinner_grid), alignment);
-	gtk_container_add (GTK_CONTAINER (dialog_data->spinner_grid), spinner_label);
+	gtk_container_add (GTK_CONTAINER (fsd->spinner_grid), alignment);
+	gtk_container_add (GTK_CONTAINER (fsd->spinner_grid), spinner_label);
 
 	/* Pack the TreeView into dialog's content area */
-	gtk_box_pack_start (content_area, GTK_WIDGET (dialog_data->spinner_grid), TRUE, TRUE, 6);
-	gtk_widget_show_all (GTK_WIDGET (dialog_data->dialog));
+	gtk_box_pack_start (content_area, GTK_WIDGET (fsd->spinner_grid), TRUE, TRUE, 6);
+	gtk_widget_show_all (GTK_WIDGET (fsd->dialog));
 
-	dialog_data->profile = g_strdup (profile);
+	cancellable = g_cancellable_new ();
+	fsd->profile = g_strdup (camel_mapi_settings_get_profile (mapi_settings));
+	fsd->username = g_strdup (camel_network_settings_get_user (CAMEL_NETWORK_SETTINGS (mapi_settings)));
+	fsd->host = g_strdup (camel_network_settings_get_host (CAMEL_NETWORK_SETTINGS (mapi_settings)));
+	fsd->cancellable = g_object_ref (cancellable);
 
-	/* Fetch folder list and size information in a thread */
-	g_thread_create (mapi_settings_get_folder_size, dialog_data, FALSE, NULL);
+	g_return_if_fail (g_thread_create (mapi_settings_get_folder_size_thread, fsd, FALSE, NULL));
 
 	/* Start the dialog */
-	gtk_dialog_run (dialog_data->dialog);
-
-	gtk_widget_destroy (GTK_WIDGET (dialog_data->dialog));
+	gtk_dialog_run (GTK_DIALOG (dialog));
 
-	g_free (dialog_data->profile);
-	g_free (dialog_data);
+	g_cancellable_cancel (cancellable);
+	g_object_unref (cancellable);
+	gtk_widget_destroy (GTK_WIDGET (dialog));
 }
 
 static void
 folder_size_clicked (GtkButton *button,
                      CamelMapiSettings *mapi_settings)
 {
-	const gchar *profile;
-
-	profile = camel_mapi_settings_get_profile (mapi_settings);
-	mapi_settings_run_folder_size_dialog (profile, NULL);
+	mapi_settings_run_folder_size_dialog (mapi_settings);
 }
 
 static gchar *
@@ -271,12 +311,18 @@ action_folder_size_cb (GtkAction *action,
 		       EShellView *shell_view)
 {
 	gchar *profile;
+	CamelStore *store = NULL;
+	CamelMapiSettings *mapi_settings;
 
-	profile = get_profile_name_from_folder_tree (shell_view, NULL, NULL);
-	if (profile)
-		mapi_settings_run_folder_size_dialog (profile, NULL);
+	profile = get_profile_name_from_folder_tree (shell_view, NULL, &store);
+	if (profile && store) {
+		mapi_settings = CAMEL_MAPI_SETTINGS (camel_service_get_settings (CAMEL_SERVICE (store)));
+		mapi_settings_run_folder_size_dialog (mapi_settings);
+	}
 
 	g_free (profile);
+	if (store)
+		g_object_unref (store);
 }
 
 static void
diff --git a/src/account-setup-eplugin/e-mapi-account-setup.c b/src/account-setup-eplugin/e-mapi-account-setup.c
index fd8af88..bbfaead 100644
--- a/src/account-setup-eplugin/e-mapi-account-setup.c
+++ b/src/account-setup-eplugin/e-mapi-account-setup.c
@@ -31,6 +31,7 @@
 #include <glib/gi18n-lib.h>
 
 #include <gtk/gtk.h>
+#include <libedataserver/e-flag.h>
 #include <libedataserver/e-xml-hash-utils.h>
 #include <libedataserver/e-credentials.h>
 #include <libedataserverui/e-passwords.h>
@@ -38,7 +39,6 @@
 #include <e-util/e-dialog-utils.h>
 #include <e-util/e-plugin-util.h>
 #include "mail/em-config.h"
-#include "e-mapi-account-setup.h"
 #include <addressbook/gui/widgets/eab-config.h>
 #include <calendar/gui/e-cal-config.h>
 #include <shell/e-shell.h>
@@ -47,6 +47,8 @@
 #include <e-mapi-connection.h>
 #include <e-mapi-utils.h>
 
+#include "e-mapi-account-setup.h"
+
 #define d(x)
 
 gint e_plugin_lib_enable (EPlugin *ep, gint enable);
@@ -94,6 +96,16 @@ e_mapi_accounts_peek_config_listener ()
 	return config_listener;
 }
 
+static gboolean
+e_mapi_test_is_online (void)
+{
+	EShell *shell;
+
+	shell = e_shell_get_default ();
+
+	return shell && e_shell_get_online (shell);
+}
+
 enum {
   COL_MAPI_FULL_NAME = 0,
   COL_MAPI_ACCOUNT,
@@ -142,38 +154,29 @@ transform_boolean_to_security_method (GBinding *binding,
 	return TRUE;
 }
 
-/* Callback for ProcessNetworkProfile. If we have more than one username,
- we need to let the user select. */
-static uint32_t
-create_profile_callback (struct SRowSet *rowset, gconstpointer data)
+struct ECreateProfileData
 {
-	struct SPropValue *lpProp_fullname, *lpProp_account;
+	const gchar *username;
+	struct SRowSet *rowset;
+	gint index;
+	EFlag *flag;
+};
+
+static gboolean
+create_profile_callback_in_main (gpointer user_data)
+{
+	struct ECreateProfileData *cpd = user_data;
 	gint response;
-	guint32	i, index = 0;
+	gint i, index = 0;
 	GtkTreeIter iter;
 	GtkListStore *store;
 	GtkCellRenderer *renderer;
 	GtkTreeSelection *selection;
 	GtkWidget *dialog, *view;
 	GtkBox *content_area;
-	const gchar *username = (const gchar *)data;
 
-	/* If we can find the exact username, then find & return its index. */
-	for (i = 0; i < rowset->cRows; i++) {
-		lpProp_account = get_SPropValue_SRow(&(rowset->aRow[i]), PR_ACCOUNT_UNICODE);
-		if (!lpProp_account)
-			lpProp_account = get_SPropValue_SRow(&(rowset->aRow[i]), PR_ACCOUNT);
+	g_return_val_if_fail (cpd != NULL, FALSE);
 
-		if (lpProp_account && lpProp_account->value.lpszA &&
-		    !g_strcmp0 (username, lpProp_account->value.lpszA))
-			return i;
-	}
-
-	/* NOTE: A good way would be display the list of username entries */
-	/* using GtkEntryCompletion in the username gtkentry. But plugins */
-	/* as of now does not have access to it */
-
-	/*TODO : Fix strings*/
 	dialog = gtk_dialog_new_with_buttons (_("Select username"),
 					      NULL, GTK_DIALOG_MODAL,
 					      GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
@@ -199,21 +202,16 @@ create_profile_callback (struct SRowSet *rowset, gconstpointer data)
 	store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
 	gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL (store));
 
-	for (i = 0; i < rowset->cRows; i++) {
-		lpProp_fullname = get_SPropValue_SRow(&(rowset->aRow[i]), PR_DISPLAY_NAME_UNICODE);
-		if (!lpProp_fullname)
-			lpProp_fullname = get_SPropValue_SRow(&(rowset->aRow[i]), PR_DISPLAY_NAME);
-		lpProp_account = get_SPropValue_SRow(&(rowset->aRow[i]), PR_ACCOUNT_UNICODE);
-		if (!lpProp_account)
-			lpProp_account = get_SPropValue_SRow(&(rowset->aRow[i]), PR_ACCOUNT);
-
-		if (lpProp_fullname && lpProp_fullname->value.lpszA &&
-		    lpProp_account && lpProp_account->value.lpszA) {
+	for (i = 0; i < cpd->rowset->cRows; i++) {
+		const gchar *fullname = e_mapi_util_find_row_propval (&(cpd->rowset->aRow[i]), PidTagDisplayName);
+		const gchar *account = e_mapi_util_find_row_propval (&(cpd->rowset->aRow[i]), PidTagAccount);
+
+		if (fullname && account) {
 			gtk_list_store_append (store, &iter);
 			/* Preserve the index inside the store*/
 			gtk_list_store_set (store, &iter,
-					    COL_MAPI_FULL_NAME, lpProp_fullname->value.lpszA,
-					    COL_MAPI_ACCOUNT, lpProp_account->value.lpszA,
+					    COL_MAPI_FULL_NAME, fullname,
+					    COL_MAPI_ACCOUNT, account,
 					    COL_MAPI_INDEX, i, -1);
 		}
 	}
@@ -236,33 +234,188 @@ create_profile_callback (struct SRowSet *rowset, gconstpointer data)
 		if (gtk_tree_selection_get_selected (selection, NULL, &iter))
 			gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COL_MAPI_INDEX, &index, -1);
 		else
-			index = rowset->cRows + 1;
+			index = cpd->rowset->cRows + 1;
 	} else /* If we return a value > available, we are canceling the login.*/
-	       index = rowset->cRows + 1;
+	       index = cpd->rowset->cRows + 1;
 
 	gtk_widget_destroy (dialog);
 
-	return index;
+	cpd->index = index;
+	e_flag_set (cpd->flag);
+
+	return FALSE;
+}
+
+/* Callback for ProcessNetworkProfile. If we have more than one username,
+ we need to let the user select. */
+static gint
+create_profile_callback_in_thread (struct SRowSet *rowset,
+				   gconstpointer data)
+{
+	struct ECreateProfileData cpd;
+	const gchar *username = (const gchar *) data;
+	gint i;
+
+	/* If we can find the exact username, then find & return its index. */
+	for (i = 0; i < rowset->cRows; i++) {
+		const gchar *account = e_mapi_util_find_row_propval (&(rowset->aRow[i]), PidTagAccount);
+
+		if (account && g_strcmp0 (username, account) == 0)
+			return i;
+	}
+
+	cpd.username = username;
+	cpd.rowset = rowset;
+	cpd.index = -1;
+	cpd.flag = e_flag_new ();
+
+	g_timeout_add (100, create_profile_callback_in_main, &cpd);
+
+	e_flag_wait (cpd.flag);
+	e_flag_free (cpd.flag);
+
+	return cpd.index;
 }
 
-static char*
-prompt_password(const gchar *user, const gchar *host, const gchar *key,
-		EMConfigTargetSettings *account)
+static gchar *
+prompt_password (const gchar *user,
+		 const gchar *host,
+		 const gchar *key)
 {
-	guint32 pw_flags = E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET;
+	guint32 pw_flags = E_PASSWORDS_REMEMBER_FOREVER | E_PASSWORDS_SECRET;
 	gchar *password, *title;
 	gboolean save = TRUE;
 
 	title = g_strdup_printf (_("Enter Password for %s %s"), user, host);
-	password = e_passwords_ask_password (title, NULL, key, title, pw_flags,
-					     &save, NULL);
+	password = e_passwords_ask_password (title, NULL, key, title, pw_flags, &save, NULL);
 	g_free (title);
 
 	return password;
 }
 
+static GtkWindow *
+get_widget_toplevel_window (GtkWidget *widget)
+{
+	if (!widget)
+		return NULL;
+
+	if (!GTK_IS_WINDOW (widget))
+		widget = gtk_widget_get_toplevel (widget);
+
+	if (GTK_IS_WINDOW (widget))
+		return GTK_WINDOW (widget);
+
+	return NULL;
+}
+
+struct EMapiValidateCredentialsData
+{
+	gchar *username;
+	gchar *password;
+	gchar *domain;
+	gchar *server;
+	gboolean use_ssl;
+	gboolean krb_sso;
+	gchar *krb_realm;
+	gchar *key;
+	CamelMapiSettings *mapi_settings;
+	gboolean success;
+};
+
+static void
+e_mapi_validate_credentials_data_free (gpointer ptr)
+{
+	struct EMapiValidateCredentialsData *vcd = ptr;
+
+	if (!vcd)
+		return;
+
+	g_free (vcd->username);
+	e_credentials_util_safe_free_string (vcd->password);
+	g_free (vcd->domain);
+	g_free (vcd->server);
+	g_free (vcd->krb_realm);
+	g_free (vcd->key);
+	g_object_unref (vcd->mapi_settings);
+	g_free (vcd);
+}
+
+static void
+validate_credentials_idle (GObject *button,
+			   gpointer user_data,
+			   GCancellable *cancellable,
+			   GError **perror)
+{
+	struct EMapiValidateCredentialsData *vcd = user_data;
+
+	g_return_if_fail (vcd != NULL);
+
+	if (vcd->success)
+		e_notice (NULL, GTK_MESSAGE_INFO, "%s", _("Authentication finished successfully."));
+	else
+		e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Authentication failed."));
+}
+
+static void
+validate_credentials_thread (GObject *button,
+			     gpointer user_data,
+			     GCancellable *cancellable,
+			     GError **perror)
+{
+	struct EMapiValidateCredentialsData *vcd = user_data;
+	EMapiProfileData empd;
+	gboolean status;
+	struct mapi_context *mapi_ctx = NULL;
+
+
+	g_return_if_fail (vcd != NULL);
+
+	empd.username = vcd->username;
+	empd.password = vcd->password;
+	empd.domain = vcd->domain;
+	empd.server = vcd->server;
+	empd.use_ssl = vcd->use_ssl;
+	empd.krb_sso = vcd->krb_sso;
+	empd.krb_realm = vcd->krb_realm;
+	
+	status = e_mapi_utils_create_mapi_context (&mapi_ctx, perror);
+	status = status && e_mapi_create_profile (mapi_ctx, &empd, create_profile_callback_in_thread, empd.username, NULL, perror);
+	if (status && !g_cancellable_is_cancelled (cancellable)) {
+		/* profile was created, try to connect to the server */
+		EMapiConnection *conn;
+		gchar *profname;
+
+		status = FALSE;
+		profname = e_mapi_util_profile_name (mapi_ctx, &empd, FALSE);
+
+		conn = e_mapi_connection_new (profname, empd.password, cancellable, perror);
+		if (conn) {
+			status = e_mapi_connection_connected (conn);
+			g_object_unref (conn);
+		}
+
+		g_free (profname);
+	}
+
+	if (status) {
+		/* Things are successful */
+		gchar *profname = NULL;
+
+		profname = e_mapi_util_profile_name (mapi_ctx, &empd, FALSE);
+		camel_mapi_settings_set_profile (vcd->mapi_settings, profname);
+		g_free (profname);
+
+		vcd->success = TRUE;
+	} else {
+		e_passwords_forget_password (NULL, vcd->key);
+	}
+
+	e_mapi_utils_destroy_mapi_context (mapi_ctx);
+}
+
 static void
-validate_credentials (GtkWidget *widget, EConfig *config)
+validate_credentials_cb (GtkWidget *widget,
+			 EConfig *config)
 {
 	EMConfigTargetSettings *target_account = (EMConfigTargetSettings *)(config->target);
 	CamelURL *url = NULL;
@@ -275,8 +428,8 @@ validate_credentials (GtkWidget *widget, EConfig *config)
 	const gchar *user;
 	GError *error = NULL;
 
-	if (!e_shell_get_online (e_shell_get_default ())) {
-		e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Cannot create MAPI folders in offline mode."));
+	if (!e_mapi_test_is_online ()) {
+		e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Cannot authenticate MAPI accounts in offline mode"));
 		return;
 	}
 
@@ -312,7 +465,7 @@ validate_credentials (GtkWidget *widget, EConfig *config)
 		return;
 	}
 
-	url = g_malloc0 (sizeof (CamelURL));
+	url = camel_url_new ("dummy://", NULL);
 	camel_settings_save_to_url (settings, url);
 	key = camel_url_to_string (url, CAMEL_URL_HIDE_PARAMS);
 	camel_url_free (url);
@@ -320,55 +473,30 @@ validate_credentials (GtkWidget *widget, EConfig *config)
 	if (empd.krb_sso) {
 		e_mapi_util_trigger_krb_auth (&empd, &error);
 	} else {
-		empd.password = prompt_password(empd.username, empd.server,
-						key, target_account);
+		empd.password = prompt_password (empd.username, empd.server, key);
 	}
 
-	if (COMPLETE_PROFILEDATA(&empd)) {
-		gboolean status;
-		struct mapi_context *mapi_ctx = NULL;
-
-		status = e_mapi_utils_create_mapi_context (&mapi_ctx, &error);
-		status = status && e_mapi_create_profile (mapi_ctx, &empd, (mapi_profile_callback_t) create_profile_callback, empd.username, NULL, &error);
-		if (status) {
-			/* profile was created, try to connect to the server */
-			EMapiConnection *conn;
-			gchar *profname;
-
-			status = FALSE;
-			profname = e_mapi_util_profile_name (mapi_ctx, &empd, FALSE);
-
-			conn = e_mapi_connection_new (profname, empd.password, NULL, &error);
-			if (conn) {
-				status = e_mapi_connection_connected (conn);
-				g_object_unref (conn);
-			}
-
-			g_free (profname);
-		}
-
-		if (status) {
-			/* Things are successful */
-			gchar *profname = NULL;
-
-			profname = e_mapi_util_profile_name (mapi_ctx, &empd, FALSE);
-			camel_mapi_settings_set_profile (mapi_settings, profname);
-			g_free (profname);
-
-			e_notice (NULL, GTK_MESSAGE_INFO, "%s", _("Authentication finished successfully."));
-		} else {
-			gchar *e;
-
-			e_passwords_forget_password (NULL, key);
-
-			e = g_strconcat (_("Authentication failed."), "\n", error ? error->message : NULL, NULL);
-
-			e_notice (NULL, GTK_MESSAGE_ERROR, "%s", e);
-
-			g_free (e);
-		}
-
-		e_mapi_utils_destroy_mapi_context (mapi_ctx);
+	if (COMPLETE_PROFILEDATA (&empd)) {
+		struct EMapiValidateCredentialsData *vcd = g_new0 (struct EMapiValidateCredentialsData, 1);
+
+		vcd->username = g_strdup (empd.username);
+		vcd->password = g_strdup (empd.password);
+		vcd->domain = g_strdup (empd.domain);
+		vcd->server = g_strdup (empd.server);
+		vcd->use_ssl = empd.use_ssl;
+		vcd->krb_sso = empd.krb_sso;
+		vcd->krb_realm = g_strdup (empd.krb_realm);
+		vcd->key = g_strdup (key);
+		vcd->mapi_settings = g_object_ref (vcd->mapi_settings);
+		vcd->success = FALSE;
+
+		e_mapi_run_in_thread_with_feedback_modal (get_widget_toplevel_window (widget),
+			G_OBJECT (widget),
+			_("Connecting to a server, please wait..."),
+			validate_credentials_thread,
+			validate_credentials_idle,
+			vcd,
+			e_mapi_validate_credentials_data_free);
 	} else {
 		e_passwords_forget_password (NULL, key);
 		e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Authentication failed."));
@@ -377,7 +505,7 @@ validate_credentials (GtkWidget *widget, EConfig *config)
 	if (error)
 		g_error_free (error);
 
-	g_free (empd.password);
+	e_credentials_util_safe_free_string (empd.password);
 	g_free (key);
 }
 
@@ -419,7 +547,7 @@ org_gnome_e_mapi_account_setup (EPlugin *epl, EConfigHookItemFactoryData *data)
 
 	auth_button = gtk_button_new_with_mnemonic (_("_Authenticate"));
 	gtk_container_add (GTK_CONTAINER (hgrid), auth_button);
-	g_signal_connect (auth_button, "clicked",  G_CALLBACK (validate_credentials), data->config);
+	g_signal_connect (auth_button, "clicked",  G_CALLBACK (validate_credentials_cb), data->config);
 
 	gtk_table_attach (GTK_TABLE (data->parent), label, 0, 1, row, row+1, 0, 0, 0, 0);
 	gtk_widget_show_all (GTK_WIDGET (hgrid));
@@ -704,8 +832,119 @@ e_mapi_source_to_folder_category (ESource *source)
 	return E_MAPI_FOLDER_CATEGORY_PERSONAL;
 }
 
+struct EMapiFolderStructureData
+{
+	EMapiFolderType folder_type;
+	GSList *folders;
+	GtkWidget *tree_view;
+	ESource *source;
+};
+
+static void
+e_mapi_folder_structure_data_free (gpointer ptr)
+{
+	struct EMapiFolderStructureData *fsd = ptr;
+
+	if (!fsd)
+		return;
+
+	e_mapi_folder_free_list (fsd->folders);
+	g_object_unref (fsd->tree_view);
+	g_object_unref (fsd->source);
+	g_free (fsd);
+}
+
+static void
+e_mapi_download_folder_structure_idle (GObject *source_obj,
+				       gpointer user_data,
+				       GCancellable *cancellable,
+				       GError **perror)
+{
+	struct EMapiFolderStructureData *fsd = user_data;
+	GtkTreeStore *tree_store;
+	ESource *source;
+
+	g_return_if_fail (fsd != NULL);
+	g_return_if_fail (fsd->tree_view != NULL);
+	g_return_if_fail (source_obj != NULL);
+	g_return_if_fail (E_IS_SOURCE (source_obj));
+
+	source = E_SOURCE (source_obj);
+	tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fsd->tree_view)));
+	g_return_if_fail (tree_store != NULL);
+
+	add_folders (fsd->folders, tree_store, fsd->folder_type);
+	gtk_tree_view_expand_all (GTK_TREE_VIEW (fsd->tree_view));
+
+	if (e_source_get_property (source, "folder-id")) {
+		mapi_id_t fid;
+
+		e_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &fid);
+
+		select_folder (GTK_TREE_MODEL (tree_store), fid, fsd->tree_view);
+	}
+}
+
+static void
+e_mapi_download_folder_structure_thread (GObject *source_obj,
+					 gpointer user_data,
+					 GCancellable *cancellable,
+					 GError **perror)
+{
+	struct EMapiFolderStructureData *fsd = user_data;
+	ESource *source;
+	EMapiConnection *conn;
+
+	g_return_if_fail (fsd != NULL);
+	g_return_if_fail (fsd->tree_view != NULL);
+	g_return_if_fail (source_obj != NULL);
+	g_return_if_fail (E_IS_SOURCE (source_obj));
+
+	source = E_SOURCE (source_obj);
+
+	conn = e_mapi_account_open_connection_for (NULL,
+		e_source_get_property (source, "profile"),
+		e_source_get_property (source, "username"),
+		e_source_get_property (source, "host"),
+		cancellable,
+		perror);
+
+	if (!conn)
+		return;
+
+	if (conn && e_mapi_connection_connected (conn)) {
+		fsd->folders = e_mapi_connection_peek_folders_list (conn);
+		if (fsd->folders)
+			fsd->folders = e_mapi_folder_copy_list (fsd->folders);
+	}
+
+	if (conn)
+		g_object_unref (conn);
+}
+
+static gboolean
+e_mapi_invoke_folder_structure_download_idle (gpointer user_data)
+{
+	struct EMapiFolderStructureData *fsd = user_data;
+
+	g_return_val_if_fail (fsd != NULL, FALSE);
+
+	e_mapi_run_in_thread_with_feedback (get_widget_toplevel_window (fsd->tree_view),
+		G_OBJECT (fsd->source),
+		_("Searching remote MAPI folder structure, please wait..."),
+		e_mapi_download_folder_structure_thread,
+		e_mapi_download_folder_structure_idle,
+		fsd,
+		e_mapi_folder_structure_data_free);
+
+	return FALSE;
+}
+
 static GtkWidget *
-e_mapi_create (GtkWidget *parent, ESource *source, EMapiFolderType folder_type)
+e_mapi_create (GtkWidget *dialog,
+	       GtkWidget *parent,
+	       ESource *source,
+	       EMapiFolderType folder_type)
 {
 	GtkWidget *table, *label, *scroll, *tv;
 	gchar *uri_text, *profile = NULL;
@@ -715,9 +954,7 @@ e_mapi_create (GtkWidget *parent, ESource *source, EMapiFolderType folder_type)
 	GtkTreeStore *ts;
 	GtkTreeViewColumn *tvc;
 	const gchar *acc;
-	GSList *folders;
-	EMapiConnection *conn;
-	mapi_id_t fid = 0;
+	gboolean is_new_source;
 
 	uri_text = e_source_get_uri (source);
 	if (uri_text && g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH)) {
@@ -739,25 +976,29 @@ e_mapi_create (GtkWidget *parent, ESource *source, EMapiFolderType folder_type)
 		break;
 	}
 
-	folders = NULL;
 	group = e_source_peek_group (source);
 	profile = g_strdup (e_source_get_property (source, "profile"));
-	if (profile == NULL) {
+	is_new_source = e_source_get_property (source, "folder-id") == NULL;
+	if (is_new_source) {
+		gchar *tmp;
+
+		g_free (profile);
+
 		profile = e_source_group_get_property (group, "profile");
 		e_source_set_property (source, "profile", profile);
+
+		tmp = e_source_group_get_property (group, "username");
+		e_source_set_property (source, "username", tmp);
+		g_free (tmp);
+
+		tmp = e_source_group_get_property (group, "host");
+		e_source_set_property (source, "host", tmp);
+		g_free (tmp);
 	}
-	conn = e_mapi_connection_find (profile);
 	g_free (profile);
-	if (conn && e_mapi_connection_connected (conn))
-		folders = e_mapi_connection_peek_folders_list (conn);
+
 	acc = e_source_group_peek_name (group);
 	ts = gtk_tree_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_INT64, G_TYPE_POINTER);
-
-	add_folders (folders, ts, folder_type);
-
-	if (conn)
-		g_object_unref (conn);
-
 	table = g_object_new (GTK_TYPE_TABLE, NULL);
 
 	if (folder_type == E_MAPI_FOLDER_TYPE_CONTACT) {
@@ -767,34 +1008,69 @@ e_mapi_create (GtkWidget *parent, ESource *source, EMapiFolderType folder_type)
 		gtk_table_attach (GTK_TABLE (parent), table, 0, 2, row, row + 1, GTK_FILL|GTK_EXPAND, 0, 0, 0);
 	}
 
-	label = gtk_label_new_with_mnemonic (_("_Location:"));
-	gtk_widget_show (label);
-	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	if (is_new_source && !e_mapi_test_is_online ()) {
+		const gchar *msg;
 
-	rcell = gtk_cell_renderer_text_new ();
-	tvc = gtk_tree_view_column_new_with_attributes (acc, rcell, "text", NAME_COL, NULL);
-	tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (ts));
-	gtk_tree_view_append_column (GTK_TREE_VIEW (tv), tvc);
-	g_object_set (tv,"expander-column", tvc, "headers-visible", TRUE, NULL);
-	gtk_tree_view_expand_all (GTK_TREE_VIEW (tv));
+		switch (folder_type) {
+		case E_MAPI_FOLDER_TYPE_APPOINTMENT:
+			msg = _("Cannot create MAPI calendar in offline mode");
+			break;
+		case E_MAPI_FOLDER_TYPE_TASK:
+			msg = _("Cannot create MAPI task list in offline mode");
+			break;
+		case E_MAPI_FOLDER_TYPE_MEMO:
+			msg = _("Cannot create MAPI memo list in offline mode");
+			break;
+		case E_MAPI_FOLDER_TYPE_CONTACT:
+			msg = _("Cannot create MAPI address book in offline mode");
+			break;
+		default:
+			g_warn_if_reached ();
+			msg = _("Cannot create MAPI source in offline mode");
+			break;
+		}
 
-	if (e_source_get_property (source, "folder-id")) {
-		e_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &fid);
-		select_folder (GTK_TREE_MODEL (ts), fid, tv);
+		label = gtk_label_new (msg);
+		gtk_widget_show (label);
+		gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+		gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	} else {
+		label = gtk_label_new_with_mnemonic (_("_Location:"));
+		gtk_widget_show (label);
+		gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+		gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+
+		rcell = gtk_cell_renderer_text_new ();
+		tvc = gtk_tree_view_column_new_with_attributes (acc, rcell, "text", NAME_COL, NULL);
+		tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (ts));
+		gtk_tree_view_append_column (GTK_TREE_VIEW (tv), tvc);
+		g_object_set (tv,"expander-column", tvc, "headers-visible", TRUE, NULL);
+		gtk_widget_set_sensitive (tv, is_new_source);
+
+		scroll = gtk_scrolled_window_new (NULL, NULL);
+		gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+		gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
+		g_object_set (scroll, "height-request", 150, NULL);
+		gtk_container_add (GTK_CONTAINER (scroll), tv);
+		gtk_label_set_mnemonic_widget (GTK_LABEL (label), tv);
+		g_signal_connect (G_OBJECT (tv), "cursor-changed", G_CALLBACK (e_mapi_cursor_change), source);
+		gtk_widget_show_all (scroll);
+
+		gtk_table_attach (GTK_TABLE (table), scroll, 0, 1, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+
+		if (e_mapi_test_is_online ()) {
+			struct EMapiFolderStructureData *fsd;
+
+			fsd = g_new0 (struct EMapiFolderStructureData, 1);
+			fsd->folder_type = folder_type;
+			fsd->folders = NULL;
+			fsd->tree_view = g_object_ref (tv);
+			fsd->source = g_object_ref (source);
+
+			g_idle_add (e_mapi_invoke_folder_structure_download_idle, fsd);
+		}
 	}
 
-	scroll = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
-	g_object_set (scroll, "height-request", 150, NULL);
-	gtk_container_add (GTK_CONTAINER (scroll), tv);
-	gtk_label_set_mnemonic_widget (GTK_LABEL (label), tv);
-	g_signal_connect (G_OBJECT (tv), "cursor-changed", G_CALLBACK (e_mapi_cursor_change), source);
-	gtk_widget_show_all (scroll);
-
-	gtk_table_attach (GTK_TABLE (table), scroll, 0, 1, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-
 	gtk_widget_show_all (table);
 
 	return table;
@@ -805,7 +1081,7 @@ e_mapi_create_addressbook (EPlugin *epl, EConfigHookItemFactoryData *data)
 {
 	EABConfigTargetSource *t = (EABConfigTargetSource *) data->target;
 
-	return e_mapi_create (data->parent, t->source, E_MAPI_FOLDER_TYPE_CONTACT);
+	return e_mapi_create (data->target->widget, data->parent, t->source, E_MAPI_FOLDER_TYPE_CONTACT);
 }
 
 GtkWidget *
@@ -828,7 +1104,7 @@ e_mapi_create_calendar (EPlugin *epl, EConfigHookItemFactoryData *data)
 		g_return_val_if_reached (NULL);
 	}
 
-	return e_mapi_create (data->parent, t->source, folder_type);
+	return e_mapi_create (data->target->widget, data->parent, t->source, folder_type);
 }
 
 gboolean
@@ -849,6 +1125,10 @@ e_mapi_book_check (EPlugin *epl, EConfigHookPageCheckData *data)
 
 	g_free (uri_text);
 
+	if (!e_source_get_property (source, "folder-id") &&
+	    !e_mapi_test_is_online ())
+		return FALSE;
+
 	/* does not have a parent-fid which is needed for folder creation on server */
 	return e_source_get_property (source, "parent-fid") ||
 		e_source_get_property (source, "foreign-username") ||
@@ -886,86 +1166,192 @@ emas_open_folder (ESource *source,
 	return res;
 }
 
-void
-e_mapi_book_commit (EPlugin *epl, EConfigTarget *target)
+struct EMapiCreateFolderData
 {
-	EABConfigTargetSource *t = (EABConfigTargetSource *) target;
-	ESource *source = t->source;
-	gchar *uri_text, *r_uri, *sfid;
-	const gchar *kerberos = NULL;
-	ESourceGroup *grp;
+	ESource *source;
+	gchar *folder_name;
+	gchar *folder_type;
+
+	gchar * (* create_error_string) (const gchar *folder_name, const GError *error);
+	mapi_id_t parent_fid;
+	mapi_id_t *created_fid;
+};
+
+static void
+e_mapi_create_folder_data_free (gpointer ptr)
+{
+	struct EMapiCreateFolderData *cfd = ptr;
+
+	if (!cfd)
+		return;
+
+	g_object_unref (cfd->source);
+	g_free (cfd->folder_name);
+	g_free (cfd->folder_type);
+	g_free (cfd);
+}
+
+static void
+e_mapi_create_folder_thread (GObject *source_obj,
+			     gpointer user_data,
+			     GCancellable *cancellable,
+			     GError **perror)
+{
+	struct EMapiCreateFolderData *cfd = user_data;
 	EMapiConnection *conn;
 	mapi_id_t fid, pfid;
 	mapi_object_t obj_folder;
+	ESource *source;
 	GError *mapi_error = NULL;
 
-	uri_text = e_source_get_uri (source);
-	if (uri_text && g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH))
-		return;
+	g_return_if_fail (cfd != NULL);
+	g_return_if_fail (cfd->folder_name != NULL);
+	g_return_if_fail (cfd->folder_type != NULL);
+	g_return_if_fail (cfd->created_fid != NULL);
+	g_return_if_fail (source_obj != NULL);
 
-	switch (e_mapi_source_to_folder_category (source)) {
-	case E_MAPI_FOLDER_CATEGORY_FOREIGN:
-	case E_MAPI_FOLDER_CATEGORY_PUBLIC:
-		/* no extra changes for subscribed folders */
+	source = E_SOURCE (source_obj);
+	conn = e_mapi_account_open_connection_for (NULL,
+		e_source_get_property (source, "profile"),
+		e_source_get_property (source, "username"),
+		e_source_get_property (source, "host"),
+		cancellable,
+		perror);
+
+	if (!conn)
 		return;
-	default:
-		break;
-	}
 
 	e_mapi_util_mapi_id_from_string (e_source_get_property (source, "parent-fid"), &pfid);
 
-	/* the profile should be already connected */
-	conn = e_mapi_connection_find (e_source_get_property (source, "profile"));
-	g_return_if_fail (conn != NULL);
-
 	fid = 0;
-	if (emas_open_folder (source, conn, pfid, &obj_folder, NULL, NULL)) {
-		if (!e_mapi_connection_create_folder (conn, &obj_folder, e_source_peek_name (source), IPF_CONTACT, &fid, NULL, &mapi_error))
+	if (emas_open_folder (source, conn, pfid, &obj_folder, cancellable, &mapi_error)) {
+		if (!e_mapi_connection_create_folder (conn, &obj_folder, cfd->folder_name, cfd->folder_type, &fid, cancellable, &mapi_error))
 			fid = 0;
-		e_mapi_connection_close_folder (conn, &obj_folder, NULL, NULL);
+		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 	}
 
 	g_object_unref (conn);
 
 	if (!fid) {
-		if (mapi_error) {
-			e_notice (NULL, GTK_MESSAGE_ERROR, _("Failed to create address book '%s': %s"), e_source_peek_name (source), mapi_error->message);
-			g_error_free (mapi_error);
+		gchar *error_str;
+
+		if (cfd->create_error_string)
+			error_str = cfd->create_error_string (cfd->folder_name, mapi_error);
+		else if (mapi_error) {
+			error_str = g_strdup_printf (_("Failed to create folder '%s': %s"), cfd->folder_name, mapi_error->message);
 		} else {
-			e_notice (NULL, GTK_MESSAGE_ERROR, _("Failed to create address book '%s'"), e_source_peek_name (source));
+			error_str = g_strdup_printf (_("Failed to create folder '%s'"), cfd->folder_name);
 		}
 
-		return;
+		g_return_if_fail (error_str != NULL);
+
+		g_set_error_literal (perror, E_MAPI_ERROR, mapi_error ? mapi_error->code : MAPI_E_CALL_FAILED, error_str);
+
+		g_clear_error (&mapi_error);
+		g_free (error_str);
 	}
 
-	sfid = e_mapi_util_mapi_id_to_string (fid);
-	r_uri = g_strconcat (";", sfid, NULL);
-	e_source_set_relative_uri (source, r_uri);
+	*cfd->created_fid = fid;
+}
+
+static gchar *
+create_book_error_string (const gchar *folder_name,
+			  const GError *error)
+{
+	if (error)
+		return g_strdup_printf (_("Failed to create address book '%s': %s"), folder_name, error->message);
+
+	return g_strdup_printf (_("Failed to create address book '%s'"), folder_name);
+}
+
+void
+e_mapi_book_commit (EPlugin *epl, EConfigTarget *target)
+{
+	EABConfigTargetSource *t = (EABConfigTargetSource *) target;
+	ESource *source = t->source;
+	gchar *uri_text, *tmp;
+	ESourceGroup *grp;
+
+	uri_text = e_source_get_uri (source);
+	if (uri_text && g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH))
+		return;
+
+	switch (e_mapi_source_to_folder_category (source)) {
+	case E_MAPI_FOLDER_CATEGORY_FOREIGN:
+	case E_MAPI_FOLDER_CATEGORY_PUBLIC:
+		/* no extra changes for subscribed folders */
+		return;
+	default:
+		break;
+	}
 
 	grp = e_source_peek_group (source);
 	e_source_set_property (source, "auth", "plain/password");
-	e_source_set_property(source, "user", NULL);
-	e_source_set_property(source, "username", e_source_group_get_property (grp, "username") ? e_source_group_get_property (grp, "username") : e_source_group_get_property (grp, "user"));
-	e_source_set_property(source, "host", e_source_group_get_property (grp, "host"));
-	e_source_set_property(source, "profile", e_source_group_get_property (grp, "profile"));
-	e_source_set_property(source, "domain", e_source_group_get_property (grp, "domain"));
-	e_source_set_property(source, "realm", e_source_group_get_property (grp, "realm"));
-	kerberos = e_source_group_get_property (grp, "kerberos");
-	e_source_set_property(source, "kerberos", kerberos);
-	if (kerberos && g_str_equal (kerberos, "required")) {
+	e_source_set_property (source, "user", NULL);
+
+	tmp = e_source_group_get_property (grp, "username");
+	if (!tmp)
+		tmp = e_source_group_get_property (grp, "user");
+	e_source_set_property(source, "username", tmp);
+	g_free (tmp);
+
+	tmp = e_source_group_get_property (grp, "host");
+	e_source_set_property(source, "host", tmp);
+	g_free (tmp);
+
+	tmp = e_source_group_get_property (grp, "profile");
+	e_source_set_property(source, "profile", tmp);
+	g_free (tmp);
+
+	tmp = e_source_group_get_property (grp, "domain");
+	e_source_set_property(source, "domain", tmp);
+	g_free (tmp);
+
+	tmp = e_source_group_get_property (grp, "realm");
+	e_source_set_property(source, "realm", tmp);
+	g_free (tmp);
+
+	tmp = e_source_group_get_property (grp, "kerberos");
+	e_source_set_property (source, "kerberos", tmp);
+	if (tmp && g_str_equal (tmp, "required")) {
 		e_source_set_property (source, "auth", NULL);
 		e_source_set_property (source, "auth-type", NULL);
 	}
-	e_source_set_relative_uri (source, g_strconcat (";",e_source_peek_name (source), NULL));
+	g_free (tmp);
 
 	e_source_set_property (source, "completion", "true");
-	e_source_set_property (source, "public", "no");
-	e_source_set_property (source, "folder-id", sfid);
-
-	g_free (r_uri);
-	g_free (sfid);
+	e_source_set_property (source, "public", NULL);
+
+	if (!e_source_get_property (source, "folder-id")) {
+		struct EMapiCreateFolderData *cfd;
+		gchar *r_uri, *sfid;
+		mapi_id_t fid = 0;
+
+		cfd = g_new0 (struct EMapiCreateFolderData, 1);
+		cfd->source = g_object_ref (source);
+		cfd->folder_name = g_strdup (e_source_peek_name (source));
+		cfd->folder_type = g_strdup (IPF_CONTACT);
+		cfd->create_error_string = create_book_error_string;
+		cfd->created_fid = &fid;
+
+		e_mapi_run_in_thread_with_feedback_modal (get_widget_toplevel_window (target->widget),
+			G_OBJECT (source),
+			_("Creating address book on a server, please wait..."),
+			e_mapi_create_folder_thread,
+			NULL,
+			cfd,
+			e_mapi_create_folder_data_free);
+
+		if (!fid)
+			return;
 
-	return;
+		sfid = e_mapi_util_mapi_id_to_string (fid);
+		r_uri = g_strconcat (";", sfid, NULL);
+		e_source_set_relative_uri (source, r_uri);
+		e_source_set_property (source, "folder-id", sfid);
+		g_free (r_uri);
+		g_free (sfid);
+	}
 }
 
 /* New calendar/task list/memo list */
@@ -987,24 +1373,54 @@ e_mapi_cal_check (EPlugin *epl, EConfigHookPageCheckData *data)
 
 	g_free (uri_text);
 
+	if (!e_source_get_property (source, "folder-id") &&
+	    !e_mapi_test_is_online ())
+		return FALSE;
+
 	return e_source_get_property (source, "parent-fid") ||
 		e_source_get_property (source, "foreign-username") ||
 		g_strcmp0 (e_source_get_property (source, "public"), "yes") == 0;
 }
 
+static gchar *
+create_cal_error_string (const gchar *folder_name,
+			 const GError *error)
+{
+	if (error)
+		return g_strdup_printf (_("Failed to create calendar '%s': %s"), folder_name, error->message);
+
+	return g_strdup_printf (_("Failed to create calendar '%s'"), folder_name);
+}
+
+static gchar *
+create_task_error_string (const gchar *folder_name,
+			  const GError *error)
+{
+	if (error)
+		return g_strdup_printf (_("Failed to create task list '%s': %s"), folder_name, error->message);
+
+	return g_strdup_printf (_("Failed to create task list '%s'"), folder_name);
+}
+
+static gchar *
+create_memo_error_string (const gchar *folder_name,
+			  const GError *error)
+{
+	if (error)
+		return g_strdup_printf (_("Failed to create memo list '%s': %s"), folder_name, error->message);
+
+	return g_strdup_printf (_("Failed to create memo list '%s'"), folder_name);
+}
+
 void
 e_mapi_cal_commit (EPlugin *epl, EConfigTarget *target)
 {
-	EMapiConnection *conn;
 	ECalConfigTargetSource *t = (ECalConfigTargetSource *) target;
 	ESourceGroup *group;
 	ESource *source = t->source;
-	gchar *tmp, *sfid;
-	mapi_id_t fid, pfid;
-	mapi_object_t obj_folder;
+	gchar *tmp;
 	const gchar *type;
 	gchar *uri_text = e_source_get_uri (source);
-	GError *mapi_error = NULL;
 
 	if (!uri_text || g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH))
 		return;
@@ -1034,38 +1450,6 @@ e_mapi_cal_commit (EPlugin *epl, EConfigTarget *target)
 			return;
 	}
 
-	e_mapi_util_mapi_id_from_string (e_source_get_property (source, "parent-fid"), &pfid);
-
-	/* the profile should be already connected */
-	conn = e_mapi_connection_find (e_source_get_property (source, "profile"));
-	g_return_if_fail (conn != NULL);
-
-	fid = 0;
-	if (emas_open_folder (source, conn, pfid, &obj_folder, NULL, NULL)) {
-		if (!e_mapi_connection_create_folder (conn, &obj_folder, e_source_peek_name (source), type, &fid, NULL, &mapi_error))
-			fid = 0;
-		e_mapi_connection_close_folder (conn, &obj_folder, NULL, NULL);
-	}
-
-	g_object_unref (conn);
-
-	if (!fid) {
-		if (mapi_error) {
-			e_notice (NULL, GTK_MESSAGE_ERROR, _("Failed to create calendar '%s': %s"), e_source_peek_name (source), mapi_error->message);
-			g_error_free (mapi_error);
-		} else {
-			e_notice (NULL, GTK_MESSAGE_ERROR, _("Failed to create calendar '%s'"), e_source_peek_name (source));
-		}
-
-		return;
-	}
-
-	sfid = e_mapi_util_mapi_id_to_string (fid);
-	tmp = g_strconcat (";", sfid, NULL);
-	e_source_set_relative_uri (source, tmp);
-	g_free (tmp);
-	g_free (sfid);
-
 	e_source_set_property (source, "auth", "1");
 	e_source_set_property (source, "auth-type", "plain/password");
 	e_source_set_property (source, "public", "no");
@@ -1100,12 +1484,6 @@ e_mapi_cal_commit (EPlugin *epl, EConfigTarget *target)
 	}
 	g_free (tmp);
 
-	tmp = e_mapi_util_mapi_id_to_string (fid);
-	e_source_set_property (source, "folder-id", tmp);
-	g_free (tmp);
-
-	e_source_set_property (source, "offline_sync", "0");
-
 	/* Delegatees can never create folders for delegators. So we can copy safely. */
 	tmp = e_source_group_get_property (group, "acl-user-name");
 	e_source_set_property (source, "acl-user-name", tmp);
@@ -1120,8 +1498,55 @@ e_mapi_cal_commit (EPlugin *epl, EConfigTarget *target)
 	e_source_set_property (source, "acl-owner-email", tmp);
 	g_free (tmp);
 
-	// Update the folder list in the plugin and EMapiFolder
-	return;
+	if (!e_source_get_property (source, "folder-id")) {
+		struct EMapiCreateFolderData *cfd;
+		const gchar *msg = NULL;
+		gchar *r_uri, *sfid;
+		mapi_id_t fid = 0;
+
+		cfd = g_new0 (struct EMapiCreateFolderData, 1);
+		cfd->source = g_object_ref (source);
+		cfd->folder_name = g_strdup (e_source_peek_name (source));
+		cfd->folder_type = g_strdup (type);
+		switch (t->source_type) {
+		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+			cfd->create_error_string = create_cal_error_string;
+			msg = _("Creating calendar on a server, please wait...");
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+			cfd->create_error_string = create_task_error_string;
+			msg = _("Creating task list on a server, please wait...");
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+			cfd->create_error_string = create_memo_error_string;
+			msg = _("Creating memo list on a server, please wait...");
+			break;
+		default:
+			g_warn_if_reached ();
+			msg = "???";
+			break;
+		}
+		cfd->created_fid = &fid;
+
+		e_mapi_run_in_thread_with_feedback_modal (get_widget_toplevel_window (target->widget),
+			G_OBJECT (source),
+			msg,
+			e_mapi_create_folder_thread,
+			NULL,
+			cfd,
+			e_mapi_create_folder_data_free);
+
+		if (!fid)
+			return;
+
+		sfid = e_mapi_util_mapi_id_to_string (fid);
+		r_uri = g_strconcat (";", sfid, NULL);
+		e_source_set_relative_uri (source, r_uri);
+		e_source_set_property (source, "folder-id", sfid);
+
+		g_free (r_uri);
+		g_free (sfid);
+	}
 }
 
 struct RunWithFeedbackData
@@ -1135,6 +1560,7 @@ struct RunWithFeedbackData
 	gpointer user_data;
 	GDestroyNotify free_user_data;
 	GError *error;
+	gboolean run_modal;
 };
 
 static void
@@ -1177,6 +1603,8 @@ run_with_feedback_idle (gpointer user_data)
 			gtk_widget_destroy (rfd->dialog);
 			rfd->dialog = NULL;
 		}
+	} else {
+		was_cancelled = TRUE;
 	}
 
 	if (!was_cancelled) {
@@ -1189,6 +1617,19 @@ run_with_feedback_idle (gpointer user_data)
 	return FALSE;
 }
 
+static gboolean
+run_with_feedback_response_idle (gpointer user_data)
+{
+	struct RunWithFeedbackData *rfd = user_data;
+
+	g_return_val_if_fail (rfd != NULL, FALSE);
+
+	if (rfd->dialog)
+		gtk_dialog_response (GTK_DIALOG (rfd->dialog), GTK_RESPONSE_CLOSE);
+
+	return FALSE;
+}
+
 static gpointer
 run_with_feedback_thread (gpointer user_data)
 {
@@ -1200,7 +1641,10 @@ run_with_feedback_thread (gpointer user_data)
 	if (!g_cancellable_is_cancelled (rfd->cancellable))
 		rfd->thread_func (rfd->with_object, rfd->user_data, rfd->cancellable, &rfd->error);
 
-	g_idle_add (run_with_feedback_idle, rfd);
+	if (rfd->run_modal)
+		g_idle_add (run_with_feedback_response_idle, rfd);
+	else
+		g_idle_add (run_with_feedback_idle, rfd);
 
 	return NULL;
 }
@@ -1212,20 +1656,24 @@ run_with_feedback_response_cb (GtkWidget *dialog,
 {
 	g_return_if_fail (rfd != NULL);
 
-	rfd->dialog = NULL;
+	if (!rfd->run_modal)
+		rfd->dialog = NULL;
+
 	g_cancellable_cancel (rfd->cancellable);
 
-	gtk_widget_destroy (dialog);
+	if (!rfd->run_modal)
+		gtk_widget_destroy (dialog);
 }
 
-void
-e_mapi_run_in_thread_with_feedback (GtkWindow *parent,
-				    GObject *with_object,
-				    const gchar *description,
-				    EMapiSetupFunc thread_func,
-				    EMapiSetupFunc idle_func,
-				    gpointer user_data,
-				    GDestroyNotify free_user_data)
+static void
+e_mapi_run_in_thread_with_feedback_general (GtkWindow *parent,
+					    GObject *with_object,
+					    const gchar *description,
+					    EMapiSetupFunc thread_func,
+					    EMapiSetupFunc idle_func,
+					    gpointer user_data,
+					    GDestroyNotify free_user_data,
+					    gboolean run_modal)
 {
 	GtkWidget *dialog, *label, *content;
 	struct RunWithFeedbackData *rfd;
@@ -1258,12 +1706,45 @@ e_mapi_run_in_thread_with_feedback (GtkWindow *parent,
 	rfd->user_data = user_data;
 	rfd->free_user_data = free_user_data;
 	rfd->error = NULL;
+	rfd->run_modal = run_modal;
 
 	g_signal_connect (dialog, "response", G_CALLBACK (run_with_feedback_response_cb), rfd);
 
-	gtk_widget_show (dialog);
+	if (run_modal) {
+		g_return_if_fail (g_thread_create (run_with_feedback_thread, rfd, FALSE, NULL));
+
+		gtk_dialog_run (GTK_DIALOG (dialog));
+
+		run_with_feedback_idle (rfd);
+	} else {
+		gtk_widget_show (dialog);
+
+		g_return_if_fail (g_thread_create (run_with_feedback_thread, rfd, FALSE, NULL));
+	}
+}
+
+void
+e_mapi_run_in_thread_with_feedback (GtkWindow *parent,
+				    GObject *with_object,
+				    const gchar *description,
+				    EMapiSetupFunc thread_func,
+				    EMapiSetupFunc idle_func,
+				    gpointer user_data,
+				    GDestroyNotify free_user_data)
+{
+	e_mapi_run_in_thread_with_feedback_general (parent, with_object, description, thread_func, idle_func, user_data, free_user_data, FALSE);
+}
 
-	g_return_if_fail (g_thread_create (run_with_feedback_thread, rfd, FALSE, NULL));
+void
+e_mapi_run_in_thread_with_feedback_modal (GtkWindow *parent,
+					  GObject *with_object,
+					  const gchar *description,
+					  EMapiSetupFunc thread_func,
+					  EMapiSetupFunc idle_func,
+					  gpointer user_data,
+					  GDestroyNotify free_user_data)
+{
+	e_mapi_run_in_thread_with_feedback_general (parent, with_object, description, thread_func, idle_func, user_data, free_user_data, TRUE);
 }
 
 EMapiConnection	*
diff --git a/src/account-setup-eplugin/e-mapi-account-setup.h b/src/account-setup-eplugin/e-mapi-account-setup.h
index 3239872..6d5d82e 100644
--- a/src/account-setup-eplugin/e-mapi-account-setup.h
+++ b/src/account-setup-eplugin/e-mapi-account-setup.h
@@ -47,6 +47,14 @@ void			e_mapi_run_in_thread_with_feedback	(GtkWindow *parent,
 								 gpointer user_data,
 								 GDestroyNotify free_user_data);
 
+void			e_mapi_run_in_thread_with_feedback_modal(GtkWindow *parent,
+								 GObject *with_object,
+								 const gchar *description,
+								 EMapiSetupFunc thread_func,
+								 EMapiSetupFunc idle_func,
+								 gpointer user_data,
+								 GDestroyNotify free_user_data);
+
 EMapiConnection	*	e_mapi_account_open_connection_for	(GtkWindow *parent,
 								 const gchar *login_profile,
 								 const gchar *login_username,



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