[evolution-ews] Bug #685795 - Option to subscribe to other user's folder with subfolders



commit fc96af8bdd9160b01188f642069443c499454d6e
Author: Milan Crha <mcrha redhat com>
Date:   Fri Nov 16 17:16:26 2012 +0100

    Bug #685795 - Option to subscribe to other user's folder with subfolders

 src/camel/camel-ews-store-summary.c                |   78 ++++++++
 src/camel/camel-ews-store-summary.h                |   11 ++
 src/camel/camel-ews-store.c                        |  184 ++++++++++++++++++++
 src/configuration/e-ews-subscribe-foreign-folder.c |   21 ++-
 src/server/e-ews-connection.c                      |  180 +++++++++++++++++++-
 src/server/e-ews-connection.h                      |   20 ++
 src/server/e-ews-folder.c                          |   18 ++-
 src/server/e-ews-folder.h                          |    2 +
 src/server/e-source-ews-folder.c                   |   52 ++++++-
 src/server/e-source-ews-folder.h                   |    5 +
 10 files changed, 564 insertions(+), 7 deletions(-)
---
diff --git a/src/camel/camel-ews-store-summary.c b/src/camel/camel-ews-store-summary.c
index 978fba8..45549ef 100644
--- a/src/camel/camel-ews-store-summary.c
+++ b/src/camel/camel-ews-store-summary.c
@@ -562,6 +562,21 @@ camel_ews_store_summary_set_foreign (CamelEwsStoreSummary *ews_summary,
 }
 
 void
+camel_ews_store_summary_set_foreign_subfolders (CamelEwsStoreSummary *ews_summary,
+						const gchar *folder_id,
+						gboolean foreign_subfolders)
+{
+	S_LOCK (ews_summary);
+
+	g_key_file_set_boolean (
+		ews_summary->priv->key_file,
+		folder_id, "ForeignSubfolders", foreign_subfolders);
+	ews_summary->priv->dirty = TRUE;
+
+	S_UNLOCK (ews_summary);
+}
+
+void
 camel_ews_store_summary_store_string_val (CamelEwsStoreSummary *ews_summary,
                                           const gchar *key,
                                           const gchar *value)
@@ -765,6 +780,23 @@ camel_ews_store_summary_get_foreign (CamelEwsStoreSummary *ews_summary,
 	return ret;
 }
 
+gboolean
+camel_ews_store_summary_get_foreign_subfolders (CamelEwsStoreSummary *ews_summary,
+						const gchar *folder_id,
+						GError **error)
+{
+	gboolean ret;
+
+	S_LOCK (ews_summary);
+
+	ret = g_key_file_get_boolean (
+		ews_summary->priv->key_file, folder_id, "ForeignSubfolders", error);
+
+	S_UNLOCK (ews_summary);
+
+	return ret;
+}
+
 gchar *
 camel_ews_store_summary_get_string_val (CamelEwsStoreSummary *ews_summary,
                                          const gchar *key,
@@ -822,6 +854,52 @@ camel_ews_store_summary_get_folders (CamelEwsStoreSummary *ews_summary,
 	return folders;
 }
 
+/* get list of folder IDs, which are foreign folders */
+GSList *
+camel_ews_store_summary_get_foreign_folders (CamelEwsStoreSummary *ews_summary,
+					     const gchar *prefix)
+{
+	GSList *folders = NULL;
+	gchar **groups = NULL;
+	gsize length;
+	gint prefixlen = 0;
+	gint i;
+
+	if (prefix)
+		prefixlen = strlen (prefix);
+
+	S_LOCK (ews_summary);
+
+	groups = g_key_file_get_groups (ews_summary->priv->key_file, &length);
+
+	S_UNLOCK (ews_summary);
+
+	for (i = 0; i < length; i++) {
+		if (!g_ascii_strcasecmp (groups[i], STORE_GROUP_NAME))
+			continue;
+
+		if (!camel_ews_store_summary_get_foreign (ews_summary, groups[i], NULL))
+			continue;
+
+		if (prefixlen) {
+			const gchar *fname;
+
+			fname = g_hash_table_lookup (
+				ews_summary->priv->id_fname_hash, groups[i]);
+
+			if (!fname || strncmp (fname, prefix, prefixlen) ||
+			    (fname[prefixlen] && fname[prefixlen] != '/'))
+				continue;
+		}
+
+		folders = g_slist_append (folders, g_strdup (groups[i]));
+	}
+
+	g_strfreev (groups);
+
+	return folders;
+}
+
 gboolean
 camel_ews_store_summary_remove_folder (CamelEwsStoreSummary *ews_summary,
                                        const gchar *folder_id,
diff --git a/src/camel/camel-ews-store-summary.h b/src/camel/camel-ews-store-summary.h
index 47e68eb..a1231dc 100644
--- a/src/camel/camel-ews-store-summary.h
+++ b/src/camel/camel-ews-store-summary.h
@@ -93,6 +93,10 @@ void		camel_ews_store_summary_set_foreign
 						(CamelEwsStoreSummary *ews_summary,
 						 const gchar *folder_id,
 						 gboolean is_foreign);
+void		camel_ews_store_summary_set_foreign_subfolders
+						(CamelEwsStoreSummary *ews_summary,
+						 const gchar *folder_id,
+						 gboolean foreign_subfolders);
 
 gchar *	camel_ews_store_summary_get_folder_name
 						(CamelEwsStoreSummary *ews_summary,
@@ -134,10 +138,17 @@ gboolean	camel_ews_store_summary_get_foreign
 						(CamelEwsStoreSummary *ews_summary,
 						 const gchar *folder_id,
 						 GError **error);
+gboolean	camel_ews_store_summary_get_foreign_subfolders
+						(CamelEwsStoreSummary *ews_summary,
+						 const gchar *folder_id,
+						 GError **error);
 
 GSList *	camel_ews_store_summary_get_folders
 						(CamelEwsStoreSummary *ews_summary,
 						 const gchar *prefix);
+GSList *	camel_ews_store_summary_get_foreign_folders
+						(CamelEwsStoreSummary *ews_summary,
+						 const gchar *prefix);
 
 void		camel_ews_store_summary_store_string_val
 						(CamelEwsStoreSummary *ews_summary,
diff --git a/src/camel/camel-ews-store.c b/src/camel/camel-ews-store.c
index 3301689..e46515f 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -526,6 +526,166 @@ ews_store_forget_all_folders (CamelEwsStore *ews_store)
 	g_slist_free_full (folders, g_free);
 }
 
+struct EwsUpdateForeignSubfoldersData
+{
+	CamelEwsStore *ews_store;
+	gchar *folder_id;
+};
+
+static void
+ews_update_foreign_subfolders_data_free (gpointer data)
+{
+	struct EwsUpdateForeignSubfoldersData *euf = data;
+
+	if (euf) {
+		g_object_unref (euf->ews_store);
+		g_free (euf->folder_id);
+		g_free (euf);
+	}
+}
+
+static void
+ews_store_update_foreign_subfolders (CamelSession *session,
+				     GCancellable *cancellable,
+				     gpointer user_data,
+				     GError **error)
+{
+	struct EwsUpdateForeignSubfoldersData *euf = user_data;
+	CamelEwsStore *ews_store;
+	EEwsConnection *conn;
+	GSList *tocheck = NULL, *remote_folders = NULL, *local_folders = NULL;
+	const gchar *fid;
+	GError *local_error = NULL;
+
+	g_return_if_fail (euf != NULL);
+
+	ews_store = euf->ews_store;
+	fid = euf->folder_id;
+
+	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store)))
+		return;
+
+	conn = camel_ews_store_ref_connection (ews_store);
+	g_return_if_fail (conn != NULL);
+
+	camel_operation_push_message (cancellable, _("Updating foreign folder structure"));
+
+	/* read remote folder structure at the server */
+	while (fid && !g_cancellable_is_cancelled (cancellable) && !local_error) {
+		gboolean includes_last_item = FALSE;
+		EwsFolderId *folder_id = e_ews_folder_id_new (fid, NULL, FALSE);
+
+		while (!includes_last_item && !g_cancellable_is_cancelled (cancellable) && !local_error) {
+			GSList *folders = NULL, *ff;
+
+			if (!e_ews_connection_find_folder_sync (conn, EWS_PRIORITY_MEDIUM, folder_id,
+				&includes_last_item, &folders, cancellable, &local_error))
+				break;
+
+			for (ff = folders; ff != NULL; ff = ff->next) {
+				EEwsFolder *folder = ff->data;
+
+				e_ews_folder_set_parent_id (folder, e_ews_folder_id_new (fid, NULL, FALSE));
+
+				remote_folders = g_slist_prepend (remote_folders, folder);
+
+				if (e_ews_folder_get_child_count (folder) > 0 && e_ews_folder_get_id (folder))
+					tocheck = g_slist_prepend (tocheck, e_ews_folder_get_id (folder)->id);
+			}
+		}
+
+		e_ews_folder_id_free (folder_id);
+
+		if (tocheck) {
+			fid = g_slist_last (tocheck)->data;
+			tocheck = g_slist_remove (tocheck, fid);
+		} else {
+			fid = NULL;
+		}
+	}
+
+	/* get local folder structure */
+	if (!local_error && !g_cancellable_is_cancelled (cancellable)) {
+		gchar *full_name = camel_ews_store_summary_get_folder_full_name (ews_store->summary, euf->folder_id, NULL);
+		if (full_name) {
+			local_folders = camel_ews_store_summary_get_folders (ews_store->summary, full_name);
+		}
+		g_free (full_name);
+	}
+
+	/* merge local and remote folder structures */
+	if (!local_error && !g_cancellable_is_cancelled (cancellable)) {
+		GHashTable *locals = g_hash_table_new (g_str_hash, g_str_equal);
+		GSList *ii;
+
+		remote_folders = g_slist_reverse (remote_folders);
+
+		for (ii = local_folders; ii; ii = ii->next) {
+			g_hash_table_insert (locals, ii->data, ii->data);
+		}
+
+		for (ii = remote_folders; ii; ii = ii->next) {
+			EEwsFolder *folder = ii->data;
+			const EwsFolderId *folder_id = e_ews_folder_get_id (folder);
+			const EwsFolderId *parent_fid = e_ews_folder_get_parent_id (folder);
+
+			if (e_ews_folder_get_folder_type (folder) == E_EWS_FOLDER_TYPE_MAILBOX &&
+			    folder_id && folder_id->id) {
+				if (!g_hash_table_remove (locals, folder_id->id)) {
+					CamelFolderInfo *fi;
+
+					/* it's a new folder, add it */
+					camel_ews_store_summary_new_folder (
+						ews_store->summary,
+						folder_id->id, parent_fid ? parent_fid->id : euf->folder_id, folder_id->change_key,
+						e_ews_folder_get_name (folder), E_EWS_FOLDER_TYPE_MAILBOX,
+						CAMEL_FOLDER_SUBSCRIBED, e_ews_folder_get_total_count (folder), TRUE);
+
+					fi = camel_ews_utils_build_folder_info (ews_store, folder_id->id);
+					camel_store_folder_created (CAMEL_STORE (ews_store), fi);
+					camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
+					camel_folder_info_free (fi);
+				}
+			}
+		}
+
+		/* to not remove the parent */
+		g_hash_table_remove (locals, euf->folder_id);
+
+		/* and now the locals contains only folders which were removed */
+		if (g_hash_table_size (locals) > 0) {
+			CamelSubscribable *subscribable = CAMEL_SUBSCRIBABLE (ews_store);
+			CamelStore *store = CAMEL_STORE (ews_store);
+			GHashTableIter iter;
+			gpointer key, value;
+
+			g_hash_table_iter_init (&iter, locals);
+			while (g_hash_table_iter_next (&iter, &key, &value)) {
+				CamelFolderInfo *fi;
+
+				fi = camel_ews_utils_build_folder_info (ews_store, key);
+				camel_subscribable_folder_unsubscribed (subscribable, fi);
+				camel_store_folder_deleted (store, fi);
+				camel_folder_info_free (fi);
+			}
+		}
+
+		g_hash_table_destroy (locals);
+
+		camel_ews_store_summary_save (ews_store->summary, &local_error);
+	}
+
+	if (local_error)
+		g_propagate_error (error, local_error);
+
+	camel_operation_pop_message (cancellable);
+
+	g_slist_free_full (remote_folders, g_object_unref);
+	g_slist_free_full (local_folders, g_free);
+	g_slist_free (tocheck);
+	g_object_unref (conn);
+}
+
 static CamelAuthenticationResult
 ews_authenticate_sync (CamelService *service,
                        const gchar *mechanism,
@@ -605,6 +765,9 @@ ews_authenticate_sync (CamelService *service,
 	}
 
 	if (local_error == NULL) {
+		GSList *foreign_fids, *ff;
+		CamelSession *session;
+
 		g_mutex_lock (&ews_store->priv->connection_lock);
 		if (ews_store->priv->connection != NULL)
 			g_object_unref (ews_store->priv->connection);
@@ -615,6 +778,27 @@ ews_authenticate_sync (CamelService *service,
 		ews_update_folder_hierarchy (
 			ews_store, new_sync_state, includes_last_folder,
 			folders_created, folders_deleted, folders_updated);
+
+		/* Also update folder structures of foreign folders,
+		   those which are subscribed with subfolders */
+		session = camel_service_get_session (service);
+		foreign_fids = camel_ews_store_summary_get_foreign_folders (ews_store->summary, NULL);
+		for (ff = foreign_fids; ff != NULL; ff = ff->next) {
+			const gchar *fid = ff->data;
+
+			if (camel_ews_store_summary_get_foreign_subfolders (ews_store->summary, fid, NULL)) {
+				struct EwsUpdateForeignSubfoldersData *euf;
+
+				euf = g_new0 (struct EwsUpdateForeignSubfoldersData, 1);
+				euf->ews_store = g_object_ref (ews_store);
+				euf->folder_id = g_strdup (fid);
+
+				camel_session_submit_job (session, ews_store_update_foreign_subfolders,
+					euf, ews_update_foreign_subfolders_data_free);
+			}
+		}
+
+		g_slist_free_full (foreign_fids, g_free);
 	} else {
 		g_mutex_lock (&ews_store->priv->connection_lock);
 		if (ews_store->priv->connection != NULL) {
diff --git a/src/configuration/e-ews-subscribe-foreign-folder.c b/src/configuration/e-ews-subscribe-foreign-folder.c
index 5523270..35b07fc 100644
--- a/src/configuration/e-ews-subscribe-foreign-folder.c
+++ b/src/configuration/e-ews-subscribe-foreign-folder.c
@@ -41,6 +41,7 @@
 
 #define STR_USER_NAME_SELECTOR_ENTRY	"e-ews-name-selector-entry"
 #define STR_FOLDER_NAME_COMBO		"e-ews-folder-name-combo"
+#define STR_SUBFOLDERS_CHECK		"e-ews-subfolders-check"
 #define STR_EWS_CAMEL_SESSION		"e-ews-camel-session"
 #define STR_EWS_CAMEL_STORE		"e-ews-camel-store"
 #define STR_EWS_DIRECT_EMAIL		"e-ews-direct-email"
@@ -65,6 +66,7 @@ static gboolean
 add_foreign_folder_to_camel (CamelEwsStore *ews_store,
                              const gchar *foreign_email,
                              EEwsFolder *folder,
+			     gboolean include_subfolders,
                              const gchar *display_username,
                              const gchar *display_foldername,
                              GError **perror)
@@ -142,6 +144,8 @@ add_foreign_folder_to_camel (CamelEwsStore *ews_store,
 	}
 
 	camel_ews_store_ensure_virtual_folders (ews_store);
+	camel_ews_store_summary_set_foreign_subfolders (ews_store->summary, fid->id, include_subfolders);
+	camel_ews_store_summary_save (ews_store->summary, perror);
 
 	announce_new_folder (ews_store, EWS_FOREIGN_FOLDER_ROOT_ID);
 	announce_new_folder (ews_store, foreign_mailbox_id);
@@ -196,7 +200,8 @@ name_entry_changed_cb (GObject *dialog)
 }
 
 static void
-folder_name_combo_changed_cb (GObject *dialog)
+folder_name_combo_changed_cb (GObject *dialog,
+			      GtkComboBox *combo)
 {
 	enable_ok_button_by_data (dialog);
 }
@@ -204,6 +209,7 @@ folder_name_combo_changed_cb (GObject *dialog)
 struct EEwsCheckForeignFolderData
 {
 	GtkWidget *dialog;
+	gboolean include_subfolders;
 	gchar *email;
 	gchar *direct_email;
 	gchar *user_displayname;
@@ -422,6 +428,7 @@ check_foreign_folder_idle (GObject *with_object,
 	     !add_foreign_folder_to_camel (ews_store,
 		cffd->email,
 		cffd->folder,
+		cffd->include_subfolders,
 		base_username,
 		base_foldername,
 		perror)) ||
@@ -429,6 +436,7 @@ check_foreign_folder_idle (GObject *with_object,
 		camel_ews_settings_get_hosturl (ews_settings),
 		camel_network_settings_get_user (CAMEL_NETWORK_SETTINGS (ews_settings)),
 		cffd->folder,
+		cffd->include_subfolders,
 		TRUE,
 		0,
 		cancellable,
@@ -450,6 +458,7 @@ subscribe_foreign_response_cb (GObject *dialog,
 	struct EEwsCheckForeignFolderData *cffd;
 	ENameSelectorEntry *entry;
 	GtkComboBoxText *combo_text;
+	GtkToggleButton *subfolders_check;
 	EDestinationStore *dest_store;
 	CamelStore *cstore;
 	gchar *description;
@@ -465,6 +474,7 @@ subscribe_foreign_response_cb (GObject *dialog,
 
 	entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
 	combo_text = g_object_get_data (dialog, STR_FOLDER_NAME_COMBO);
+	subfolders_check = g_object_get_data (dialog, STR_SUBFOLDERS_CHECK);
 	cstore = g_object_get_data (dialog, STR_EWS_CAMEL_STORE);
 
 	g_return_if_fail (entry != NULL);
@@ -518,6 +528,7 @@ subscribe_foreign_response_cb (GObject *dialog,
 	cffd->direct_email = g_strdup (g_object_get_data (G_OBJECT (entry), STR_EWS_DIRECT_EMAIL));
 	cffd->orig_foldername = orig_foldername;
 	cffd->use_foldername = use_foldername;
+	cffd->include_subfolders = gtk_toggle_button_get_active (subfolders_check);
 	cffd->folder = NULL;
 
 	description = g_strdup_printf (
@@ -587,7 +598,7 @@ e_ews_subscribe_foreign_folder (GtkWindow *parent,
 	ENameSelectorDialog *name_selector_dialog;
 	GObject *dialog;
 	GtkWidget *content;
-	GtkWidget *label, *widget, *entry;
+	GtkWidget *label, *widget, *entry, *check;
 	GtkGrid *grid;
 	GtkComboBoxText *combo_text;
 	gint row;
@@ -714,9 +725,15 @@ e_ews_subscribe_foreign_folder (GtkWindow *parent,
 	gtk_grid_attach (grid, label, 0, row, 1, 1);
 	gtk_grid_attach (grid, widget, 1, row, 2, 1);
 
+	row++;
+
+	check = gtk_check_button_new_with_mnemonic (_("Include _subfolders"));
+	gtk_grid_attach (grid, check, 1, row, 2, 1);
+
 	/* remember widgets for later use */
 	g_object_set_data (dialog, STR_USER_NAME_SELECTOR_ENTRY, entry);
 	g_object_set_data (dialog, STR_FOLDER_NAME_COMBO, widget);
+	g_object_set_data (dialog, STR_SUBFOLDERS_CHECK, check);
 
 	g_object_set_data_full (dialog, STR_EWS_CAMEL_SESSION, g_object_ref (session), g_object_unref);
 	g_object_set_data_full (dialog, STR_EWS_CAMEL_STORE, g_object_ref (store), g_object_unref);
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index b9c74ff..fee4ea0 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -808,8 +808,8 @@ get_folder_response_cb (ESoapResponse *response,
 }
 
 static void
-ews_handle_root_folder_param (ESoapParameter *subparam,
-                              EwsAsyncData *async_data)
+ews_handle_root_folder_param_items (ESoapParameter *subparam,
+				    EwsAsyncData *async_data)
 {
 	ESoapParameter *node, *subparam1;
 	gchar *last, *total;
@@ -872,7 +872,7 @@ find_folder_items_response_cb (ESoapResponse *response,
 		}
 
 		if (CHECK_ELEMENT (name, "FindItemResponseMessage"))
-			ews_handle_root_folder_param (subparam, async_data);
+			ews_handle_root_folder_param_items (subparam, async_data);
 
 		subparam = e_soap_parameter_get_next_child (subparam);
 	}
@@ -7588,3 +7588,177 @@ e_ews_connection_get_folder_info_sync (EEwsConnection *cnc,
 
 	return success;
 }
+
+static void
+ews_handle_root_folder_param_folders (ESoapParameter *subparam,
+				      EwsAsyncData *async_data)
+{
+	ESoapParameter *node, *subparam1;
+	gchar *last, *total;
+	gint total_items;
+	EEwsFolder *folder;
+	gboolean includes_last_item = FALSE;
+
+	node = e_soap_parameter_get_first_child_by_name (subparam, "RootFolder");
+	total = e_soap_parameter_get_property (node, "TotalItemsInView");
+	total_items = atoi (total);
+	g_free (total);
+	last = e_soap_parameter_get_property (node, "IncludesLastItemInRange");
+	if (!strcmp (last, "true"))
+		includes_last_item = TRUE;
+	g_free (last);
+
+	node = e_soap_parameter_get_first_child_by_name (node, "Folders");
+	for (subparam1 = e_soap_parameter_get_first_child (node);
+	     subparam1; subparam1 = e_soap_parameter_get_next_child (subparam1)) {
+		folder = e_ews_folder_new_from_soap_parameter (subparam1);
+		if (!folder) continue;
+		async_data->items = g_slist_append (async_data->items, folder);
+	}
+	async_data->total_items = total_items;
+	async_data->includes_last_item = includes_last_item;
+}
+
+static void
+find_folder_response_cb (ESoapResponse *response,
+			 GSimpleAsyncResult *simple)
+{
+	EwsAsyncData *async_data;
+	ESoapParameter *param;
+	ESoapParameter *subparam;
+	GError *error = NULL;
+
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+	param = e_soap_response_get_first_parameter_by_name (
+		response, "ResponseMessages", &error);
+
+	/* Sanity check */
+	g_return_if_fail (
+		(param != NULL && error == NULL) ||
+		(param == NULL && error != NULL));
+
+	if (error != NULL) {
+		g_simple_async_result_take_error (simple, error);
+		return;
+	}
+
+	subparam = e_soap_parameter_get_first_child (param);
+
+	while (subparam != NULL) {
+		const gchar *name = (const gchar *) subparam->name;
+
+		if (!ews_get_response_status (subparam, &error)) {
+			g_simple_async_result_take_error (simple, error);
+			return;
+		}
+
+		if (CHECK_ELEMENT (name, "FindFolderResponseMessage"))
+			ews_handle_root_folder_param_folders (subparam, async_data);
+
+		subparam = e_soap_parameter_get_next_child (subparam);
+	}
+}
+
+void
+e_ews_connection_find_folder (EEwsConnection *cnc,
+			      gint pri,
+			      const EwsFolderId *fid,
+			      GCancellable *cancellable,
+			      GAsyncReadyCallback callback,
+			      gpointer user_data)
+{
+	ESoapMessage *msg;
+	GSimpleAsyncResult *simple;
+	EwsAsyncData *async_data;
+
+	g_return_if_fail (cnc != NULL);
+
+	msg = e_ews_message_new_with_header (cnc->priv->uri, cnc->priv->impersonate_user, "FindFolder", "Traversal", "Shallow", EWS_EXCHANGE_2007_SP1);
+	e_soap_message_start_element (msg, "FolderShape", "messages", NULL);
+	e_ews_message_write_string_parameter (msg, "BaseShape", NULL, "Default");
+	e_soap_message_end_element (msg);
+
+	e_soap_message_start_element (msg, "ParentFolderIds", "messages", NULL);
+
+	if (fid->is_distinguished_id)
+		e_ews_message_write_string_parameter_with_attribute (msg, "DistinguishedFolderId", NULL, NULL, "Id", fid->id);
+	else
+		e_ews_message_write_string_parameter_with_attribute (msg, "FolderId", NULL, NULL, "Id", fid->id);
+
+	e_soap_message_end_element (msg);
+
+	/* Complete the footer and print the request */
+	e_ews_message_write_footer (msg);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (cnc), callback, user_data,
+		e_ews_connection_find_folder);
+
+	async_data = g_new0 (EwsAsyncData, 1);
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_data, (GDestroyNotify) async_data_free);
+
+	e_ews_connection_queue_request (
+		cnc, msg, find_folder_response_cb,
+		pri, cancellable, simple);
+
+	g_object_unref (simple);
+}
+
+gboolean
+e_ews_connection_find_folder_finish (EEwsConnection *cnc,
+				     GAsyncResult *result,
+				     gboolean *includes_last_item,
+				     GSList **folders,
+				     GError **error)
+{
+	GSimpleAsyncResult *simple;
+	EwsAsyncData *async_data;
+
+	g_return_val_if_fail (cnc != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (cnc), e_ews_connection_find_folder),
+		FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	*includes_last_item = async_data->includes_last_item;
+	*folders = async_data->items;
+
+	return TRUE;
+}
+
+gboolean
+e_ews_connection_find_folder_sync (EEwsConnection *cnc,
+				   gint pri,
+				   const EwsFolderId *fid,
+				   gboolean *includes_last_item,
+				   GSList **folders,
+				   GCancellable *cancellable,
+				   GError **error)
+{
+	EAsyncClosure *closure;
+	GAsyncResult *result;
+	gboolean success;
+
+	g_return_val_if_fail (cnc != NULL, FALSE);
+
+	closure = e_async_closure_new ();
+
+	e_ews_connection_find_folder (cnc, pri, fid, cancellable, e_async_closure_callback, closure);
+
+	result = e_async_closure_wait (closure);
+
+	success = e_ews_connection_find_folder_finish (
+		cnc, result, includes_last_item, folders, error);
+
+	e_async_closure_free (closure);
+
+	return success;
+}
diff --git a/src/server/e-ews-connection.h b/src/server/e-ews-connection.h
index 93b571f..e3732b9 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -967,6 +967,26 @@ gboolean	e_ews_connection_get_folder_info_sync
 						 EEwsFolder **folder,
 						 GCancellable *cancellable,
 						 GError **error);
+void		e_ews_connection_find_folder	(EEwsConnection *cnc,
+						 gint pri,
+						 const EwsFolderId *fid,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_ews_connection_find_folder_finish
+						(EEwsConnection *cnc,
+						 GAsyncResult *result,
+						 gboolean *includes_last_item,
+						 GSList **folders,
+						 GError **error);
+gboolean	e_ews_connection_find_folder_sync
+						(EEwsConnection *cnc,
+						 gint pri,
+						 const EwsFolderId *fid,
+						 gboolean *includes_last_item,
+						 GSList **folders,
+						 GCancellable *cancellable,
+						 GError **error);
 
 G_END_DECLS
 
diff --git a/src/server/e-ews-folder.c b/src/server/e-ews-folder.c
index 50bf832..6551b80 100644
--- a/src/server/e-ews-folder.c
+++ b/src/server/e-ews-folder.c
@@ -147,7 +147,19 @@ e_ews_folder_set_from_soap_parameter (EEwsFolder *folder,
 
 	g_return_val_if_fail (param != NULL, FALSE);
 
-	if ((node = e_soap_parameter_get_first_child_by_name (param, "Folder")))
+	if (g_strcmp0 (e_soap_parameter_get_name (param), "Folder") == 0) {
+		node = param;
+		priv->folder_type = E_EWS_FOLDER_TYPE_MAILBOX;
+	} else if (g_strcmp0 (e_soap_parameter_get_name (param), "CalendarFolder") == 0) {
+		node = param;
+		priv->folder_type = E_EWS_FOLDER_TYPE_CALENDAR;
+	} else if (g_strcmp0 (e_soap_parameter_get_name (param), "ContactsFolder") == 0) {
+		node = param;
+		priv->folder_type = E_EWS_FOLDER_TYPE_CONTACTS;
+	} else if (g_strcmp0 (e_soap_parameter_get_name (param), "TasksFolder") == 0) {
+		node = param;
+		priv->folder_type = E_EWS_FOLDER_TYPE_TASKS;
+	} else if ((node = e_soap_parameter_get_first_child_by_name (param, "Folder")))
 		priv->folder_type = E_EWS_FOLDER_TYPE_MAILBOX;
 	else if ((node = e_soap_parameter_get_first_child_by_name (param, "CalendarFolder")))
 		priv->folder_type = E_EWS_FOLDER_TYPE_CALENDAR;
@@ -467,6 +479,7 @@ e_ews_folder_utils_populate_esource (ESource *source,
                                      const gchar *master_hosturl,
                                      const gchar *master_username,
                                      EEwsFolder *folder,
+				     gboolean include_subfolders,
                                      gboolean offline_sync,
                                      gint color_seed,
                                      GCancellable *cancellable,
@@ -518,6 +531,7 @@ e_ews_folder_utils_populate_esource (ESource *source,
 			e_source_ews_folder_set_id (folder_ext, folder_id->id);
 			e_source_ews_folder_set_change_key (folder_ext, NULL);
 			e_source_ews_folder_set_foreign (folder_ext, e_ews_folder_get_foreign (folder));
+			e_source_ews_folder_set_foreign_subfolders (folder_ext, include_subfolders);
 
 			offline_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_OFFLINE);
 			e_source_offline_set_stay_synchronized (offline_ext, offline_sync);
@@ -553,6 +567,7 @@ e_ews_folder_utils_add_as_esource (ESourceRegistry *pregistry,
                                    const gchar *master_hosturl,
                                    const gchar *master_username,
                                    EEwsFolder *folder,
+				   gboolean include_subfolders,
                                    gboolean offline_sync,
                                    gint color_seed,
                                    GCancellable *cancellable,
@@ -589,6 +604,7 @@ e_ews_folder_utils_add_as_esource (ESourceRegistry *pregistry,
 		master_hosturl,
 		master_username,
 		folder,
+		include_subfolders,
 		offline_sync,
 		color_seed,
 		cancellable,
diff --git a/src/server/e-ews-folder.h b/src/server/e-ews-folder.h
index 2cec0c4..53d6fca 100644
--- a/src/server/e-ews-folder.h
+++ b/src/server/e-ews-folder.h
@@ -87,6 +87,7 @@ gboolean	e_ews_folder_utils_populate_esource		(ESource *source,
 								 const gchar *master_hosturl,
 								 const gchar *master_username,
 								 EEwsFolder *folder,
+								 gboolean include_subfolders,
 								 gboolean offline_sync,
 								 gint color_seed,
 								 GCancellable *cancellable,
@@ -95,6 +96,7 @@ gboolean	e_ews_folder_utils_add_as_esource		(ESourceRegistry *pregistry,
 								 const gchar *master_hosturl,
 								 const gchar *master_username,
 								 EEwsFolder *folder,
+								 gboolean include_subfolders,
 								 gboolean offline_sync,
 								 gint color_seed,
 								 GCancellable *cancellable,
diff --git a/src/server/e-source-ews-folder.c b/src/server/e-source-ews-folder.c
index ba9cd4e..4eb6961 100644
--- a/src/server/e-source-ews-folder.c
+++ b/src/server/e-source-ews-folder.c
@@ -31,13 +31,15 @@ struct _ESourceEwsFolderPrivate {
 	gchar *change_key;
 	gchar *id;
 	gboolean foreign;
+	gboolean foreign_subfolders;
 };
 
 enum {
 	PROP_0,
 	PROP_CHANGE_KEY,
 	PROP_ID,
-	PROP_FOREIGN
+	PROP_FOREIGN,
+	PROP_FOREIGN_SUBFOLDERS
 };
 
 G_DEFINE_DYNAMIC_TYPE (
@@ -69,6 +71,12 @@ source_ews_folder_set_property (GObject *object,
 				E_SOURCE_EWS_FOLDER (object),
 				g_value_get_boolean (value));
 			return;
+
+		case PROP_FOREIGN_SUBFOLDERS:
+			e_source_ews_folder_set_foreign_subfolders (
+				E_SOURCE_EWS_FOLDER (object),
+				g_value_get_boolean (value));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -101,6 +109,13 @@ source_ews_folder_get_property (GObject *object,
 				e_source_ews_folder_get_foreign (
 				E_SOURCE_EWS_FOLDER (object)));
 			return;
+
+		case PROP_FOREIGN_SUBFOLDERS:
+			g_value_set_boolean (
+				value,
+				e_source_ews_folder_get_foreign_subfolders (
+				E_SOURCE_EWS_FOLDER (object)));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -177,6 +192,19 @@ e_source_ews_folder_class_init (ESourceEwsFolderClass *class)
 			G_PARAM_CONSTRUCT |
 			G_PARAM_STATIC_STRINGS |
 			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FOREIGN_SUBFOLDERS,
+		g_param_spec_boolean (
+			"foreign-subfolders",
+			"ForeignSubfolders",
+			"Whether to search for subfolders of (this) foreign folder",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
 }
 
 static void
@@ -333,3 +361,25 @@ e_source_ews_folder_set_foreign (ESourceEwsFolder *extension,
 
 	g_object_notify (G_OBJECT (extension), "foreign");
 }
+
+gboolean
+e_source_ews_folder_get_foreign_subfolders (ESourceEwsFolder *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), FALSE);
+
+	return extension->priv->foreign_subfolders;
+}
+
+void
+e_source_ews_folder_set_foreign_subfolders (ESourceEwsFolder *extension,
+					    gboolean foreign_subfolders)
+{
+	g_return_if_fail (E_IS_SOURCE_EWS_FOLDER (extension));
+
+	if ((extension->priv->foreign_subfolders ? 1 : 0) == (foreign_subfolders ? 1 : 0))
+		return;
+
+	extension->priv->foreign_subfolders = foreign_subfolders;
+
+	g_object_notify (G_OBJECT (extension), "foreign-subfolders");
+}
diff --git a/src/server/e-source-ews-folder.h b/src/server/e-source-ews-folder.h
index e15b7a9..ad0f284 100644
--- a/src/server/e-source-ews-folder.h
+++ b/src/server/e-source-ews-folder.h
@@ -79,6 +79,11 @@ EwsFolderId *	e_source_ews_folder_dup_folder_id
 gboolean	e_source_ews_folder_get_foreign	(ESourceEwsFolder *extension);
 void		e_source_ews_folder_set_foreign	(ESourceEwsFolder *extension,
 						 gboolean is_foreign);
+gboolean	e_source_ews_folder_get_foreign_subfolders
+						(ESourceEwsFolder *extension);
+void		e_source_ews_folder_set_foreign_subfolders
+						(ESourceEwsFolder *extension,
+						 gboolean foreign_subfolders);
 
 G_END_DECLS
 



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