[evolution-ews] Implement "Subscribe to folder of other user" feature



commit 74437db8bec94a623d5bd9ba34c29f8c97187186
Author: Milan Crha <mcrha redhat com>
Date:   Wed Aug 15 09:07:51 2012 +0200

    Implement "Subscribe to folder of other user" feature

 po/POTFILES.in                                     |    2 +
 src/camel/camel-ews-folder.c                       |    4 +
 src/camel/camel-ews-store-summary.c                |   68 ++-
 src/camel/camel-ews-store-summary.h                |   13 +-
 src/camel/camel-ews-store.c                        |  407 +++++++++++-
 src/camel/camel-ews-store.h                        |    8 +
 src/camel/camel-ews-utils.c                        |    6 +-
 src/camel/camel-ews-utils.h                        |    2 +-
 src/collection/e-ews-backend.c                     |  137 +++--
 src/configuration/Makefile.am                      |    2 +
 src/configuration/e-ews-config-utils.c             |   21 +-
 src/configuration/e-ews-subscribe-foreign-folder.c |  716 ++++++++++++++++++++
 src/configuration/e-ews-subscribe-foreign-folder.h |   34 +
 src/server/e-ews-connection.c                      |  175 +++++-
 src/server/e-ews-connection.h                      |   22 +
 src/server/e-ews-folder.c                          |  370 ++++++++++-
 src/server/e-ews-folder.h                          |   44 ++
 src/server/e-source-ews-folder.c                   |   52 ++-
 src/server/e-source-ews-folder.h                   |    4 +
 19 files changed, 1992 insertions(+), 95 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ae9a67f..a87b6d5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -14,6 +14,7 @@ src/collection/module-ews-backend.c
 src/configuration/e-ews-config-utils.c
 src/configuration/e-ews-edit-folder-permissions.c
 src/configuration/e-ews-search-user.c
+src/configuration/e-ews-subscribe-foreign-folder.c
 src/configuration/e-mail-config-ews-autodiscover.c
 src/configuration/e-mail-config-ews-backend.c
 src/configuration/e-mail-config-ews-gal.c
@@ -21,4 +22,5 @@ src/configuration/e-mail-config-ews-delegates-page.c
 src/configuration/e-mail-config-ews-ooo-page.c
 src/configuration/module-ews-configuration.error.xml
 src/server/e-ews-connection.c
+src/server/e-ews-folder.c
 src/utils/ews-camel-common.c
diff --git a/src/camel/camel-ews-folder.c b/src/camel/camel-ews-folder.c
index c0b6d75..dec71b4 100644
--- a/src/camel/camel-ews-folder.c
+++ b/src/camel/camel-ews-folder.c
@@ -1060,6 +1060,10 @@ ews_folder_count_notify_cb (CamelFolderSummary *folder_summary,
 	store_summary = ews_store->summary;
 	folder_id = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, camel_folder_get_full_name (folder));
 
+	/* this can happen on folder delete/unsubscribe, after folder summary clear */
+	if (!folder_id)
+		return;
+
 	if (g_strcmp0 (g_param_spec_get_name (param), "saved-count") == 0) {
 		count = camel_folder_summary_get_saved_count (folder_summary);
 		camel_ews_store_summary_set_folder_total (store_summary, folder_id, count);
diff --git a/src/camel/camel-ews-store-summary.c b/src/camel/camel-ews-store-summary.c
index 08e4dcc..0ebbbfd 100644
--- a/src/camel/camel-ews-store-summary.c
+++ b/src/camel/camel-ews-store-summary.c
@@ -105,6 +105,9 @@ load_id_fname_hash (CamelEwsStoreSummary *ews_summary)
 {
 	GSList *folders, *l;
 
+	g_hash_table_remove_all (ews_summary->priv->fname_id_hash);
+	g_hash_table_remove_all (ews_summary->priv->id_fname_hash);
+
 	folders = camel_ews_store_summary_get_folders (ews_summary, NULL);
 
 	for (l = folders; l != NULL; l = g_slist_next (l)) {
@@ -189,10 +192,10 @@ camel_ews_store_summary_load (CamelEwsStoreSummary *ews_summary,
 		camel_ews_store_summary_clear (ews_summary);
 
 		g_key_file_set_integer (priv->key_file, STORE_GROUP_NAME, "Version", CURRENT_SUMMARY_VERSION);
-	} else {
-		load_id_fname_hash (ews_summary);
 	}
 
+	load_id_fname_hash (ews_summary);
+
 	S_UNLOCK (ews_summary);
 
 	return ret;
@@ -261,6 +264,16 @@ camel_ews_store_summary_remove (CamelEwsStoreSummary *ews_summary)
 	return (ret == 0);
 }
 
+void
+camel_ews_store_summary_rebuild_hashes (CamelEwsStoreSummary *ews_summary)
+{
+	g_return_if_fail (CAMEL_IS_EWS_STORE_SUMMARY (ews_summary));
+
+	S_LOCK (ews_summary);
+	load_id_fname_hash (ews_summary);
+	S_UNLOCK (ews_summary);
+}
+
 struct subfolder_match {
 	GSList *ids;
 	gchar *match;
@@ -355,7 +368,8 @@ camel_ews_store_summary_new_folder (CamelEwsStoreSummary *ews_summary,
                                     const gchar *display_name,
                                     EEwsFolderType folder_type,
                                     guint64 folder_flags,
-                                    guint64 total)
+                                    guint64 total,
+				    gboolean foreign)
 {
 	const gchar *folder_type_nick;
 
@@ -365,12 +379,14 @@ camel_ews_store_summary_new_folder (CamelEwsStoreSummary *ews_summary,
 
 	S_LOCK (ews_summary);
 
-	g_key_file_set_string (
-		ews_summary->priv->key_file,
-		folder_id, "ParentFolderId", parent_fid);
-	g_key_file_set_string (
-		ews_summary->priv->key_file,
-		folder_id, "ChangeKey", change_key);
+	if (parent_fid)
+		g_key_file_set_string (
+			ews_summary->priv->key_file,
+			folder_id, "ParentFolderId", parent_fid);
+	if (change_key)
+		g_key_file_set_string (
+			ews_summary->priv->key_file,
+			folder_id, "ChangeKey", change_key);
 	g_key_file_set_string (
 		ews_summary->priv->key_file,
 		folder_id, "DisplayName", display_name);
@@ -383,6 +399,9 @@ camel_ews_store_summary_new_folder (CamelEwsStoreSummary *ews_summary,
 	g_key_file_set_uint64 (
 		ews_summary->priv->key_file,
 		folder_id, "Total", total);
+	g_key_file_set_boolean (
+		ews_summary->priv->key_file,
+		folder_id, "Foreign", foreign);
 
 	ews_ss_hash_replace (ews_summary, g_strdup (folder_id), NULL, FALSE);
 
@@ -511,6 +530,21 @@ camel_ews_store_summary_set_folder_type (CamelEwsStoreSummary *ews_summary,
 }
 
 void
+camel_ews_store_summary_set_foreign (CamelEwsStoreSummary *ews_summary,
+				     const gchar *folder_id,
+				     gboolean is_foreign)
+{
+	S_LOCK (ews_summary);
+
+	g_key_file_set_boolean (
+		ews_summary->priv->key_file,
+		folder_id, "Foreign", is_foreign);
+	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)
@@ -697,6 +731,22 @@ camel_ews_store_summary_get_folder_type (CamelEwsStoreSummary *ews_summary,
 	return folder_type;
 }
 
+gboolean
+camel_ews_store_summary_get_foreign (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, "Foreign", error);
+
+	S_UNLOCK (ews_summary);
+
+	return ret;
+}
+
 gchar *
 camel_ews_store_summary_get_string_val (CamelEwsStoreSummary *ews_summary,
                                          const gchar *key,
diff --git a/src/camel/camel-ews-store-summary.h b/src/camel/camel-ews-store-summary.h
index 7fdb63e..524b483 100644
--- a/src/camel/camel-ews-store-summary.h
+++ b/src/camel/camel-ews-store-summary.h
@@ -52,6 +52,8 @@ gboolean	camel_ews_store_summary_save	(CamelEwsStoreSummary *ews_summary,
 						 GError **error);
 gboolean	camel_ews_store_summary_clear	(CamelEwsStoreSummary *ews_summary);
 gboolean	camel_ews_store_summary_remove	(CamelEwsStoreSummary *ews_summary);
+void		camel_ews_store_summary_rebuild_hashes
+						(CamelEwsStoreSummary *ews_summary);
 
 void		camel_ews_store_summary_set_folder_name
 						(CamelEwsStoreSummary *ews_summary,
@@ -85,6 +87,10 @@ void		camel_ews_store_summary_set_folder_type
 						(CamelEwsStoreSummary *ews_summary,
 						 const gchar *folder_id,
 						 EEwsFolderType folder_type);
+void		camel_ews_store_summary_set_foreign
+						(CamelEwsStoreSummary *ews_summary,
+						 const gchar *folder_id,
+						 gboolean is_foreign);
 
 gchar *	camel_ews_store_summary_get_folder_name
 						(CamelEwsStoreSummary *ews_summary,
@@ -122,6 +128,10 @@ EEwsFolderType	camel_ews_store_summary_get_folder_type
 						(CamelEwsStoreSummary *ews_summary,
 						 const gchar *folder_id,
 						 GError **error);
+gboolean	camel_ews_store_summary_get_foreign
+						(CamelEwsStoreSummary *ews_summary,
+						 const gchar *folder_id,
+						 GError **error);
 
 GSList *	camel_ews_store_summary_get_folders
 						(CamelEwsStoreSummary *ews_summary,
@@ -150,7 +160,8 @@ void		camel_ews_store_summary_new_folder
 						 const gchar *display_name,
 						 EEwsFolderType folder_type,
 						 guint64 folder_flags,
-						 guint64 total);
+						 guint64 total,
+						 gboolean foreign);
 
 gchar *		camel_ews_store_summary_get_folder_id_from_name
 						(CamelEwsStoreSummary *ews_summary,
diff --git a/src/camel/camel-ews-store.c b/src/camel/camel-ews-store.c
index 9ee158b..074b908 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -70,12 +70,15 @@ static gboolean	ews_store_construct	(CamelService *service, CamelSession *sessio
 					 CamelProvider *provider, GError **error);
 
 static void camel_ews_store_initable_init (GInitableIface *interface);
+static void camel_ews_subscribable_init (CamelSubscribableInterface *interface);
 static GInitableIface *parent_initable_interface;
 
 G_DEFINE_TYPE_WITH_CODE (
 	CamelEwsStore, camel_ews_store, CAMEL_TYPE_OFFLINE_STORE,
 	G_IMPLEMENT_INTERFACE (
-		G_TYPE_INITABLE, camel_ews_store_initable_init))
+		G_TYPE_INITABLE, camel_ews_store_initable_init)
+	G_IMPLEMENT_INTERFACE (
+		CAMEL_TYPE_SUBSCRIBABLE, camel_ews_subscribable_init))
 
 static void
 ews_migrate_to_user_cache_dir (CamelService *service)
@@ -193,6 +196,265 @@ ews_store_construct (CamelService *service,
 	return TRUE;
 }
 
+/* free returned pointer with g_free() */
+static gchar *
+ews_get_owenr_mailbox_name (CamelEwsStore *ews_store)
+{
+	const gchar *email;
+	gchar *mailbox_name = NULL, *username = NULL;
+	CamelEwsSettings *ews_settings;
+
+	g_return_val_if_fail (CAMEL_IS_EWS_STORE (ews_store), NULL);
+
+	ews_settings = CAMEL_EWS_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE (ews_store)));
+	email = camel_ews_settings_get_email (ews_settings);
+
+	if (email && *email && camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) {
+		/* get username from the server */
+		EEwsConnection *conn;
+
+		conn = camel_ews_store_ref_connection (ews_store);
+		if (conn) {
+			GSList *mailboxes = NULL;
+			gboolean includes_last_item = FALSE;
+
+			if (e_ews_connection_resolve_names_sync (conn, G_PRIORITY_DEFAULT,
+				email, EWS_SEARCH_AD, NULL, FALSE, &mailboxes, NULL,
+				&includes_last_item, NULL, NULL)) {
+				GSList *iter;
+
+				for (iter = mailboxes; iter; iter = iter->next) {
+					EwsMailbox *mailbox = iter->data;
+
+					if (mailbox && mailbox->email && email &&
+					    g_ascii_strcasecmp (email, mailbox->email) == 0) {
+						username = g_strdup (mailbox->name);
+						break;
+					}
+				}
+
+				g_slist_free_full (mailboxes, (GDestroyNotify) e_ews_mailbox_free);
+			}
+
+			g_object_unref (conn);
+		}
+	}
+
+	/* Translators: The '%s' is replaced with user name, to whom the foreign mailbox belongs.
+	   Example result: "Mailbox - John Smith"
+	*/
+	mailbox_name = g_strdup_printf (C_("ForeignFolder", "Mailbox - %s"), username ? username : (email ? email : C_("ForeignFolder", "Owner")));
+
+	g_object_unref (ews_settings);
+	g_free (username);
+
+	return mailbox_name;
+}
+
+void
+camel_ews_store_ensure_virtual_folders (CamelEwsStore *ews_store)
+{
+	gchar *inbox_id, *inbox_parent_id;
+	gboolean needs_foreign = FALSE, has_foreign = FALSE;
+	GSList *folders, *iter;
+	GHashTable *children_count;
+	GHashTableIter tab_iter;
+	gpointer key, value;
+
+	g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
+
+	folders = camel_ews_store_summary_get_folders (ews_store->summary, NULL);
+	if (!folders)
+		return;
+
+	children_count = g_hash_table_new (g_str_hash, g_str_equal);
+
+	for (iter = folders; iter; iter = iter->next) {
+		const gchar *fid = iter->data;
+		GError *error = NULL;
+
+		if (!fid)
+			continue;
+
+		if (g_str_has_prefix (fid, "ForeignMailbox::") &&
+		    !g_hash_table_contains (children_count, fid))
+			g_hash_table_insert (children_count, (gpointer) fid, GINT_TO_POINTER (0));
+
+		if (!has_foreign && g_str_equal (fid, EWS_FOREIGN_FOLDER_ROOT_ID))
+			has_foreign = TRUE;
+		else if (camel_ews_store_summary_get_foreign (ews_store->summary, fid, &error) && !error) {
+			gchar *pfid;
+
+			needs_foreign = TRUE;
+
+			pfid = camel_ews_store_summary_get_parent_folder_id (ews_store->summary, fid, NULL);
+			if (pfid && g_str_has_prefix (pfid, "ForeignMailbox::")) {
+				gint count = GPOINTER_TO_INT (g_hash_table_lookup (children_count, pfid));
+
+				g_hash_table_insert (children_count, (gpointer) pfid, GINT_TO_POINTER (count + 1));
+			}
+		}
+
+		g_clear_error (&error);
+	}
+
+	inbox_id = camel_ews_store_summary_get_folder_id_from_folder_type (ews_store->summary, CAMEL_FOLDER_TYPE_INBOX);
+	g_return_if_fail (inbox_id != NULL);
+
+	inbox_parent_id = camel_ews_store_summary_get_parent_folder_id (ews_store->summary, inbox_id, NULL);
+	g_free (inbox_id);
+
+	g_return_if_fail (inbox_parent_id != NULL);
+
+	g_hash_table_iter_init (&tab_iter, children_count);
+	while (g_hash_table_iter_next (&tab_iter, &key, &value)) {
+		gint count = GPOINTER_TO_INT (value);
+
+		if (!count) {
+			CamelFolderInfo *fi;
+
+			fi = camel_ews_utils_build_folder_info (ews_store, key);
+			camel_ews_store_summary_remove_folder (ews_store->summary, key, NULL);
+
+			camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
+			camel_store_folder_deleted (CAMEL_STORE (ews_store), fi);
+			camel_folder_info_free (fi);
+		}
+	}
+
+	g_hash_table_destroy (children_count);
+
+	if (needs_foreign && !has_foreign) {
+		camel_ews_store_summary_new_folder (ews_store->summary,
+			EWS_FOREIGN_FOLDER_ROOT_ID, NULL, NULL,
+			EWS_FOREIGN_FOLDER_ROOT_DISPLAY_NAME,
+			E_EWS_FOLDER_TYPE_MAILBOX,
+			CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOSELECT,
+			0, FALSE);
+	} else if (has_foreign && !needs_foreign) {
+		CamelFolderInfo *fi;
+
+		fi = camel_ews_utils_build_folder_info (ews_store, EWS_FOREIGN_FOLDER_ROOT_ID);
+		camel_ews_store_summary_remove_folder (ews_store->summary, EWS_FOREIGN_FOLDER_ROOT_ID, NULL);
+
+		camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
+		camel_store_folder_deleted (CAMEL_STORE (ews_store), fi);
+		camel_folder_info_free (fi);
+	}
+
+	if (!camel_ews_store_summary_has_folder (ews_store->summary, inbox_parent_id)) {
+		/* all standard mail folders should be renamed */
+		GHashTable *old_names, *new_names;
+		CamelStore *store;
+		gchar *mailbox_name;
+
+		store = CAMEL_STORE (ews_store);
+		old_names = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+		new_names = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+		for (iter = folders; iter; iter = iter->next) {
+			const gchar *fid = iter->data;
+			GError *error = NULL;
+
+			if (!fid)
+				continue;
+
+			if (g_str_equal (fid, EWS_FOREIGN_FOLDER_ROOT_ID) ||
+			    g_str_equal (fid, inbox_parent_id)) {
+				/* these are not needed for rename */
+			} else if (!camel_ews_store_summary_get_foreign (ews_store->summary, fid, &error) || error) {
+				gchar *full_name = camel_ews_store_summary_get_folder_full_name (
+					ews_store->summary, fid, NULL);
+
+				if (full_name)
+					g_hash_table_insert (old_names, (gpointer) fid, full_name);
+			}
+
+			g_clear_error (&error);
+		}
+
+		mailbox_name = ews_get_owenr_mailbox_name (ews_store);
+		camel_ews_store_summary_new_folder (ews_store->summary,
+			inbox_parent_id, NULL, NULL,
+			mailbox_name, E_EWS_FOLDER_TYPE_MAILBOX,
+			CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOSELECT,
+			0, FALSE);
+
+		g_free (mailbox_name);
+
+		g_hash_table_iter_init (&tab_iter, old_names);
+		while (g_hash_table_iter_next (&tab_iter, &key, &value)) {
+			const gchar *fid = key;
+			gchar *full_name = camel_ews_store_summary_get_folder_full_name (
+				ews_store->summary, fid, NULL);
+
+			if (g_strcmp0 (full_name, value) != 0) {
+				g_hash_table_insert (new_names, (gpointer) fid, full_name);
+			}
+
+			g_free (full_name);
+		}
+
+		g_hash_table_iter_init (&tab_iter, new_names);
+		while (g_hash_table_iter_next (&tab_iter, &key, &value)) {
+			/* just rename folders.db folders, as this might
+			   be done before any ask for folder structure */
+			camel_db_rename_folder (store->cdb_w, g_hash_table_lookup (old_names, key), value, NULL);
+		}
+
+		g_hash_table_destroy (old_names);
+		g_hash_table_destroy (new_names);
+	}
+
+	camel_ews_store_summary_rebuild_hashes (ews_store->summary);
+	camel_ews_store_summary_save (ews_store->summary, NULL);
+
+	g_free (inbox_parent_id);
+	g_slist_free_full (folders, g_free);
+}
+
+void
+camel_ews_store_ensure_unique_path (CamelEwsStore *ews_store,
+				    gchar **ppath)
+{
+	gboolean done;
+	guint counter = 0;
+	gchar *base_path = NULL;
+
+	g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
+	g_return_if_fail (ews_store->summary != NULL);
+	g_return_if_fail (ppath != NULL);
+	g_return_if_fail (*ppath != NULL);
+
+	done = FALSE;
+	while (!done) {
+		gchar *fid;
+
+		done = TRUE;
+
+		fid = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, *ppath);
+		if (fid) {
+			g_free (fid);
+
+			done = FALSE;
+			counter++;
+			if (!counter) {
+				g_debug ("%s: Counter overflow", G_STRFUNC);
+				break;
+			}
+
+			if (!base_path)
+				base_path = *ppath;
+			else
+				g_free (*ppath);
+
+			*ppath = g_strdup_printf ("%s_%u", base_path, counter);
+		}
+	}
+
+	g_free (base_path);
+}
+
 static void
 ews_update_folder_hierarchy (CamelEwsStore *ews_store,
                              gchar *sync_state,
@@ -202,6 +464,8 @@ ews_update_folder_hierarchy (CamelEwsStore *ews_store,
                              GSList *folders_updated)
 {
 	ews_utils_sync_folders (ews_store, folders_created, folders_deleted, folders_updated);
+	camel_ews_store_ensure_virtual_folders (ews_store);
+
 	camel_ews_store_summary_store_string_val (ews_store->summary, "sync_state", sync_state);
 	camel_ews_store_summary_save (ews_store->summary, NULL);
 
@@ -612,11 +876,11 @@ ews_folder_hierarchy_ready_cb (GObject *obj,
 		g_mutex_unlock (priv->get_finfo_lock);
 		goto exit;
 	}
+	g_mutex_lock (priv->get_finfo_lock);
 	ews_update_folder_hierarchy (
 		ews_store, sync_state, includes_last_folder,
 		folders_created, folders_deleted, folders_updated);
 
-	g_mutex_lock (priv->get_finfo_lock);
 	ews_store->priv->last_refresh_time = time (NULL);
 	g_mutex_unlock (priv->get_finfo_lock);
 
@@ -672,12 +936,21 @@ ews_get_folder_info_sync (CamelStore *store,
 	gboolean success;
 	GError *local_error = NULL;
 
+	if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0) {
+		g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+			_("Cannot list folders available for subscription of Exchange Web Services account, "
+			  "use 'Subscribe to folder of other user' context menu option above the account node "
+			  "in the folder tree instead."));
+		return NULL;
+	}
+
 	ews_store = (CamelEwsStore *) store;
 	priv = ews_store->priv;
 
 	g_mutex_lock (priv->get_finfo_lock);
 	if (!(camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))
 	      && camel_service_connect_sync ((CamelService *) store, cancellable, error))) {
+		camel_ews_store_ensure_virtual_folders (ews_store);
 		g_mutex_unlock (priv->get_finfo_lock);
 		goto offline;
 	}
@@ -794,11 +1067,12 @@ ews_create_folder_sync (CamelStore *store,
 		fid, folder_id->change_key,
 		folder_name,
 		E_EWS_FOLDER_TYPE_MAILBOX,
-		0, 0);
+		0, 0, FALSE);
 	fi = camel_ews_utils_build_folder_info (ews_store, folder_id->id);
 	e_ews_folder_id_free (folder_id);
 
 	camel_store_folder_created (store, fi);
+	camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
 
 	g_free (full_name);
 	g_free (fid);
@@ -815,7 +1089,6 @@ ews_delete_folder_sync (CamelStore *store,
 	CamelEwsStoreSummary *ews_summary = ews_store->summary;
 	gchar *fid;
 	CamelFolderInfo *fi = NULL;
-	EEwsConnection *connection;
 	gboolean success;
 	GError *local_error = NULL;
 
@@ -833,15 +1106,23 @@ ews_delete_folder_sync (CamelStore *store,
 		return FALSE;
 	}
 
-	connection = camel_ews_store_ref_connection (ews_store);
+	if (camel_ews_store_summary_get_foreign (ews_store->summary, fid, NULL)) {
+		/* do not delete foreign folders,
+		   just remove them from local store */
+		success = TRUE;
+	} else {
+		EEwsConnection *connection;
 
-	success = e_ews_connection_delete_folder_sync (
-		connection,
-		EWS_PRIORITY_MEDIUM,
-		fid, FALSE, "HardDelete",
-		cancellable, &local_error);
+		connection = camel_ews_store_ref_connection (ews_store);
 
-	g_object_unref (connection);
+		success = e_ews_connection_delete_folder_sync (
+			connection,
+			EWS_PRIORITY_MEDIUM,
+			fid, FALSE, "HardDelete",
+			cancellable, &local_error);
+
+		g_object_unref (connection);
+	}
 
 	if (!success) {
 		camel_ews_store_maybe_disconnect (ews_store, local_error);
@@ -853,11 +1134,15 @@ ews_delete_folder_sync (CamelStore *store,
 	fi = camel_ews_utils_build_folder_info (ews_store, fid);
 	camel_ews_store_summary_remove_folder (ews_summary, fid, error);
 
+	camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
 	camel_store_folder_deleted (store, fi);
 	camel_folder_info_free (fi);
 
 	g_free (fid);
 
+	camel_ews_store_ensure_virtual_folders (ews_store);
+	camel_ews_store_summary_save (ews_store->summary, NULL);
+
 	return TRUE;
 }
 
@@ -1184,6 +1469,98 @@ ews_can_refresh_folder (CamelStore *store,
 		can_refresh_folder (store, info, error);
 }
 
+static gboolean
+ews_store_folder_is_subscribed (CamelSubscribable *subscribable,
+				const gchar *folder_name)
+{
+	CamelEwsStore *ews_store = CAMEL_EWS_STORE (subscribable);
+	gchar *fid;
+	gboolean truth = FALSE;
+	GError *error = NULL;
+
+	fid = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, folder_name);
+	if (!fid)
+		return FALSE;
+
+	if (camel_ews_store_summary_get_foreign (ews_store->summary, fid, &error) && !error) {
+		truth = TRUE;
+	}
+
+	g_clear_error (&error);
+	g_free (fid);
+
+	return truth;
+}
+
+static gboolean
+ews_store_subscribe_folder_sync (CamelSubscribable *subscribable,
+                                 const gchar *folder_name,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+	CamelEwsStore *ews_store = CAMEL_EWS_STORE (subscribable);
+
+	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) {
+		g_set_error_literal (
+			error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
+			_("Cannot subscribe EWS folders in offline mode"));
+		return FALSE;
+	}
+
+	g_set_error (
+		error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
+		_("Folder '%s' not found"), folder_name);
+
+	return TRUE;
+}
+
+static gboolean
+ews_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
+                                   const gchar *folder_name,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+	CamelEwsStore *ews_store = CAMEL_EWS_STORE (subscribable);
+	gboolean res = TRUE;
+	gchar *fid;
+
+	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) {
+		g_set_error_literal (
+			error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
+			_("Cannot unsubscribe EWS folders in offline mode"));
+		return FALSE;
+	}
+
+	fid = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, folder_name);
+	if (!fid) {
+		/* no such folder in the cache, might be unsubscribed already */
+		return TRUE;
+	}
+
+	if (!camel_ews_store_summary_get_foreign (ews_store->summary, fid, NULL)) {
+		g_set_error (
+			error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
+			_("Cannot subscribe EWS folder '%s'"), folder_name);
+		res = FALSE;
+	} else {
+		CamelFolderInfo *fi;
+
+		fi = camel_ews_utils_build_folder_info (ews_store, fid);
+		camel_ews_store_summary_remove_folder (ews_store->summary, fid, error);
+
+		camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
+		camel_store_folder_deleted (CAMEL_STORE (ews_store), fi);
+		camel_folder_info_free (fi);
+
+		camel_ews_store_ensure_virtual_folders (ews_store);
+		camel_ews_store_summary_save (ews_store->summary, NULL);
+	}
+
+	g_free (fid);
+
+	return res;
+}
+
 gboolean
 camel_ews_store_connected (CamelEwsStore *ews_store,
                            GError **error)
@@ -1296,6 +1673,14 @@ camel_ews_store_class_init (CamelEwsStoreClass *class)
 }
 
 static void
+camel_ews_subscribable_init (CamelSubscribableInterface *interface)
+{
+	interface->folder_is_subscribed = ews_store_folder_is_subscribed;
+	interface->subscribe_folder_sync = ews_store_subscribe_folder_sync;
+	interface->unsubscribe_folder_sync = ews_store_unsubscribe_folder_sync;
+}
+
+static void
 camel_ews_store_init (CamelEwsStore *ews_store)
 {
 	ews_store->priv =
diff --git a/src/camel/camel-ews-store.h b/src/camel/camel-ews-store.h
index 37b2bf3..d4115a3 100644
--- a/src/camel/camel-ews-store.h
+++ b/src/camel/camel-ews-store.h
@@ -51,6 +51,9 @@
 
 #define EWS_PARAM_FILTER_INBOX		(1 << 0)
 
+#define EWS_FOREIGN_FOLDER_ROOT_ID		"ForeignRoot"
+#define EWS_FOREIGN_FOLDER_ROOT_DISPLAY_NAME	_("Foreign Folders")
+
 G_BEGIN_DECLS
 
 typedef struct _CamelEwsStore CamelEwsStore;
@@ -79,6 +82,11 @@ gboolean	camel_ews_store_connected	(CamelEwsStore *store,
 void		camel_ews_store_maybe_disconnect
 						(CamelEwsStore *store,
 						 const GError *error);
+void		camel_ews_store_ensure_virtual_folders
+						(CamelEwsStore *ews_store);
+void		camel_ews_store_ensure_unique_path
+						(CamelEwsStore *ews_store,
+						 gchar **ppath);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-ews-utils.c b/src/camel/camel-ews-utils.c
index e1e5cc8..c783c8b 100644
--- a/src/camel/camel-ews-utils.c
+++ b/src/camel/camel-ews-utils.c
@@ -339,6 +339,8 @@ sync_deleted_folders (CamelEwsStore *store,
 			fi = camel_ews_utils_build_folder_info (store, fid);
 
 			camel_ews_store_summary_remove_folder (ews_summary, fid, &error);
+
+			camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (store), fi);
 			camel_store_folder_deleted ((CamelStore *) store, fi);
 
 			g_clear_error (&error);
@@ -476,7 +478,8 @@ add_folder_to_summary (CamelEwsStore *store,
 	camel_ews_store_summary_new_folder (
 		ews_summary, fid->id,
 		pfid->id, fid->change_key,
-		dname, ftype, 0, total);
+		dname, ftype, 0, total,
+		e_ews_folder_get_foreign (folder));
 	camel_ews_store_summary_set_folder_unread (ews_summary, fid->id, unread);
 }
 
@@ -508,6 +511,7 @@ sync_created_folders (CamelEwsStore *ews_store,
 		if (ftype == E_EWS_FOLDER_TYPE_MAILBOX) {
 			fi = camel_ews_utils_build_folder_info (ews_store, fid->id);
 			camel_store_folder_created ((CamelStore *) ews_store, fi);
+			camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
 			camel_folder_info_free (fi);
 		}
 	}
diff --git a/src/camel/camel-ews-utils.h b/src/camel/camel-ews-utils.h
index 6916fa7..5ee80c3 100644
--- a/src/camel/camel-ews-utils.h
+++ b/src/camel/camel-ews-utils.h
@@ -83,7 +83,7 @@ void	ews_utils_sync_folders	(CamelEwsStore *ews_store,
 
 CamelFolderInfo *
 	camel_ews_utils_build_folder_info	(CamelEwsStore *store,
-						 const gchar *fname);
+						 const gchar *fid);
 
 void	camel_ews_utils_sync_deleted_items	(CamelEwsFolder *ews_folder,
 						 GSList *items_deleted);
diff --git a/src/collection/e-ews-backend.c b/src/collection/e-ews-backend.c
index f7d0824..907c46f 100644
--- a/src/collection/e-ews-backend.c
+++ b/src/collection/e-ews-backend.c
@@ -656,7 +656,7 @@ ews_backend_create_resource_sync (ECollectionBackend *backend,
                                   GCancellable *cancellable,
                                   GError **error)
 {
-	EEwsConnection *connection;
+	EEwsConnection *connection = NULL;
 	EwsFolderId *out_folder_id = NULL;
 	EEwsFolderType folder_type = E_EWS_FOLDER_TYPE_UNKNOWN;
 	const gchar *extension_name;
@@ -664,68 +664,80 @@ ews_backend_create_resource_sync (ECollectionBackend *backend,
 	gchar *folder_name;
 	gboolean success = FALSE;
 
-	connection = e_ews_backend_ref_connection_sync (
-		E_EWS_BACKEND (backend), cancellable, error);
-	if (connection == NULL)
-		return FALSE;
-
-	extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+	extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
 	if (e_source_has_extension (source, extension_name)) {
-		folder_type = E_EWS_FOLDER_TYPE_CONTACTS;
-		parent_folder_id = "contacts";
-	}
+		ESourceEwsFolder *extension;
 
-	extension_name = E_SOURCE_EXTENSION_CALENDAR;
-	if (e_source_has_extension (source, extension_name)) {
-		folder_type = E_EWS_FOLDER_TYPE_CALENDAR;
-		parent_folder_id = "calendar";
+		/* foreign folders are just added */
+		extension = e_source_get_extension (source, extension_name);
+		if (e_source_ews_folder_get_foreign (extension))
+			success = TRUE;
 	}
 
-	extension_name = E_SOURCE_EXTENSION_TASK_LIST;
-	if (e_source_has_extension (source, extension_name)) {
-		folder_type = E_EWS_FOLDER_TYPE_TASKS;
-		parent_folder_id = "tasks";
-	}
+	if (!success) {
+		connection = e_ews_backend_ref_connection_sync (
+			E_EWS_BACKEND (backend), cancellable, error);
+		if (connection == NULL)
+			return FALSE;
 
-	/* FIXME No support for memo lists. */
+		extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+		if (e_source_has_extension (source, extension_name)) {
+			folder_type = E_EWS_FOLDER_TYPE_CONTACTS;
+			parent_folder_id = "contacts";
+		}
 
-	if (parent_folder_id == NULL) {
-		g_set_error (
-			error, G_IO_ERROR,
-			G_IO_ERROR_INVALID_ARGUMENT,
-			_("Could not determine a suitable folder "
-			"class for a new folder named '%s'"),
-			e_source_get_display_name (source));
-		goto exit;
-	}
+		extension_name = E_SOURCE_EXTENSION_CALENDAR;
+		if (e_source_has_extension (source, extension_name)) {
+			folder_type = E_EWS_FOLDER_TYPE_CALENDAR;
+			parent_folder_id = "calendar";
+		}
 
-	folder_name = e_source_dup_display_name (source);
+		extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+		if (e_source_has_extension (source, extension_name)) {
+			folder_type = E_EWS_FOLDER_TYPE_TASKS;
+			parent_folder_id = "tasks";
+		}
 
-	success = e_ews_connection_create_folder_sync (
-		connection, EWS_PRIORITY_MEDIUM,
-		parent_folder_id, TRUE,
-		folder_name, folder_type,
-		&out_folder_id, cancellable, error);
+		/* FIXME No support for memo lists. */
 
-	g_free (folder_name);
+		if (parent_folder_id == NULL) {
+			g_set_error (
+				error, G_IO_ERROR,
+				G_IO_ERROR_INVALID_ARGUMENT,
+				_("Could not determine a suitable folder "
+				"class for a new folder named '%s'"),
+				e_source_get_display_name (source));
+			goto exit;
+		}
 
-	/* Sanity check */
-	g_warn_if_fail (
-		(success && out_folder_id != NULL) ||
-		(!success && out_folder_id == NULL));
+		folder_name = e_source_dup_display_name (source);
 
-	if (out_folder_id != NULL) {
-		ESourceEwsFolder *extension;
-		const gchar *extension_name;
+		success = e_ews_connection_create_folder_sync (
+			connection, EWS_PRIORITY_MEDIUM,
+			parent_folder_id, TRUE,
+			folder_name, folder_type,
+			&out_folder_id, cancellable, error);
 
-		extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
-		extension = e_source_get_extension (source, extension_name);
-		e_source_ews_folder_set_id (
-			extension, out_folder_id->id);
-		e_source_ews_folder_set_change_key (
-			extension, out_folder_id->change_key);
+		g_free (folder_name);
+
+		/* Sanity check */
+		g_warn_if_fail (
+			(success && out_folder_id != NULL) ||
+			(!success && out_folder_id == NULL));
+
+		if (out_folder_id != NULL) {
+			ESourceEwsFolder *extension;
+			const gchar *extension_name;
 
-		e_ews_folder_id_free (out_folder_id);
+			extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
+			extension = e_source_get_extension (source, extension_name);
+			e_source_ews_folder_set_id (
+				extension, out_folder_id->id);
+			e_source_ews_folder_set_change_key (
+				extension, out_folder_id->change_key);
+
+			e_ews_folder_id_free (out_folder_id);
+		}
 	}
 
 	if (success) {
@@ -755,8 +767,9 @@ ews_backend_create_resource_sync (ECollectionBackend *backend,
 		g_object_unref (server);
 	}
 
-exit:
-	g_object_unref (connection);
+ exit:
+	if (connection)
+		g_object_unref (connection);
 
 	return success;
 }
@@ -770,7 +783,6 @@ ews_backend_delete_resource_sync (ECollectionBackend *backend,
 	EEwsConnection *connection;
 	ESourceEwsFolder *extension;
 	const gchar *extension_name;
-	gchar *folder_id;
 	gboolean success = FALSE;
 
 	connection = e_ews_backend_ref_connection_sync (
@@ -789,11 +801,22 @@ ews_backend_delete_resource_sync (ECollectionBackend *backend,
 		goto exit;
 	}
 	extension = e_source_get_extension (source, extension_name);
-	folder_id = e_source_ews_folder_dup_id (extension);
 
-	success = e_ews_connection_delete_folder_sync (
-		connection, EWS_PRIORITY_MEDIUM, folder_id,
-		FALSE, "HardDelete", cancellable, error);
+	if (e_source_ews_folder_get_foreign (extension)) {
+		/* do not delete foreign folders,
+		   just remove them from local store */
+		success = TRUE;
+	} else {
+		gchar *folder_id;
+
+		folder_id = e_source_ews_folder_dup_id (extension);
+
+		success = e_ews_connection_delete_folder_sync (
+			connection, EWS_PRIORITY_MEDIUM, folder_id,
+			FALSE, "HardDelete", cancellable, error);
+
+		g_free (folder_id);
+	}
 
 	if (success) {
 		ESourceRegistryServer *server;
diff --git a/src/configuration/Makefile.am b/src/configuration/Makefile.am
index 9c059ae..ad5f142 100644
--- a/src/configuration/Makefile.am
+++ b/src/configuration/Makefile.am
@@ -38,6 +38,8 @@ module_ews_configuration_la_SOURCES = \
 	e-ews-edit-folder-permissions.h \
 	e-ews-search-user.c \
 	e-ews-search-user.h \
+	e-ews-subscribe-foreign-folder.c \
+	e-ews-subscribe-foreign-folder.h \
 	$(NULL)
 
 module_ews_configuration_la_LIBADD = \
diff --git a/src/configuration/e-ews-config-utils.c b/src/configuration/e-ews-config-utils.c
index 4bcd550..17bead9 100644
--- a/src/configuration/e-ews-config-utils.c
+++ b/src/configuration/e-ews-config-utils.c
@@ -47,6 +47,7 @@
 
 #include "e-ews-config-utils.h"
 #include "e-ews-search-user.h"
+#include "e-ews-subscribe-foreign-folder.h"
 
 struct RunWithFeedbackData
 {
@@ -107,8 +108,11 @@ run_with_feedback_idle (gpointer user_data)
 	}
 
 	if (!was_cancelled) {
-		if (rfd->error)
+		if (rfd->error) {
+			g_dbus_error_strip_remote_error (rfd->error);
+
 			e_notice (rfd->parent, GTK_MESSAGE_ERROR, "%s", rfd->error->message);
+		}
 	}
 
 	free_run_with_feedback_data (rfd);
@@ -458,7 +462,6 @@ get_ews_store_from_folder_tree (EShellView *shell_view,
 	return found;
 }
 
-#if 0
 static void
 action_subscribe_foreign_folder_cb (GtkAction *action,
                                     EShellView *shell_view)
@@ -479,9 +482,7 @@ action_subscribe_foreign_folder_cb (GtkAction *action,
 
 	g_object_unref (session);
 	g_object_unref (store);
-	g_free (profile);
 }
-#endif
 
 static void
 action_folder_permissions_mail_cb (GtkAction *action,
@@ -580,17 +581,15 @@ ews_ui_enable_actions (GtkActionGroup *action_group,
 	}
 }
 
-#if 0
 static GtkActionEntry mail_account_context_entries[] = {
 
 	{ "mail-ews-subscribe-foreign-folder",
 	  NULL,
 	  N_("Subscribe to folder of other user..."),
 	  NULL,
-	  NULL,  / * XXX Add a tooltip! * /
+	  NULL,  /* XXX Add a tooltip! */
 	  G_CALLBACK (action_subscribe_foreign_folder_cb) }
 };
-#endif
 
 static GtkActionEntry mail_folder_context_entries[] = {
 	{ "mail-ews-folder-permissions",
@@ -604,7 +603,7 @@ static GtkActionEntry mail_folder_context_entries[] = {
 static const gchar *ews_ui_mail_def =
 	"<popup name=\"mail-folder-popup\">\n"
 	"  <placeholder name=\"mail-folder-popup-actions\">\n"
-	/*"    <menuitem action=\"mail-ews-subscribe-foreign-folder\"/>\n"*/
+	"    <menuitem action=\"mail-ews-subscribe-foreign-folder\"/>\n"
 	"    <menuitem action=\"mail-ews-folder-permissions\"/>\n"
 	"  </placeholder>\n"
 	"</popup>\n";
@@ -659,7 +658,7 @@ ews_ui_update_actions_mail_cb (EShellView *shell_view,
 			g_object_unref (session);
 	}
 
-	/* ews_ui_enable_actions (action_group, mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), account_node, online); */
+	ews_ui_enable_actions (action_group, mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), account_node, online);
 	ews_ui_enable_actions (action_group, mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), folder_node, online);
 }
 
@@ -679,8 +678,8 @@ ews_ui_init_mail (GtkUIManager *ui_manager,
 	action_group = e_shell_window_get_action_group (shell_window, "mail");
 
 	/* Add actions to the "mail" action group. */
-	/*e_action_group_add_actions_localized (action_group, GETTEXT_PACKAGE,
-		mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), shell_view);*/
+	e_action_group_add_actions_localized (action_group, GETTEXT_PACKAGE,
+		mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), shell_view);
 	e_action_group_add_actions_localized (
 		action_group, GETTEXT_PACKAGE,
 		mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), shell_view);
diff --git a/src/configuration/e-ews-subscribe-foreign-folder.c b/src/configuration/e-ews-subscribe-foreign-folder.c
new file mode 100644
index 0000000..ab2bdda
--- /dev/null
+++ b/src/configuration/e-ews-subscribe-foreign-folder.c
@@ -0,0 +1,716 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *    Milan Crha <mcrha redhat com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include <libedataserverui/libedataserverui.h>
+#include <libemail-engine/e-mail-session.h>
+
+#include "camel/camel-ews-store.h"
+#include "camel/camel-ews-store-summary.h"
+#include "camel/camel-ews-utils.h"
+
+#include "e-ews-config-utils.h"
+#include "e-ews-search-user.h"
+#include "e-ews-subscribe-foreign-folder.h"
+
+#define STR_USER_NAME_SELECTOR_ENTRY	"e-ews-name-selector-entry"
+#define STR_FOLDER_NAME_COMBO		"e-ews-folder-name-combo"
+#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"
+
+static void
+announce_new_folder (CamelEwsStore *ews_store,
+		     const gchar *fid)
+{
+	CamelFolderInfo *fi;
+
+	g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
+	g_return_if_fail (fid != NULL);
+	g_return_if_fail (camel_ews_store_summary_has_folder (ews_store->summary, fid));
+
+	fi = camel_ews_utils_build_folder_info (ews_store, fid);
+	camel_store_folder_created (CAMEL_STORE (ews_store), fi);
+	camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
+	camel_folder_info_free (fi);
+}
+
+static gboolean
+add_foreign_folder_to_camel (CamelEwsStore *ews_store,
+			     const gchar *foreign_email,
+			     EEwsFolder *folder,
+			     const gchar *display_username,
+			     const gchar *display_foldername,
+			     GError **perror)
+{
+	gchar *foreign_mailbox_id;
+	gchar *mailbox, *fullname;
+	const EwsFolderId *fid, *parent_fid;
+
+	g_return_val_if_fail (ews_store != NULL, FALSE);
+	g_return_val_if_fail (ews_store->summary != NULL, FALSE);
+	g_return_val_if_fail (foreign_email != NULL, FALSE);
+	g_return_val_if_fail (folder != NULL, FALSE);
+	g_return_val_if_fail (display_username != NULL, FALSE);
+	g_return_val_if_fail (display_foldername != NULL, FALSE);
+
+	fid = e_ews_folder_get_id (folder);
+	parent_fid = e_ews_folder_get_parent_id (folder);
+
+	g_return_val_if_fail (fid != NULL, FALSE);
+	g_return_val_if_fail (parent_fid != NULL, FALSE);
+	g_return_val_if_fail (g_strcmp0 (fid->id, parent_fid->id) != 0, FALSE);
+
+	if (camel_ews_store_summary_has_folder (ews_store->summary, fid->id)) {
+		gchar *full_name = camel_ews_store_summary_get_folder_full_name (ews_store->summary, fid->id, NULL);
+
+		g_propagate_error (perror,
+			g_error_new (EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDEREXISTS,
+			_("Cannot add folder, folder already exists as '%s'"), full_name));
+
+		g_free (full_name);
+
+		return FALSE;
+	}
+
+	/* Translators: The '%s' is replaced with user name, to whom the foreign mailbox belongs.
+	   Example result: "Mailbox - John Smith"
+	*/
+	mailbox = g_strdup_printf (C_("ForeignFolder", "Mailbox - %s"), display_username);
+
+	foreign_mailbox_id = g_strdup_printf ("ForeignMailbox::%s", foreign_email);
+	if (!camel_ews_store_summary_has_folder (ews_store->summary, foreign_mailbox_id)) {
+		camel_ews_store_summary_new_folder (ews_store->summary,
+			foreign_mailbox_id, EWS_FOREIGN_FOLDER_ROOT_ID, NULL,
+			mailbox, E_EWS_FOLDER_TYPE_MAILBOX,
+			CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOSELECT,
+			0, FALSE);
+	}
+
+	if (camel_ews_store_summary_has_folder (ews_store->summary, parent_fid->id)) {
+		camel_ews_store_summary_new_folder (ews_store->summary,
+			fid->id, parent_fid->id, fid->change_key,
+			display_foldername, E_EWS_FOLDER_TYPE_MAILBOX,
+			CAMEL_FOLDER_SUBSCRIBED, e_ews_folder_get_total_count (folder), TRUE);
+	} else {
+		const gchar *displayname;
+
+		fullname = g_strdup_printf ("%s/%s/%s", EWS_FOREIGN_FOLDER_ROOT_DISPLAY_NAME, mailbox, display_foldername);
+
+		/* make sure the path is unique */
+		camel_ews_store_ensure_unique_path (ews_store, &fullname);
+
+		displayname = strrchr (fullname, '/');
+		displayname++;
+
+		camel_ews_store_summary_new_folder (ews_store->summary,
+			fid->id, foreign_mailbox_id, fid->change_key,
+			displayname, E_EWS_FOLDER_TYPE_MAILBOX,
+			CAMEL_FOLDER_SUBSCRIBED, e_ews_folder_get_total_count (folder), TRUE);
+
+		g_free (fullname);
+	}
+
+	camel_ews_store_ensure_virtual_folders (ews_store);
+
+	announce_new_folder (ews_store, EWS_FOREIGN_FOLDER_ROOT_ID);
+	announce_new_folder (ews_store, foreign_mailbox_id);
+	announce_new_folder (ews_store, fid->id);
+
+	g_free (foreign_mailbox_id);
+	g_free (mailbox);
+
+	return TRUE;
+}
+
+static void
+enable_ok_button_by_data (GObject *dialog)
+{
+	GtkEntry *entry;
+	GtkComboBoxText *combo;
+	const gchar *entry_text;
+	gchar *combo_text;
+
+	g_return_if_fail (dialog != NULL);
+
+	entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
+	g_return_if_fail (entry != NULL);
+
+	combo = g_object_get_data (dialog, STR_FOLDER_NAME_COMBO);
+	g_return_if_fail (combo != NULL);
+
+	entry_text = gtk_entry_get_text (entry);
+	combo_text = gtk_combo_box_text_get_active_text (combo);
+
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK,
+		entry_text && *entry_text && *entry_text != ' ' && *entry_text != ',' &&
+		combo_text && *combo_text);
+
+	g_free (combo_text);
+}
+
+static void
+name_entry_changed_cb (GObject *dialog)
+{
+	GtkEntry *entry;
+
+	g_return_if_fail (dialog != NULL);
+
+	entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
+	g_return_if_fail (entry != NULL);
+
+	g_object_set_data (G_OBJECT (entry), STR_EWS_DIRECT_EMAIL, NULL);
+
+	enable_ok_button_by_data (dialog);
+}
+
+static void
+folder_name_combo_changed_cb (GObject *dialog)
+{
+	enable_ok_button_by_data (dialog);
+}
+
+struct EEwsCheckForeignFolderData
+{
+	GtkWidget *dialog;
+	gchar *email;
+	gchar *direct_email;
+	gchar *user_displayname;
+	gchar *orig_foldername;
+	gchar *use_foldername;
+	EEwsFolder *folder;
+};
+
+static void
+e_ews_check_foreign_folder_data_free (gpointer ptr)
+{
+	struct EEwsCheckForeignFolderData *cffd = ptr;
+
+	if (!cffd)
+		return;
+
+	g_free (cffd->email);
+	g_free (cffd->direct_email);
+	g_free (cffd->user_displayname);
+	g_free (cffd->orig_foldername);
+	g_free (cffd->use_foldername);
+
+	/* folder tells whether successfully finished,
+	   then the dialog can be destroyed */
+	if (cffd->folder && cffd->dialog)
+		gtk_widget_destroy (cffd->dialog);
+
+	if (cffd->folder)
+		g_object_unref (cffd->folder);
+
+	g_free (cffd);
+}
+
+static void
+check_foreign_folder_thread (GObject *with_object,
+			     gpointer user_data,
+			     GCancellable *cancellable,
+			     GError **perror)
+{
+	struct EEwsCheckForeignFolderData *cffd = user_data;
+	GError *local_error = NULL;
+	EEwsConnection *conn;
+	EwsFolderId fid;
+	EEwsFolder *folder = NULL;
+
+	g_return_if_fail (with_object != NULL);
+	g_return_if_fail (CAMEL_IS_EWS_STORE (with_object));
+	g_return_if_fail (user_data != NULL);
+	g_return_if_fail (cffd->email != NULL);
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror))
+		return;
+
+	conn = camel_ews_store_ref_connection (CAMEL_EWS_STORE (with_object));
+	if (!conn) {
+		g_set_error_literal (
+			perror, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_NORESPONSE,
+			_("Cannot test foreign folder availability while in offline mode"));
+		return;
+	}
+
+	if (cffd->direct_email && *cffd->direct_email) {
+		g_return_if_fail (cffd->user_displayname == NULL);
+
+		cffd->user_displayname = cffd->email;
+		cffd->email = g_strdup (cffd->direct_email);
+	} else {
+		GSList *mailboxes = NULL;
+		EwsMailbox *mailbox = NULL;
+		gboolean includes_last_item = FALSE;
+
+		if (!e_ews_connection_resolve_names_sync (conn, G_PRIORITY_DEFAULT,
+			cffd->email, EWS_SEARCH_AD, NULL, FALSE,
+			&mailboxes, NULL, &includes_last_item,
+			cancellable, perror)) {
+			g_object_unref (conn);
+			return;
+		}
+
+		if (!mailboxes) {
+			g_set_error (
+				perror, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_MAILRECIPIENTNOTFOUND,
+				_("User '%s' was not found on the server"), cffd->email);
+			g_object_unref (conn);
+			return;
+		}
+
+		/* is there only one result? */
+		if (mailboxes->next == NULL) {
+			mailbox = mailboxes->data;
+		} else {
+			GSList *iter;
+
+			for (iter = mailboxes; iter; iter = iter->next) {
+				EwsMailbox *mb = iter->data;
+
+				if (!mb)
+					continue;
+
+				if (mb->name && g_utf8_collate (mb->name, cffd->email) == 0) {
+					mailbox = mb;
+					break;
+				}
+			}
+		}
+
+		if (mailbox) {
+			g_free (cffd->user_displayname);
+			cffd->user_displayname = g_strdup (mailbox->name);
+			g_free (cffd->email);
+			cffd->email = g_strdup (mailbox->email);
+		}
+
+		g_slist_free_full (mailboxes, (GDestroyNotify) e_ews_mailbox_free);
+
+		if (!mailbox) {
+			g_set_error (
+				perror, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ITEMNOTFOUND,
+				_("User name '%s' is ambiguous, specify it more precisely, please"), cffd->email);
+			g_object_unref (conn);
+			return;
+		}
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		g_object_unref (conn);
+		return;
+	}
+
+	fid.id = (gchar *) (cffd->use_foldername ? cffd->use_foldername : cffd->orig_foldername);
+	fid.change_key = NULL;
+	fid.is_distinguished_id = cffd->use_foldername != NULL;
+
+	if (!e_ews_connection_get_folder_info_sync (conn, G_PRIORITY_DEFAULT,
+		cffd->email, &fid, &folder, cancellable, &local_error)) {
+		if (g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ITEMNOTFOUND) ||
+		    g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDERNOTFOUND)) {
+			g_clear_error (&local_error);
+			local_error = g_error_new (EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDERNOTFOUND,
+				_("Folder '%s' not found. Either it does not exist or you do not have permission to access it."),
+				cffd->orig_foldername);
+		}
+
+		g_propagate_error (perror, local_error);
+		g_object_unref (conn);
+		return;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		g_object_unref (folder);
+		g_object_unref (conn);
+		return;
+	}
+
+	if (e_ews_folder_get_folder_type (folder) == E_EWS_FOLDER_TYPE_UNKNOWN) {
+		g_propagate_error (perror, g_error_new_literal (EWS_CONNECTION_ERROR,
+			EWS_CONNECTION_ERROR_FOLDERNOTFOUND, _("Cannot add folder, cannot determine folder's type")));
+		g_object_unref (folder);
+		g_object_unref (conn);
+		return;
+	}
+
+	e_ews_folder_set_foreign (folder, TRUE);
+
+	cffd->folder = folder;
+	g_object_unref (conn);
+}
+
+static void
+check_foreign_folder_idle (GObject *with_object,
+			   gpointer user_data,
+			   GCancellable *cancellable,
+			   GError **perror)
+{
+	struct EEwsCheckForeignFolderData *cffd = user_data;
+	gchar *folder_name;
+	const gchar *base_username, *base_foldername;
+	CamelSettings *settings;
+	CamelEwsSettings *ews_settings;
+	CamelEwsStore *ews_store;
+	ESourceRegistry *registry = NULL;
+	CamelSession *session;
+	EEwsFolderType folder_type;
+
+	g_return_if_fail (with_object != NULL);
+	g_return_if_fail (CAMEL_IS_EWS_STORE (with_object));
+	g_return_if_fail (user_data != NULL);
+	g_return_if_fail (cffd->email != NULL);
+
+	if (!cffd->folder)
+		return;
+
+	folder_type = e_ews_folder_get_folder_type (cffd->folder);
+	base_username = cffd->user_displayname ? cffd->user_displayname : cffd->email;
+	base_foldername = e_ews_folder_get_name (cffd->folder) ? e_ews_folder_get_name (cffd->folder) : cffd->orig_foldername;
+
+	/* Translators: This is used to name foreign folder.
+	   The first '%s' is replaced with user name to whom the folder belongs,
+	   the second '%s' is replaced with folder name.
+	   Example result: "John Smith - Calendar"
+	*/
+	folder_name = g_strdup_printf (C_("ForeignFolder", "%s - %s"), base_username, base_foldername);
+	if (folder_type != E_EWS_FOLDER_TYPE_MAILBOX)
+		e_ews_folder_set_name (cffd->folder, folder_name);
+
+	ews_store = CAMEL_EWS_STORE (with_object);
+	settings = camel_service_ref_settings (CAMEL_SERVICE (ews_store));
+	ews_settings = CAMEL_EWS_SETTINGS (settings);
+	session = camel_service_get_session (CAMEL_SERVICE (ews_store));
+	if (E_IS_MAIL_SESSION (session))
+		registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
+
+	if ((folder_type == E_EWS_FOLDER_TYPE_MAILBOX &&
+	     !add_foreign_folder_to_camel (ews_store,
+		cffd->email,
+		cffd->folder,
+		base_username,
+		base_foldername,
+		perror)) ||
+	    (folder_type != E_EWS_FOLDER_TYPE_MAILBOX && !e_ews_folder_utils_add_as_esource (registry,
+		camel_ews_settings_get_hosturl (ews_settings),
+		camel_network_settings_get_user (CAMEL_NETWORK_SETTINGS (ews_settings)),
+		cffd->folder,
+		TRUE,
+		0,
+		cancellable,
+		perror))
+	) {
+		/* to not destroy the dialog on error */
+		g_object_unref (cffd->folder);
+		cffd->folder = NULL;
+	}
+
+	g_free (folder_name);
+	g_object_unref (settings);
+}
+
+static void
+subscribe_foreign_response_cb (GObject *dialog,
+			       gint response_id)
+{
+	struct EEwsCheckForeignFolderData *cffd;
+	ENameSelectorEntry *entry;
+	GtkComboBoxText *combo_text;
+	EDestinationStore *dest_store;
+	CamelStore *cstore;
+	gchar *description;
+	const gchar *username;
+	gchar *orig_foldername, *use_foldername = NULL, *show_foldername = NULL;
+
+	if (response_id != GTK_RESPONSE_OK) {
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+		return;
+	}
+
+	g_return_if_fail (dialog != NULL);
+
+	entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
+	combo_text = g_object_get_data (dialog, STR_FOLDER_NAME_COMBO);
+	cstore = g_object_get_data (dialog, STR_EWS_CAMEL_STORE);
+
+	g_return_if_fail (entry != NULL);
+	g_return_if_fail (cstore != NULL);
+
+	username = NULL;
+	dest_store = e_name_selector_entry_peek_destination_store (entry);
+	if (dest_store && e_destination_store_get_destination_count (dest_store) > 0) {
+		EDestination *dest;
+		GList *dests = e_destination_store_list_destinations (dest_store);
+
+		g_return_if_fail (dests != NULL);
+
+		/* pick the first, there is no option to limit to only one destination */
+		dest = dests->data;
+		if (dest) {
+			username = e_destination_get_email (dest);
+			if (!username || !*username)
+				username = e_destination_get_name (dest);
+		}
+
+		g_list_free (dests);
+	}
+
+	if (!username || !*username)
+		username = gtk_entry_get_text (GTK_ENTRY (entry));
+
+	orig_foldername = gtk_combo_box_text_get_active_text (combo_text);
+	if (!orig_foldername)
+		orig_foldername = g_strdup ("");
+
+	/* convert well-known names to their non-localized form */
+	if (g_strcmp0 (orig_foldername, _("Inbox")) == 0) {
+		use_foldername = g_strdup ("inbox");
+	} else if (g_strcmp0 (orig_foldername, _("Contacts")) == 0) {
+		use_foldername = g_strdup ("contacts");
+	} else if (g_strcmp0 (orig_foldername, _("Calendar")) == 0) {
+		use_foldername = g_strdup ("calendar");
+	} else if (g_strcmp0 (orig_foldername, _("Memos")) == 0) {
+		use_foldername = g_strdup ("notes");
+	} else if (g_strcmp0 (orig_foldername, _("Tasks")) == 0) {
+		use_foldername = g_strdup ("tasks");
+	} else if (strlen (orig_foldername) > 13) {
+		/* if its a folder ID, then show only first 10 letters of it */
+		show_foldername = g_strdup_printf ("%.10s...", orig_foldername);
+	}
+
+	cffd = g_new0 (struct EEwsCheckForeignFolderData, 1);
+	cffd->dialog = GTK_WIDGET (dialog);
+	cffd->email = g_strdup (username ? username : "");
+	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->folder = NULL;
+
+	description = g_strdup_printf (_("Testing availability of folder '%s' of user '%s', please wait..."),
+		show_foldername ? show_foldername : cffd->orig_foldername, cffd->email);
+
+	e_ews_config_utils_run_in_thread_with_feedback (
+		GTK_WINDOW (dialog),
+		G_OBJECT (cstore),
+		description,
+		check_foreign_folder_thread,
+		check_foreign_folder_idle,
+		cffd,
+		e_ews_check_foreign_folder_data_free);
+
+	g_free (description);
+	g_free (show_foldername);
+}
+
+static void
+pick_gal_user_clicked_cb (GtkButton *button,
+			  GObject *dialog)
+{
+	GtkEntry *entry;
+	CamelEwsStore *ews_store;
+	EEwsConnection *conn;
+	gchar *text, *display_name = NULL, *email = NULL;
+
+	g_return_if_fail (dialog != NULL);
+
+	entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
+	ews_store = g_object_get_data (dialog, STR_EWS_CAMEL_STORE);
+
+	g_return_if_fail (entry != NULL);
+	g_return_if_fail (ews_store != NULL);
+
+	text = g_strstrip (g_strdup (gtk_entry_get_text (entry)));
+	conn = camel_ews_store_ref_connection (ews_store);
+
+	if (e_ews_search_user_modal (GTK_WINDOW (dialog),
+				     conn,
+				     text,
+				     &display_name,
+				     &email)) {
+		if (display_name && email && *email) {
+			gtk_entry_set_text (entry, display_name);
+			g_object_set_data_full (G_OBJECT (entry), STR_EWS_DIRECT_EMAIL, g_strdup (email), g_free);
+		}
+	}
+
+	g_free (text);
+	g_free (display_name);
+	g_free (email);
+	g_object_unref (conn);
+}
+
+/* Opens dialog to subscribe to folders of other
+   users in the given store */
+void
+e_ews_subscribe_foreign_folder (GtkWindow *parent,
+				CamelSession *session,
+				CamelStore *store)
+{
+	PangoAttrList *attrs;
+	ENameSelector *name_selector;
+	ENameSelectorModel *name_selector_model;
+	ENameSelectorDialog *name_selector_dialog;
+	GObject *dialog;
+	GtkWidget *content;
+	GtkWidget *label, *widget, *entry;
+	GtkGrid *grid;
+	GtkComboBoxText *combo_text;
+	gint row;
+
+	g_return_if_fail (session != NULL);
+	g_return_if_fail (store != NULL);
+	g_return_if_fail (CAMEL_IS_EWS_STORE (store));
+
+	dialog = G_OBJECT (gtk_dialog_new_with_buttons (
+		_("Subscribe to folder of other EWS user..."),
+		parent,
+		GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL));
+
+	g_signal_connect (dialog, "response", G_CALLBACK (subscribe_foreign_response_cb), NULL);
+
+	content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+	grid = GTK_GRID (gtk_grid_new ());
+	gtk_grid_set_row_homogeneous (grid, FALSE);
+	gtk_grid_set_row_spacing (grid, 6);
+	gtk_grid_set_column_homogeneous (grid, FALSE);
+	gtk_grid_set_column_spacing (grid, 6);
+	gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
+	gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
+
+	row = 0;
+
+	label = gtk_label_new (_("Account:"));
+	g_object_set (G_OBJECT (label),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		"halign", GTK_ALIGN_START,
+		NULL);
+
+	attrs = pango_attr_list_new ();
+	pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+	widget = gtk_label_new (camel_service_get_display_name (CAMEL_SERVICE (store)));
+	g_object_set (G_OBJECT (widget),
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		"use-underline", FALSE,
+		"attributes", attrs,
+		"xalign", 0.0,
+		"halign", GTK_ALIGN_START,
+		NULL);
+	pango_attr_list_unref (attrs);
+
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	gtk_grid_attach (grid, widget, 1, row, 2, 1);
+
+	row++;
+
+	name_selector = e_name_selector_new (e_mail_session_get_registry (E_MAIL_SESSION (session)));
+	name_selector_model = e_name_selector_peek_model (name_selector);
+	e_name_selector_model_add_section (name_selector_model, "User", _("User"), NULL);
+	name_selector_dialog = e_name_selector_peek_dialog (name_selector);
+	g_signal_connect (name_selector_dialog, "response", G_CALLBACK (gtk_widget_hide), name_selector);
+	e_name_selector_load_books (name_selector);
+
+	g_object_set_data_full (dialog, "e-ews-name-selector", name_selector, g_object_unref);
+
+	label = gtk_label_new_with_mnemonic (_("_User:"));
+	g_object_set (G_OBJECT (label),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		NULL);
+
+	entry = GTK_WIDGET (e_name_selector_peek_section_entry (name_selector, "User"));
+	g_object_set (G_OBJECT (entry),
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		NULL);
+
+	widget = gtk_button_new_with_mnemonic (_("C_hoose..."));
+	g_object_set (G_OBJECT (entry),
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		NULL);
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+	g_signal_connect (widget, "clicked", G_CALLBACK (pick_gal_user_clicked_cb), dialog);
+
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	gtk_grid_attach (grid, entry, 1, row, 1, 1);
+	gtk_grid_attach (grid, widget, 2, row, 1, 1);
+
+	row++;
+
+	label = gtk_label_new_with_mnemonic (_("_Folder name:"));
+	g_object_set (G_OBJECT (label),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		NULL);
+
+	widget = GTK_WIDGET (g_object_new (gtk_combo_box_text_get_type (),
+		"has-entry", TRUE,
+		"entry-text-column", 0,
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		NULL));
+
+	combo_text = GTK_COMBO_BOX_TEXT (widget);
+	gtk_combo_box_text_append_text (combo_text, _("Inbox"));
+	gtk_combo_box_text_append_text (combo_text, _("Contacts"));
+	gtk_combo_box_text_append_text (combo_text, _("Calendar"));
+	gtk_combo_box_text_append_text (combo_text, _("Memos"));
+	gtk_combo_box_text_append_text (combo_text, _("Tasks"));
+	gtk_combo_box_set_active (GTK_COMBO_BOX (combo_text), 0);
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	gtk_grid_attach (grid, widget, 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_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);
+
+	g_signal_connect_swapped (entry, "changed", G_CALLBACK (name_entry_changed_cb), dialog);
+	g_signal_connect_swapped (combo_text, "changed", G_CALLBACK (folder_name_combo_changed_cb), dialog);
+
+	name_entry_changed_cb (dialog);
+
+	gtk_widget_show_all (content);
+	gtk_widget_show (GTK_WIDGET (dialog));
+}
diff --git a/src/configuration/e-ews-subscribe-foreign-folder.h b/src/configuration/e-ews-subscribe-foreign-folder.h
new file mode 100644
index 0000000..04a7956
--- /dev/null
+++ b/src/configuration/e-ews-subscribe-foreign-folder.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *    Milan Crha <mcrha redhat com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_EWS_SUBSCRIBE_FOREIGN_FOLDER_H
+#define E_EWS_SUBSCRIBE_FOREIGN_FOLDER_H
+
+#include <gtk/gtk.h>
+#include <camel/camel.h>
+
+void	e_ews_subscribe_foreign_folder	(GtkWindow *parent,
+					 CamelSession *session,
+					 CamelStore *store);
+
+#endif /* E_EWS_SUBSCRIBE_FOREIGN_FOLDER_H */
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index 3099c57..a3c5739 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -3101,8 +3101,11 @@ ews_append_folder_ids_to_msg (ESoapMessage *msg,
 		if (fid->change_key)
 			e_soap_message_add_attribute (msg, "ChangeKey", fid->change_key, NULL, NULL);
 
-		if (fid->is_distinguished_id && email)
-			e_ews_message_write_string_parameter (msg, "Mailbox", NULL, email);
+		if (fid->is_distinguished_id && email) {
+			e_soap_message_start_element (msg, "Mailbox", NULL, NULL);
+			e_ews_message_write_string_parameter (msg, "EmailAddress", NULL, email);
+			e_soap_message_end_element (msg);
+		}
 
 		e_soap_message_end_element (msg);
 	}
@@ -7323,3 +7326,171 @@ e_ews_connection_get_password_expiration_sync (EEwsConnection *cnc,
 
 	return success;
 }
+
+static void
+get_folder_info_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, "GetFolderResponseMessage")) {
+			ESoapParameter *node;
+
+			node = e_soap_parameter_get_first_child_by_name (subparam, "Folders");
+			if (node) {
+				EEwsFolder *folder = e_ews_folder_new_from_soap_parameter (node);
+
+				if (folder)
+					async_data->items = g_slist_prepend (NULL, folder);
+			}
+
+			break;
+		}
+
+		subparam = e_soap_parameter_get_next_child (subparam);
+	}
+}
+
+void
+e_ews_connection_get_folder_info (EEwsConnection *cnc,
+				  gint pri,
+				  const gchar *mail_id,
+				  const EwsFolderId *folder_id,
+				  GCancellable *cancellable,
+				  GAsyncReadyCallback callback,
+				  gpointer user_data)
+{
+	ESoapMessage *msg;
+	GSimpleAsyncResult *simple;
+	EwsAsyncData *async_data;
+	GSList *folder_ids;
+
+	g_return_if_fail (cnc != NULL);
+	g_return_if_fail (folder_id != NULL);
+
+	msg = e_ews_message_new_with_header (cnc->priv->uri, "GetFolder", NULL, NULL, 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_start_element (msg, "AdditionalProperties", NULL, NULL);
+	e_ews_message_write_string_parameter_with_attribute (msg, "FieldURI", NULL, NULL, "FieldURI", "folder:FolderClass");
+	e_ews_message_write_string_parameter_with_attribute (msg, "FieldURI", NULL, NULL, "FieldURI", "folder:ParentFolderId");
+	e_soap_message_end_element (msg); /* AdditionalProperties */
+	e_soap_message_end_element (msg); /* FolderShape */
+
+	folder_ids = g_slist_append (NULL, (gpointer) folder_id);
+	e_soap_message_start_element (msg, "FolderIds", "messages", NULL);
+	ews_append_folder_ids_to_msg (msg, mail_id, folder_ids);
+	e_soap_message_end_element (msg);
+	g_slist_free (folder_ids);
+
+	e_ews_message_write_footer (msg);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (cnc), callback, user_data,
+		e_ews_connection_get_folder_info);
+
+	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, get_folder_info_response_cb,
+		pri, cancellable, simple);
+
+	g_object_unref (simple);
+}
+
+gboolean
+e_ews_connection_get_folder_info_finish (EEwsConnection *cnc,
+					 GAsyncResult *result,
+					 EEwsFolder **folder,
+					 GError **error)
+{
+	GSimpleAsyncResult *simple;
+	EwsAsyncData *async_data;
+
+	g_return_val_if_fail (cnc != NULL, FALSE);
+	g_return_val_if_fail (folder != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (cnc), e_ews_connection_get_folder_info),
+		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;
+
+	if (!async_data->items)
+		return FALSE;
+
+	*folder = async_data->items ? async_data->items->data : NULL;
+
+	g_slist_free (async_data->items);
+	async_data->items = NULL;
+
+	return TRUE;
+}
+
+gboolean
+e_ews_connection_get_folder_info_sync (EEwsConnection *cnc,
+				       gint pri,
+				       const gchar *mail_id,
+				       const EwsFolderId *folder_id,
+				       EEwsFolder **folder,
+				       GCancellable *cancellable,
+				       GError **error)
+{
+	EAsyncClosure *closure;
+	GAsyncResult *result;
+	gboolean success;
+
+	g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (folder_id != NULL, FALSE);
+	g_return_val_if_fail (folder != NULL, FALSE);
+
+	closure = e_async_closure_new ();
+
+	e_ews_connection_get_folder_info (
+		cnc, pri, mail_id, folder_id, cancellable,
+		e_async_closure_callback, closure);
+
+	result = e_async_closure_wait (closure);
+
+	success = e_ews_connection_get_folder_info_finish (
+		cnc, result, folder, 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 269f710..923bd30 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -931,6 +931,28 @@ gboolean	e_ews_connection_get_password_expiration_sync
 						 GCancellable *cancellable,
 						 GError **error);
 
+void		e_ews_connection_get_folder_info
+						(EEwsConnection *cnc,
+						 gint pri,
+						 const gchar *mail_id,
+						 const EwsFolderId *folder_id,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_ews_connection_get_folder_info_finish
+						(EEwsConnection *cnc,
+						 GAsyncResult *result,
+						 EEwsFolder **folder,
+						 GError **error);
+gboolean	e_ews_connection_get_folder_info_sync
+						(EEwsConnection *cnc,
+						 gint pri,
+						 const gchar *mail_id,
+						 const EwsFolderId *folder_id,
+						 EEwsFolder **folder,
+						 GCancellable *cancellable,
+						 GError **error);
+
 G_END_DECLS
 
 #endif
diff --git a/src/server/e-ews-folder.c b/src/server/e-ews-folder.c
index 7872549..77440d3 100644
--- a/src/server/e-ews-folder.c
+++ b/src/server/e-ews-folder.c
@@ -23,9 +23,14 @@
 #include <config.h>
 #endif
 #include <string.h>
+#include <glib/gi18n-lib.h>
+
 #include "e-ews-folder.h"
 #include "e-ews-message.h"
 #include "e-ews-enumtypes.h"
+#include "ews-errors.h"
+#include "e-source-ews-folder.h"
+#include "camel-ews-settings.h"
 
 G_DEFINE_TYPE (EEwsFolder, e_ews_folder, G_TYPE_OBJECT)
 
@@ -38,6 +43,7 @@ struct _EEwsFolderPrivate {
 	guint32 unread;
 	guint32 total;
 	guint32 child_count;
+	gboolean foreign;
 };
 
 static GObjectClass *parent_class = NULL;
@@ -110,6 +116,7 @@ e_ews_folder_init (EEwsFolder *folder)
 	folder->priv = priv;
 
 	priv->folder_type = E_EWS_FOLDER_TYPE_MAILBOX;
+	priv->foreign = FALSE;
 }
 
 /* FIXME pick it from folder_type and make it set folder_type */
@@ -372,7 +379,6 @@ e_ews_folder_get_unread_count (EEwsFolder *folder)
 	g_return_val_if_fail (E_IS_EWS_FOLDER (folder), -1);
 
 	return folder->priv->unread;
-
 }
 
 guint32
@@ -381,5 +387,367 @@ e_ews_folder_get_child_count (EEwsFolder *folder)
 	g_return_val_if_fail (E_IS_EWS_FOLDER (folder), -1);
 
 	return folder->priv->child_count;
+}
+
+gboolean
+e_ews_folder_get_foreign (EEwsFolder *folder)
+{
+	g_return_val_if_fail (E_IS_EWS_FOLDER (folder), FALSE);
+
+	return folder->priv->foreign;
+}
+
+void
+e_ews_folder_set_foreign (EEwsFolder *folder,
+			  gboolean is_foreign)
+{
+	g_return_if_fail (E_IS_EWS_FOLDER (folder));
+
+	folder->priv->foreign = is_foreign;
+}
+
+gchar *
+e_ews_folder_utils_pick_color_spec (gint move_by,
+				    gboolean around_middle)
+{
+	static gint color_mover = 0;
+	static gint color_indexer = -1;
+	const guint32 colors[] = {
+		0x1464ae, /* dark blue */
+		0x14ae64, /* dark green */
+		0xae1464, /* dark red */
+		0
+	};
+	guint32 color;
+
+	if (move_by <= 0)
+		move_by = 1;
+
+	while (move_by > 0) {
+		move_by--;
+
+		color_indexer++;
+		if (colors[color_indexer] == 0) {
+			color_mover += 1;
+			color_indexer = 0;
+		}
+	}
+
+	color = colors[color_indexer];
+	color = (color & ~(0xFF << (color_indexer * 8))) |
+		(((((color >> (color_indexer * 8)) & 0xFF) + (0x33 * color_mover)) % 0xFF) << (color_indexer * 8));
+
+	if (around_middle) {
+		gint rr, gg, bb, diff;
+
+		rr = (0xFF0000 & color) >> 16;
+		gg = (0x00FF00 & color) >>  8;
+		bb = (0x0000FF & color);
+
+		diff = 0x80 - rr;
+		if (diff < 0x80 - gg)
+			diff = 0x80 - gg;
+		if (diff < 0x80 - bb)
+			diff = 0x80 - bb;
+
+		rr = rr + diff < 0 ? 0 : rr + diff > 0xCC ? 0xCC : rr + diff;
+		gg = gg + diff < 0 ? 0 : gg + diff > 0xCC ? 0xCC : gg + diff;
+		bb = bb + diff < 0 ? 0 : bb + diff > 0xCC ? 0xCC : bb + diff;
+
+		color = (rr << 16) + (gg << 8) + bb;
+	}
+
+	return g_strdup_printf ("#%06x", color);
+}
+
+gboolean
+e_ews_folder_utils_populate_esource (ESource *source,
+				     const GList *sources,
+				     const gchar *master_hosturl,
+				     const gchar *master_username,
+				     EEwsFolder *folder,
+				     gboolean offline_sync,
+				     gint color_seed,
+				     GCancellable *cancellable,
+				     GError **perror)
+{
+	ESource *master_source;
+	gboolean res = FALSE;
+
+	master_source = e_ews_folder_utils_get_master_source (sources, master_hosturl, master_username);
+
+	if (master_source) {
+		ESourceBackend *backend_ext;
+		EEwsFolderType folder_type;
+		const EwsFolderId *folder_id = e_ews_folder_get_id (folder);
+
+		g_return_val_if_fail (folder_id != NULL, FALSE);
+
+		folder_type = e_ews_folder_get_folder_type (folder);
+
+		e_source_set_parent (source, e_source_get_uid (master_source));
+		e_source_set_display_name (source, e_ews_folder_get_name (folder));
+
+		switch (folder_type) {
+			case E_EWS_FOLDER_TYPE_CALENDAR:
+				backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR);
+				break;
+			/*case E_EWS_FOLDER_TYPE_JOURNAL:
+			case E_EWS_FOLDER_TYPE_MEMO:
+				backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MEMO_LIST);
+				break;*/
+			case E_EWS_FOLDER_TYPE_TASKS:
+				backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_TASK_LIST);
+				break;
+			case E_EWS_FOLDER_TYPE_CONTACTS:
+				backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK);
+				break;
+			default:
+				backend_ext = NULL;
+				break;
+		}
+
+		if (backend_ext) {
+			ESourceEwsFolder *folder_ext;
+			ESourceOffline *offline_ext;
+
+			e_source_backend_set_backend_name (backend_ext , "ews");
+
+			folder_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
+			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));
+
+			offline_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_OFFLINE);
+			e_source_offline_set_stay_synchronized (offline_ext, offline_sync);
+
+			/* set also color for calendar-like sources */
+			if (folder_type != E_EWS_FOLDER_TYPE_CONTACTS) {
+				gchar *color_str;
+
+				color_str = e_ews_folder_utils_pick_color_spec (1 + g_list_length ((GList *) sources),
+					folder_type != E_EWS_FOLDER_TYPE_CALENDAR);
+				e_source_selectable_set_color (E_SOURCE_SELECTABLE (backend_ext), color_str);
+				g_free (color_str);
+			}
+
+			res = TRUE;
+		} else {
+			g_propagate_error (perror, g_error_new_literal (EWS_CONNECTION_ERROR,
+				EWS_CONNECTION_ERROR_NORESPONSE, _("Cannot add folder, unsupported folder type")));
+		}
+	} else {
+		g_propagate_error (perror, g_error_new_literal (EWS_CONNECTION_ERROR,
+			EWS_CONNECTION_ERROR_NORESPONSE, _("Cannot add folder, master source not found")));
+	}
+
+	return res;
+}
+
+gboolean
+e_ews_folder_utils_add_as_esource (ESourceRegistry *pregistry,
+				   const gchar *master_hosturl,
+				   const gchar *master_username,
+				   EEwsFolder *folder,
+				   gboolean offline_sync,
+				   gint color_seed,
+				   GCancellable *cancellable,
+				   GError **perror)
+{
+	ESourceRegistry *registry;
+	GList *sources;
+	ESource *source, *old_source;
+	const EwsFolderId *fid;
+	gboolean res = FALSE;
+
+	registry = pregistry;
+	if (!registry) {
+		registry = e_source_registry_new_sync (cancellable, perror);
+		if (!registry)
+			return FALSE;
+	}
+
+	sources = e_source_registry_list_sources (registry, NULL);
+	source = e_source_new (NULL, NULL, NULL);
+	fid = e_ews_folder_get_id (folder);
+
+	old_source = e_ews_folder_utils_get_source_for_folder (sources, master_hosturl, master_username, fid->id);
+	if (old_source) {
+		res = FALSE;
+
+		g_propagate_error (perror,
+			g_error_new (EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDEREXISTS,
+			_("Cannot add folder, folder already exists as '%s'"), e_source_get_display_name (old_source)));
+	} else if (e_ews_folder_utils_populate_esource (
+		source,
+		sources,
+		master_hosturl,
+		master_username,
+		folder,
+		offline_sync,
+		color_seed,
+		cancellable,
+		perror)) {
+		res = e_source_registry_commit_source_sync (registry, source, cancellable, perror);
+	}
+	g_object_unref (source);
+
+	g_list_free_full (sources, g_object_unref);
+	if (!pregistry)
+		g_object_unref (registry);
+
+	return res;
+}
+
+gboolean
+e_ews_folder_utils_remove_as_esource (ESourceRegistry *pregistry,
+				      const gchar *master_hosturl,
+				      const gchar *master_username,
+				      const gchar *folder_id,
+				      GCancellable *cancellable,
+				      GError **perror)
+{
+	ESourceRegistry *registry;
+	ESource *source;
+	GList *sources;
+	gboolean res = TRUE;
+
+	registry = pregistry;
+	if (!registry) {
+		registry = e_source_registry_new_sync (cancellable, perror);
+		if (!registry)
+			return FALSE;
+	}
+
+	sources = e_source_registry_list_sources (registry, NULL);
+	source = e_ews_folder_utils_get_source_for_folder (sources, master_hosturl, master_username, folder_id);
+
+	if (source)
+		res = e_source_remove_sync (source, cancellable, perror);
+
+	g_list_free_full (sources, g_object_unref);
+	if (!pregistry)
+		g_object_unref (registry);
+
+	return res;
+}
+
+gboolean
+e_ews_folder_utils_is_subscribed_as_esource (const GList *esources,
+					     const gchar *master_hosturl,
+					     const gchar *master_username,
+					     const gchar *folder_id)
+{
+	return e_ews_folder_utils_get_source_for_folder (esources, master_hosturl, master_username, folder_id) != NULL;
+}
+
+static gboolean
+is_for_account (ESource *source,
+		const gchar *master_hosturl,
+		const gchar *master_username)
+{
+	ESourceCamel *camel_extension;
+	ESourceAuthentication *auth_extension;
+	CamelEwsSettings *settings;
+	const gchar *extension_name;
+
+	if (!source)
+		return FALSE;
+
+	if (!master_hosturl && !master_username)
+		return TRUE;
+
+	extension_name = e_source_camel_get_extension_name ("ews");
+	if (!e_source_has_extension (source, extension_name))
+		return FALSE;
+
+	camel_extension = e_source_get_extension (source, extension_name);
+	settings = CAMEL_EWS_SETTINGS (e_source_camel_get_settings (camel_extension));
+
+	if (!settings || g_strcmp0 (camel_ews_settings_get_hosturl (settings), master_hosturl) != 0)
+		return FALSE;
+
+	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+	if (!e_source_has_extension (source, extension_name))
+		return FALSE;
+
+	auth_extension = e_source_get_extension (source, extension_name);
+	return g_strcmp0 (e_source_authentication_get_user (auth_extension), master_username) == 0;
+}
+
+/* filters @esources thus the resulting list will contain ESource-s only for @profile;
+   free returned list with g_list_free_full (list, g_object_unref); */
+GList *
+e_ews_folder_utils_filter_sources_for_account (const GList *esources,
+					       const gchar *master_hosturl,
+					       const gchar *master_username)
+{
+	GList *found = NULL;
+	const GList *iter;
+	ESource *master_source;
+
+	master_source = e_ews_folder_utils_get_master_source (esources, master_hosturl, master_username);
+	if (!master_source)
+		return NULL;
+
+	for (iter = esources; iter; iter = iter->next) {
+		ESource *source = iter->data;
+
+		if (is_for_account (source, master_hosturl, master_username) ||
+		    g_strcmp0 (e_source_get_uid (master_source), e_source_get_parent (source)) == 0)
+			found = g_list_prepend (found, g_object_ref (source));
+	}
+
+	return g_list_reverse (found);
+}
+
+/* returns (not-reffed) member of @esources, which is for @profile and @folder_id */
+ESource *
+e_ews_folder_utils_get_source_for_folder (const GList *esources,
+					  const gchar *master_hosturl,
+					  const gchar *master_username,
+					  const gchar *folder_id)
+{
+	ESource *master_source;
+	const GList *iter;
+	
+	master_source = e_ews_folder_utils_get_master_source (esources, master_hosturl, master_username);
+	if (!master_source)
+		return NULL;
+
+	for (iter = esources; iter; iter = iter->next) {
+		ESource *source = iter->data;
+
+		if ((is_for_account (source, master_hosturl, master_username) ||
+		    g_strcmp0 (e_source_get_uid (master_source), e_source_get_parent (source)) == 0) &&
+		    e_source_has_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER)) {
+			ESourceEwsFolder *folder_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
+
+			g_return_val_if_fail (folder_ext != NULL, NULL);
+
+			if (g_strcmp0 (e_source_ews_folder_get_id (folder_ext), folder_id) == 0)
+				return source;
+		}
+	}
+
+	return NULL;
+}
+
+/* returns (not-reffed) member of @esources, which is master (with no parent) source for @profile */
+ESource *
+e_ews_folder_utils_get_master_source (const GList *esources,
+				      const gchar *master_hosturl,
+				      const gchar *master_username)
+{
+	const GList *iter;
+
+	for (iter = esources; iter; iter = iter->next) {
+		ESource *source = iter->data;
+
+		if (!e_source_get_parent (source) &&
+		    is_for_account (source, master_hosturl, master_username))
+			return source;
+	}
 
+	return NULL;
 }
diff --git a/src/server/e-ews-folder.h b/src/server/e-ews-folder.h
index a721e53..2cec0c4 100644
--- a/src/server/e-ews-folder.h
+++ b/src/server/e-ews-folder.h
@@ -22,6 +22,8 @@
 #ifndef E_EWS_FOLDER_H
 #define E_EWS_FOLDER_H
 
+#include <libedataserver/libedataserver.h>
+
 #include "e-ews-enums.h"
 #include "e-soap-message.h"
 
@@ -70,12 +72,54 @@ gboolean	e_ews_folder_get_is_writable (EEwsFolder *folder);
 void		e_ews_folder_set_is_writable (EEwsFolder *folder, gboolean writable);
 EEwsFolderType	e_ews_folder_get_folder_type (EEwsFolder *folder);
 void		e_ews_folder_set_folder_type (EEwsFolder *folder, EEwsFolderType folder_type);
+gboolean	e_ews_folder_get_foreign (EEwsFolder *folder);
+void		e_ews_folder_set_foreign (EEwsFolder *folder, gboolean is_foreign);
 
 EwsFolderId *	e_ews_folder_id_new (const gchar *id,
 				     const gchar *change_key,
 				     gboolean is_distinguished_id);
 void		e_ews_folder_id_free (EwsFolderId *fid);
 
+gchar *		e_ews_folder_utils_pick_color_spec		(gint move_by,
+								 gboolean around_middle);
+gboolean	e_ews_folder_utils_populate_esource		(ESource *source,
+								 const GList *sources,
+								 const gchar *master_hosturl,
+								 const gchar *master_username,
+								 EEwsFolder *folder,
+								 gboolean offline_sync,
+								 gint color_seed,
+								 GCancellable *cancellable,
+								 GError **perror);
+gboolean	e_ews_folder_utils_add_as_esource		(ESourceRegistry *pregistry,
+								 const gchar *master_hosturl,
+								 const gchar *master_username,
+								 EEwsFolder *folder,
+								 gboolean offline_sync,
+								 gint color_seed,
+								 GCancellable *cancellable,
+								 GError **perror);
+gboolean	e_ews_folder_utils_remove_as_esource		(ESourceRegistry *pregistry,
+								 const gchar *master_hosturl,
+								 const gchar *master_username,
+								 const gchar *folder_id,
+								 GCancellable *cancellable,
+								 GError **perror);
+gboolean	e_ews_folder_utils_is_subscribed_as_esource	(const GList *esources,
+								 const gchar *master_hosturl,
+								 const gchar *master_username,
+								 const gchar *folder_id);
+GList *		e_ews_folder_utils_filter_sources_for_account	(const GList *esources,
+								 const gchar *master_hosturl,
+								 const gchar *master_username);
+ESource *	e_ews_folder_utils_get_source_for_folder	(const GList *esources,
+								 const gchar *master_hosturl,
+								 const gchar *master_username,
+								 const gchar *folder_id);
+ESource *	e_ews_folder_utils_get_master_source		(const GList *esources,
+								 const gchar *master_hosturl,
+								 const gchar *master_username);
+
 G_END_DECLS
 
 #endif
diff --git a/src/server/e-source-ews-folder.c b/src/server/e-source-ews-folder.c
index dcdc6b5..eef7306 100644
--- a/src/server/e-source-ews-folder.c
+++ b/src/server/e-source-ews-folder.c
@@ -26,12 +26,14 @@ struct _ESourceEwsFolderPrivate {
 	GMutex *property_lock;
 	gchar *change_key;
 	gchar *id;
+	gboolean foreign;
 };
 
 enum {
 	PROP_0,
 	PROP_CHANGE_KEY,
-	PROP_ID
+	PROP_ID,
+	PROP_FOREIGN
 };
 
 G_DEFINE_DYNAMIC_TYPE (
@@ -57,6 +59,12 @@ source_ews_folder_set_property (GObject *object,
 				E_SOURCE_EWS_FOLDER (object),
 				g_value_get_string (value));
 			return;
+
+		case PROP_FOREIGN:
+			e_source_ews_folder_set_foreign (
+				E_SOURCE_EWS_FOLDER (object),
+				g_value_get_boolean (value));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -82,6 +90,13 @@ source_ews_folder_get_property (GObject *object,
 				e_source_ews_folder_dup_id (
 				E_SOURCE_EWS_FOLDER (object)));
 			return;
+
+		case PROP_FOREIGN:
+			g_value_set_boolean (
+				value,
+				e_source_ews_folder_get_foreign (
+				E_SOURCE_EWS_FOLDER (object)));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -145,6 +160,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,
+		g_param_spec_boolean (
+			"foreign",
+			"Foreign",
+			"The folder is a foreign folder, aka belongs to other user",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
 }
 
 static void
@@ -278,3 +306,25 @@ e_source_ews_folder_dup_folder_id (ESourceEwsFolder *extension)
 
 	return folder_id;
 }
+
+gboolean
+e_source_ews_folder_get_foreign (ESourceEwsFolder *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), FALSE);
+
+	return extension->priv->foreign;
+}
+
+void
+e_source_ews_folder_set_foreign (ESourceEwsFolder *extension,
+				 gboolean is_foreign)
+{
+	g_return_if_fail (E_IS_SOURCE_EWS_FOLDER (extension));
+
+	if ((extension->priv->foreign ? 1 : 0) == (is_foreign ? 1 : 0))
+		return;
+
+	extension->priv->foreign = is_foreign;
+
+	g_object_notify (G_OBJECT (extension), "foreign");
+}
diff --git a/src/server/e-source-ews-folder.h b/src/server/e-source-ews-folder.h
index f6202bd..e15b7a9 100644
--- a/src/server/e-source-ews-folder.h
+++ b/src/server/e-source-ews-folder.h
@@ -76,6 +76,10 @@ void		e_source_ews_folder_set_id	(ESourceEwsFolder *extension,
 EwsFolderId *	e_source_ews_folder_dup_folder_id
 						(ESourceEwsFolder *extension);
 
+gboolean	e_source_ews_folder_get_foreign	(ESourceEwsFolder *extension);
+void		e_source_ews_folder_set_foreign	(ESourceEwsFolder *extension,
+						 gboolean is_foreign);
+
 G_END_DECLS
 
 #endif /* E_SOURCE_EWS_FOLDER_H */



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