[evolution-ews] Bug #656377 - Support for public folders



commit 2a61b5b2b155d50a5a9b6bbee1d96bbbd5411675
Author: Milan Crha <mcrha redhat com>
Date:   Thu Jan 17 12:11:07 2013 +0100

    Bug #656377 - Support for public folders

 src/camel/camel-ews-folder.c                       |   22 +-
 src/camel/camel-ews-store-summary.c                |   45 ++-
 src/camel/camel-ews-store-summary.h                |   11 +-
 src/camel/camel-ews-store.c                        |  709 ++++++++++++++++++--
 src/camel/camel-ews-store.h                        |    2 +
 src/camel/camel-ews-utils.c                        |   42 +-
 src/collection/e-ews-backend.c                     |   21 +-
 src/configuration/e-ews-subscribe-foreign-folder.c |    9 +-
 src/server/e-ews-connection.c                      |    4 +
 src/server/e-ews-folder.c                          |   54 ++-
 src/server/e-ews-folder.h                          |   18 +-
 src/server/e-source-ews-folder.c                   |   52 ++-
 src/server/e-source-ews-folder.h                   |    3 +
 13 files changed, 896 insertions(+), 96 deletions(-)
---
diff --git a/src/camel/camel-ews-folder.c b/src/camel/camel-ews-folder.c
index 26489a2..0eeb54b 100644
--- a/src/camel/camel-ews-folder.c
+++ b/src/camel/camel-ews-folder.c
@@ -1003,6 +1003,7 @@ ews_synchronize_sync (CamelFolder *folder,
 	gint mi_list_len = 0;
 	gboolean success = TRUE;
 	gint i;
+	GError *local_error = NULL;
 
 	ews_store = (CamelEwsStore *) camel_folder_get_parent_store (folder);
 
@@ -1056,28 +1057,39 @@ ews_synchronize_sync (CamelFolder *folder,
 		}
 
 		if (mi_list_len == EWS_MAX_FETCH_COUNT) {
-			success = ews_sync_mi_flags (folder, mi_list, cancellable, error);
+			success = ews_sync_mi_flags (folder, mi_list, cancellable, &local_error);
 			mi_list = NULL;
 			mi_list_len = 0;
 		}
 	}
 
-	if (mi_list_len)
-		success = ews_sync_mi_flags (folder, mi_list, cancellable, error);
+	if (mi_list_len && success) {
+		success = ews_sync_mi_flags (folder, mi_list, cancellable, &local_error);
+		if (local_error && g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ACCESSDENIED)) {
+			/* if cannot save flags, then it can be a public or
+			   a foreign folder with no write access;
+			   the flags will be saved locally, at least */
+			g_clear_error (&local_error);
+			success = TRUE;
+		}			
+	}
 
 	if (deleted_uids && success)
-		success = ews_delete_messages (folder, deleted_uids, ews_folder_is_of_type (folder, CAMEL_FOLDER_TYPE_TRASH), cancellable, error);
+		success = ews_delete_messages (folder, deleted_uids, ews_folder_is_of_type (folder, CAMEL_FOLDER_TYPE_TRASH), cancellable, &local_error);
 	else
 		g_slist_free_full (deleted_uids, (GDestroyNotify) camel_pstring_free);
 
 	if (junk_uids && success)
-		success = ews_move_to_junk_folder (folder, junk_uids, cancellable, error);
+		success = ews_move_to_junk_folder (folder, junk_uids, cancellable, &local_error);
 	else
 		g_slist_free_full (junk_uids, (GDestroyNotify) camel_pstring_free);
 
 	camel_folder_summary_save_to_db (folder->summary, NULL);
 	camel_folder_summary_free_array (uids);
 
+	if (local_error)
+		g_propagate_error (error, local_error);
+
 	return success;
 }
 
diff --git a/src/camel/camel-ews-store-summary.c b/src/camel/camel-ews-store-summary.c
index 45549ef..f0c8edd 100644
--- a/src/camel/camel-ews-store-summary.c
+++ b/src/camel/camel-ews-store-summary.c
@@ -386,7 +386,8 @@ camel_ews_store_summary_new_folder (CamelEwsStoreSummary *ews_summary,
                                     EEwsFolderType folder_type,
                                     guint64 folder_flags,
                                     guint64 total,
-                                    gboolean foreign)
+                                    gboolean foreign,
+				    gboolean public_folder)
 {
 	const gchar *folder_type_nick;
 
@@ -410,15 +411,19 @@ camel_ews_store_summary_new_folder (CamelEwsStoreSummary *ews_summary,
 	g_key_file_set_string (
 		ews_summary->priv->key_file,
 		folder_id, "FolderType", folder_type_nick);
-	g_key_file_set_uint64 (
-		ews_summary->priv->key_file,
-		folder_id, "Flags", folder_flags);
+	if (folder_flags)
+		g_key_file_set_uint64 (
+			ews_summary->priv->key_file,
+			folder_id, "Flags", folder_flags);
 	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);
+	g_key_file_set_boolean (
+		ews_summary->priv->key_file,
+		folder_id, "Public", public_folder);
 
 	ews_ss_hash_replace (ews_summary, g_strdup (folder_id), NULL, FALSE);
 
@@ -577,6 +582,21 @@ camel_ews_store_summary_set_foreign_subfolders (CamelEwsStoreSummary *ews_summar
 }
 
 void
+camel_ews_store_summary_set_public (CamelEwsStoreSummary *ews_summary,
+                                    const gchar *folder_id,
+                                    gboolean is_public)
+{
+	S_LOCK (ews_summary);
+
+	g_key_file_set_boolean (
+		ews_summary->priv->key_file,
+		folder_id, "Public", is_public);
+	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)
@@ -797,6 +817,23 @@ camel_ews_store_summary_get_foreign_subfolders (CamelEwsStoreSummary *ews_summar
 	return ret;
 }
 
+gboolean
+camel_ews_store_summary_get_public (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, "Public", 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 a1231dc..54770fb 100644
--- a/src/camel/camel-ews-store-summary.h
+++ b/src/camel/camel-ews-store-summary.h
@@ -97,6 +97,10 @@ void		camel_ews_store_summary_set_foreign_subfolders
 						(CamelEwsStoreSummary *ews_summary,
 						 const gchar *folder_id,
 						 gboolean foreign_subfolders);
+void		camel_ews_store_summary_set_public
+						(CamelEwsStoreSummary *ews_summary,
+						 const gchar *folder_id,
+						 gboolean is_public);
 
 gchar *	camel_ews_store_summary_get_folder_name
 						(CamelEwsStoreSummary *ews_summary,
@@ -142,6 +146,10 @@ gboolean	camel_ews_store_summary_get_foreign_subfolders
 						(CamelEwsStoreSummary *ews_summary,
 						 const gchar *folder_id,
 						 GError **error);
+gboolean	camel_ews_store_summary_get_public
+						(CamelEwsStoreSummary *ews_summary,
+						 const gchar *folder_id,
+						 GError **error);
 
 GSList *	camel_ews_store_summary_get_folders
 						(CamelEwsStoreSummary *ews_summary,
@@ -174,7 +182,8 @@ void		camel_ews_store_summary_new_folder
 						 EEwsFolderType folder_type,
 						 guint64 folder_flags,
 						 guint64 total,
-						 gboolean foreign);
+						 gboolean foreign,
+						 gboolean public_folder);
 
 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 f05eb84..67f97f3 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -39,6 +39,7 @@
 #include <glib/gstdio.h>
 
 #include <libemail-engine/e-mail-folder-utils.h>
+#include <libemail-engine/e-mail-session.h>
 
 #include "server/camel-ews-settings.h"
 #include "server/e-ews-item-change.h"
@@ -68,6 +69,7 @@ struct _CamelEwsStorePrivate {
 	GMutex get_finfo_lock;
 	EEwsConnection *connection;
 	GMutex connection_lock;
+	GSList *public_folders; /* EEwsFolder * objects */
 };
 
 static gboolean	ews_store_construct	(CamelService *service, CamelSession *session,
@@ -200,10 +202,42 @@ ews_store_construct (CamelService *service,
 	return TRUE;
 }
 
+/* returns NULL when it's safe to use the default "Public Folders" name; otherwise g_free() it */
+static gchar *
+ews_store_get_public_folders_name (CamelEwsStore *ews_store)
+{
+	gchar *use_name = NULL;
+	gchar *tmp_fid;
+	gint counter = 0;
+
+	tmp_fid = camel_ews_store_summary_get_folder_id_from_name (
+		ews_store->summary, EWS_PUBLIC_FOLDER_ROOT_DISPLAY_NAME);
+	while (tmp_fid) {
+		counter++;
+
+		g_free (tmp_fid);
+		g_free (use_name);
+
+		/* Translators: This composes a "Public Folders" folder name for case when
+		 * user has such in his store already. The %s is replaced with "Public Folders",
+		 * the %d with counter, thus it composes name like "Public Folders_1"
+		*/
+		use_name = g_strdup_printf (
+			C_("PublicFolders", "%s_%d"),
+			EWS_PUBLIC_FOLDER_ROOT_DISPLAY_NAME, counter);
+
+		tmp_fid = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, use_name);
+	}
+
+	return use_name;
+}
+
 void
 camel_ews_store_ensure_virtual_folders (CamelEwsStore *ews_store)
 {
 	gboolean needs_foreign = FALSE, has_foreign = FALSE;
+	gboolean needs_public = FALSE, has_public = FALSE;
+	CamelFolderInfo *fi;
 	GSList *folders, *iter;
 	GHashTable *children_count;
 	GHashTableIter tab_iter;
@@ -228,6 +262,10 @@ camel_ews_store_ensure_virtual_folders (CamelEwsStore *ews_store)
 		    !g_hash_table_contains (children_count, fid))
 			g_hash_table_insert (children_count, (gpointer) fid, GINT_TO_POINTER (0));
 
+		if (g_str_equal (fid, EWS_PUBLIC_FOLDER_ROOT_ID) &&
+		    !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) {
@@ -244,6 +282,32 @@ camel_ews_store_ensure_virtual_folders (CamelEwsStore *ews_store)
 		}
 
 		g_clear_error (&error);
+
+		if (!has_public && g_str_equal (fid, EWS_PUBLIC_FOLDER_ROOT_ID))
+			has_public = TRUE;
+		else if (camel_ews_store_summary_get_public (ews_store->summary, fid, &error) && !error) {
+			EEwsFolderType ftype;
+			gchar *pfid;
+
+			ftype = camel_ews_store_summary_get_folder_type (ews_store->summary, fid, &error);
+			if (ftype == E_EWS_FOLDER_TYPE_MAILBOX && !error) {
+				guint64 fflags;
+
+				fflags = camel_ews_store_summary_get_folder_flags (ews_store->summary, fid, &error);
+				if ((fflags & CAMEL_FOLDER_SUBSCRIBED) != 0 && !error) {
+					needs_public = TRUE;
+
+					pfid = camel_ews_store_summary_get_parent_folder_id (ews_store->summary, fid, NULL);
+					if (pfid && g_str_equal (pfid, EWS_PUBLIC_FOLDER_ROOT_ID)) {
+						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);
 	}
 
 	g_hash_table_iter_init (&tab_iter, children_count);
@@ -253,6 +317,12 @@ camel_ews_store_ensure_virtual_folders (CamelEwsStore *ews_store)
 		if (!count) {
 			CamelFolderInfo *fi;
 
+			if (has_foreign && g_str_equal (key, EWS_FOREIGN_FOLDER_ROOT_ID))
+				has_foreign = FALSE;
+
+			if (has_public && g_str_equal (key, EWS_PUBLIC_FOLDER_ROOT_ID))
+				has_public = FALSE;
+
 			fi = camel_ews_utils_build_folder_info (ews_store, key);
 			camel_ews_store_summary_remove_folder (ews_store->summary, key, NULL);
 
@@ -294,9 +364,14 @@ camel_ews_store_ensure_virtual_folders (CamelEwsStore *ews_store)
 			use_name ? use_name : EWS_FOREIGN_FOLDER_ROOT_DISPLAY_NAME,
 			E_EWS_FOLDER_TYPE_MAILBOX,
 			CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOSELECT,
-			0, FALSE);
+			0, FALSE, FALSE);
 
 		g_free (use_name);
+
+		fi = camel_ews_utils_build_folder_info (ews_store, EWS_FOREIGN_FOLDER_ROOT_ID);
+		camel_store_folder_created (CAMEL_STORE (ews_store), fi);
+		camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
+		camel_folder_info_free (fi);
 	} else if (has_foreign && !needs_foreign) {
 		CamelFolderInfo *fi;
 
@@ -308,6 +383,36 @@ camel_ews_store_ensure_virtual_folders (CamelEwsStore *ews_store)
 		camel_folder_info_free (fi);
 	}
 
+	if (needs_public && !has_public) {
+		gchar *use_name;
+
+		use_name = ews_store_get_public_folders_name (ews_store);
+
+		camel_ews_store_summary_new_folder (
+			ews_store->summary,
+			EWS_PUBLIC_FOLDER_ROOT_ID, NULL, NULL,
+			use_name ? use_name : EWS_PUBLIC_FOLDER_ROOT_DISPLAY_NAME,
+			E_EWS_FOLDER_TYPE_MAILBOX,
+			CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOSELECT,
+			0, FALSE, FALSE);
+
+		g_free (use_name);
+
+		fi = camel_ews_utils_build_folder_info (ews_store, EWS_PUBLIC_FOLDER_ROOT_ID);
+		camel_store_folder_created (CAMEL_STORE (ews_store), fi);
+		camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
+		camel_folder_info_free (fi);
+	} else if (has_public && !needs_public) {
+		CamelFolderInfo *fi;
+
+		fi = camel_ews_utils_build_folder_info (ews_store, EWS_PUBLIC_FOLDER_ROOT_ID);
+		camel_ews_store_summary_remove_folder (ews_store->summary, EWS_PUBLIC_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);
+	}
+
 	camel_ews_store_summary_rebuild_hashes (ews_store->summary);
 	camel_ews_store_summary_save (ews_store->summary, NULL);
 
@@ -641,7 +746,7 @@ ews_store_update_foreign_subfolders (CamelSession *session,
 						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);
+						CAMEL_FOLDER_SUBSCRIBED, e_ews_folder_get_total_count (folder), TRUE, FALSE);
 
 					fi = camel_ews_utils_build_folder_info (ews_store, folder_id->id);
 					camel_store_folder_created (CAMEL_STORE (ews_store), fi);
@@ -1068,42 +1173,198 @@ ews_get_folder_sync (CamelStore *store,
 	return folder;
 }
 
+static gchar *
+get_public_folder_full_name (EEwsFolder *folder,
+			     GHashTable *folders_by_id)
+{
+	const EwsFolderId *parent_fid;
+	GString *full_name;
+
+	g_return_val_if_fail (folder != NULL, NULL);
+	g_return_val_if_fail (folders_by_id != NULL, NULL);
+
+	full_name = g_string_new (e_ews_folder_get_name (folder));
+	while (folder) {
+		parent_fid = e_ews_folder_get_parent_id (folder);
+		if (!parent_fid || !parent_fid->id)
+			break;
+
+		folder = g_hash_table_lookup (folders_by_id, parent_fid->id);
+		if (folder) {
+			g_string_prepend (full_name, "/");
+			g_string_prepend (full_name, e_ews_folder_get_name (folder));
+		}
+	}
+
+	g_string_prepend (full_name, "/");
+	g_string_prepend (full_name, EWS_PUBLIC_FOLDER_ROOT_DISPLAY_NAME);
+
+	return g_string_free (full_name, FALSE);
+}
+
 static CamelFolderInfo *
 folder_info_from_store_summary (CamelEwsStore *store,
                                 const gchar *top,
                                 guint32 flags,
+				GCancellable *cancellable,
                                 GError **error)
 {
 	CamelEwsStoreSummary *ews_summary;
-	GSList *folders, *l;
-	GPtrArray *folder_infos;
-	CamelFolderInfo *root_fi = NULL;
+	GPtrArray *folder_infos = NULL;
+	CamelFolderInfo *root_fi = NULL, *fi;
 
-	ews_summary = store->summary;
-	folders = camel_ews_store_summary_get_folders (ews_summary, top);
+	/* search in public folders */
+	if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0) {
+		GHashTable *folders_by_id;
+		GSList *fiter;
+		GList *esources = NULL;
+		gchar *hosturl = NULL, *username = NULL;
 
-	if (!folders)
-		return NULL;
+		g_mutex_lock (&store->priv->get_finfo_lock);
 
-	folder_infos = g_ptr_array_new ();
+		if (!store->priv->public_folders) {
+			g_mutex_unlock (&store->priv->get_finfo_lock);
+			return NULL;
+		}
 
-	for (l = folders; l != NULL; l = g_slist_next (l)) {
-		CamelFolderInfo *fi;
-		EEwsFolderType ftype;
+		folder_infos = g_ptr_array_new ();
+		folders_by_id = g_hash_table_new (g_str_hash, g_str_equal);
 
-		ftype = camel_ews_store_summary_get_folder_type (ews_summary, l->data, NULL);
-		if (ftype != E_EWS_FOLDER_TYPE_MAILBOX)
-			continue;
+		for (fiter = store->priv->public_folders; fiter != NULL; fiter = g_slist_next (fiter)) {
+			EEwsFolder *folder = fiter->data;
+			const EwsFolderId *fid;
+
+			if (!folder)
+				continue;
+
+			fid = e_ews_folder_get_id (folder);
+			if (!fid || !fid->id)
+				continue;
+
+			g_hash_table_insert (folders_by_id, fid->id, folder);
+		}
+
+		fi = camel_folder_info_new ();
+		fi->full_name = g_strdup (EWS_PUBLIC_FOLDER_ROOT_DISPLAY_NAME);
+		fi->display_name = g_strdup (fi->full_name);
+		fi->flags = CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOSELECT;
+		fi->unread = 0;
+		fi->total = 0;
 
-		fi = camel_ews_utils_build_folder_info (store, l->data);
 		g_ptr_array_add (folder_infos, fi);
+
+		for (fiter = store->priv->public_folders; fiter != NULL; fiter = g_slist_next (fiter)) {
+			EEwsFolder *folder = fiter->data;
+			const EwsFolderId *fid;
+
+			if (!folder)
+				continue;
+
+			fid = e_ews_folder_get_id (folder);
+			if (!fid || !fid->id)
+				continue;
+
+			fi = camel_folder_info_new ();
+			fi->full_name = get_public_folder_full_name (folder, folders_by_id);
+			fi->display_name = g_strdup (e_ews_folder_get_name (folder));
+			fi->flags = 0;
+			fi->unread = 0;
+			fi->total = 0;
+
+			switch (e_ews_folder_get_folder_type (folder)) {
+			case E_EWS_FOLDER_TYPE_CALENDAR:
+				fi->flags |= CAMEL_FOLDER_TYPE_EVENTS;
+				break;
+			case E_EWS_FOLDER_TYPE_CONTACTS:
+				fi->flags |= CAMEL_FOLDER_TYPE_CONTACTS;
+				break;
+			case E_EWS_FOLDER_TYPE_TASKS:
+				fi->flags |= CAMEL_FOLDER_TYPE_TASKS;
+				break;
+			case E_EWS_FOLDER_TYPE_MEMOS:
+				fi->flags |= CAMEL_FOLDER_TYPE_MEMOS;
+				break;
+			default:
+				break;
+			}
+
+			if (camel_ews_store_summary_has_folder (store->summary, fid->id)) {
+				guint64 fflags = camel_ews_store_summary_get_folder_flags (store->summary, fid->id, NULL);
+
+				if ((fflags & CAMEL_FOLDER_SUBSCRIBED) != 0)
+					fi->flags |= CAMEL_FOLDER_SUBSCRIBED;
+			}
+
+			if (!(fi->flags & CAMEL_FOLDER_SUBSCRIBED) &&
+			    e_ews_folder_get_folder_type (folder) != E_EWS_FOLDER_TYPE_MAILBOX) {
+				if (!hosturl && !username && !esources) {
+					CamelSession *session;
+					CamelSettings *settings;
+					CamelEwsSettings *ews_settings;
+					ESourceRegistry *registry = NULL;
+
+					settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+					ews_settings = CAMEL_EWS_SETTINGS (settings);
+					session = camel_service_get_session (CAMEL_SERVICE (store));
+					if (E_IS_MAIL_SESSION (session))
+						registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
+
+					hosturl = camel_ews_settings_dup_hosturl (ews_settings);
+					username = camel_network_settings_dup_user (CAMEL_NETWORK_SETTINGS (ews_settings));
+					esources = e_ews_folder_utils_get_esources (registry, hosturl, username, cancellable, NULL);
+
+					g_object_unref (settings);
+				}
+
+				if (e_ews_folder_utils_is_subscribed_as_esource (esources, hosturl, username, fid->id))
+					fi->flags |= CAMEL_FOLDER_SUBSCRIBED;
+			}
+
+			g_ptr_array_add (folder_infos, fi);
+		}
+
+		g_list_free_full (esources, g_object_unref);
+		g_hash_table_destroy (folders_by_id);
+		g_free (hosturl);
+		g_free (username);
+		g_mutex_unlock (&store->priv->get_finfo_lock);
+
+	/* search in regular/subscribed folders */
+	} else {
+		GSList *folders, *fiter;
+
+		ews_summary = store->summary;
+		folders = camel_ews_store_summary_get_folders (ews_summary, top);
+		if (!folders)
+			return NULL;
+
+		folder_infos = g_ptr_array_new ();
+
+		for (fiter = folders; fiter != NULL; fiter = g_slist_next (fiter)) {
+			EEwsFolderType ftype;
+			const gchar *fid = fiter->data;
+
+			ftype = camel_ews_store_summary_get_folder_type (ews_summary, fid, NULL);
+			if (ftype != E_EWS_FOLDER_TYPE_MAILBOX)
+				continue;
+
+			if (camel_ews_store_summary_get_public (ews_summary, fid, NULL)) {
+				guint64 fflags;
+
+				fflags = camel_ews_store_summary_get_folder_flags (ews_summary, fid, NULL);
+				if (!(fflags & CAMEL_FOLDER_SUBSCRIBED))
+					continue;
+			}
+
+			fi = camel_ews_utils_build_folder_info (store, fid);
+			g_ptr_array_add (folder_infos, fi);
+		}
+
+		g_slist_free_full (folders, g_free);
 	}
 
 	root_fi = camel_folder_info_build (folder_infos, top, '/', TRUE);
-
 	g_ptr_array_free (folder_infos, TRUE);
-	g_slist_foreach (folders, (GFunc) g_free, NULL);
-	g_slist_free (folders);
 
 	return root_fi;
 }
@@ -1197,18 +1458,97 @@ 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;
 
+	if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0) {
+		gboolean includes_last_folder = TRUE;
+		GSList *folders = NULL, *to_check = NULL;
+		EwsFolderId *folder_id;
+
+		if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) {
+			g_set_error_literal (
+				error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
+				_("Cannot list EWS public folders in offline mode"));
+			return NULL;
+		}
+
+		g_mutex_lock (&priv->get_finfo_lock);
+
+		g_slist_free_full (priv->public_folders, g_object_unref);
+		priv->public_folders = NULL;
+
+		connection = camel_ews_store_ref_connection (ews_store);
+		folder_id = e_ews_folder_id_new ("publicfoldersroot", NULL, TRUE);
+		to_check = g_slist_append (to_check, folder_id);
+
+		while (!local_error && !g_cancellable_is_cancelled (cancellable) && to_check) {
+			folder_id = to_check->data;
+			to_check = g_slist_remove (to_check, folder_id);
+
+			while (e_ews_connection_find_folder_sync (connection, EWS_PRIORITY_MEDIUM, folder_id, &includes_last_folder, &folders,
+				cancellable, &local_error) && !local_error &&
+				!g_cancellable_is_cancelled (cancellable)) {
+				GSList *fiter;
+
+				if (!folders)
+					break;
+
+				for (fiter = folders; fiter != NULL; fiter = fiter->next) {
+					EEwsFolder *folder = fiter->data;
+
+					if (e_ews_folder_get_child_count (folder) > 0) {
+						const EwsFolderId *fid = e_ews_folder_get_id (folder);
+
+						if (fid)
+							to_check = g_slist_prepend (to_check,
+								e_ews_folder_id_new (fid->id, fid->change_key, fid->is_distinguished_id));
+					}
+
+					if (!e_ews_folder_get_parent_id (folder)) {
+						if (!folder_id->is_distinguished_id) {
+							e_ews_folder_set_parent_id (folder,
+								e_ews_folder_id_new (folder_id->id, folder_id->change_key, folder_id->is_distinguished_id));
+						} else {
+							e_ews_folder_set_parent_id (folder, e_ews_folder_id_new (EWS_PUBLIC_FOLDER_ROOT_ID, NULL, FALSE));
+						}
+					}
+				}
+
+				priv->public_folders = g_slist_concat (priv->public_folders, folders);
+				folders = NULL;
+
+				if (includes_last_folder)
+					break;
+			}
+
+			e_ews_folder_id_free (folder_id);
+		}
+
+		g_mutex_unlock (&priv->get_finfo_lock);
+
+		g_object_unref (connection);
+		g_slist_free_full (to_check, (GDestroyNotify) e_ews_folder_id_free);
+
+		camel_ews_store_ensure_virtual_folders (ews_store);
+
+		if (local_error) {
+			camel_ews_store_maybe_disconnect (ews_store, local_error);
+			g_propagate_error (error, local_error);
+
+			return NULL;
+		}
+
+		if (!priv->public_folders) {
+			g_set_error_literal (
+				error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
+				_("Cannot find any EWS public folders"));
+			return NULL;
+		}
+
+		goto offline;
+	}
+
 	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))) {
@@ -1276,7 +1616,7 @@ ews_get_folder_info_sync (CamelStore *store,
 	g_mutex_unlock (&priv->get_finfo_lock);
 
 offline:
-	fi = folder_info_from_store_summary ( (CamelEwsStore *) store, top, flags, error);
+	fi = folder_info_from_store_summary (ews_store, top, flags, cancellable, error);
 	return fi;
 }
 
@@ -1336,6 +1676,16 @@ ews_create_folder_sync (CamelStore *store,
 				parent_name);
 			return NULL;
 		}
+
+		if (g_str_equal (fid, EWS_PUBLIC_FOLDER_ROOT_ID)) {
+			g_free (fid);
+
+			g_set_error (
+				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+				_("Cannot create folder under '%s', it is used for public folders only"),
+				parent_name);
+			return NULL;
+		}
 	}
 
 	if (!camel_ews_store_connected (ews_store, cancellable, error)) {
@@ -1371,7 +1721,7 @@ ews_create_folder_sync (CamelStore *store,
 		fid, folder_id->change_key,
 		folder_name,
 		E_EWS_FOLDER_TYPE_MAILBOX,
-		0, 0, FALSE);
+		0, 0, FALSE, FALSE);
 	fi = camel_ews_utils_build_folder_info (ews_store, folder_id->id);
 	e_ews_folder_id_free (folder_id);
 
@@ -1415,14 +1765,25 @@ ews_delete_folder_sync (CamelStore *store,
 		return FALSE;
 	}
 
+	if (g_str_equal (fid, EWS_PUBLIC_FOLDER_ROOT_ID)) {
+		g_free (fid);
+
+		g_set_error (
+			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+			_("Cannot remove folder '%s', it is used for public folders only"),
+			folder_name);
+		return FALSE;
+	}
+
 	if (!camel_ews_store_connected (ews_store, cancellable, error)) {
 		g_free (fid);
 		return FALSE;
 	}
 
-	if (camel_ews_store_summary_get_foreign (ews_store->summary, fid, NULL)) {
-		/* do not delete foreign folders,
-		 * just remove them from local store */
+	if (camel_ews_store_summary_get_foreign (ews_store->summary, fid, NULL) ||
+	    camel_ews_store_summary_get_public (ews_store->summary, fid, NULL)) {
+		/* do not delete foreign or public folders,
+		 * only remove them from local store */
 		success = TRUE;
 	} else {
 		EEwsConnection *connection;
@@ -1797,13 +2158,121 @@ ews_store_folder_is_subscribed (CamelSubscribable *subscribable,
 	if (camel_ews_store_summary_get_foreign (ews_store->summary, fid, &error) && !error) {
 		truth = TRUE;
 	}
+	g_clear_error (&error);
 
+	if (!truth && camel_ews_store_summary_get_public (ews_store->summary, fid, &error) && !error) {
+		truth = TRUE;
+	}
 	g_clear_error (&error);
+
 	g_free (fid);
 
 	return truth;
 }
 
+/* caller should hold ews_store->priv->get_finfo_lock already */
+static EEwsFolder *
+ews_store_find_public_folder (CamelEwsStore *ews_store,
+			      const gchar *folder_name)
+{
+	EEwsFolder *folder = NULL;
+	GSList *piter;
+	gchar **folders;
+	gint ii;
+
+	g_return_val_if_fail (CAMEL_IS_EWS_STORE (ews_store), NULL);
+	g_return_val_if_fail (folder_name != NULL, NULL);
+
+	folders = g_strsplit (folder_name, "/", -1);
+	if (!folders || !folders[0] || g_strcmp0 (folders[0], EWS_PUBLIC_FOLDER_ROOT_DISPLAY_NAME) != 0) {
+		g_strfreev (folders);
+		return NULL;
+	}
+
+	/* they are stored in public_folders from top level to bottom level */
+	piter = ews_store->priv->public_folders;
+	for (ii = 1; folders[ii] && piter; ii++) {
+		const gchar *fname = folders[ii];
+
+		while (piter) {
+			EEwsFolder *subf = piter->data;
+			const EwsFolderId *parent_id;
+
+			if (!subf) {
+				piter = NULL;
+				break;
+			}
+
+			if (g_strcmp0 (e_ews_folder_get_name (subf), fname) == 0) {
+				parent_id = e_ews_folder_get_parent_id (subf);
+				if (!folder && (!parent_id || g_strcmp0 (parent_id->id, EWS_PUBLIC_FOLDER_ROOT_ID) == 0)) {
+					folder = subf;
+					break;
+				} else if (parent_id && folder) {
+					const EwsFolderId *fid = e_ews_folder_get_id (folder);
+
+					if (fid && g_strcmp0 (fid->id, parent_id->id) == 0) {
+						folder = subf;
+						break;
+					}
+				}
+			}
+
+			piter = piter->next;
+		}
+	}
+
+	if (!piter || folders[ii])
+		folder = NULL;
+
+	g_strfreev (folders);
+
+	return folder;
+}
+
+/* ppath contains proposed path, this only makes sure that it's a unique path */
+static void
+ews_store_ensure_unique_path (CamelEwsStore *ews_store,
+			      gchar **ppath)
+{
+	gboolean done;
+	guint counter = 0;
+	gchar *base_path = NULL;
+
+	g_return_if_fail (ews_store != NULL);
+	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 gboolean
 ews_store_subscribe_folder_sync (CamelSubscribable *subscribable,
                                  const gchar *folder_name,
@@ -1811,6 +2280,10 @@ ews_store_subscribe_folder_sync (CamelSubscribable *subscribable,
                                  GError **error)
 {
 	CamelEwsStore *ews_store = CAMEL_EWS_STORE (subscribable);
+	EEwsFolder *folder;
+	const EwsFolderId *fid;
+	gboolean res = TRUE;
+	gchar *tmp;
 
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) {
 		g_set_error_literal (
@@ -1819,9 +2292,102 @@ ews_store_subscribe_folder_sync (CamelSubscribable *subscribable,
 		return FALSE;
 	}
 
-	/* it does nothing currently */
+	/* can subscribe only public folders,
+	   thus skip anything known */
+	tmp = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, folder_name);
+	if (tmp) {
+		g_free (tmp);
+		return TRUE;
+	}
 
-	return TRUE;
+	g_mutex_lock (&ews_store->priv->get_finfo_lock);
+	if (!ews_store->priv->public_folders) {
+		g_mutex_unlock (&ews_store->priv->get_finfo_lock);
+
+		g_set_error (
+			error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER,
+			_("Cannot subscribe folder '%s', no public folder available"), folder_name);
+		return FALSE;
+	}
+
+	folder = ews_store_find_public_folder (ews_store, folder_name);
+	if (!folder) {
+		g_mutex_unlock (&ews_store->priv->get_finfo_lock);
+
+		g_set_error (
+			error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER,
+			_("Cannot subscribe folder '%s', folder not found"), folder_name);
+		return FALSE;
+	}
+
+	fid = e_ews_folder_get_id (folder);
+
+	g_return_val_if_fail (fid != NULL, FALSE);
+
+	if (camel_ews_store_summary_has_folder (ews_store->summary, EWS_PUBLIC_FOLDER_ROOT_ID)) {
+		gchar *parent_name = camel_ews_store_summary_get_folder_name (ews_store->summary, EWS_PUBLIC_FOLDER_ROOT_ID, NULL);
+
+		g_return_val_if_fail (parent_name != NULL, FALSE);
+
+		tmp = g_strconcat (parent_name, "/", e_ews_folder_get_name (folder), NULL);
+		g_free (parent_name);
+	} else {
+		tmp = g_strconcat (EWS_PUBLIC_FOLDER_ROOT_DISPLAY_NAME, "/", e_ews_folder_get_name (folder), NULL);
+	}
+
+	if (e_ews_folder_get_folder_type (folder) != E_EWS_FOLDER_TYPE_MAILBOX) {
+		CamelSession *session;
+		CamelSettings *settings;
+		CamelEwsSettings *ews_settings;
+		ESourceRegistry *registry = NULL;
+
+		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));
+
+		res = 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)),
+			folder,
+			E_EWS_ESOURCE_FLAG_OFFLINE_SYNC | E_EWS_ESOURCE_FLAG_PUBLIC_FOLDER,
+			0,
+			cancellable,
+			error);
+
+		g_object_unref (settings);
+	}
+
+	if (res) {
+		ews_store_ensure_unique_path (ews_store, &tmp);
+
+		camel_ews_store_summary_new_folder (ews_store->summary, fid->id, EWS_PUBLIC_FOLDER_ROOT_ID,
+			NULL,
+			strrchr (tmp, '/') + 1,
+			e_ews_folder_get_folder_type (folder),
+			CAMEL_FOLDER_SUBSCRIBED,
+			e_ews_folder_get_total_count (folder),
+			FALSE, TRUE);
+
+		if (e_ews_folder_get_folder_type (folder) == E_EWS_FOLDER_TYPE_MAILBOX) {
+			CamelFolderInfo *fi;
+
+			camel_ews_store_ensure_virtual_folders (ews_store);
+
+			fi = camel_ews_utils_build_folder_info (ews_store, fid->id);
+			camel_store_folder_created (CAMEL_STORE (ews_store), fi);
+			camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
+			camel_folder_info_free (fi);
+		}
+	}
+
+	camel_ews_store_summary_save (ews_store->summary, NULL);
+
+	g_free (tmp);
+	g_mutex_unlock (&ews_store->priv->get_finfo_lock);
+
+	return res;
 }
 
 static gboolean
@@ -1831,8 +2397,11 @@ ews_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
                                    GError **error)
 {
 	CamelEwsStore *ews_store = CAMEL_EWS_STORE (subscribable);
+	EEwsFolderType folder_type;
+	EEwsFolder *folder;
+	gboolean is_public;
 	gboolean res = TRUE;
-	gchar *fid;
+	gchar *fid = NULL;
 
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) {
 		g_set_error_literal (
@@ -1841,19 +2410,35 @@ ews_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
 		return FALSE;
 	}
 
-	fid = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, folder_name);
+	folder = ews_store_find_public_folder (ews_store, folder_name);
+	if (folder) {
+		const EwsFolderId *folder_id = e_ews_folder_get_id (folder);
+
+		if (folder_id) {
+			fid = g_strdup (folder_id->id);
+			folder_type = e_ews_folder_get_folder_type (folder);
+		}
+	}
+
+	if (!fid) {
+		fid = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, folder_name);
+		if (fid)
+			folder_type = camel_ews_store_summary_get_folder_type (ews_store->summary, fid, NULL);
+	}
+
 	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)) {
+	is_public = camel_ews_store_summary_get_public (ews_store->summary, fid, NULL);
+	if (!is_public && !camel_ews_store_summary_get_foreign (ews_store->summary, fid, NULL)) {
 		/* nothing to do for regular folders */
 		res = TRUE;
 	} else {
 		CamelFolderInfo *fi;
 
-		if (camel_ews_store_summary_get_foreign_subfolders (ews_store->summary, fid, NULL)) {
+		if (!is_public && camel_ews_store_summary_get_foreign_subfolders (ews_store->summary, fid, NULL)) {
 			/* when subscribed with subfolders, then unsubscribe with subfolders as well */
 			GSList *local_folders = NULL, *ii;
 			gchar *full_name = camel_ews_store_summary_get_folder_full_name (ews_store->summary, fid, NULL);
@@ -1884,14 +2469,41 @@ ews_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
 			g_slist_free_full (local_folders, g_free);
 		}
 
-		fi = camel_ews_utils_build_folder_info (ews_store, fid);
-		camel_ews_store_summary_remove_folder (ews_store->summary, fid, error);
+		if (folder_type != E_EWS_FOLDER_TYPE_MAILBOX) {
+			CamelSession *session;
+			CamelSettings *settings;
+			CamelEwsSettings *ews_settings;
+			ESourceRegistry *registry = NULL;
+
+			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));
+
+			res = e_ews_folder_utils_remove_as_esource (registry,
+				camel_ews_settings_get_hosturl (ews_settings),
+				camel_network_settings_get_user (CAMEL_NETWORK_SETTINGS (ews_settings)),
+				fid,
+				cancellable,
+				error);
+
+			g_object_unref (settings);
+		}
 
-		camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
-		camel_store_folder_deleted (CAMEL_STORE (ews_store), fi);
-		camel_folder_info_free (fi);
+		if (res) {
+			fi = camel_ews_utils_build_folder_info (ews_store, fid);
+			camel_ews_store_summary_remove_folder (ews_store->summary, fid, error);
+
+			if (folder_type == E_EWS_FOLDER_TYPE_MAILBOX) {
+				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_ensure_virtual_folders (ews_store);
 		camel_ews_store_summary_save (ews_store->summary, NULL);
 	}
 
@@ -1959,6 +2571,11 @@ ews_store_dispose (GObject *object)
 		ews_store->priv->connection = NULL;
 	}
 
+	if (ews_store->priv->public_folders) {
+		g_slist_free_full (ews_store->priv->public_folders, g_object_unref);
+		ews_store->priv->public_folders = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (camel_ews_store_parent_class)->dispose (object);
 }
diff --git a/src/camel/camel-ews-store.h b/src/camel/camel-ews-store.h
index 60f5288..0420f47 100644
--- a/src/camel/camel-ews-store.h
+++ b/src/camel/camel-ews-store.h
@@ -53,6 +53,8 @@
 
 #define EWS_FOREIGN_FOLDER_ROOT_ID		"ForeignRoot"
 #define EWS_FOREIGN_FOLDER_ROOT_DISPLAY_NAME	_("Foreign Folders")
+#define EWS_PUBLIC_FOLDER_ROOT_ID		"PublicRoot"
+#define EWS_PUBLIC_FOLDER_ROOT_DISPLAY_NAME	_("Public Folders")
 
 G_BEGIN_DECLS
 
diff --git a/src/camel/camel-ews-utils.c b/src/camel/camel-ews-utils.c
index c58d593..5035337 100644
--- a/src/camel/camel-ews-utils.c
+++ b/src/camel/camel-ews-utils.c
@@ -48,6 +48,14 @@ camel_ews_utils_build_folder_info (CamelEwsStore *store,
 	fi = camel_folder_info_new ();
 	fi->full_name = camel_ews_store_summary_get_folder_full_name (
 		ews_summary, fid, NULL);
+
+	if (!fi->full_name) {
+		camel_folder_info_free (fi);
+		g_warn_if_reached ();
+
+		return NULL;
+	}
+
 	fi->display_name = camel_ews_store_summary_get_folder_name (
 		ews_summary, fid, NULL);
 	fi->flags = camel_ews_store_summary_get_folder_flags (
@@ -57,6 +65,25 @@ camel_ews_utils_build_folder_info (CamelEwsStore *store,
 	fi->total = camel_ews_store_summary_get_folder_total (
 		ews_summary, fid, NULL);
 
+	if (!(fi->flags & CAMEL_FOLDER_TYPE_MASK)) {
+		switch (camel_ews_store_summary_get_folder_type (ews_summary, fid, NULL)) {
+		case E_EWS_FOLDER_TYPE_CALENDAR:
+			fi->flags |= CAMEL_FOLDER_TYPE_EVENTS;
+			break;
+		case E_EWS_FOLDER_TYPE_CONTACTS:
+			fi->flags |= CAMEL_FOLDER_TYPE_CONTACTS;
+			break;
+		case E_EWS_FOLDER_TYPE_TASKS:
+			fi->flags |= CAMEL_FOLDER_TYPE_TASKS;
+			break;
+		case E_EWS_FOLDER_TYPE_MEMOS:
+			fi->flags |= CAMEL_FOLDER_TYPE_MEMOS;
+			break;
+		default:
+			break;
+		}
+	}
+
 	return fi;
 }
 
@@ -81,12 +108,12 @@ sync_deleted_folders (CamelEwsStore *store,
 		if (ftype == E_EWS_FOLDER_TYPE_MAILBOX) {
 			fi = camel_ews_utils_build_folder_info (store, fid);
 
-			camel_ews_store_summary_remove_folder (
-				ews_summary, fid, &error);
+			camel_ews_store_summary_remove_folder (ews_summary, fid, &error);
 
-			camel_subscribable_folder_unsubscribed (
-				CAMEL_SUBSCRIBABLE (store), fi);
-			camel_store_folder_deleted (CAMEL_STORE (store), fi);
+			if ((fi->flags & CAMEL_FOLDER_SUBSCRIBED) != 0) {
+				camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (store), fi);
+				camel_store_folder_deleted (CAMEL_STORE (store), fi);
+			}
 
 			g_clear_error (&error);
 		}
@@ -227,9 +254,10 @@ add_folder_to_summary (CamelEwsStore *store,
 
 	camel_ews_store_summary_new_folder (
 		ews_summary, fid->id,
-		pfid->id, fid->change_key,
+		pfid ? pfid->id : NULL, fid->change_key,
 		dname, ftype, 0, total,
-		e_ews_folder_get_foreign (folder));
+		e_ews_folder_get_foreign (folder),
+		FALSE);
 	camel_ews_store_summary_set_folder_unread (
 		ews_summary, fid->id, unread);
 }
diff --git a/src/collection/e-ews-backend.c b/src/collection/e-ews-backend.c
index e709d4d..db72aae 100644
--- a/src/collection/e-ews-backend.c
+++ b/src/collection/e-ews-backend.c
@@ -514,9 +514,10 @@ add_remote_sources (EEwsBackend *backend)
 		if (!e_source_has_extension (source, extension_name))
 			continue;
 
-		/* foreign folders are just added */
+		/* foreign or public folders are just added */
 		extension = e_source_get_extension (source, extension_name);
-		if (e_source_ews_folder_get_foreign (extension)) {
+		if (e_source_ews_folder_get_foreign (extension) ||
+		    e_source_ews_folder_get_public (extension)) {
 			e_server_side_source_set_writable (
 				E_SERVER_SIDE_SOURCE (source), TRUE);
 			e_server_side_source_set_remote_deletable (
@@ -752,9 +753,10 @@ ews_backend_create_resource_sync (ECollectionBackend *backend,
 	if (e_source_has_extension (source, extension_name)) {
 		ESourceEwsFolder *extension;
 
-		/* foreign folders are just added */
+		/* foreign and public folders are just added */
 		extension = e_source_get_extension (source, extension_name);
-		if (e_source_ews_folder_get_foreign (extension))
+		if (e_source_ews_folder_get_foreign (extension) ||
+		    e_source_ews_folder_get_public (extension))
 			success = TRUE;
 	}
 
@@ -841,10 +843,8 @@ ews_backend_create_resource_sync (ECollectionBackend *backend,
 			E_SERVER_SIDE_SOURCE (source), cache_dir);
 
 		/* Set permissions for clients. */
-		e_server_side_source_set_writable (
-			E_SERVER_SIDE_SOURCE (source), TRUE);
-		e_server_side_source_set_remote_deletable (
-			E_SERVER_SIDE_SOURCE (source), TRUE);
+		e_server_side_source_set_writable (E_SERVER_SIDE_SOURCE (source), TRUE);
+		e_server_side_source_set_remote_deletable (E_SERVER_SIDE_SOURCE (source), TRUE);
 
 		server = e_collection_backend_ref_server (backend);
 		e_source_registry_server_add_source (server, source);
@@ -886,8 +886,9 @@ ews_backend_delete_resource_sync (ECollectionBackend *backend,
 	}
 	extension = e_source_get_extension (source, extension_name);
 
-	if (e_source_ews_folder_get_foreign (extension)) {
-		/* do not delete foreign folders,
+	if (e_source_ews_folder_get_foreign (extension) ||
+	    e_source_ews_folder_get_public (extension)) {
+		/* do not delete foreign or public folders,
 		 * just remove them from local store */
 		success = TRUE;
 	} else {
diff --git a/src/configuration/e-ews-subscribe-foreign-folder.c b/src/configuration/e-ews-subscribe-foreign-folder.c
index 80c86fb..8562165 100644
--- a/src/configuration/e-ews-subscribe-foreign-folder.c
+++ b/src/configuration/e-ews-subscribe-foreign-folder.c
@@ -113,7 +113,7 @@ add_foreign_folder_to_camel (CamelEwsStore *ews_store,
 			foreign_mailbox_id, EWS_FOREIGN_FOLDER_ROOT_ID, NULL,
 			mailbox, E_EWS_FOLDER_TYPE_MAILBOX,
 			CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOSELECT,
-			0, FALSE);
+			0, FALSE, FALSE);
 	}
 
 	if (camel_ews_store_summary_has_folder (ews_store->summary, parent_fid->id)) {
@@ -121,7 +121,7 @@ add_foreign_folder_to_camel (CamelEwsStore *ews_store,
 			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);
+			CAMEL_FOLDER_SUBSCRIBED, e_ews_folder_get_total_count (folder), TRUE, FALSE);
 	} else {
 		const gchar *displayname;
 
@@ -137,7 +137,7 @@ add_foreign_folder_to_camel (CamelEwsStore *ews_store,
 			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);
+			CAMEL_FOLDER_SUBSCRIBED, e_ews_folder_get_total_count (folder), TRUE, FALSE);
 
 		g_free (fullname);
 	}
@@ -438,8 +438,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,
+		(cffd->include_subfolders ? E_EWS_ESOURCE_FLAG_INCLUDE_SUBFOLDERS : 0) | E_EWS_ESOURCE_FLAG_OFFLINE_SYNC,
 		0,
 		cancellable,
 		perror))
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index 7e60170..fe5abf1 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -7714,6 +7714,10 @@ e_ews_connection_find_folder (EEwsConnection *cnc,
 	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_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:ChildFolderCount");
+	e_soap_message_end_element (msg); /* AdditionalProperties */
 	e_soap_message_end_element (msg);
 
 	e_soap_message_start_element (msg, "ParentFolderIds", "messages", NULL);
diff --git a/src/server/e-ews-folder.c b/src/server/e-ews-folder.c
index f789171..9a86e74 100644
--- a/src/server/e-ews-folder.c
+++ b/src/server/e-ews-folder.c
@@ -472,8 +472,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,
+				     EEwsESourceFlags flags,
                                      gint color_seed,
                                      GCancellable *cancellable,
                                      GError **perror)
@@ -499,10 +498,9 @@ e_ews_folder_utils_populate_esource (ESource *source,
 			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:
+			case E_EWS_FOLDER_TYPE_MEMOS:
 				backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MEMO_LIST);
-				break;*/
+				break;
 			case E_EWS_FOLDER_TYPE_TASKS:
 				backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_TASK_LIST);
 				break;
@@ -524,10 +522,11 @@ 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);
+			e_source_ews_folder_set_foreign_subfolders (folder_ext, (flags & E_EWS_ESOURCE_FLAG_INCLUDE_SUBFOLDERS) != 0);
+			e_source_ews_folder_set_public (folder_ext, (flags & E_EWS_ESOURCE_FLAG_PUBLIC_FOLDER) != 0);
 
 			offline_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_OFFLINE);
-			e_source_offline_set_stay_synchronized (offline_ext, offline_sync);
+			e_source_offline_set_stay_synchronized (offline_ext, (flags & E_EWS_ESOURCE_FLAG_OFFLINE_SYNC) != 0);
 
 			/* set also color for calendar-like sources */
 			if (folder_type != E_EWS_FOLDER_TYPE_CONTACTS) {
@@ -560,8 +559,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,
+				   EEwsESourceFlags flags,
                                    gint color_seed,
                                    GCancellable *cancellable,
                                    GError **perror)
@@ -597,8 +595,7 @@ e_ews_folder_utils_add_as_esource (ESourceRegistry *pregistry,
 		master_hosturl,
 		master_username,
 		folder,
-		include_subfolders,
-		offline_sync,
+		flags,
 		color_seed,
 		cancellable,
 		perror)) {
@@ -636,8 +633,12 @@ e_ews_folder_utils_remove_as_esource (ESourceRegistry *pregistry,
 	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);
+	if (source) {
+		if (e_source_get_removable (source))
+			res = e_source_remove_sync (source, cancellable, perror);
+		else
+			res = e_source_remote_delete_sync (source, cancellable, perror);
+	}
 
 	g_list_free_full (sources, g_object_unref);
 	if (!pregistry)
@@ -646,6 +647,33 @@ e_ews_folder_utils_remove_as_esource (ESourceRegistry *pregistry,
 	return res;
 }
 
+GList *
+e_ews_folder_utils_get_esources (ESourceRegistry *pregistry,
+				 const gchar *master_hosturl,
+				 const gchar *master_username,
+				 GCancellable *cancellable,
+				 GError **perror)
+{
+	ESourceRegistry *registry;
+	GList *all_sources, *esources = NULL;
+
+	registry = pregistry;
+	if (!registry) {
+		registry = e_source_registry_new_sync (cancellable, perror);
+		if (!registry)
+			return NULL;
+	}
+
+	all_sources = e_source_registry_list_sources (registry, NULL);
+	esources = e_ews_folder_utils_filter_sources_for_account (all_sources, master_hosturl, master_username);
+
+	g_list_free_full (all_sources, g_object_unref);
+	if (!pregistry)
+		g_object_unref (registry);
+
+	return esources;
+}
+
 gboolean
 e_ews_folder_utils_is_subscribed_as_esource (const GList *esources,
                                              const gchar *master_hosturl,
diff --git a/src/server/e-ews-folder.h b/src/server/e-ews-folder.h
index 53d6fca..f410b32 100644
--- a/src/server/e-ews-folder.h
+++ b/src/server/e-ews-folder.h
@@ -80,6 +80,13 @@ EwsFolderId *	e_ews_folder_id_new (const gchar *id,
 				     gboolean is_distinguished_id);
 void		e_ews_folder_id_free (EwsFolderId *fid);
 
+typedef enum {
+	E_EWS_ESOURCE_FLAG_NONE			= 0,
+	E_EWS_ESOURCE_FLAG_INCLUDE_SUBFOLDERS	= 1 << 0,
+	E_EWS_ESOURCE_FLAG_OFFLINE_SYNC		= 1 << 1,
+	E_EWS_ESOURCE_FLAG_PUBLIC_FOLDER	= 1 << 2
+} EEwsESourceFlags;
+
 gchar *		e_ews_folder_utils_pick_color_spec		(gint move_by,
 								 gboolean around_middle);
 gboolean	e_ews_folder_utils_populate_esource		(ESource *source,
@@ -87,8 +94,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,
+								 EEwsESourceFlags flags,
 								 gint color_seed,
 								 GCancellable *cancellable,
 								 GError **perror);
@@ -96,8 +102,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,
+								 EEwsESourceFlags flags,
 								 gint color_seed,
 								 GCancellable *cancellable,
 								 GError **perror);
@@ -107,6 +112,11 @@ gboolean	e_ews_folder_utils_remove_as_esource		(ESourceRegistry *pregistry,
 								 const gchar *folder_id,
 								 GCancellable *cancellable,
 								 GError **perror);
+GList *		e_ews_folder_utils_get_esources			(ESourceRegistry *pregistry,
+								 const gchar *master_hosturl,
+								 const gchar *master_username,
+								 GCancellable *cancellable,
+								 GError **perror);
 gboolean	e_ews_folder_utils_is_subscribed_as_esource	(const GList *esources,
 								 const gchar *master_hosturl,
 								 const gchar *master_username,
diff --git a/src/server/e-source-ews-folder.c b/src/server/e-source-ews-folder.c
index 4eb6961..8404760 100644
--- a/src/server/e-source-ews-folder.c
+++ b/src/server/e-source-ews-folder.c
@@ -32,6 +32,7 @@ struct _ESourceEwsFolderPrivate {
 	gchar *id;
 	gboolean foreign;
 	gboolean foreign_subfolders;
+	gboolean is_public;
 };
 
 enum {
@@ -39,7 +40,8 @@ enum {
 	PROP_CHANGE_KEY,
 	PROP_ID,
 	PROP_FOREIGN,
-	PROP_FOREIGN_SUBFOLDERS
+	PROP_FOREIGN_SUBFOLDERS,
+	PROP_PUBLIC
 };
 
 G_DEFINE_DYNAMIC_TYPE (
@@ -77,6 +79,12 @@ source_ews_folder_set_property (GObject *object,
 				E_SOURCE_EWS_FOLDER (object),
 				g_value_get_boolean (value));
 			return;
+
+		case PROP_PUBLIC:
+			e_source_ews_folder_set_public (
+				E_SOURCE_EWS_FOLDER (object),
+				g_value_get_boolean (value));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -116,6 +124,13 @@ source_ews_folder_get_property (GObject *object,
 				e_source_ews_folder_get_foreign_subfolders (
 				E_SOURCE_EWS_FOLDER (object)));
 			return;
+
+		case PROP_PUBLIC:
+			g_value_set_boolean (
+				value,
+				e_source_ews_folder_get_public (
+				E_SOURCE_EWS_FOLDER (object)));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -205,6 +220,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_PUBLIC,
+		g_param_spec_boolean (
+			"public",
+			"Public",
+			"The folder is a public folder, part of Public Folders",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
 }
 
 static void
@@ -383,3 +411,25 @@ e_source_ews_folder_set_foreign_subfolders (ESourceEwsFolder *extension,
 
 	g_object_notify (G_OBJECT (extension), "foreign-subfolders");
 }
+
+gboolean
+e_source_ews_folder_get_public (ESourceEwsFolder *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), FALSE);
+
+	return extension->priv->is_public;
+}
+
+void
+e_source_ews_folder_set_public (ESourceEwsFolder *extension,
+                                 gboolean is_public)
+{
+	g_return_if_fail (E_IS_SOURCE_EWS_FOLDER (extension));
+
+	if ((extension->priv->is_public ? 1 : 0) == (is_public ? 1 : 0))
+		return;
+
+	extension->priv->is_public = is_public;
+
+	g_object_notify (G_OBJECT (extension), "public");
+}
diff --git a/src/server/e-source-ews-folder.h b/src/server/e-source-ews-folder.h
index ad0f284..c0637d8 100644
--- a/src/server/e-source-ews-folder.h
+++ b/src/server/e-source-ews-folder.h
@@ -84,6 +84,9 @@ gboolean	e_source_ews_folder_get_foreign_subfolders
 void		e_source_ews_folder_set_foreign_subfolders
 						(ESourceEwsFolder *extension,
 						 gboolean foreign_subfolders);
+gboolean	e_source_ews_folder_get_public	(ESourceEwsFolder *extension);
+void		e_source_ews_folder_set_public	(ESourceEwsFolder *extension,
+						 gboolean is_public);
 
 G_END_DECLS
 



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