[evolution-ews] Be able to read/write folder permissions



commit aca6b4852df17b500e5b36f823c130cfee10d56e
Author: Milan Crha <mcrha redhat com>
Date:   Tue Jul 31 16:20:18 2012 +0200

    Be able to read/write folder permissions

 po/POTFILES.in                                    |    3 +
 src/addressbook/e-book-backend-ews.c              |    6 +-
 src/camel/camel-ews-store.c                       |    4 +-
 src/configuration/Makefile.am                     |    8 +
 src/configuration/e-ews-config-ui-extension.c     |  154 +++
 src/configuration/e-ews-config-ui-extension.h     |   47 +
 src/configuration/e-ews-config-utils.c            | 1049 +++++++++++++++++
 src/configuration/e-ews-config-utils.h            |   69 ++
 src/configuration/e-ews-edit-folder-permissions.c | 1254 +++++++++++++++++++++
 src/configuration/e-ews-edit-folder-permissions.h |   43 +
 src/configuration/e-ews-search-user.c             |  548 +++++++++
 src/configuration/e-ews-search-user.h             |   37 +
 src/configuration/module-ews-configuration.c      |    6 +
 src/server/e-ews-connection.c                     |  364 ++++++-
 src/server/e-ews-connection.h                     |   40 +
 src/server/e-ews-folder.c                         |   18 +-
 src/server/e-ews-folder.h                         |    5 +-
 src/server/e-ews-item.c                           |  342 ++++++
 src/server/e-ews-item.h                           |   47 +
 src/server/e-source-ews-folder.c                  |   18 +-
 src/server/e-source-ews-folder.h                  |    4 +
 src/server/tests/test-createfolder.c              |    2 +-
 src/server/tests/test-libews.c                    |    2 +-
 src/utils/ews-test-finditem-query.c               |    6 +-
 24 files changed, 4061 insertions(+), 15 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 65eeb97..6066ad0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,6 +11,9 @@ src/camel/camel-ews-transport.c
 src/camel/camel-ews-utils.c
 src/collection/e-ews-backend.c
 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-mail-config-ews-autodiscover.c
 src/configuration/e-mail-config-ews-backend.c
 src/configuration/e-mail-config-ews-gal.c
diff --git a/src/addressbook/e-book-backend-ews.c b/src/addressbook/e-book-backend-ews.c
index 34592bd..86b3977 100644
--- a/src/addressbook/e-book-backend-ews.c
+++ b/src/addressbook/e-book-backend-ews.c
@@ -1431,7 +1431,7 @@ e_book_backend_ews_get_contact_list (EBookBackend *backend,
 		convert_error_to_edb_error (&error);
 		e_data_book_respond_get_contact_list (book, opid, error, vcard_list);
 
-		e_ews_folder_free_fid (fid);
+		e_ews_folder_id_free (fid);
 		g_slist_foreach (vcard_list, (GFunc) g_free, NULL);
 		g_slist_free (vcard_list);
 		return;
@@ -2556,7 +2556,7 @@ e_book_backend_ews_start_book_view (EBookBackend *backend,
 		&includes_last_item, cancellable, &error);
 	g_free (auto_comp_str);
 	g_hash_table_remove (priv->ops, book_view);
-	e_ews_folder_free_fid (fid);
+	e_ews_folder_id_free (fid);
 	if (error != NULL) {
 		e_data_book_view_notify_complete (book_view, error);
 		e_data_book_view_unref (book_view);
@@ -2973,7 +2973,7 @@ book_backend_ews_try_password_sync (ESourceAuthenticator *authenticator,
 		connection, EWS_PRIORITY_MEDIUM, "Default",
 		NULL, ids, &folders, cancellable, &local_error);
 
-	e_ews_folder_free_fid (fid);
+	e_ews_folder_id_free (fid);
 	g_slist_free (ids);
 	ids = NULL;
 
diff --git a/src/camel/camel-ews-store.c b/src/camel/camel-ews-store.c
index 2fa85a8..19c76d3 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -458,7 +458,7 @@ ews_authenticate_sync (CamelService *service,
 			d(printf ("folders for respective distinguished ids don't exist"));
 
 		g_slist_foreach (folders, (GFunc) g_object_unref, NULL);
-		g_slist_foreach (folder_ids, (GFunc) e_ews_folder_free_fid, NULL);
+		g_slist_foreach (folder_ids, (GFunc) e_ews_folder_id_free, NULL);
 		g_slist_free (folders);
 		g_slist_free (folder_ids);
 		g_clear_error (&folder_err);
@@ -774,7 +774,7 @@ ews_create_folder_sync (CamelStore *store,
 					    EWS_FOLDER_TYPE_MAILBOX,
 					    0, 0);
 	fi = camel_ews_utils_build_folder_info (ews_store, folder_id->id);
-	e_ews_folder_free_fid (folder_id);
+	e_ews_folder_id_free (folder_id);
 
 	camel_store_folder_created (store, fi);
 
diff --git a/src/configuration/Makefile.am b/src/configuration/Makefile.am
index 60a54a0..b5c384f 100644
--- a/src/configuration/Makefile.am
+++ b/src/configuration/Makefile.am
@@ -27,6 +27,14 @@ module_ews_configuration_la_SOURCES = \
 	e-mail-config-ews-oal-combo-box.h \
 	e-mail-config-ews-ooo-page.c \
 	e-mail-config-ews-ooo-page.h \
+	e-ews-config-ui-extension.c \
+	e-ews-config-ui-extension.h \
+	e-ews-config-utils.c \
+	e-ews-config-utils.h \
+	e-ews-edit-folder-permissions.c \
+	e-ews-edit-folder-permissions.h \
+	e-ews-search-user.c \
+	e-ews-search-user.h \
 	$(NULL)
 
 module_ews_configuration_la_LIBADD = \
diff --git a/src/configuration/e-ews-config-ui-extension.c b/src/configuration/e-ews-config-ui-extension.c
new file mode 100644
index 0000000..5a11cdd
--- /dev/null
+++ b/src/configuration/e-ews-config-ui-extension.c
@@ -0,0 +1,154 @@
+/*
+ * e-ews-config-ui-extension.c
+ *
+ * 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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include <shell/e-shell-view.h>
+
+#include "e-ews-config-utils.h"
+
+#include "e-ews-config-ui-extension.h"
+
+G_DEFINE_DYNAMIC_TYPE (
+	EEwsConfigUIExtension,
+	e_ews_config_ui_extension,
+	E_TYPE_EXTENSION)
+
+static void
+e_ews_config_ui_extension_shell_view_toggled_cb (EShellView *shell_view,
+						 EEwsConfigUIExtension *ui_ext)
+{
+	EShellViewClass *shell_view_class;
+	EShellWindow *shell_window;
+	GtkUIManager *ui_manager;
+	gpointer key = NULL, value = NULL;
+	const gchar *ui_def;
+	gboolean is_active, need_update;
+
+	g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+	g_return_if_fail (ui_ext != NULL);
+
+	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+	g_return_if_fail (shell_view_class != NULL);
+
+	shell_window = e_shell_view_get_shell_window (shell_view);
+	ui_manager = e_shell_window_get_ui_manager (shell_window);
+
+	need_update = ui_ext->current_ui_id != 0;
+	if (ui_ext->current_ui_id) {
+		gtk_ui_manager_remove_ui (ui_manager, ui_ext->current_ui_id);
+		ui_ext->current_ui_id = 0;
+	}
+
+	is_active = e_shell_view_is_active (shell_view);
+	if (!is_active) {
+		if (need_update)
+			gtk_ui_manager_ensure_update (ui_manager);
+
+		return;
+	}
+
+	if (!g_hash_table_lookup_extended (ui_ext->ui_definitions, shell_view_class->ui_manager_id, &key, &value)) {
+		gchar *ui_definition = NULL;
+
+		e_ews_config_utils_init_ui (shell_view, shell_view_class->ui_manager_id, &ui_definition);
+		g_hash_table_insert (ui_ext->ui_definitions, g_strdup (shell_view_class->ui_manager_id), ui_definition);
+	}
+
+	ui_def = g_hash_table_lookup (ui_ext->ui_definitions, shell_view_class->ui_manager_id);
+	if (ui_def) {
+		GError *error = NULL;
+
+		ui_ext->current_ui_id = gtk_ui_manager_add_ui_from_string (ui_manager, ui_def, -1, &error);
+		need_update = TRUE;
+
+		if (error) {
+			g_warning ("%s: Failed to add ui definition: %s", G_STRFUNC, error->message);
+			g_error_free (error);
+		}
+	}
+
+	if (need_update)
+		gtk_ui_manager_ensure_update (ui_manager);
+}
+
+static void
+e_ews_config_ui_extension_constructed (GObject *object)
+{
+	EExtension *extension;
+	EExtensible *extensible;
+
+	extension = E_EXTENSION (object);
+	extensible = e_extension_get_extensible (extension);
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (e_ews_config_ui_extension_parent_class)->constructed (object);
+
+	g_signal_connect (E_SHELL_VIEW (extensible), "toggled", G_CALLBACK (e_ews_config_ui_extension_shell_view_toggled_cb), extension);
+}
+
+static void
+e_ews_config_ui_extension_finalize (GObject *object)
+{
+	EEwsConfigUIExtension *ui_ext = (EEwsConfigUIExtension *) object;
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_ews_config_ui_extension_parent_class)->finalize (object);
+
+	g_hash_table_destroy (ui_ext->ui_definitions);
+}
+
+static void
+e_ews_config_ui_extension_class_init (EEwsConfigUIExtensionClass *class)
+{
+	GObjectClass *object_class;
+	EExtensionClass *extension_class;
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->constructed = e_ews_config_ui_extension_constructed;
+	object_class->finalize = e_ews_config_ui_extension_finalize;
+
+	extension_class = E_EXTENSION_CLASS (class);
+	extension_class->extensible_type = E_TYPE_SHELL_VIEW;
+}
+
+static void
+e_ews_config_ui_extension_class_finalize (EEwsConfigUIExtensionClass *class)
+{
+}
+
+static void
+e_ews_config_ui_extension_init (EEwsConfigUIExtension *extension)
+{
+	extension->current_ui_id = 0;
+	extension->ui_definitions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+}
+
+void
+e_ews_config_ui_extension_type_register (GTypeModule *type_module)
+{
+	/* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+	 *     function, so we have to wrap it with a public function in
+	 *     order to register types from a separate compilation unit. */
+	e_ews_config_ui_extension_register_type (type_module);
+}
diff --git a/src/configuration/e-ews-config-ui-extension.h b/src/configuration/e-ews-config-ui-extension.h
new file mode 100644
index 0000000..39e3ba0
--- /dev/null
+++ b/src/configuration/e-ews-config-ui-extension.h
@@ -0,0 +1,47 @@
+/*
+ * e-ews-config-ui-extension.h
+ *
+ * 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/>
+ *
+ */
+
+#ifndef E_EWS_CONFIG_UI_EXTENSION_H
+#define E_EWS_CONFIG_UI_EXTENSION_H
+
+#include <libebackend/libebackend.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EEwsConfigUIExtension EEwsConfigUIExtension;
+typedef struct _EEwsConfigUIExtensionClass EEwsConfigUIExtensionClass;
+
+struct _EEwsConfigUIExtension
+{
+	EExtension parent;
+
+	guint current_ui_id;
+	GHashTable *ui_definitions;
+};
+
+struct _EEwsConfigUIExtensionClass
+{
+	EExtensionClass parent;
+};
+
+GType	e_ews_config_ui_extension_get_type	(void);
+void	e_ews_config_ui_extension_type_register	(GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_EWS_CONFIG_UI_EXTENSION_H */
diff --git a/src/configuration/e-ews-config-utils.c b/src/configuration/e-ews-config-utils.c
new file mode 100644
index 0000000..2021586
--- /dev/null
+++ b/src/configuration/e-ews-config-utils.c
@@ -0,0 +1,1049 @@
+/*
+ * e-ews-config-utils.c
+ *
+ * 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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <unistd.h>
+#include <glib/gi18n-lib.h>
+
+#include <gtk/gtk.h>
+#include <libedataserver/libedataserver.h>
+#include <libedataserverui/libedataserverui.h>
+#include <e-util/e-dialog-utils.h>
+#include <e-util/e-util.h>
+#include <mail/em-folder-tree.h>
+#include <misc/e-book-source-config.h>
+#include <misc/e-cal-source-config.h>
+#include <shell/e-shell.h>
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+#include <shell/e-shell-window.h>
+
+#include "server/e-ews-connection.h"
+#include "server/e-source-ews-folder.h"
+
+#include "e-ews-edit-folder-permissions.h"
+
+#include "camel/camel-ews-store.h"
+#include "camel/camel-ews-store-summary.h"
+
+#include "e-ews-config-utils.h"
+#include "e-ews-search-user.h"
+
+struct RunWithFeedbackData
+{
+	GtkWindow *parent;
+	GtkWidget *dialog;
+	GCancellable *cancellable;
+	GObject *with_object;
+	EEwsSetupFunc thread_func;
+	EEwsSetupFunc idle_func;
+	gpointer user_data;
+	GDestroyNotify free_user_data;
+	GError *error;
+	gboolean run_modal;
+};
+
+static void
+free_run_with_feedback_data (gpointer ptr)
+{
+	struct RunWithFeedbackData *rfd = ptr;
+
+	if (!rfd)
+		return;
+
+	if (rfd->dialog)
+		gtk_widget_destroy (rfd->dialog);
+
+	g_object_unref (rfd->cancellable);
+	g_object_unref (rfd->with_object);
+
+	if (rfd->free_user_data)
+		rfd->free_user_data (rfd->user_data);
+
+	g_clear_error (&rfd->error);
+
+	g_free (rfd);
+}
+
+static gboolean
+run_with_feedback_idle (gpointer user_data)
+{
+	struct RunWithFeedbackData *rfd = user_data;
+	gboolean was_cancelled = FALSE;
+
+	g_return_val_if_fail (rfd != NULL, FALSE);
+
+	if (!g_cancellable_is_cancelled (rfd->cancellable)) {
+		if (rfd->idle_func && !rfd->error)
+			rfd->idle_func (rfd->with_object, rfd->user_data, rfd->cancellable, &rfd->error);
+
+		was_cancelled = g_cancellable_is_cancelled (rfd->cancellable);
+
+		if (rfd->dialog) {
+			gtk_widget_destroy (rfd->dialog);
+			rfd->dialog = NULL;
+		}
+	} else {
+		was_cancelled = TRUE;
+	}
+
+	if (!was_cancelled) {
+		if (rfd->error)
+			e_notice (rfd->parent, GTK_MESSAGE_ERROR, "%s", rfd->error->message);
+	}
+
+	free_run_with_feedback_data (rfd);
+
+	return FALSE;
+}
+
+static gpointer
+run_with_feedback_thread (gpointer user_data)
+{
+	struct RunWithFeedbackData *rfd = user_data;
+
+	g_return_val_if_fail (rfd != NULL, NULL);
+	g_return_val_if_fail (rfd->thread_func != NULL, NULL);
+
+	if (!g_cancellable_is_cancelled (rfd->cancellable))
+		rfd->thread_func (rfd->with_object, rfd->user_data, rfd->cancellable, &rfd->error);
+
+	g_idle_add (run_with_feedback_idle, rfd);
+
+	return NULL;
+}
+
+static void
+run_with_feedback_response_cb (GtkWidget *dialog,
+			       gint resonse_id,
+			       struct RunWithFeedbackData *rfd)
+{
+	g_return_if_fail (rfd != NULL);
+
+	rfd->dialog = NULL;
+
+	g_cancellable_cancel (rfd->cancellable);
+
+	gtk_widget_destroy (dialog);
+}
+
+static void
+e_ews_config_utils_run_in_thread_with_feedback_general (GtkWindow *parent,
+							GObject *with_object,
+							const gchar *description,
+							EEwsSetupFunc thread_func,
+							EEwsSetupFunc idle_func,
+							gpointer user_data,
+							GDestroyNotify free_user_data,
+							gboolean run_modal)
+{
+	GtkWidget *dialog, *label, *content, *spinner, *box;
+	struct RunWithFeedbackData *rfd;
+
+	g_return_if_fail (with_object != NULL);
+	g_return_if_fail (description != NULL);
+	g_return_if_fail (thread_func != NULL);
+
+	dialog = gtk_dialog_new_with_buttons ("",
+		parent,
+		GTK_DIALOG_MODAL,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		NULL);
+
+	box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
+	spinner = gtk_spinner_new ();
+	gtk_spinner_start (GTK_SPINNER (spinner));
+	gtk_box_pack_start (GTK_BOX (box), spinner, FALSE, FALSE, 0);
+
+	label = gtk_label_new (description);
+	gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+
+	gtk_widget_show_all (box);
+
+	content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+	gtk_container_add (GTK_CONTAINER (content), box);
+	gtk_container_set_border_width (GTK_CONTAINER (content), 12);
+
+	rfd = g_new0 (struct RunWithFeedbackData, 1);
+	rfd->parent = parent;
+	rfd->dialog = dialog;
+	rfd->cancellable = g_cancellable_new ();
+	rfd->with_object = g_object_ref (with_object);
+	rfd->thread_func = thread_func;
+	rfd->idle_func = idle_func;
+	rfd->user_data = user_data;
+	rfd->free_user_data = free_user_data;
+	rfd->error = NULL;
+	rfd->run_modal = run_modal;
+
+	g_signal_connect (dialog, "response", G_CALLBACK (run_with_feedback_response_cb), rfd);
+
+	if (run_modal) {
+		GCancellable *cancellable;
+
+		cancellable = g_object_ref (rfd->cancellable);
+
+		g_return_if_fail (g_thread_create (run_with_feedback_thread, rfd, FALSE, NULL));
+
+		gtk_dialog_run (GTK_DIALOG (dialog));
+
+		g_cancellable_cancel (cancellable);
+		g_object_unref (cancellable);
+	} else {
+		gtk_widget_show (dialog);
+
+		g_return_if_fail (g_thread_create (run_with_feedback_thread, rfd, FALSE, NULL));
+	}
+}
+
+void
+e_ews_config_utils_run_in_thread_with_feedback (GtkWindow *parent,
+						GObject *with_object,
+						const gchar *description,
+						EEwsSetupFunc thread_func,
+						EEwsSetupFunc idle_func,
+						gpointer user_data,
+						GDestroyNotify free_user_data)
+{
+	e_ews_config_utils_run_in_thread_with_feedback_general (parent, with_object, description, thread_func, idle_func, user_data, free_user_data, FALSE);
+}
+
+void
+e_ews_config_utils_run_in_thread_with_feedback_modal (GtkWindow *parent,
+						      GObject *with_object,
+						      const gchar *description,
+						      EEwsSetupFunc thread_func,
+						      EEwsSetupFunc idle_func,
+						      gpointer user_data,
+						      GDestroyNotify free_user_data)
+{
+	e_ews_config_utils_run_in_thread_with_feedback_general (parent, with_object, description, thread_func, idle_func, user_data, free_user_data, TRUE);
+}
+
+typedef struct _EEwsConfigUtilsAuthenticator EEwsConfigUtilsAuthenticator;
+typedef struct _EEwsConfigUtilsAuthenticatorClass EEwsConfigUtilsAuthenticatorClass;
+
+struct _EEwsConfigUtilsAuthenticator {
+	GObject parent;
+
+	ESourceRegistry *registry;
+	CamelEwsSettings *ews_settings;
+	EEwsConnection *conn;
+};
+
+struct _EEwsConfigUtilsAuthenticatorClass {
+	GObjectClass parent_class;
+};
+
+static ESourceAuthenticationResult
+ews_config_utils_authenticator_try_password_sync (ESourceAuthenticator *auth,
+						  const GString *password,
+						  GCancellable *cancellable,
+						  GError **error)
+{
+	EEwsConfigUtilsAuthenticator *authenticator = (EEwsConfigUtilsAuthenticator *) auth;
+	CamelNetworkSettings *network_settings;
+	gchar *hosturl, *user;
+	EwsFolderId *fid;
+	GSList *ids = NULL, *folders = NULL;
+	GError *local_error = NULL;
+
+	network_settings = CAMEL_NETWORK_SETTINGS (authenticator->ews_settings);
+
+	hosturl = camel_ews_settings_dup_hosturl (authenticator->ews_settings);
+	user = camel_network_settings_dup_user (network_settings);
+
+	authenticator->conn = e_ews_connection_new (
+		hosturl, user, password->str,
+		camel_network_settings_get_auth_mechanism (network_settings),
+		camel_ews_settings_get_timeout (authenticator->ews_settings),
+		NULL, NULL, &local_error);
+
+	g_free (hosturl);
+	g_free (user);
+
+	if (local_error) {
+		g_warn_if_fail (!authenticator->conn);
+		authenticator->conn = NULL;
+
+		g_propagate_error (error, local_error);
+
+		return E_SOURCE_AUTHENTICATION_ERROR;
+	}
+
+	g_warn_if_fail (authenticator->conn);
+
+	/* test whether connection works with some simple operation */
+	fid = g_new0 (EwsFolderId, 1);
+	fid->id = g_strdup ("inbox");
+	fid->is_distinguished_id = TRUE;
+	ids = g_slist_append (ids, fid);
+
+	e_ews_connection_get_folder_sync (
+		authenticator->conn, EWS_PRIORITY_MEDIUM, "Default",
+		NULL, ids, &folders, cancellable, &local_error);
+
+	e_ews_folder_id_free (fid);
+	g_slist_free (ids);
+	g_slist_free_full (folders, g_object_unref);
+
+	if (local_error) {
+		g_object_unref (authenticator->conn);
+		authenticator->conn = NULL;
+
+		if (g_error_matches (
+		    local_error, EWS_CONNECTION_ERROR,
+		    EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED)) {
+			g_clear_error (&local_error);
+			return E_SOURCE_AUTHENTICATION_REJECTED;
+		}
+
+		g_propagate_error (error, local_error);
+
+		return E_SOURCE_AUTHENTICATION_ERROR;
+	}
+
+	return E_SOURCE_AUTHENTICATION_ACCEPTED;
+}
+
+#define E_TYPE_EWS_CONFIG_UTILS_AUTHENTICATOR (e_ews_config_utils_authenticator_get_type ())
+
+GType e_ews_config_utils_authenticator_get_type (void) G_GNUC_CONST;
+
+static void e_ews_config_utils_authenticator_authenticator_init (ESourceAuthenticatorInterface *interface);
+
+G_DEFINE_TYPE_EXTENDED (EEwsConfigUtilsAuthenticator, e_ews_config_utils_authenticator, G_TYPE_OBJECT, 0,
+	G_IMPLEMENT_INTERFACE (E_TYPE_SOURCE_AUTHENTICATOR, e_ews_config_utils_authenticator_authenticator_init))
+
+static void
+ews_config_utils_authenticator_finalize (GObject *object)
+{
+	EEwsConfigUtilsAuthenticator *authenticator = (EEwsConfigUtilsAuthenticator *) object;
+
+	g_object_unref (authenticator->registry);
+	g_object_unref (authenticator->ews_settings);
+	if (authenticator->conn)
+		g_object_unref (authenticator->conn);
+
+	G_OBJECT_CLASS (e_ews_config_utils_authenticator_parent_class)->finalize (object);
+}
+
+static void
+e_ews_config_utils_authenticator_class_init (EEwsConfigUtilsAuthenticatorClass *class)
+{
+	GObjectClass *object_class;
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = ews_config_utils_authenticator_finalize;
+}
+
+static void
+e_ews_config_utils_authenticator_authenticator_init (ESourceAuthenticatorInterface *interface)
+{
+	interface->try_password_sync = ews_config_utils_authenticator_try_password_sync;
+}
+
+static void
+e_ews_config_utils_authenticator_init (EEwsConfigUtilsAuthenticator *authenticator)
+{
+}
+
+EEwsConnection	*
+e_ews_config_utils_open_connection_for (GtkWindow *parent,
+					ESourceRegistry *registry,
+					ESource *source,
+					CamelEwsSettings *ews_settings,
+					GCancellable *cancellable,
+					GError **perror)
+{
+	EEwsConnection *conn = NULL;
+	CamelNetworkSettings *network_settings;
+	GError *local_error = NULL;
+
+	g_return_val_if_fail (registry != NULL, NULL);
+	g_return_val_if_fail (source != NULL, NULL);
+	g_return_val_if_fail (ews_settings != NULL, NULL);
+
+	network_settings = CAMEL_NETWORK_SETTINGS (ews_settings);
+
+	/* use the one from mailer, if there, otherwise open new */
+	conn = e_ews_connection_find (
+		camel_ews_settings_get_hosturl (ews_settings),
+		camel_network_settings_get_user (network_settings));
+	if (conn)
+		return conn;
+
+	while (!conn && !g_cancellable_is_cancelled (cancellable) && !local_error) {
+		EEwsConfigUtilsAuthenticator *authenticator = g_object_new (E_TYPE_EWS_CONFIG_UTILS_AUTHENTICATOR, NULL);
+
+		authenticator->ews_settings = g_object_ref (ews_settings);
+		authenticator->registry = g_object_ref (registry);
+
+		e_source_registry_authenticate_sync (
+			registry, source, E_SOURCE_AUTHENTICATOR (authenticator),
+			cancellable, &local_error);
+
+		if (authenticator->conn)
+			conn = g_object_ref (authenticator->conn);
+
+		g_object_unref (authenticator);
+	}
+
+	if (local_error)
+		g_propagate_error (perror, local_error);
+
+	return conn;
+}
+
+static gboolean
+get_ews_store_from_folder_tree (EShellView *shell_view,
+				gchar **pfolder_path,
+				CamelStore **pstore)
+{
+	EShellSidebar *shell_sidebar;
+	EMFolderTree *folder_tree;
+	gchar *selected_path = NULL;
+	CamelStore *selected_store = NULL;
+	gboolean found = FALSE;
+
+	/* Get hold of Folder Tree */
+	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+	g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
+	if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
+	    em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
+		if (selected_store) {
+			CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));
+
+			if (provider && g_ascii_strcasecmp (provider->protocol, "ews") == 0) {
+				found = TRUE;
+
+				if (pstore)
+					*pstore = g_object_ref (selected_store);
+
+				if (pfolder_path)
+					*pfolder_path = selected_path;
+				else
+					g_free (selected_path);
+
+				selected_path = NULL;
+			}
+
+			g_object_unref (selected_store);
+		}
+
+		g_free (selected_path);
+	}
+
+	g_object_unref (folder_tree);
+
+	return found;
+}
+
+/* static void
+action_subscribe_foreign_folder_cb (GtkAction *action,
+				    EShellView *shell_view)
+{
+	GtkWindow *parent;
+	EShellBackend *backend;
+	CamelSession *session = NULL;
+	CamelStore *store = NULL;
+
+	if (!get_ews_store_from_folder_tree (shell_view, NULL, &store))
+		return;
+
+	parent = GTK_WINDOW (e_shell_view_get_shell_window (shell_view));
+	backend = e_shell_view_get_shell_backend (shell_view);
+	g_object_get (G_OBJECT (backend), "session", &session, NULL);
+
+	e_ews_subscribe_foreign_folder (parent, session, store);
+
+	g_object_unref (session);
+	g_object_unref (store);
+	g_free (profile);
+} */
+
+static void
+action_folder_permissions_mail_cb (GtkAction *action,
+				   EShellView *shell_view)
+{
+	gchar *folder_path = NULL;
+	EShellWindow *shell_window;
+	GtkWindow *parent;
+	CamelStore *store = NULL;
+	CamelEwsStore *ews_store;
+	CamelNetworkSettings *network_settings;
+	gchar *str_folder_id;
+
+	if (!get_ews_store_from_folder_tree (shell_view, &folder_path, &store))
+		return;
+
+	ews_store = CAMEL_EWS_STORE (store);
+	g_return_if_fail (ews_store != NULL);
+	g_return_if_fail (folder_path != NULL);
+
+	network_settings = CAMEL_NETWORK_SETTINGS (camel_service_get_settings (CAMEL_SERVICE (store)));
+	g_return_if_fail (network_settings != NULL);
+
+	shell_window = e_shell_view_get_shell_window (shell_view);
+	parent = GTK_WINDOW (shell_window);
+
+	str_folder_id = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, folder_path);
+	if (!str_folder_id) {
+		e_notice (parent, GTK_MESSAGE_ERROR, _("Cannot edit permissions of folder '%s', choose other folder."), folder_path);
+	} else {
+		ESourceRegistry *registry = e_shell_get_registry (e_shell_window_get_shell (shell_window));
+		ESource *source;
+		EwsFolderId *folder_id;
+		gchar *str_change_key;
+
+		source = e_source_registry_ref_source (registry, camel_service_get_uid (CAMEL_SERVICE (store)));
+		g_return_if_fail (source != NULL);
+
+		str_change_key = camel_ews_store_summary_get_change_key (ews_store->summary, str_folder_id, NULL);
+
+		folder_id = e_ews_folder_id_new (str_folder_id, str_change_key, FALSE);
+
+		e_ews_edit_folder_permissions (parent,
+			registry,
+			source,
+			CAMEL_EWS_SETTINGS (network_settings),
+			camel_service_get_display_name (CAMEL_SERVICE (store)),
+			folder_path,
+			folder_id,
+			EWS_FOLDER_TYPE_MAILBOX);
+
+		g_object_unref (source);
+		g_free (str_folder_id);
+		g_free (str_change_key);
+		e_ews_folder_id_free (folder_id);
+	}
+
+	g_object_unref (store);
+	g_free (folder_path);
+}
+
+static void
+ews_ui_enable_actions (GtkActionGroup *action_group,
+		       const GtkActionEntry *entries,
+		       guint n_entries,
+		       gboolean can_show,
+		       gboolean is_online)
+{
+	gint ii;
+
+	g_return_if_fail (action_group != NULL);
+	g_return_if_fail (entries != NULL);
+
+	for (ii = 0; ii < n_entries; ii++) {
+		GtkAction *action;
+
+		action = gtk_action_group_get_action (action_group, entries[ii].name);
+		if (!action)
+			continue;
+
+		gtk_action_set_visible (action, can_show);
+		if (can_show)
+			gtk_action_set_sensitive (action, is_online);
+	}
+}
+
+/*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! * /
+	  G_CALLBACK (action_subscribe_foreign_folder_cb) }
+};*/
+
+static GtkActionEntry mail_folder_context_entries[] = {
+	{ "mail-ews-folder-permissions",
+	  "folder-new",
+	  N_("Permissions..."),
+	  NULL,
+	  N_("Edit EWS folder permissions"),
+	  G_CALLBACK (action_folder_permissions_mail_cb) }
+};
+
+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-folder-permissions\"/>\n"
+	"  </placeholder>\n"
+	"</popup>\n";
+
+static void
+ews_ui_update_actions_mail_cb (EShellView *shell_view,
+			       GtkActionEntry *entries)
+{
+	EShellWindow *shell_window;
+	GtkActionGroup *action_group;
+	GtkUIManager *ui_manager;
+	EShellSidebar *shell_sidebar;
+	EMFolderTree *folder_tree;
+	CamelStore *selected_store = NULL;
+	gchar *selected_path = NULL;
+	gboolean account_node = FALSE, folder_node = FALSE;
+	gboolean online = FALSE;
+
+	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+	g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
+	if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
+	    em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
+		if (selected_store) {
+			CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));
+
+			if (provider && g_ascii_strcasecmp (provider->protocol, "ews") == 0) {
+				account_node = !selected_path || !*selected_path;
+				folder_node = !account_node;
+			}
+
+			g_object_unref (selected_store);
+		}
+	}
+	g_object_unref (folder_tree);
+
+	g_free (selected_path);
+
+	shell_window = e_shell_view_get_shell_window (shell_view);
+	ui_manager = e_shell_window_get_ui_manager (shell_window);
+	action_group = e_lookup_action_group (ui_manager, "mail");
+
+	if (account_node || folder_node) {
+		EShellBackend *backend;
+		CamelSession *session = NULL;
+
+		backend = e_shell_view_get_shell_backend (shell_view);
+		g_object_get (G_OBJECT (backend), "session", &session, NULL);
+
+		online = session && camel_session_get_online (session);
+
+		if (session)
+			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_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), folder_node, online);
+}
+
+static void
+ews_ui_init_mail (GtkUIManager *ui_manager,
+                  EShellView *shell_view,
+		  gchar **ui_definition)
+{
+	EShellWindow *shell_window;
+	GtkActionGroup *action_group;
+
+	g_return_if_fail (ui_definition != NULL);
+
+	*ui_definition = g_strdup (ews_ui_mail_def);
+
+	shell_window = e_shell_view_get_shell_window (shell_view);
+	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_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), shell_view);
+
+	/* Decide whether we want this option to be visible or not */
+	g_signal_connect (shell_view, "update-actions",
+			  G_CALLBACK (ews_ui_update_actions_mail_cb),
+			  shell_view);
+
+	g_object_unref (action_group);
+}
+
+static gboolean
+get_selected_ews_source (EShellView *shell_view,
+			 ESource **selected_source,
+			 ESourceRegistry **registry)
+{
+	ESource *source;
+	EShellSidebar *shell_sidebar;
+	ESourceSelector *selector = NULL;
+
+	g_return_val_if_fail (shell_view != NULL, FALSE);
+
+	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+	g_return_val_if_fail (shell_sidebar != NULL, FALSE);
+
+	g_object_get (shell_sidebar, "selector", &selector, NULL);
+	g_return_val_if_fail (selector != NULL, FALSE);
+
+	source = e_source_selector_ref_primary_selection (selector);
+	if (source) {
+		ESourceBackend *backend_ext = NULL;
+
+		if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK))
+			backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK);
+		else if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
+			backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR);
+		else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST))
+			backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MEMO_LIST);
+		else if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
+			backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_TASK_LIST);
+		else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT))
+			backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
+
+		if (!backend_ext ||
+		    g_strcmp0 (e_source_backend_get_backend_name (backend_ext), "ews") != 0) {
+			g_object_unref (source);
+			source = NULL;
+		}
+	}
+
+	if (source && registry)
+		*registry = g_object_ref (e_source_selector_get_registry (selector));
+
+	g_object_unref (selector);
+
+	if (selected_source)
+		*selected_source = source;
+	else if (source)
+		g_object_unref (source);
+
+	return source != NULL;
+}
+
+/* how many menu entries are defined; all calendar/tasks/memos/contacts
+   actions should have same count */
+#define EWS_ESOURCE_NUM_ENTRIES 1
+
+static void
+update_ews_source_entries_cb (EShellView *shell_view,
+			      GtkActionEntry *entries)
+{
+	GtkActionGroup *action_group;
+	EShell *shell;
+	EShellWindow *shell_window;
+	const gchar *group;
+	gboolean is_ews_source, is_online;
+
+	g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+	g_return_if_fail (entries != NULL);
+
+	if (strstr (entries->name, "calendar"))
+		group = "calendar";
+	else if (strstr (entries->name, "tasks"))
+		group = "tasks";
+	else if (strstr (entries->name, "memos"))
+		group = "memos";
+	else if (strstr (entries->name, "contacts"))
+		group = "contacts";
+	else
+		g_return_if_reached ();
+
+	is_ews_source = get_selected_ews_source (shell_view, NULL, NULL);
+	shell_window = e_shell_view_get_shell_window (shell_view);
+	shell = e_shell_window_get_shell (shell_window);
+
+	is_online = shell && e_shell_get_online (shell);
+	action_group = e_shell_window_get_action_group (shell_window, group);
+
+	ews_ui_enable_actions (action_group, entries, EWS_ESOURCE_NUM_ENTRIES, is_ews_source, is_online);
+}
+
+static void
+setup_ews_source_actions (EShellView *shell_view,
+			  GtkUIManager *ui_manager,
+			  GtkActionEntry *entries,
+			  guint n_entries)
+{
+	EShellWindow *shell_window;
+	const gchar *group;
+
+	g_return_if_fail (shell_view != NULL);
+	g_return_if_fail (ui_manager != NULL);
+	g_return_if_fail (entries != NULL);
+	g_return_if_fail (n_entries > 0);
+	g_return_if_fail (n_entries == EWS_ESOURCE_NUM_ENTRIES);
+
+	if (strstr (entries->name, "calendar"))
+		group = "calendar";
+	else if (strstr (entries->name, "tasks"))
+		group = "tasks";
+	else if (strstr (entries->name, "memos"))
+		group = "memos";
+	else if (strstr (entries->name, "contacts"))
+		group = "contacts";
+	else
+		g_return_if_reached ();
+
+	shell_window = e_shell_view_get_shell_window (shell_view);
+
+	e_action_group_add_actions_localized (
+		e_shell_window_get_action_group (shell_window, group), GETTEXT_PACKAGE,
+		entries, EWS_ESOURCE_NUM_ENTRIES, shell_view);
+
+	g_signal_connect (shell_view, "update-actions", G_CALLBACK (update_ews_source_entries_cb), entries);
+}
+
+static void
+action_folder_permissions_source_cb (GtkAction *action,
+				     EShellView *shell_view)
+{
+	ESourceRegistry *registry = NULL;
+	ESource *source = NULL, *parent_source;
+	ESourceEwsFolder *folder_ext;
+	ESourceCamel *extension;
+	CamelSettings *settings;
+	const gchar *extension_name;
+	EwsFolderId *folder_id;
+	EwsFolderType folder_type;
+
+	g_return_if_fail (action != NULL);
+	g_return_if_fail (shell_view != NULL);
+	g_return_if_fail (get_selected_ews_source (shell_view, &source, &registry));
+	g_return_if_fail (source != NULL);
+	g_return_if_fail (e_source_has_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER));
+	g_return_if_fail (gtk_action_get_name (action) != NULL);
+
+	folder_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
+	folder_id = e_source_ews_folder_dup_folder_id (folder_ext);
+	g_return_if_fail (folder_id != NULL);
+
+	parent_source = e_source_registry_ref_source (registry, e_source_get_parent (source));
+
+	extension_name = e_source_camel_get_extension_name ("ews");
+	extension = e_source_get_extension (parent_source, extension_name);
+	settings = e_source_camel_get_settings (extension);
+
+	folder_type = EWS_FOLDER_TYPE_MAILBOX;
+	if (strstr (gtk_action_get_name (action), "calendar") != NULL)
+		folder_type = EWS_FOLDER_TYPE_CALENDAR;
+	else if (strstr (gtk_action_get_name (action), "contacts") != NULL)
+		folder_type = EWS_FOLDER_TYPE_CONTACTS;
+	else if (strstr (gtk_action_get_name (action), "tasks") != NULL)
+		folder_type = EWS_FOLDER_TYPE_TASKS;
+
+	e_ews_edit_folder_permissions (NULL,
+		registry,
+		source,
+		CAMEL_EWS_SETTINGS (settings),
+		e_source_get_display_name (parent_source),
+		e_source_get_display_name (source),
+		folder_id,
+		folder_type);
+
+	g_object_unref (source);
+	g_object_unref (parent_source);
+	g_object_unref (registry);
+	e_ews_folder_id_free (folder_id);
+}
+
+static GtkActionEntry calendar_context_entries[] = {
+
+	{ "calendar-ews-folder-permissions",
+	  "folder-new",
+	  N_("Permissions..."),
+	  NULL,
+	  N_("Edit EWS calendar permissions"),
+	  G_CALLBACK (action_folder_permissions_source_cb) }
+};
+
+static const gchar *ews_ui_cal_def =
+	"<popup name=\"calendar-popup\">\n"
+	"  <placeholder name=\"calendar-popup-actions\">\n"
+	"    <menuitem action=\"calendar-ews-folder-permissions\"/>\n"
+	"  </placeholder>\n"
+	"</popup>\n";
+
+static void
+ews_ui_init_calendar (GtkUIManager *ui_manager,
+		      EShellView *shell_view,
+		      gchar **ui_definition)
+{
+	g_return_if_fail (ui_definition != NULL);
+
+	*ui_definition = g_strdup (ews_ui_cal_def);
+
+	setup_ews_source_actions (shell_view, ui_manager,
+		calendar_context_entries, G_N_ELEMENTS (calendar_context_entries));
+}
+
+static GtkActionEntry tasks_context_entries[] = {
+
+	{ "tasks-ews-folder-permissions",
+	  "folder-new",
+	  N_("Permissions..."),
+	  NULL,
+	  N_("Edit EWS tasks permissions"),
+	  G_CALLBACK (action_folder_permissions_source_cb) }
+};
+
+static const gchar *ews_ui_task_def =
+	"<popup name=\"task-list-popup\">\n"
+	"  <placeholder name=\"task-list-popup-actions\">\n"
+	"    <menuitem action=\"tasks-ews-folder-permissions\"/>\n"
+	"  </placeholder>\n"
+	"</popup>\n";
+
+static void
+ews_ui_init_tasks (GtkUIManager *ui_manager,
+		   EShellView *shell_view,
+		   gchar **ui_definition)
+{
+	g_return_if_fail (ui_definition != NULL);
+
+	*ui_definition = g_strdup (ews_ui_task_def);
+
+	setup_ews_source_actions (shell_view, ui_manager,
+		tasks_context_entries, G_N_ELEMENTS (tasks_context_entries));
+}
+
+static GtkActionEntry memos_context_entries[] = {
+
+	{ "memos-ews-folder-permissions",
+	  "folder-new",
+	  N_("Permissions..."),
+	  NULL,
+	  N_("Edit EWS memos permissions"),
+	  G_CALLBACK (action_folder_permissions_source_cb) }
+};
+
+static const gchar *ews_ui_memo_def =
+	"<popup name=\"memo-list-popup\">\n"
+	"  <placeholder name=\"memo-list-popup-actions\">\n"
+	"    <menuitem action=\"memos-ews-folder-permissions\"/>\n"
+	"  </placeholder>\n"
+	"</popup>\n";
+
+static void
+ews_ui_init_memos (GtkUIManager *ui_manager,
+		   EShellView *shell_view,
+		   gchar **ui_definition)
+{
+	g_return_if_fail (ui_definition != NULL);
+
+	*ui_definition = g_strdup (ews_ui_memo_def);
+
+	setup_ews_source_actions (shell_view, ui_manager,
+		memos_context_entries, G_N_ELEMENTS (memos_context_entries));
+}
+
+static GtkActionEntry contacts_context_entries[] = {
+
+	{ "contacts-ews-folder-permissions",
+	  "folder-new",
+	  N_("Permissions..."),
+	  NULL,
+	  N_("Edit EWS contacts permissions"),
+	  G_CALLBACK (action_folder_permissions_source_cb) }
+};
+
+static const gchar *ews_ui_book_def =
+	"<popup name=\"address-book-popup\">\n"
+	"  <placeholder name=\"address-book-popup-actions\">\n"
+	"    <menuitem action=\"contacts-ews-folder-permissions\"/>\n"
+	"  </placeholder>\n"
+	"</popup>\n";
+
+static void
+ews_ui_init_contacts (GtkUIManager *ui_manager,
+		      EShellView *shell_view,
+		      gchar **ui_definition)
+{
+	g_return_if_fail (ui_definition != NULL);
+
+	*ui_definition = g_strdup (ews_ui_book_def);
+
+	setup_ews_source_actions (shell_view, ui_manager,
+		contacts_context_entries, G_N_ELEMENTS (contacts_context_entries));
+}
+
+void
+e_ews_config_utils_init_ui (EShellView *shell_view,
+			    const gchar *ui_manager_id,
+			    gchar **ui_definition)
+{
+	EShellWindow *shell_window;
+	GtkUIManager *ui_manager;
+
+	g_return_if_fail (shell_view != NULL);
+	g_return_if_fail (ui_manager_id != NULL);
+	g_return_if_fail (ui_definition != NULL);
+
+	shell_window = e_shell_view_get_shell_window (shell_view);
+	ui_manager = e_shell_window_get_ui_manager (shell_window);
+
+	if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.mail") == 0)
+		ews_ui_init_mail (ui_manager, shell_view, ui_definition);
+	else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.calendars") == 0)
+		ews_ui_init_calendar (ui_manager, shell_view, ui_definition);
+	else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.tasks") == 0)
+		ews_ui_init_tasks (ui_manager, shell_view, ui_definition);
+	else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.memos") == 0)
+		ews_ui_init_memos (ui_manager, shell_view, ui_definition);
+	else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.contacts") == 0)
+		ews_ui_init_contacts (ui_manager, shell_view, ui_definition);
+}
+
+gboolean
+e_ews_config_utils_is_online (void)
+{
+	EShell *shell;
+
+	shell = e_shell_get_default ();
+
+	return shell && e_shell_get_online (shell);
+}
+
+GtkWindow *
+e_ews_config_utils_get_widget_toplevel_window (GtkWidget *widget)
+{
+	if (!widget)
+		return NULL;
+
+	if (!GTK_IS_WINDOW (widget))
+		widget = gtk_widget_get_toplevel (widget);
+
+	if (GTK_IS_WINDOW (widget))
+		return GTK_WINDOW (widget);
+
+	return NULL;
+}
+
+static gpointer
+ews_config_utils_unref_in_thread (gpointer user_data)
+{
+	g_object_unref (user_data);
+
+	return NULL;
+}
+
+void
+e_ews_config_utils_unref_in_thread (GObject *object)
+{
+	GThread *thread;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (G_IS_OBJECT (object));
+
+	thread = g_thread_new (NULL, ews_config_utils_unref_in_thread, object);
+	g_thread_unref (thread);
+}
diff --git a/src/configuration/e-ews-config-utils.h b/src/configuration/e-ews-config-utils.h
new file mode 100644
index 0000000..e4f1207
--- /dev/null
+++ b/src/configuration/e-ews-config-utils.h
@@ -0,0 +1,69 @@
+/*
+ * e-ews-config-utils.h
+ *
+ * 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/>
+ *
+ */
+
+#ifndef E_EWS_CONFIG_UTILS_H
+#define E_EWS_CONFIG_UTILS_H
+
+#include <gtk/gtk.h>
+
+#include <shell/e-shell-view.h>
+#include <misc/e-source-config.h>
+#include <misc/e-source-config-backend.h>
+
+#include "server/e-ews-connection.h"
+#include "server/camel-ews-settings.h"
+
+typedef void		(* EEwsSetupFunc)					(GObject *with_object,
+										 gpointer user_data,
+										 GCancellable *cancellable,
+										 GError **perror);
+
+void			e_ews_config_utils_run_in_thread_with_feedback		(GtkWindow *parent,
+										 GObject *with_object,
+										 const gchar *description,
+										 EEwsSetupFunc thread_func,
+										 EEwsSetupFunc idle_func,
+										 gpointer user_data,
+										 GDestroyNotify free_user_data);
+
+void			e_ews_config_utils_run_in_thread_with_feedback_modal	(GtkWindow *parent,
+										 GObject *with_object,
+										 const gchar *description,
+										 EEwsSetupFunc thread_func,
+										 EEwsSetupFunc idle_func,
+										 gpointer user_data,
+										 GDestroyNotify free_user_data);
+
+EEwsConnection	*	e_ews_config_utils_open_connection_for			(GtkWindow *parent,
+										 ESourceRegistry *registry,
+										 ESource *source,
+										 CamelEwsSettings *ews_settings,
+										 GCancellable *cancellable,
+										 GError **perror);
+
+void			e_ews_config_utils_init_ui				(EShellView *shell_view,
+										 const gchar *ui_manager_id,
+										 gchar **ui_definition);
+
+gboolean		e_ews_config_utils_is_online				(void);
+
+GtkWindow *		e_ews_config_utils_get_widget_toplevel_window		(GtkWidget *widget);
+
+void			e_ews_config_utils_unref_in_thread			(GObject *object);
+
+#endif /* E_EWS_CONFIG_UTILS */
diff --git a/src/configuration/e-ews-edit-folder-permissions.c b/src/configuration/e-ews-edit-folder-permissions.c
new file mode 100644
index 0000000..c272d7b
--- /dev/null
+++ b/src/configuration/e-ews-edit-folder-permissions.c
@@ -0,0 +1,1254 @@
+/* -*- 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 "e-ews-config-utils.h"
+#include "e-ews-edit-folder-permissions.h"
+#include "e-ews-search-user.h"
+
+#define E_EWS_PERM_DLG_WIDGETS "e-ews-perm-dlg-widgets"
+
+enum {
+	COL_NAME = 0,
+	COL_PERMISSION_LEVEL,
+	COL_E_EWS_PERMISSION,
+	COL_E_EWS_PERMISSION_USER_TYPE,
+	COL_IS_NEW
+};
+
+struct EEwsPermissionsDialogWidgets
+{
+	ESourceRegistry *registry;
+	ESource *source;
+	CamelEwsSettings *ews_settings;
+	EwsFolderId *folder_id;
+	EwsFolderType folder_type;
+
+	EEwsConnection *conn;
+
+	guint updating;
+
+	GtkWidget *dialog;
+	GtkWidget *tree_view;
+
+	GtkWidget *add_button;
+	GtkWidget *remove_button;
+	GtkWidget *level_combo;
+
+	GtkWidget *read_none_radio;
+	GtkWidget *read_full_radio;
+	GtkWidget *read_fb_time_radio;
+	GtkWidget *read_fb_detail_radio;
+
+	GtkWidget *write_create_items_check;
+	GtkWidget *write_create_subfolders_check;
+	GtkWidget *write_edit_own_check;
+	GtkWidget *write_edit_all_check;
+
+	GtkWidget *delete_none_radio;
+	GtkWidget *delete_own_radio;
+	GtkWidget *delete_all_radio;
+
+	GtkWidget *other_folder_owner_check;
+	GtkWidget *other_folder_contact_check;
+	GtkWidget *other_folder_visible_check;
+};
+
+static const struct EEwsPredefinedLevels {
+	const gchar *name;
+	uint32_t rights;
+} predefined_levels[] = {
+	{ NC_("PermissionsLevel", "None"), 0 },
+	{ NC_("PermissionsLevel", "Owner"), 	E_EWS_PERMISSION_BIT_READ_ANY |
+						E_EWS_PERMISSION_BIT_CREATE |
+						E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER |
+						E_EWS_PERMISSION_BIT_EDIT_OWNED |
+						E_EWS_PERMISSION_BIT_EDIT_ANY |
+						E_EWS_PERMISSION_BIT_DELETE_OWNED |
+						E_EWS_PERMISSION_BIT_DELETE_ANY |
+						E_EWS_PERMISSION_BIT_FOLDER_OWNER |
+						E_EWS_PERMISSION_BIT_FOLDER_CONTACT |
+						E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+	{ NC_("PermissionsLevel", "Publishing Editor"),
+						E_EWS_PERMISSION_BIT_READ_ANY |
+						E_EWS_PERMISSION_BIT_CREATE |
+						E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER |
+						E_EWS_PERMISSION_BIT_EDIT_OWNED |
+						E_EWS_PERMISSION_BIT_EDIT_ANY |
+						E_EWS_PERMISSION_BIT_DELETE_OWNED |
+						E_EWS_PERMISSION_BIT_DELETE_ANY |
+						E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+	{ NC_("PermissionsLevel", "Editor"),
+						E_EWS_PERMISSION_BIT_READ_ANY |
+						E_EWS_PERMISSION_BIT_CREATE |
+						E_EWS_PERMISSION_BIT_EDIT_OWNED |
+						E_EWS_PERMISSION_BIT_EDIT_ANY |
+						E_EWS_PERMISSION_BIT_DELETE_OWNED |
+						E_EWS_PERMISSION_BIT_DELETE_ANY |
+						E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+	{ NC_("PermissionsLevel", "Publishing Author"),
+						E_EWS_PERMISSION_BIT_READ_ANY |
+						E_EWS_PERMISSION_BIT_CREATE |
+						E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER |
+						E_EWS_PERMISSION_BIT_EDIT_OWNED |
+						E_EWS_PERMISSION_BIT_DELETE_OWNED |
+						E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+	{ NC_("PermissionsLevel", "Author"),
+						E_EWS_PERMISSION_BIT_READ_ANY |
+						E_EWS_PERMISSION_BIT_CREATE |
+						E_EWS_PERMISSION_BIT_EDIT_OWNED |
+						E_EWS_PERMISSION_BIT_DELETE_OWNED |
+						E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+	{ NC_("PermissionsLevel", "Nonediting Author"),
+						E_EWS_PERMISSION_BIT_READ_ANY |
+						E_EWS_PERMISSION_BIT_CREATE |
+						E_EWS_PERMISSION_BIT_DELETE_OWNED |
+						E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+	{ NC_("PermissionsLevel", "Reviewer"),
+						E_EWS_PERMISSION_BIT_READ_ANY |
+						E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+	{ NC_("PermissionsLevel", "Contributor"),
+						E_EWS_PERMISSION_BIT_CREATE |
+						E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+	{ NC_("PermissionsLevel", "Free/Busy time"),
+						E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE },
+	{ NC_("PermissionsLevel", "Free/Busy time, subject, location"),
+						E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED },
+	{ NC_("PermissionsLevel", "Custom"), ~0 } /* make sure 'Custom' is always the last */
+};
+
+static void
+edit_permissions_widgets_free (gpointer ptr)
+{
+	struct EEwsPermissionsDialogWidgets *widgets = ptr;
+
+	if (!widgets)
+		return;
+
+	g_object_unref (widgets->registry);
+	g_object_unref (widgets->source);
+	g_object_unref (widgets->ews_settings);
+	e_ews_folder_id_free (widgets->folder_id);
+	if (widgets->conn)
+		e_ews_config_utils_unref_in_thread (G_OBJECT (widgets->conn));
+	g_free (widgets);
+}
+
+static void
+folder_permissions_clear_all_permissions (GObject *dialog)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	g_return_if_fail (dialog != NULL);
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+	g_return_if_fail (widgets->tree_view != NULL);
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widgets->tree_view));
+	g_return_if_fail (model != NULL);
+
+	if (!gtk_tree_model_get_iter_first (model, &iter))
+		return;
+
+	do {
+		EEwsPermission *perm = NULL;
+
+		gtk_tree_model_get (model, &iter, COL_E_EWS_PERMISSION, &perm, -1);
+
+		e_ews_permission_free (perm);
+	} while (gtk_tree_model_iter_next (model, &iter));
+
+	gtk_list_store_clear (GTK_LIST_STORE (model));
+}
+
+static void
+write_folder_permissions_thread (GObject *dialog,
+				 gpointer user_data,
+				 GCancellable *cancellable,
+				 GError **perror)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	const GSList *permissions = user_data;
+
+	g_return_if_fail (dialog != NULL);
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+	g_return_if_fail (widgets->conn != NULL);
+
+	e_ews_connection_set_folder_permissions_sync (widgets->conn,
+		G_PRIORITY_DEFAULT, widgets->folder_id, widgets->folder_type, permissions, cancellable, perror);
+}
+
+static void
+write_folder_permissions_idle (GObject *dialog,
+			       gpointer user_data,
+			       GCancellable *cancellable,
+			       GError **perror)
+{
+	/* does this only if no error was raised from the thread function */
+	folder_permissions_clear_all_permissions (dialog);
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+edit_permissions_response_cb (GObject *dialog,
+			      gint response_id)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	GSList *write_permissions = NULL;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	g_return_if_fail (dialog != NULL);
+
+	if (response_id != GTK_RESPONSE_OK) {
+		folder_permissions_clear_all_permissions (dialog);
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+		return;
+	}
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+	g_return_if_fail (widgets->tree_view != NULL);
+	g_return_if_fail (widgets->conn != NULL);
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widgets->tree_view));
+	g_return_if_fail (model != NULL);
+
+	if (gtk_tree_model_get_iter_first (model, &iter)) {
+		do {
+			EEwsPermission *perm = NULL;
+
+			gtk_tree_model_get (model, &iter, COL_E_EWS_PERMISSION, &perm, -1);
+
+			if (perm)
+				write_permissions = g_slist_prepend (write_permissions, perm);
+		} while (gtk_tree_model_iter_next (model, &iter));
+
+		write_permissions = g_slist_reverse (write_permissions);
+	}
+
+	e_ews_config_utils_run_in_thread_with_feedback (GTK_WINDOW (dialog), dialog,
+		_("Writing folder permissions, please wait..."),
+		write_folder_permissions_thread,
+		write_folder_permissions_idle,
+		write_permissions, (GDestroyNotify) g_slist_free);
+}
+
+static void
+enable_all_widgets (struct EEwsPermissionsDialogWidgets *widgets,
+		    gboolean enabled)
+{
+	g_return_if_fail (widgets != NULL);
+
+	gtk_widget_set_sensitive (widgets->add_button, enabled || gtk_widget_get_sensitive (widgets->tree_view));
+	gtk_widget_set_sensitive (widgets->remove_button, enabled);
+	gtk_widget_set_sensitive (widgets->level_combo, enabled);
+	gtk_widget_set_sensitive (widgets->read_none_radio, enabled);
+	gtk_widget_set_sensitive (widgets->read_full_radio, enabled);
+	if (widgets->read_fb_time_radio)
+		gtk_widget_set_sensitive (widgets->read_fb_time_radio, enabled);
+	if (widgets->read_fb_detail_radio)
+		gtk_widget_set_sensitive (widgets->read_fb_detail_radio, enabled);
+	gtk_widget_set_sensitive (widgets->write_create_items_check, enabled);
+	gtk_widget_set_sensitive (widgets->write_create_subfolders_check, enabled);
+	gtk_widget_set_sensitive (widgets->write_edit_own_check, enabled);
+	gtk_widget_set_sensitive (widgets->write_edit_all_check, enabled);
+	gtk_widget_set_sensitive (widgets->delete_none_radio, enabled);
+	gtk_widget_set_sensitive (widgets->delete_own_radio, enabled);
+	gtk_widget_set_sensitive (widgets->delete_all_radio, enabled);
+	gtk_widget_set_sensitive (widgets->other_folder_owner_check, enabled);
+	gtk_widget_set_sensitive (widgets->other_folder_contact_check, enabled);
+	gtk_widget_set_sensitive (widgets->other_folder_visible_check, enabled);
+}
+
+static uint32_t
+folder_permissions_dialog_to_rights (GObject *dialog)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	uint32_t rights;
+
+	g_return_val_if_fail (dialog != NULL, 0);
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_val_if_fail (widgets != NULL, 0);
+
+	#define set_bit_by_active(x, bt) G_STMT_START {					\
+		if (widgets->x &&							\
+		    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->x)) &&	\
+		    gtk_widget_get_sensitive (widgets->x)) {				\
+			rights |= bt;							\
+		} } G_STMT_END
+
+	rights = 0;
+
+	set_bit_by_active (read_none_radio, 0);
+	set_bit_by_active (read_full_radio, E_EWS_PERMISSION_BIT_READ_ANY);
+	set_bit_by_active (read_fb_time_radio, E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+	set_bit_by_active (read_fb_detail_radio, E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED);
+	set_bit_by_active (write_create_items_check, E_EWS_PERMISSION_BIT_CREATE);
+	set_bit_by_active (write_create_subfolders_check, E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER);
+	set_bit_by_active (write_edit_own_check, E_EWS_PERMISSION_BIT_EDIT_OWNED);
+	set_bit_by_active (write_edit_all_check, E_EWS_PERMISSION_BIT_EDIT_ANY | E_EWS_PERMISSION_BIT_EDIT_OWNED);
+	set_bit_by_active (delete_none_radio, 0);
+	set_bit_by_active (delete_own_radio, E_EWS_PERMISSION_BIT_DELETE_OWNED);
+	set_bit_by_active (delete_all_radio, E_EWS_PERMISSION_BIT_DELETE_ANY | E_EWS_PERMISSION_BIT_DELETE_OWNED);
+	set_bit_by_active (other_folder_owner_check, E_EWS_PERMISSION_BIT_FOLDER_OWNER);
+	set_bit_by_active (other_folder_contact_check, E_EWS_PERMISSION_BIT_FOLDER_CONTACT);
+	set_bit_by_active (other_folder_visible_check, E_EWS_PERMISSION_BIT_FOLDER_VISIBLE);
+
+	#undef set_bit_by_active
+
+	return rights;
+}
+
+static void
+update_folder_permissions_sensitivity (GObject *dialog,
+				       gboolean member_valid,
+				       EEwsPermissionUserType user_type)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+
+	g_return_if_fail (dialog != NULL);
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+
+	enable_all_widgets (widgets, member_valid);
+
+	if (user_type == E_EWS_PERMISSION_USER_TYPE_DEFAULT ||
+	    user_type == E_EWS_PERMISSION_USER_TYPE_ANONYMOUS)
+		gtk_widget_set_sensitive (widgets->other_folder_contact_check, FALSE);
+
+	if (member_valid)
+		gtk_widget_set_sensitive (widgets->remove_button,
+			user_type != E_EWS_PERMISSION_USER_TYPE_DEFAULT &&
+			user_type != E_EWS_PERMISSION_USER_TYPE_ANONYMOUS);
+
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check))) {
+		gtk_widget_set_sensitive (widgets->write_edit_own_check, FALSE);
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->write_edit_own_check), TRUE);
+	}
+}
+
+static void
+update_folder_permissions_by_rights (GObject *dialog,
+				     uint32_t rights)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+
+	g_return_if_fail (dialog != NULL);
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+
+	#define set_active(x, act) G_STMT_START { if (widgets->x) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->x), act); } G_STMT_END
+	#define set_active_by_bit(x, bt) set_active (x, (rights & (bt)) != 0)
+
+	widgets->updating++;
+
+	set_active (read_none_radio, TRUE);
+	set_active_by_bit (read_full_radio, E_EWS_PERMISSION_BIT_READ_ANY);
+	set_active_by_bit (read_fb_time_radio, E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+	set_active_by_bit (read_fb_detail_radio, E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED);
+	set_active_by_bit (write_create_items_check, E_EWS_PERMISSION_BIT_CREATE);
+	set_active_by_bit (write_create_subfolders_check, E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER);
+	set_active_by_bit (write_edit_own_check, E_EWS_PERMISSION_BIT_EDIT_OWNED | E_EWS_PERMISSION_BIT_EDIT_ANY);
+	set_active_by_bit (write_edit_all_check, E_EWS_PERMISSION_BIT_EDIT_ANY);
+	set_active (delete_none_radio, TRUE);
+	set_active_by_bit (delete_own_radio, E_EWS_PERMISSION_BIT_DELETE_OWNED);
+	set_active_by_bit (delete_all_radio, E_EWS_PERMISSION_BIT_DELETE_ANY);
+	set_active_by_bit (other_folder_owner_check, E_EWS_PERMISSION_BIT_FOLDER_OWNER);
+	set_active_by_bit (other_folder_contact_check, E_EWS_PERMISSION_BIT_FOLDER_CONTACT);
+	set_active_by_bit (other_folder_visible_check, E_EWS_PERMISSION_BIT_FOLDER_VISIBLE);
+
+	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check)) &&
+	    gtk_widget_get_sensitive (widgets->write_edit_all_check)) {
+		gtk_widget_set_sensitive (widgets->write_edit_own_check, TRUE);
+	} else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check))) {
+		gtk_widget_set_sensitive (widgets->write_edit_own_check, FALSE);
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->write_edit_own_check), TRUE);
+	}
+
+	widgets->updating--;
+
+	#undef set_active_by_bit
+	#undef set_active
+}
+
+static void
+update_folder_permissions_tree_view (GObject *dialog,
+				     struct EEwsPermissionsDialogWidgets *widgets)
+{
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	uint32_t rights;
+
+	g_return_if_fail (dialog != NULL);
+	g_return_if_fail (widgets != NULL);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widgets->tree_view));
+	if (selection && gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		gchar *combo_text;
+		EEwsPermission *perm = NULL;
+
+		combo_text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widgets->level_combo));
+		rights = folder_permissions_dialog_to_rights (dialog);
+
+		gtk_tree_model_get (model, &iter, COL_E_EWS_PERMISSION, &perm, -1);
+
+		if (perm) {
+			if (!widgets->read_fb_time_radio)
+				rights = rights | (perm->rights & (E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED | E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE));
+
+			perm->rights = rights;
+
+			gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_PERMISSION_LEVEL, combo_text, -1);
+		}
+
+		g_free (combo_text);
+	}
+}
+
+static void
+update_permission_level_combo_by_dialog (GObject *dialog)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	uint32_t rights;
+	gint ii;
+
+	g_return_if_fail (dialog != NULL);
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+
+	if (widgets->updating)
+		return;
+
+	rights = folder_permissions_dialog_to_rights (dialog);
+	if (!widgets->read_fb_time_radio)
+		rights = rights & ~(E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED |
+			E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+
+	for (ii = 0; ii < G_N_ELEMENTS (predefined_levels) - 1; ii++) {
+		if (predefined_levels[ii].rights == rights) {
+			break;
+		}
+	}
+
+	if (!widgets->read_fb_time_radio && ii > G_N_ELEMENTS (predefined_levels) - 3)
+		ii = G_N_ELEMENTS (predefined_levels) - 3;
+
+	/* ii points to the matched or the last item, which is 'Custom' */
+	widgets->updating++;
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widgets->level_combo), ii);
+
+	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check)) &&
+	    gtk_widget_get_sensitive (widgets->write_edit_all_check)) {
+		gtk_widget_set_sensitive (widgets->write_edit_own_check, TRUE);
+		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_own_check))) {
+			rights |= E_EWS_PERMISSION_BIT_EDIT_OWNED;
+
+			for (ii = 0; ii < G_N_ELEMENTS (predefined_levels) - 1; ii++) {
+				if (predefined_levels[ii].rights == rights) {
+					break;
+				}
+			}
+
+			if (!widgets->read_fb_time_radio && ii > G_N_ELEMENTS (predefined_levels) - 3)
+				ii = G_N_ELEMENTS (predefined_levels) - 3;
+
+			gtk_combo_box_set_active (GTK_COMBO_BOX (widgets->level_combo), ii);
+		}
+	} else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check))) {
+		gtk_widget_set_sensitive (widgets->write_edit_own_check, FALSE);
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->write_edit_own_check), TRUE);
+	}
+
+	update_folder_permissions_tree_view (dialog, widgets);
+
+	widgets->updating--;
+}
+
+static void
+update_permission_dialog_by_level_combo (GObject *dialog)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	uint32_t rights;
+	gint ii;
+
+	g_return_if_fail (dialog != NULL);
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+
+	if (widgets->updating)
+		return;
+
+	ii = gtk_combo_box_get_active (GTK_COMBO_BOX (widgets->level_combo));
+	/* out of bounds or 'Customs' level, or 'Custom' without free/busy checks */
+	if (ii < 0 || ii >= G_N_ELEMENTS (predefined_levels) - 1 ||
+	    (!widgets->read_fb_time_radio && ii >= G_N_ELEMENTS (predefined_levels) - 3))
+		return;
+
+	rights = folder_permissions_dialog_to_rights (dialog);
+	rights = predefined_levels[ii].rights | (rights & (E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED |
+		E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE));
+
+	widgets->updating++;
+	update_folder_permissions_by_rights (dialog, rights);
+	update_folder_permissions_tree_view (dialog, widgets);
+	widgets->updating--;
+}
+
+static void
+add_button_clicked_cb (GObject *dialog)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	gchar *display_name = NULL;
+	gchar *primary_smtp = NULL;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	g_return_if_fail (dialog != NULL);
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+
+	if (widgets->updating)
+		return;
+
+	g_return_if_fail (widgets->tree_view != NULL);
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widgets->tree_view));
+	g_return_if_fail (model != NULL);
+
+	if (e_ews_search_user_modal (GTK_WINDOW (dialog), widgets->conn, NULL, &display_name, &primary_smtp)) {
+		EEwsPermission *perm;
+		GtkTreeSelection *selection;
+		gboolean found = FALSE;
+
+		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widgets->tree_view));
+		g_return_if_fail (selection != NULL);
+
+		if (gtk_tree_model_get_iter_first (model, &iter)) {
+			do {
+				EEwsPermissionUserType ut = E_EWS_PERMISSION_USER_TYPE_NONE;
+
+				perm = NULL;
+
+				gtk_tree_model_get (model, &iter,
+					COL_E_EWS_PERMISSION, &perm,
+					COL_E_EWS_PERMISSION_USER_TYPE, &ut,
+					-1);
+
+				if (ut == E_EWS_PERMISSION_USER_TYPE_REGULAR && perm && g_strcmp0 (perm->primary_smtp, primary_smtp)) {
+					gtk_tree_selection_select_iter (selection, &iter);
+					found = TRUE;
+					break;
+				}
+			} while (gtk_tree_model_iter_next (model, &iter));
+		}
+
+		if (!found) {
+			GtkListStore *store = GTK_LIST_STORE (model);
+
+			perm = e_ews_permission_new (E_EWS_PERMISSION_USER_TYPE_REGULAR,
+				display_name, primary_smtp, NULL,
+				widgets->read_fb_time_radio ? E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE : 0);
+
+			gtk_list_store_append (store, &iter);
+			gtk_list_store_set (store, &iter,
+				COL_NAME, perm->display_name,
+				COL_PERMISSION_LEVEL, g_dgettext ("PermissionsLevel", predefined_levels[0].name),
+				COL_E_EWS_PERMISSION, perm,
+				COL_E_EWS_PERMISSION_USER_TYPE, E_EWS_PERMISSION_USER_TYPE_REGULAR,
+				COL_IS_NEW, TRUE,
+				-1);
+
+			gtk_tree_selection_select_iter (selection, &iter);
+		}
+	}
+
+	g_free (display_name);
+	g_free (primary_smtp);
+}
+
+static void
+remove_button_clicked_cb (GObject *dialog)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model = NULL;
+	GtkTreeIter iter;
+
+	g_return_if_fail (dialog != NULL);
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+
+	if (widgets->updating)
+		return;
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widgets->tree_view));
+	if (selection && gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		GtkTreeIter select;
+		gboolean can_select = FALSE;
+		EEwsPermission *perm = NULL;
+
+		select = iter;
+		can_select = gtk_tree_model_iter_next (model, &select);
+		if (!can_select) {
+			select = iter;
+			can_select = gtk_tree_model_iter_previous (model, &select);
+		}
+
+		if (can_select)
+			gtk_tree_selection_select_iter (selection, &select);
+
+		gtk_tree_model_get (model, &iter, COL_E_EWS_PERMISSION, &perm, -1);
+
+		if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter))
+			e_ews_permission_free (perm);
+	}
+}
+
+static void
+folder_permissions_free_found_permissions (gpointer ptr)
+{
+	GSList **ppermissions = ptr;
+
+	if (!ppermissions)
+		return;
+
+	e_ews_permissions_free (*ppermissions);
+	*ppermissions = NULL;
+	g_free (ppermissions);
+}
+
+static void
+read_folder_permissions_thread (GObject *dialog,
+				gpointer user_data,
+				GCancellable *cancellable,
+				GError **perror)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	GSList **ppermissions = user_data;
+
+	g_return_if_fail (dialog != NULL);
+	g_return_if_fail (ppermissions != NULL);
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+	g_return_if_fail (widgets->registry != NULL);
+	g_return_if_fail (widgets->source != NULL);
+	g_return_if_fail (widgets->ews_settings != NULL);
+
+	widgets->conn = e_ews_config_utils_open_connection_for (GTK_WINDOW (dialog),
+		widgets->registry,
+		widgets->source,
+		widgets->ews_settings,
+		cancellable,
+		perror);
+
+	if (!widgets->conn)
+		g_cancellable_cancel (cancellable);
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	e_ews_connection_get_folder_permissions_sync (widgets->conn,
+		G_PRIORITY_DEFAULT, widgets->folder_id, ppermissions, cancellable, perror);
+}
+
+static void
+read_folder_permissions_idle (GObject *dialog,
+			      gpointer user_data,
+			      GCancellable *cancellable,
+			      GError **perror)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	GSList **ppermissions = user_data;
+	GSList *permiter;
+	GtkListStore *store;
+	GtkTreeIter iter;
+
+	g_return_if_fail (dialog != NULL);
+	g_return_if_fail (ppermissions != NULL);
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	widgets = g_object_get_data (dialog, E_EWS_PERM_DLG_WIDGETS);
+	g_return_if_fail (widgets != NULL);
+	g_return_if_fail (widgets->tree_view != NULL);
+
+	store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (widgets->tree_view)));
+	g_return_if_fail (store != NULL);
+
+	for (permiter = *ppermissions; permiter; permiter = permiter->next) {
+		EEwsPermission *perm = permiter->data;
+		const gchar *perm_level;
+		uint32_t rights;
+		gint ii;
+
+		if (!perm)
+			continue;
+
+		/* steal the perm */
+		permiter->data = NULL;
+
+		rights = perm->rights;
+		if (!widgets->read_fb_time_radio) {
+			rights = rights & ~(E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED |
+				E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+		}
+
+		for (ii = 0; ii < G_N_ELEMENTS (predefined_levels) - 1; ii++) {
+			if (predefined_levels[ii].rights == rights) {
+				break;
+			}
+		}
+
+		if (perm->user_type == E_EWS_PERMISSION_USER_TYPE_ANONYMOUS) {
+			g_free (perm->display_name);
+			perm->display_name = g_strdup (C_("User", "Anonymous"));
+		} else if (perm->user_type == E_EWS_PERMISSION_USER_TYPE_DEFAULT) {
+			g_free (perm->display_name);
+			perm->display_name = g_strdup (C_("User", "Default"));
+		} else if (!perm->display_name || !*perm->display_name) {
+			const gchar *display_name;
+
+			if (!display_name)
+				display_name = perm->primary_smtp;
+			if (!display_name)
+				display_name = C_("User", "Unknown");
+
+			g_free (perm->display_name);
+			perm->display_name = g_strdup (display_name);
+		}
+
+		perm_level = g_dgettext ("PermissionsLevel", predefined_levels[ii].name);
+
+		gtk_list_store_append (store, &iter);
+		gtk_list_store_set (store, &iter,
+			COL_NAME, perm->display_name,
+			COL_PERMISSION_LEVEL, perm_level,
+			COL_E_EWS_PERMISSION, perm,
+			COL_E_EWS_PERMISSION_USER_TYPE, perm->user_type,
+			COL_IS_NEW, FALSE,
+			-1);
+	}
+
+	gtk_widget_set_sensitive (widgets->add_button, TRUE);
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (widgets->dialog), GTK_RESPONSE_OK, TRUE);
+}
+
+static void
+folder_permissions_tree_selection_changed_cb (GtkTreeSelection *selection,
+					      struct EEwsPermissionsDialogWidgets *widgets)
+{
+	GObject *dialog;
+	GtkTreeModel *model = NULL;
+	GtkTreeIter iter;
+	gboolean has_selected;
+
+	g_return_if_fail (selection != NULL);
+	g_return_if_fail (widgets != NULL);
+	g_return_if_fail (widgets->dialog != NULL);
+	g_return_if_fail (widgets->add_button != NULL);
+	g_return_if_fail (widgets->remove_button != NULL);
+
+	dialog = G_OBJECT (widgets->dialog);
+	has_selected = gtk_tree_selection_get_selected (selection, &model, &iter);
+
+	gtk_widget_set_sensitive (widgets->add_button, TRUE);
+	gtk_widget_set_sensitive (widgets->remove_button, has_selected);
+
+	if (has_selected) {
+		EEwsPermissionUserType user_type = E_EWS_PERMISSION_USER_TYPE_NONE;
+		EEwsPermission *perm = NULL;
+
+		gtk_tree_model_get (model, &iter,
+			COL_E_EWS_PERMISSION, &perm,
+			COL_E_EWS_PERMISSION_USER_TYPE, &user_type,
+			-1);
+
+		update_folder_permissions_sensitivity (dialog, perm != NULL, user_type);
+		update_folder_permissions_by_rights (dialog, perm ? perm->rights : 0);
+	} else {
+		update_folder_permissions_sensitivity (dialog, FALSE, E_EWS_PERMISSION_USER_TYPE_NONE);
+		update_folder_permissions_by_rights (dialog, 0);
+	}
+
+	update_permission_level_combo_by_dialog (dialog);
+}
+
+static GtkWidget *
+create_permissions_tree_view (GObject *dialog,
+			      struct EEwsPermissionsDialogWidgets *widgets)
+{
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	gint pos;
+
+	g_return_val_if_fail (widgets != NULL, NULL);
+
+	tree_view = GTK_TREE_VIEW (gtk_tree_view_new_with_model (
+		GTK_TREE_MODEL (gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_BOOLEAN))));
+
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (renderer, "editable", FALSE, NULL);
+	pos = gtk_tree_view_insert_column_with_attributes (tree_view, -1, _("Name"), renderer, "text", COL_NAME, NULL);
+	column = gtk_tree_view_get_column (tree_view, pos - 1);
+	gtk_tree_view_column_set_expand (column, TRUE);
+
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (renderer, "editable", FALSE, NULL);
+	gtk_tree_view_insert_column_with_attributes (tree_view, -1, _("Permission level"), renderer, "text", COL_PERMISSION_LEVEL, NULL);
+
+	selection = gtk_tree_view_get_selection (tree_view);
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+	g_signal_connect (selection, "changed", G_CALLBACK (folder_permissions_tree_selection_changed_cb), widgets);
+
+	widgets->tree_view = GTK_WIDGET (tree_view);
+
+	return widgets->tree_view;
+}
+
+/* Opens dialog to subscribe to folders of other
+   users in the given store */
+void
+e_ews_edit_folder_permissions (GtkWindow *parent,
+			       ESourceRegistry *registry,
+			       ESource *source,
+			       CamelEwsSettings *ews_settings,
+			       const gchar *account_name,
+			       const gchar *folder_name,
+			       const EwsFolderId *folder_id,
+			       EwsFolderType folder_type)
+{
+	struct EEwsPermissionsDialogWidgets *widgets;
+	PangoAttrList *attrs;
+	GObject *dialog;
+	GtkWidget *content;
+	GtkWidget *label, *widget, *button, *frame, *hvbox;
+	GtkScrolledWindow *scrolled_window;
+	GtkComboBoxText *combo_text;
+	GtkGrid *grid;
+	GSList *radio_group, **found_permissions;
+	gboolean with_freebusy;
+	gint row, ii;
+
+	g_return_if_fail (registry != NULL);
+	g_return_if_fail (source != NULL);
+	g_return_if_fail (ews_settings != NULL);
+	g_return_if_fail (account_name != NULL);
+	g_return_if_fail (folder_name != NULL);
+	g_return_if_fail (folder_id != NULL);
+
+	with_freebusy = folder_type == EWS_FOLDER_TYPE_CALENDAR;
+
+	widgets = g_new0 (struct EEwsPermissionsDialogWidgets, 1);
+	widgets->registry = g_object_ref (registry);
+	widgets->source = g_object_ref (source);
+	widgets->ews_settings = g_object_ref (ews_settings);
+	widgets->folder_id = e_ews_folder_id_new (folder_id->id, folder_id->change_key, folder_id->is_distinguished_id);
+	widgets->folder_type = folder_type;
+
+	widgets->dialog = gtk_dialog_new_with_buttons (
+		_("Edit EWS folder permissions..."),
+		parent,
+		GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+
+	dialog = G_OBJECT (widgets->dialog);
+	g_signal_connect (dialog, "response", G_CALLBACK (edit_permissions_response_cb), NULL);
+	g_object_set_data_full (dialog, E_EWS_PERM_DLG_WIDGETS, widgets, edit_permissions_widgets_free);
+
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+	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 (account_name);
+	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, 1, 1);
+
+	row++;
+
+	label = gtk_label_new (_("Folder name:"));
+	g_object_set (G_OBJECT (label),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		NULL);
+
+	widget = gtk_label_new (folder_name);
+	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_MIDDLE);
+	gtk_widget_set_tooltip_text (widget, folder_name);
+	g_object_set (G_OBJECT (widget),
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		NULL);
+
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	label = gtk_label_new (_("Folder ID:"));
+	g_object_set (G_OBJECT (label),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		NULL);
+
+	widget = gtk_entry_new ();
+	g_object_set (G_OBJECT (widget),
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		"has-frame", FALSE,
+		"editable", FALSE,
+		"can-focus", FALSE,
+		"text", folder_id->id,
+		NULL);
+
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_scrolled_window_new (NULL, NULL);
+	scrolled_window = GTK_SCROLLED_WINDOW (widget);
+	gtk_scrolled_window_set_min_content_width (scrolled_window, 120);
+	gtk_scrolled_window_set_min_content_height (scrolled_window, 120);
+	gtk_container_add (GTK_CONTAINER (widget), create_permissions_tree_view (dialog, widgets));
+	g_object_set (G_OBJECT (widget),
+		"hexpand", TRUE,
+		"vexpand", TRUE,
+		"shadow-type", GTK_SHADOW_IN,
+		NULL);
+
+	gtk_grid_attach (grid, widget, 0, row, 2, 1);
+
+	row++;
+
+	hvbox = gtk_grid_new ();
+	gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_HORIZONTAL);
+	gtk_grid_set_column_spacing (GTK_GRID (hvbox), 6);
+	gtk_grid_set_column_homogeneous (GTK_GRID (hvbox), TRUE);
+	g_object_set (G_OBJECT (hvbox),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		"halign", GTK_ALIGN_END,
+		NULL);
+
+	button = gtk_button_new_from_stock (GTK_STOCK_ADD);
+	widgets->add_button = button;
+	gtk_container_add (GTK_CONTAINER (hvbox), button);
+
+	button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+	widgets->remove_button = button;
+	gtk_container_add (GTK_CONTAINER (hvbox), button);
+
+	gtk_grid_attach (grid, hvbox, 0, row, 2, 1);
+
+	row++;
+
+	widget = gtk_frame_new (_("Permissions"));
+	g_object_set (G_OBJECT (widget),
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		NULL);
+	gtk_grid_attach (grid, widget, 0, row, 2, 1);
+
+	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 (widget), GTK_WIDGET (grid));
+
+	row = 0;
+
+	hvbox = gtk_grid_new ();
+	gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_HORIZONTAL);
+	gtk_grid_set_column_spacing (GTK_GRID (hvbox), 6);
+
+	label = gtk_label_new_with_mnemonic (_("Permi_ssion level:"));
+	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", FALSE,
+		"entry-text-column", 0,
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		NULL));
+	widgets->level_combo = widget;
+
+	combo_text = GTK_COMBO_BOX_TEXT (widget);
+	for (ii = 0; ii < G_N_ELEMENTS (predefined_levels); ii++) {
+		if (with_freebusy ||
+		    (predefined_levels[ii].rights != E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE &&
+		     predefined_levels[ii].rights != E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED))
+			gtk_combo_box_text_append_text (combo_text, g_dgettext ("PermissionsLevel", predefined_levels[ii].name));
+	}
+	gtk_combo_box_set_active (GTK_COMBO_BOX (combo_text), 0);
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
+	gtk_container_add (GTK_CONTAINER (hvbox), label);
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	gtk_grid_attach (grid, hvbox, 0, row, 2, 1);
+
+	row++;
+
+	frame = gtk_frame_new (C_("Permissions", "Read"));
+	g_object_set (G_OBJECT (frame),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		NULL);
+
+	hvbox = gtk_grid_new ();
+	gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_VERTICAL);
+	gtk_grid_set_column_spacing (GTK_GRID (hvbox), 2);
+	gtk_container_add (GTK_CONTAINER (frame), hvbox);
+
+	widget = gtk_radio_button_new_with_label (NULL, C_("Permissions", "None"));
+	widgets->read_none_radio = widget;
+	radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	if (with_freebusy) {
+		widget = gtk_radio_button_new_with_label (radio_group, C_("Permissions", "Free/Busy time"));
+		widgets->read_fb_time_radio = widget;
+		radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+		gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+		widget = gtk_radio_button_new_with_label (radio_group, C_("Permissions", "Free/Busy time, subject, location"));
+		widgets->read_fb_detail_radio = widget;
+		radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+		gtk_container_add (GTK_CONTAINER (hvbox), widget);
+	}
+
+	widget = gtk_radio_button_new_with_label (radio_group, C_("Permissions", "Full Details"));
+	widgets->read_full_radio = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	gtk_grid_attach (grid, frame, 0, row, 1, 1);
+
+	frame = gtk_frame_new (C_("Permissions", "Write"));
+	g_object_set (G_OBJECT (frame),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		NULL);
+
+	hvbox = gtk_grid_new ();
+	gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_VERTICAL);
+	gtk_grid_set_column_spacing (GTK_GRID (hvbox), 2);
+	gtk_container_add (GTK_CONTAINER (frame), hvbox);
+
+	widget = gtk_check_button_new_with_label (C_("Permissions", "Create items"));
+	widgets->write_create_items_check = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	widget = gtk_check_button_new_with_label (C_("Permissions", "Create subfolders"));
+	widgets->write_create_subfolders_check = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	widget = gtk_check_button_new_with_label (C_("Permissions", "Edit own"));
+	widgets->write_edit_own_check = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	widget = gtk_check_button_new_with_label (C_("Permissions", "Edit all"));
+	widgets->write_edit_all_check = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	gtk_grid_attach (grid, frame, 1, row, 1, 1);
+
+	row++;
+
+	frame = gtk_frame_new (C_("Permissions", "Delete items"));
+	g_object_set (G_OBJECT (frame),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		NULL);
+
+	hvbox = gtk_grid_new ();
+	gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_VERTICAL);
+	gtk_grid_set_column_spacing (GTK_GRID (hvbox), 2);
+	gtk_container_add (GTK_CONTAINER (frame), hvbox);
+
+	widget = gtk_radio_button_new_with_label (NULL, C_("Permissions", "None"));
+	widgets->delete_none_radio = widget;
+	radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	widget = gtk_radio_button_new_with_label (radio_group, C_("Permissions", "Own"));
+	widgets->delete_own_radio = widget;
+	radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	widget = gtk_radio_button_new_with_label (radio_group, C_("Permissions", "All"));
+	widgets->delete_all_radio = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	gtk_grid_attach (grid, frame, 0, row, 1, 1);
+
+	frame = gtk_frame_new (C_("Permissions", "Other"));
+	g_object_set (G_OBJECT (frame),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		NULL);
+
+	hvbox = gtk_grid_new ();
+	gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_VERTICAL);
+	gtk_grid_set_column_spacing (GTK_GRID (hvbox), 2);
+	gtk_container_add (GTK_CONTAINER (frame), hvbox);
+
+	widget = gtk_check_button_new_with_label (C_("Permissions", "Folder owner"));
+	widgets->other_folder_owner_check = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	widget = gtk_check_button_new_with_label (C_("Permissions", "Folder contact"));
+	widgets->other_folder_contact_check = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	widget = gtk_check_button_new_with_label (C_("Permissions", "Folder visible"));
+	widgets->other_folder_visible_check = widget;
+	gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+	gtk_grid_attach (grid, frame, 1, row, 1, 1);
+
+	row++;
+
+	g_signal_connect_swapped (widgets->add_button,
+		"clicked", G_CALLBACK (add_button_clicked_cb), dialog);
+	g_signal_connect_swapped (widgets->remove_button,
+		"clicked", G_CALLBACK (remove_button_clicked_cb), dialog);
+	g_signal_connect_swapped (widgets->level_combo,
+		"changed", G_CALLBACK (update_permission_dialog_by_level_combo), dialog);
+	g_signal_connect_swapped (widgets->read_none_radio,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->read_full_radio,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	if (widgets->read_fb_time_radio)
+		g_signal_connect_swapped (widgets->read_fb_time_radio,
+			"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	if (widgets->read_fb_detail_radio)
+		g_signal_connect_swapped (widgets->read_fb_detail_radio,
+			"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->write_create_items_check,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->write_create_subfolders_check,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->write_edit_own_check,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->write_edit_all_check,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->delete_none_radio,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->delete_own_radio,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->delete_all_radio,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->other_folder_owner_check,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->other_folder_contact_check,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+	g_signal_connect_swapped (widgets->other_folder_visible_check,
+		"toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+
+	enable_all_widgets (widgets, FALSE);
+
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (widgets->dialog), GTK_RESPONSE_OK, FALSE);
+
+	gtk_widget_show_all (content);
+	gtk_widget_show (GTK_WIDGET (dialog));
+
+	found_permissions = g_new0 (GSList *, 1);
+
+	e_ews_config_utils_run_in_thread_with_feedback (GTK_WINDOW (dialog), dialog,
+		_("Reading folder permissions, please wait..."),
+		read_folder_permissions_thread,
+		read_folder_permissions_idle,
+		found_permissions, folder_permissions_free_found_permissions);
+}
diff --git a/src/configuration/e-ews-edit-folder-permissions.h b/src/configuration/e-ews-edit-folder-permissions.h
new file mode 100644
index 0000000..2940bcf
--- /dev/null
+++ b/src/configuration/e-ews-edit-folder-permissions.h
@@ -0,0 +1,43 @@
+/* -*- 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_EDIT_FOLDER_PERMISSIONS_H
+#define E_EWS_EDIT_FOLDER_PERMISSIONS_H
+
+#include <gtk/gtk.h>
+#include <libedataserver/libedataserver.h>
+
+#include "server/e-ews-item.h"
+#include "server/e-ews-folder.h"
+#include "server/camel-ews-settings.h"
+
+void	e_ews_edit_folder_permissions	(GtkWindow *parent,
+					 ESourceRegistry *registry,
+					 ESource *source,
+					 CamelEwsSettings *ews_settings,
+					 const gchar *account_name,
+					 const gchar *folder_name,
+					 const EwsFolderId *folder_id,
+					 EwsFolderType folder_type);
+
+#endif /* E_EWS_EDIT_FOLDER_PERMISSIONS_H */
diff --git a/src/configuration/e-ews-search-user.c b/src/configuration/e-ews-search-user.c
new file mode 100644
index 0000000..7ec355b
--- /dev/null
+++ b/src/configuration/e-ews-search-user.c
@@ -0,0 +1,548 @@
+/* -*- 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 "e-ews-config-utils.h"
+#include "e-ews-search-user.h"
+
+#define E_EWS_SEARCH_DLG_DATA "e-ews-search-dlg-data"
+
+enum {
+	COL_DISPLAY_NAME = 0,
+	COL_EMAIL
+};
+
+struct EEwsSearchUserData
+{
+	EEwsConnection *conn;
+	GCancellable *cancellable;
+	gchar *search_text;
+	GtkWidget *tree_view;
+	GtkWidget *info_label;
+	guint schedule_search_id;
+};
+
+static void
+e_ews_search_user_data_free (gpointer ptr)
+{
+	struct EEwsSearchUserData *pgu = ptr;
+
+	if (!pgu)
+		return;
+
+	if (pgu->schedule_search_id) {
+		g_source_remove (pgu->schedule_search_id);
+		pgu->schedule_search_id = 0;
+	}
+	if (pgu->cancellable) {
+		g_cancellable_cancel (pgu->cancellable);
+		g_object_unref (pgu->cancellable);
+		pgu->cancellable = NULL;
+	}
+	g_object_unref (pgu->conn);
+	g_free (pgu->search_text);
+	g_free (pgu);
+}
+
+struct EEwsSearchUser
+{
+	gchar *display_name;
+	gchar *email;
+};
+
+static struct EEwsSearchUser *
+e_ews_search_user_new (const gchar *display_name,
+		       const gchar *email)
+{
+	struct EEwsSearchUser *user;
+
+	if (!display_name)
+		display_name = email;
+
+	user = g_new0 (struct EEwsSearchUser, 1);
+	user->display_name = g_strdup (display_name);
+	user->email = g_strdup (email);
+
+	return user;
+}
+
+static void
+e_ews_search_user_free (gpointer ptr)
+{
+	struct EEwsSearchUser *user = ptr;
+
+	if (!user)
+		return;
+
+	g_free (user->display_name);
+	g_free (user->email);
+	g_free (user);
+}
+
+struct EEwsSearchIdleData
+{
+	EEwsConnection *conn;
+	gchar *search_text;
+	GCancellable *cancellable;
+
+	GObject *dialog;
+	GSList *found_users; /* struct EEwsSearchUser * */
+	gboolean includes_last_item;
+};
+
+static void
+e_ews_search_idle_data_free (gpointer ptr)
+{
+	struct EEwsSearchIdleData *sid = ptr;
+
+	if (!sid)
+		return;
+
+	g_object_unref (sid->conn);
+	g_object_unref (sid->cancellable);
+	g_free (sid->search_text);
+	g_slist_free_full (sid->found_users, e_ews_search_user_free);
+	g_free (sid);
+}
+
+static void
+empty_search_tree_view (GtkWidget *tree_view)
+{
+	GtkListStore *store;
+	GtkTreeModel *model;
+
+	g_return_if_fail (tree_view != NULL);
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+	g_return_if_fail (model != NULL);
+
+	store = GTK_LIST_STORE (model);
+	g_return_if_fail (store != NULL);
+
+	gtk_list_store_clear (store);
+}
+
+static void
+search_add_user (GtkListStore *store,
+		 const gchar *display_name,
+		 const gchar *email)
+{
+	GtkTreeIter iter;
+
+	g_return_if_fail (store != NULL);
+
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter,
+		COL_DISPLAY_NAME, display_name,
+		COL_EMAIL, email,
+		-1);
+}
+
+static gboolean
+search_finish_idle (gpointer user_data)
+{
+	struct EEwsSearchIdleData *sid = user_data;
+
+	g_return_val_if_fail (sid != NULL, FALSE);
+	g_return_val_if_fail (sid->dialog != NULL, FALSE);
+
+	if (!g_cancellable_is_cancelled (sid->cancellable)) {
+		struct EEwsSearchUserData *pgu;
+		GtkListStore *store;
+		guint added = 0;
+		GSList *fu;
+
+		pgu = g_object_get_data (sid->dialog, E_EWS_SEARCH_DLG_DATA);
+		g_return_val_if_fail (pgu != NULL, FALSE);
+		g_return_val_if_fail (pgu->tree_view != NULL, FALSE);
+		g_return_val_if_fail (pgu->info_label != NULL, FALSE);
+
+		empty_search_tree_view (pgu->tree_view);
+
+		store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pgu->tree_view)));
+		g_return_val_if_fail (store != NULL, FALSE);
+
+		for (fu = sid->found_users; fu; fu = fu->next) {
+			struct EEwsSearchUser *user = fu->data;
+
+			if (!user)
+				continue;
+
+			search_add_user (store, user->display_name, user->email);
+
+			added++;
+		}
+
+		if (!added) {
+			gtk_label_set_text (GTK_LABEL (pgu->info_label), _("No users found"));
+		} else if (sid->includes_last_item) {
+			gchar *str;
+			str = g_strdup_printf (ngettext ("Found one user", "Found %d users", added), added);
+			gtk_label_set_text (GTK_LABEL (pgu->info_label), str);
+			g_free (str);
+		} else {
+			gchar *str;
+			str = g_strdup_printf (ngettext ("Found more than 100 users, but showing only first %d", "Found more than 100 users, but showing only first %d", added), added);
+			gtk_label_set_text (GTK_LABEL (pgu->info_label), str);
+			g_free (str);
+		}
+	}
+
+	e_ews_search_idle_data_free (sid);
+
+	return FALSE;
+}
+
+static gpointer
+search_thread (gpointer user_data)
+{
+	struct EEwsSearchIdleData *sid = user_data;
+
+	g_return_val_if_fail (sid != NULL, NULL);
+
+	if (!g_cancellable_is_cancelled (sid->cancellable)) {
+		GSList *mailboxes = NULL;
+		GError *error = NULL;
+
+		if (e_ews_connection_resolve_names_sync (
+			sid->conn, EWS_PRIORITY_MEDIUM, sid->search_text,
+			EWS_SEARCH_AD, NULL, FALSE, &mailboxes, NULL,
+			&sid->includes_last_item, sid->cancellable, &error)) {
+			GSList *iter;
+
+			for (iter = mailboxes; iter != NULL; iter = iter->next) {
+				EwsMailbox *mb = iter->data;
+
+				if (!mb || !mb->email || !*mb->email)
+					continue;
+
+				sid->found_users = g_slist_prepend (sid->found_users,
+					e_ews_search_user_new (mb->name, mb->email));
+			}
+
+			sid->found_users = g_slist_reverse (sid->found_users);
+		}
+
+		g_slist_free_full (mailboxes, (GDestroyNotify) e_ews_mailbox_free);
+
+		if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			g_warning ("%s: Failed to search user: %s", G_STRFUNC, error->message);
+
+		g_clear_error (&error);
+
+		g_idle_add (search_finish_idle, sid);
+	} else {
+		e_ews_search_idle_data_free (sid);
+	}
+
+	return NULL;
+}
+
+static gboolean
+schedule_search_cb (gpointer user_data)
+{
+	struct EEwsSearchIdleData *sid = user_data;
+
+	g_return_val_if_fail (sid != NULL, FALSE);
+	g_return_val_if_fail (sid->dialog != NULL, FALSE);
+
+	if (!g_cancellable_is_cancelled (sid->cancellable)) {
+		struct EEwsSearchUserData *pgu;
+		GError *error = NULL;
+
+		pgu = g_object_get_data (sid->dialog, E_EWS_SEARCH_DLG_DATA);
+		g_return_val_if_fail (pgu != NULL, FALSE);
+		g_return_val_if_fail (pgu->tree_view != NULL, FALSE);
+
+		pgu->schedule_search_id = 0;
+		sid->conn = g_object_ref (pgu->conn);
+		sid->search_text = g_strdup (pgu->search_text);
+
+		if (g_thread_create (search_thread, sid, FALSE, &error)) {
+			sid = NULL;
+		} else {
+			g_object_unref (sid->conn);
+			g_warning ("%s: Failed to create search thread: %s", G_STRFUNC, error ? error->message : "Unknown error");
+		}
+
+		g_clear_error (&error);
+	}
+
+	e_ews_search_idle_data_free (sid);
+
+	return FALSE;
+}
+
+static void
+search_term_changed_cb (GtkEntry *entry,
+			GObject *dialog)
+{
+	struct EEwsSearchUserData *pgu;
+
+	g_return_if_fail (dialog != NULL);
+
+	pgu = g_object_get_data (dialog, E_EWS_SEARCH_DLG_DATA);
+	g_return_if_fail (pgu != NULL);
+	g_return_if_fail (pgu->tree_view != NULL);
+
+	if (pgu->schedule_search_id) {
+		g_source_remove (pgu->schedule_search_id);
+		pgu->schedule_search_id = 0;
+	}
+
+	if (pgu->cancellable) {
+		g_cancellable_cancel (pgu->cancellable);
+		g_object_unref (pgu->cancellable);
+	}
+
+	pgu->cancellable = g_cancellable_new ();
+
+	if (entry) {
+		g_free (pgu->search_text);
+		pgu->search_text = g_strdup (gtk_entry_get_text (entry));
+	}
+
+	empty_search_tree_view (pgu->tree_view);
+
+	if (!pgu->search_text || !*pgu->search_text) {
+		gtk_label_set_text (GTK_LABEL (pgu->info_label), _("Search for a user"));
+	} else {
+		struct EEwsSearchIdleData *sid;
+
+		sid = g_new0 (struct EEwsSearchIdleData, 1);
+		sid->cancellable = g_object_ref (pgu->cancellable);
+		sid->dialog = dialog;
+
+		gtk_label_set_text (GTK_LABEL (pgu->info_label), _("Searching..."));
+		pgu->schedule_search_id = g_timeout_add (333, schedule_search_cb, sid);
+	}
+}
+
+static void
+dialog_realized_cb (GObject *dialog)
+{
+	struct EEwsSearchUserData *pgu;
+
+	g_return_if_fail (dialog != NULL);
+
+	pgu = g_object_get_data (dialog, E_EWS_SEARCH_DLG_DATA);
+	g_return_if_fail (pgu != NULL);
+	g_return_if_fail (pgu->tree_view != NULL);
+
+	if (pgu->cancellable)
+		return;
+
+	search_term_changed_cb (NULL, dialog);
+}
+
+static void
+search_user_selection_changed_cb (GtkTreeSelection *selection,
+				  GtkDialog *dialog)
+{
+	g_return_if_fail (selection != NULL);
+	g_return_if_fail (dialog != NULL);
+
+	gtk_dialog_set_response_sensitive (dialog,
+		GTK_RESPONSE_OK,
+		gtk_tree_selection_get_selected (selection, NULL, NULL));
+}
+
+static void
+search_user_row_activated_cb (GtkTreeView *tree_view,
+			      GtkTreePath *path,
+			      GtkTreeViewColumn *column,
+			      GtkDialog *dialog)
+{
+	g_return_if_fail (tree_view != NULL);
+	g_return_if_fail (dialog != NULL);
+
+	if (path && column)
+		gtk_dialog_response (dialog, GTK_RESPONSE_OK);
+}
+
+static GtkWidget *
+create_users_tree_view (GtkWidget *dialog,
+			struct EEwsSearchUserData *pgu)
+{
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	gint pos;
+
+	g_return_val_if_fail (dialog != NULL, NULL);
+	g_return_val_if_fail (pgu != NULL, NULL);
+
+	tree_view = GTK_TREE_VIEW (gtk_tree_view_new_with_model (
+		GTK_TREE_MODEL (gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT))));
+
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (renderer, "editable", FALSE, NULL);
+	pos = gtk_tree_view_insert_column_with_attributes (tree_view, -1, _("Name"), renderer, "text", COL_DISPLAY_NAME, NULL);
+	column = gtk_tree_view_get_column (tree_view, pos - 1);
+	gtk_tree_view_column_set_expand (column, TRUE);
+
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (renderer, "editable", FALSE, NULL);
+	gtk_tree_view_insert_column_with_attributes (tree_view, -1, _("E-mail"), renderer, "text", COL_EMAIL, NULL);
+
+	selection = gtk_tree_view_get_selection (tree_view);
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+	search_user_selection_changed_cb (selection, GTK_DIALOG (dialog));
+	g_signal_connect (selection, "changed", G_CALLBACK (search_user_selection_changed_cb), dialog);
+
+	g_signal_connect (tree_view, "row-activated", G_CALLBACK (search_user_row_activated_cb), dialog);
+
+	pgu->tree_view = GTK_WIDGET (tree_view);
+
+	return pgu->tree_view;
+}
+
+gboolean
+e_ews_search_user_modal (GtkWindow *parent,
+			 EEwsConnection *conn,
+			 const gchar *search_this,
+			 gchar **display_name,
+			 gchar **email)
+{
+	gboolean res = FALSE;
+	struct EEwsSearchUserData *pgu;
+	GtkWidget *dialog;
+	GtkWidget *content, *label, *widget;
+	GtkGrid *grid;
+	GtkScrolledWindow *scrolled_window;
+	gint row;
+
+	g_return_val_if_fail (conn != NULL, FALSE);
+	g_return_val_if_fail (display_name || email, FALSE);
+
+	pgu = g_new0 (struct EEwsSearchUserData, 1);
+	pgu->conn = g_object_ref (conn);
+
+	dialog = gtk_dialog_new_with_buttons (
+		_("Choose EWS user..."),
+		parent,
+		GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+
+	g_object_set_data_full (G_OBJECT (dialog), E_EWS_SEARCH_DLG_DATA, pgu, e_ews_search_user_data_free);
+
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+	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_with_mnemonic (_("_Search:"));
+	g_object_set (G_OBJECT (label),
+		"hexpand", FALSE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		NULL);
+
+	widget = gtk_entry_new ();
+	g_object_set (G_OBJECT (widget),
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		NULL);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
+	if (search_this && *search_this) {
+		gtk_entry_set_text (GTK_ENTRY (widget), search_this);
+		pgu->search_text = g_strdup (search_this);
+	}
+
+	g_signal_connect (widget, "changed", G_CALLBACK (search_term_changed_cb), dialog);
+
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_scrolled_window_new (NULL, NULL);
+	scrolled_window = GTK_SCROLLED_WINDOW (widget);
+	gtk_scrolled_window_set_min_content_width (scrolled_window, 120);
+	gtk_scrolled_window_set_min_content_height (scrolled_window, 120);
+	gtk_container_add (GTK_CONTAINER (widget), create_users_tree_view (dialog, pgu));
+	g_object_set (G_OBJECT (widget),
+		"hexpand", TRUE,
+		"vexpand", TRUE,
+		"shadow-type", GTK_SHADOW_IN,
+		NULL);
+
+	gtk_grid_attach (grid, widget, 0, row, 2, 1);
+
+	row++;
+
+	label = gtk_label_new (_("Search for a user"));
+	g_object_set (G_OBJECT (label),
+		"hexpand", TRUE,
+		"vexpand", FALSE,
+		"xalign", 0.0,
+		NULL);
+
+	pgu->info_label = label;
+
+	gtk_grid_attach (grid, label, 0, row, 2, 1);
+
+	row++;
+
+	gtk_widget_show_all (content);
+
+	g_signal_connect (dialog, "realize", G_CALLBACK (dialog_realized_cb), NULL);
+
+	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+		GtkTreeSelection *selection;
+		GtkTreeModel *model = NULL;
+		GtkTreeIter iter;
+
+		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pgu->tree_view));
+		if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+			if (display_name)
+				gtk_tree_model_get (model, &iter, COL_DISPLAY_NAME, display_name, -1);
+			if (email)
+				gtk_tree_model_get (model, &iter, COL_EMAIL, email, -1);
+
+			res = TRUE;
+		}
+	}
+
+	gtk_widget_destroy (dialog);
+
+	return res;
+}
diff --git a/src/configuration/e-ews-search-user.h b/src/configuration/e-ews-search-user.h
new file mode 100644
index 0000000..f4a9109
--- /dev/null
+++ b/src/configuration/e-ews-search-user.h
@@ -0,0 +1,37 @@
+/* -*- 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_SEARCH_USER_H
+#define E_EWS_SEARCH_USER_H
+
+#include <gtk/gtk.h>
+#include "server/e-ews-connection.h"
+#include "server/e-ews-item.h"
+
+gboolean	e_ews_search_user_modal	(GtkWindow *parent,
+					 EEwsConnection *conn,
+					 const gchar *search_this,
+					 gchar **display_name,
+					 gchar **email);
+
+#endif /* E_EWS_SEARCH_USER_H */
diff --git a/src/configuration/module-ews-configuration.c b/src/configuration/module-ews-configuration.c
index 344d453..f71a263 100644
--- a/src/configuration/module-ews-configuration.c
+++ b/src/configuration/module-ews-configuration.c
@@ -25,6 +25,9 @@
 #include "e-mail-config-ews-oal-combo-box.h"
 #include "e-mail-config-ews-ooo-page.h"
 
+#include "e-ews-config-ui-extension.h"
+#include "server/e-source-ews-folder.h"
+
 /* Module Entry Points */
 void e_module_load (GTypeModule *type_module);
 void e_module_unload (GTypeModule *type_module);
@@ -40,6 +43,9 @@ e_module_load (GTypeModule *type_module)
 	e_mail_config_ews_notebook_type_register (type_module);
 	e_mail_config_ews_oal_combo_box_type_register (type_module);
 	e_mail_config_ews_ooo_page_type_register (type_module);
+	e_ews_config_ui_extension_type_register (type_module);
+
+	e_source_ews_folder_type_register (type_module);
 }
 
 G_MODULE_EXPORT void
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index 7f3e441..de4baa2 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -4546,9 +4546,9 @@ e_ews_connection_get_folder (EEwsConnection *cnc,
 
 	e_soap_message_start_element (msg, "FolderShape", "messages", NULL);
 	e_ews_message_write_string_parameter (msg, "BaseShape", NULL, folder_shape);
-	e_soap_message_end_element (msg);
 
 	ews_append_additional_props_to_msg (msg, add_props);
+	e_soap_message_end_element (msg);
 
 	if (folder_ids) {
 		e_soap_message_start_element (msg, "FolderIds", "messages", NULL);
@@ -6085,6 +6085,368 @@ e_ews_connection_get_delegate_sync (EEwsConnection *cnc,
 	e_async_closure_free (closure);
 
 	return success;
+}
+
+static void
+get_folder_permissions_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) {
+				subparam = node;
+
+				node = e_soap_parameter_get_first_child (subparam);
+				if (node && node->name && g_str_has_suffix ((const gchar *) node->name, "Folder")) {
+					node = e_soap_parameter_get_first_child_by_name (node, "PermissionSet");
+					if (node) {
+						async_data->items = e_ews_permissions_from_soap_param (node);
+					}
+				}
+			}
+
+			break;
+		}
+
+		subparam = e_soap_parameter_get_next_child (subparam);
+	}
+}
+
+void
+e_ews_connection_get_folder_permissions (EEwsConnection *cnc,
+					 gint pri,
+					 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, "IdOnly");
+	e_soap_message_start_element (msg, "AdditionalProperties", NULL, NULL);
+	e_ews_message_write_string_parameter_with_attribute (msg, "FieldURI", NULL, NULL, "FieldURI", "folder:PermissionSet");
+	e_soap_message_end_element (msg); /* AdditionalProperties */
+	e_soap_message_end_element (msg); /* FolderShape */
+
+	folder_ids = g_slist_append (NULL, folder_id);
+	e_soap_message_start_element (msg, "FolderIds", "messages", NULL);
+	ews_append_folder_ids_to_msg (msg, cnc->priv->email, 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_permissions);
+
+	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_permissions_response_cb,
+		pri, cancellable, simple);
+
+	g_object_unref (simple);
+}
+
+/* free permissions with e_ews_permissions_free() */
+gboolean
+e_ews_connection_get_folder_permissions_finish (EEwsConnection *cnc,
+						GAsyncResult *result,
+						GSList **permissions,
+						GError **error)
+{
+	GSimpleAsyncResult *simple;
+	EwsAsyncData *async_data;
+
+	g_return_val_if_fail (cnc != NULL, FALSE);
+	g_return_val_if_fail (permissions != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (cnc), e_ews_connection_get_folder_permissions),
+		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;
+
+	*permissions = async_data->items;
+
+	return TRUE;
+}
+
+/* free permissions with e_ews_permissions_free() */
+gboolean
+e_ews_connection_get_folder_permissions_sync (EEwsConnection *cnc,
+					      gint pri,
+					      EwsFolderId *folder_id,
+					      GSList **permissions,
+					      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 (permissions != NULL, FALSE);
+
+	closure = e_async_closure_new ();
+
+	e_ews_connection_get_folder_permissions (
+		cnc, pri, folder_id, cancellable,
+		e_async_closure_callback, closure);
+
+	result = e_async_closure_wait (closure);
+
+	success = e_ews_connection_get_folder_permissions_finish (
+		cnc, result, permissions, error);
+
+	e_async_closure_free (closure);
+
+	return success;
+}
+
+void
+e_ews_connection_set_folder_permissions (EEwsConnection *cnc,
+					 gint pri,
+					 EwsFolderId *folder_id,
+					 EwsFolderType folder_type,
+					 const GSList *permissions,
+					 GCancellable *cancellable,
+					 GAsyncReadyCallback callback,
+					 gpointer user_data)
+{
+	ESoapMessage *msg;
+	GSimpleAsyncResult *simple;
+	EwsAsyncData *async_data;
+	const GSList *iter;
+
+	g_return_if_fail (cnc != NULL);
+	g_return_if_fail (folder_id != NULL);
+	g_return_if_fail (permissions != NULL);
+
+	msg = e_ews_message_new_with_header (cnc->priv->uri, "UpdateFolder",
+					     NULL, NULL, EWS_EXCHANGE_2007_SP1);
 
+	e_soap_message_start_element (msg, "FolderChanges", "messages", NULL);
+	e_ews_message_start_item_change (msg, E_EWS_ITEMCHANGE_TYPE_FOLDER,
+					 folder_id->id, folder_id->change_key, 0);
+
+	e_soap_message_start_element (msg, "SetFolderField", NULL, NULL);
+	e_ews_message_write_string_parameter_with_attribute (msg, "FieldURI", NULL, NULL, "FieldURI", "folder:PermissionSet");
+
+	switch (folder_type) {
+	default:
+	case EWS_FOLDER_TYPE_MAILBOX:
+		e_soap_message_start_element (msg, "Folder", NULL, NULL);
+		break;
+	case EWS_FOLDER_TYPE_CALENDAR:
+		e_soap_message_start_element (msg, "CalendarFolder", NULL, NULL);
+		break;
+	case EWS_FOLDER_TYPE_CONTACTS:
+		e_soap_message_start_element (msg, "ContactsFolder", NULL, NULL);
+		break;
+	case EWS_FOLDER_TYPE_QUERY:
+		e_soap_message_start_element (msg, "SearchFolder", NULL, NULL);
+		break;
+	case EWS_FOLDER_TYPE_TASKS:
+		e_soap_message_start_element (msg, "TasksFolder", NULL, NULL);
+		break;
+	}
+
+	e_soap_message_start_element (msg, "PermissionSet", NULL, NULL);
+	e_soap_message_start_element (msg, "Permissions", NULL, NULL);
+
+	for (iter = permissions; iter; iter = iter->next) {
+		EEwsPermission *perm = iter->data;
+		const gchar *perm_level_name;
+
+		if (!perm)
+			continue;
+
+		if (folder_type == EWS_FOLDER_TYPE_CALENDAR)
+			e_soap_message_start_element (msg, "CalendarPermission", NULL, NULL);
+		else
+			e_soap_message_start_element (msg, "Permission", NULL, NULL);
+
+		e_soap_message_start_element (msg, "UserId", NULL, NULL);
+
+		switch (perm->user_type) {
+		case E_EWS_PERMISSION_USER_TYPE_NONE:
+			g_return_if_reached ();
+			break;
+		case E_EWS_PERMISSION_USER_TYPE_ANONYMOUS:
+			e_ews_message_write_string_parameter (msg, "DistinguishedUser", NULL, "Anonymous");
+			break;
+		case E_EWS_PERMISSION_USER_TYPE_DEFAULT:
+			e_ews_message_write_string_parameter (msg, "DistinguishedUser", NULL, "Default");
+			break;
+		case E_EWS_PERMISSION_USER_TYPE_REGULAR:
+			e_ews_message_write_string_parameter (msg, "PrimarySmtpAddress", NULL, perm->primary_smtp);
+			break;
+		}
+
+		e_soap_message_end_element (msg); /* UserId */
+
+		e_ews_permission_rights_to_level_name (perm->rights);
+
+		perm_level_name = e_ews_permission_rights_to_level_name (perm->rights);
+
+		if (g_strcmp0 (perm_level_name, "Custom") == 0) {
+			e_ews_message_write_string_parameter (msg, "CanCreateItems", NULL,
+				(perm->rights & E_EWS_PERMISSION_BIT_CREATE) != 0 ? "true" : "false");
+			e_ews_message_write_string_parameter (msg, "CanCreateSubFolders", NULL,
+				(perm->rights & E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER) != 0 ? "true" : "false");
+			e_ews_message_write_string_parameter (msg, "IsFolderOwner", NULL,
+				(perm->rights & E_EWS_PERMISSION_BIT_FOLDER_OWNER) != 0 ? "true" : "false");
+			e_ews_message_write_string_parameter (msg, "IsFolderVisible", NULL,
+				(perm->rights & E_EWS_PERMISSION_BIT_FOLDER_VISIBLE) != 0 ? "true" : "false");
+			e_ews_message_write_string_parameter (msg, "IsFolderContact", NULL,
+				(perm->rights & E_EWS_PERMISSION_BIT_FOLDER_CONTACT) != 0 ? "true" : "false");
+			e_ews_message_write_string_parameter (msg, "EditItems", NULL,
+				(perm->rights & E_EWS_PERMISSION_BIT_EDIT_ANY) != 0 ? "All" :
+				(perm->rights & E_EWS_PERMISSION_BIT_EDIT_OWNED) != 0 ? "Owned" : "None");
+			e_ews_message_write_string_parameter (msg, "DeleteItems", NULL,
+				(perm->rights & E_EWS_PERMISSION_BIT_DELETE_ANY) != 0 ? "All" :
+				(perm->rights & E_EWS_PERMISSION_BIT_DELETE_OWNED) != 0 ? "Owned" : "None");
+			if (folder_type == EWS_FOLDER_TYPE_CALENDAR)
+				e_ews_message_write_string_parameter (msg, "ReadItems", NULL,
+					(perm->rights & E_EWS_PERMISSION_BIT_READ_ANY) != 0 ? "FullDetails" :
+					(perm->rights & E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED) != 0 ? "TimeAndSubjectAndLocation" :
+					(perm->rights & E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE) != 0 ? "TimeOnly" : "None");
+			else
+				e_ews_message_write_string_parameter (msg, "ReadItems", NULL,
+					(perm->rights & E_EWS_PERMISSION_BIT_READ_ANY) != 0 ? "FullDetails" : "None");
+		}
+
+		e_ews_message_write_string_parameter (msg,
+			folder_type == EWS_FOLDER_TYPE_CALENDAR ? "CalendarPermissionLevel" : "PermissionLevel", NULL,
+			perm_level_name);
+
+		e_soap_message_end_element (msg); /* Permission/CalendarPermission */
+	}
+
+	e_soap_message_end_element (msg); /* Permissions */
+	e_soap_message_end_element (msg); /* PermissionSet */
+	e_soap_message_end_element (msg); /* Folder/CalendarFolder/... */
+	e_soap_message_end_element (msg); /* SetFolderField */
+
+	e_ews_message_end_item_change (msg);
+
+	e_ews_message_write_footer (msg);
+
+	simple = g_simple_async_result_new (G_OBJECT (cnc),
+				      callback,
+				      user_data,
+				      e_ews_connection_set_folder_permissions);
+
+	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, update_folder_response_cb,
+		pri, cancellable, simple);
+
+	g_object_unref (simple);
+}
+
+gboolean
+e_ews_connection_set_folder_permissions_finish (EEwsConnection *cnc,
+						GAsyncResult *result,
+						GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (cnc != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (cnc), e_ews_connection_set_folder_permissions),
+		FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
+gboolean
+e_ews_connection_set_folder_permissions_sync (EEwsConnection *cnc,
+					      gint pri,
+					      EwsFolderId *folder_id,
+					      EwsFolderType folder_type,
+					      const GSList *permissions,
+					      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 (permissions != NULL, FALSE);
+
+	closure = e_async_closure_new ();
+
+	e_ews_connection_set_folder_permissions (
+		cnc, pri, folder_id, folder_type, permissions, cancellable,
+		e_async_closure_callback, closure);
+
+	result = e_async_closure_wait (closure);
+
+	success = e_ews_connection_set_folder_permissions_finish (
+		cnc, result, 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 e799d3e..6bc2387 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -807,6 +807,46 @@ gboolean	e_ews_connection_get_delegate_sync
 						 EwsDelegateInfo **get_delegate,
 						 GCancellable *cancellable,
 						 GError **error);
+void		e_ews_connection_get_folder_permissions
+						(EEwsConnection *cnc,
+						 gint pri,
+						 EwsFolderId *folder_id,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_ews_connection_get_folder_permissions_finish
+						(EEwsConnection *cnc,
+						 GAsyncResult *result,
+						 GSList **permissions,
+						 GError **error);
+gboolean	e_ews_connection_get_folder_permissions_sync
+						(EEwsConnection *cnc,
+						 gint pri,
+						 EwsFolderId *folder_id,
+						 GSList **permissions,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_ews_connection_set_folder_permissions
+						(EEwsConnection *cnc,
+						 gint pri,
+						 EwsFolderId *folder_id,
+						 EwsFolderType folder_type,
+						 const GSList *permissions,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_ews_connection_set_folder_permissions_finish
+						(EEwsConnection *cnc,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean	e_ews_connection_set_folder_permissions_sync
+						(EEwsConnection *cnc,
+						 gint pri,
+						 EwsFolderId *folder_id,
+						 EwsFolderType folder_type,
+						 const GSList *permissions,
+						 GCancellable *cancellable,
+						 GError **error);
 
 G_END_DECLS
 
diff --git a/src/server/e-ews-folder.c b/src/server/e-ews-folder.c
index 22adea4..ee5c227 100644
--- a/src/server/e-ews-folder.c
+++ b/src/server/e-ews-folder.c
@@ -207,8 +207,23 @@ e_ews_folder_new_from_soap_parameter (ESoapParameter *param)
 	return folder;
 }
 
+EwsFolderId *
+e_ews_folder_id_new (const gchar *id,
+		     const gchar *change_key,
+		     gboolean is_distinguished_id)
+{
+	EwsFolderId *fid;
+
+	fid = g_new0 (EwsFolderId, 1);
+	fid->id = g_strdup (id);
+	fid->change_key = g_strdup (change_key);
+	fid->is_distinguished_id = is_distinguished_id;
+
+	return fid;
+}
+
 void
-e_ews_folder_free_fid (EwsFolderId *fid)
+e_ews_folder_id_free (EwsFolderId *fid)
 {
 	if (fid) {
 		g_free (fid->id);
@@ -319,4 +334,3 @@ e_ews_folder_get_child_count (EEwsFolder *folder)
 	return folder->priv->child_count;
 
 }
-
diff --git a/src/server/e-ews-folder.h b/src/server/e-ews-folder.h
index 6272971..47127b3 100644
--- a/src/server/e-ews-folder.h
+++ b/src/server/e-ews-folder.h
@@ -76,7 +76,10 @@ void		e_ews_folder_set_is_writable (EEwsFolder *folder, gboolean writable);
 EwsFolderType	e_ews_folder_get_folder_type (EEwsFolder *folder);
 void		e_ews_folder_set_folder_type (EEwsFolder *folder, EwsFolderType folder_type);
 
-void		e_ews_folder_free_fid (EwsFolderId *fid);
+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);
 
 G_END_DECLS
 
diff --git a/src/server/e-ews-item.c b/src/server/e-ews-item.c
index 3ba2653..2266396 100644
--- a/src/server/e-ews-item.c
+++ b/src/server/e-ews-item.c
@@ -21,6 +21,7 @@
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
+
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -1949,3 +1950,344 @@ e_ews_free_resolve_contact (gpointer rc)
 	g_hash_table_unref (resc->email_addresses);
 	g_free (resc);
 }
+
+/* free returned pointer with e_ews_permission_free() */
+EEwsPermission *
+e_ews_permission_new (EEwsPermissionUserType user_type,
+		      const gchar *display_name,
+		      const gchar *primary_smtp,
+		      const gchar *sid,
+		      guint32 rights)
+{
+	EEwsPermission *perm;
+
+	perm = g_new0 (EEwsPermission, 1);
+	perm->user_type = user_type;
+	perm->display_name = g_strdup (display_name);
+	perm->primary_smtp = g_strdup (primary_smtp);
+	perm->sid = g_strdup (sid);
+	perm->rights = rights;
+
+	return perm;
+}
+
+void
+e_ews_permission_free (EEwsPermission *perm)
+{
+	if (!perm)
+		return;
+
+	g_free (perm->display_name);
+	g_free (perm->primary_smtp);
+	g_free (perm->sid);
+	g_free (perm);
+}
+
+static void
+ews_level_rights_converter (const gchar **plevel_name,
+			    guint32 *prights,
+			    gboolean level_to_rights)
+{
+	struct _known {
+		const gchar *level_name;
+		guint32 rights;
+	} known[] = {
+		{ "None", 0 },
+		{ "Owner",	E_EWS_PERMISSION_BIT_READ_ANY |
+				E_EWS_PERMISSION_BIT_CREATE |
+				E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER |
+				E_EWS_PERMISSION_BIT_EDIT_OWNED |
+				E_EWS_PERMISSION_BIT_EDIT_ANY |
+				E_EWS_PERMISSION_BIT_DELETE_OWNED |
+				E_EWS_PERMISSION_BIT_DELETE_ANY |
+				E_EWS_PERMISSION_BIT_FOLDER_OWNER |
+				E_EWS_PERMISSION_BIT_FOLDER_CONTACT |
+				E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+		{ "PublishingEditor", 
+				E_EWS_PERMISSION_BIT_READ_ANY |
+				E_EWS_PERMISSION_BIT_CREATE |
+				E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER |
+				E_EWS_PERMISSION_BIT_EDIT_OWNED |
+				E_EWS_PERMISSION_BIT_EDIT_ANY |
+				E_EWS_PERMISSION_BIT_DELETE_OWNED |
+				E_EWS_PERMISSION_BIT_DELETE_ANY |
+				E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+		{ "Editor",
+				E_EWS_PERMISSION_BIT_READ_ANY |
+				E_EWS_PERMISSION_BIT_CREATE |
+				E_EWS_PERMISSION_BIT_EDIT_OWNED |
+				E_EWS_PERMISSION_BIT_EDIT_ANY |
+				E_EWS_PERMISSION_BIT_DELETE_OWNED |
+				E_EWS_PERMISSION_BIT_DELETE_ANY |
+				E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+		{ "PublishingAuthor",
+				E_EWS_PERMISSION_BIT_READ_ANY |
+				E_EWS_PERMISSION_BIT_CREATE |
+				E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER |
+				E_EWS_PERMISSION_BIT_EDIT_OWNED |
+				E_EWS_PERMISSION_BIT_DELETE_OWNED |
+				E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+		{ "Author",
+				E_EWS_PERMISSION_BIT_READ_ANY |
+				E_EWS_PERMISSION_BIT_CREATE |
+				E_EWS_PERMISSION_BIT_EDIT_OWNED |
+				E_EWS_PERMISSION_BIT_DELETE_OWNED |
+				E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+		{ "NoneditingAuthor",
+				E_EWS_PERMISSION_BIT_READ_ANY |
+				E_EWS_PERMISSION_BIT_CREATE |
+				E_EWS_PERMISSION_BIT_DELETE_OWNED |
+				E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+		{ "Reviewer",
+				E_EWS_PERMISSION_BIT_READ_ANY |
+				E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+		{ "Contributor",
+				E_EWS_PERMISSION_BIT_CREATE |
+				E_EWS_PERMISSION_BIT_FOLDER_VISIBLE },
+		{ "FreeBusyTimeOnly",
+				E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE },
+		{ "FreeBusyTimeAndSubjectAndLocation",
+				E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED }
+				
+	};
+	gint ii;
+	guint32 rights;
+
+	g_return_if_fail (plevel_name != NULL);
+	g_return_if_fail (prights != NULL);
+
+	rights = (*prights) & ~(E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE | E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED);
+
+	for (ii = 0; ii < G_N_ELEMENTS (known); ii++) {
+		if (level_to_rights) {
+			if (g_strcmp0 (*plevel_name, known[ii].level_name) == 0) {
+				*prights = known[ii].rights;
+				return;
+			}
+		} else {
+			if (*prights == known[ii].rights || (rights && rights == known[ii].rights)) {
+				*plevel_name = known[ii].level_name;
+				return;
+			}
+		}
+	}
+
+	/* here lefts only "Custom" */
+	if (level_to_rights)
+		*prights = 0;
+	else
+		*plevel_name = "Custom";
+}
+
+/* converts user rights to level name suitable for PermissionLevel/CalendarPermissionLevel */
+const gchar *
+e_ews_permission_rights_to_level_name (guint32 rights)
+{
+	const gchar *level_name = NULL;
+
+	ews_level_rights_converter (&level_name, &rights, FALSE);
+
+	return level_name;
+}
+
+/* converts PermissionLevel/CalendarPermissionLevel name to user rights */
+guint32
+e_ews_permission_level_name_to_rights (const gchar *level_name)
+{
+	guint32 rights = 0;
+
+	ews_level_rights_converter (&level_name, &rights, TRUE);
+
+	return rights;
+}
+
+static EEwsPermission *
+ews_permissions_parse (ESoapParameter *param)
+{
+	EEwsPermission *res;
+	ESoapParameter *node, *subnode;
+	EEwsPermissionUserType user_type;
+	gchar *value, *display_name = NULL, *primary_smtp = NULL, *sid = NULL;
+	guint32 rights = 0;
+
+	g_return_val_if_fail (param != NULL, NULL);
+
+	node = e_soap_parameter_get_first_child_by_name (param, "UserId");
+	if (!node)
+		return NULL;
+
+	subnode = e_soap_parameter_get_first_child_by_name (node, "DistinguishedUser");
+	if (subnode) {
+		value = e_soap_parameter_get_string_value (subnode);
+		if (g_strcmp0 (value, "Anonymous") == 0) {
+			user_type = E_EWS_PERMISSION_USER_TYPE_ANONYMOUS;
+		} else if (g_strcmp0 (value, "Default") == 0) {
+			user_type = E_EWS_PERMISSION_USER_TYPE_DEFAULT;
+		} else {
+			g_free (value);
+			return NULL;
+		}
+
+		g_free (value);
+	} else {
+		user_type = E_EWS_PERMISSION_USER_TYPE_REGULAR;
+	}
+
+	subnode = e_soap_parameter_get_first_child_by_name (node, "SID");
+	if (subnode)
+		sid = e_soap_parameter_get_string_value (subnode);
+
+	subnode = e_soap_parameter_get_first_child_by_name (node, "PrimarySmtpAddress");
+	if (subnode)
+		primary_smtp = e_soap_parameter_get_string_value (subnode);
+
+	subnode = e_soap_parameter_get_first_child_by_name (node, "DisplayName");
+	if (subnode)
+		display_name = e_soap_parameter_get_string_value (subnode);
+
+	node = e_soap_parameter_get_first_child_by_name (param, "PermissionLevel");
+	if (!node)
+		node = e_soap_parameter_get_first_child_by_name (param, "CalendarPermissionLevel");
+
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		rights = e_ews_permission_level_name_to_rights (value);
+		g_free (value);
+	}
+
+	node = e_soap_parameter_get_first_child_by_name (param, "CanCreateItems");
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		if (g_strcmp0 (value, "true") == 0)
+			rights |= E_EWS_PERMISSION_BIT_CREATE;
+		g_free (value);
+	}
+
+	node = e_soap_parameter_get_first_child_by_name (param, "CanCreateSubFolders");
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		if (g_strcmp0 (value, "true") == 0)
+			rights |= E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER;
+		g_free (value);
+	}
+
+	node = e_soap_parameter_get_first_child_by_name (param, "IsFolderOwner");
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		if (g_strcmp0 (value, "true") == 0)
+			rights |= E_EWS_PERMISSION_BIT_FOLDER_OWNER;
+		g_free (value);
+	}
+
+	node = e_soap_parameter_get_first_child_by_name (param, "IsFolderVisible");
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		if (g_strcmp0 (value, "true") == 0)
+			rights |= E_EWS_PERMISSION_BIT_FOLDER_VISIBLE;
+		g_free (value);
+	}
+
+	node = e_soap_parameter_get_first_child_by_name (param, "IsFolderContact");
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		if (g_strcmp0 (value, "true") == 0)
+			rights |= E_EWS_PERMISSION_BIT_FOLDER_CONTACT;
+		g_free (value);
+	}
+
+	node = e_soap_parameter_get_first_child_by_name (param, "EditItems");
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		if (g_strcmp0 (value, "None") == 0)
+			rights |= 0;
+		else if (g_strcmp0 (value, "Owned") == 0)
+			rights |= E_EWS_PERMISSION_BIT_EDIT_OWNED;
+		else if (g_strcmp0 (value, "All") == 0)
+			rights |= E_EWS_PERMISSION_BIT_EDIT_ANY;
+		g_free (value);
+	}
+
+	node = e_soap_parameter_get_first_child_by_name (param, "DeleteItems");
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		if (g_strcmp0 (value, "None") == 0)
+			rights |= 0;
+		else if (g_strcmp0 (value, "Owned") == 0)
+			rights |= E_EWS_PERMISSION_BIT_DELETE_OWNED;
+		else if (g_strcmp0 (value, "All") == 0)
+			rights |= E_EWS_PERMISSION_BIT_DELETE_ANY;
+		g_free (value);
+	}
+
+	node = e_soap_parameter_get_first_child_by_name (param, "ReadItems");
+	if (node) {
+		value = e_soap_parameter_get_string_value (node);
+		if (g_strcmp0 (value, "None") == 0)
+			rights |= 0;
+		else if (g_strcmp0 (value, "TimeOnly") == 0)
+			rights |= E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE;
+		else if (g_strcmp0 (value, "TimeAndSubjectAndLocation") == 0)
+			rights |= E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED;
+		else if (g_strcmp0 (value, "FullDetails") == 0)
+			rights |= E_EWS_PERMISSION_BIT_READ_ANY;
+		g_free (value);
+	}
+
+	res = e_ews_permission_new (user_type, display_name, primary_smtp, sid, rights);
+
+	g_free (display_name);
+	g_free (primary_smtp);
+	g_free (sid);
+
+	return res;
+}
+
+/* Returns GSList of EEwsPermission * objects, as read from @param.
+   Returned GSList should be freed with e_ews_permissions_free()
+   when done with it. Returns NULL when no permissions recognized
+   from @param.
+*/
+GSList *
+e_ews_permissions_from_soap_param (ESoapParameter *param)
+{
+	GSList *perms = NULL;
+	ESoapParameter *node;
+	const gchar *name;
+
+	g_return_val_if_fail (param != NULL, NULL);
+
+	name = e_soap_parameter_get_name (param);
+	if (g_ascii_strcasecmp (name, "Permissions") == 0 ||
+	    g_ascii_strcasecmp (name, "CalendarPermissions") == 0) {
+		node = param;
+	} else {
+		node = e_soap_parameter_get_first_child_by_name (param, "Permissions");
+		if (!node)
+			node = e_soap_parameter_get_first_child_by_name (param, "CalendarPermissions");
+		if (!node)
+			return NULL;
+	}
+
+	for (node = e_soap_parameter_get_first_child (node);
+	     node;
+	     node = e_soap_parameter_get_next_child (node)) {
+		name = e_soap_parameter_get_name (node);
+		if (g_ascii_strcasecmp (name, "Permission") == 0 ||
+		    g_ascii_strcasecmp (name, "CalendarPermission") == 0) {
+			EEwsPermission *perm;
+
+			perm = ews_permissions_parse (node);
+			if (perm) {
+				perms = g_slist_prepend (perms, perm);
+			}
+		}
+	}
+
+	return perms ? g_slist_reverse (perms) : NULL;
+}
+
+void
+e_ews_permissions_free (GSList *permissions)
+{
+	g_slist_free_full (permissions, (GDestroyNotify) e_ews_permission_free);
+}
diff --git a/src/server/e-ews-item.h b/src/server/e-ews-item.h
index 47db6de..cd2bfab 100644
--- a/src/server/e-ews-item.h
+++ b/src/server/e-ews-item.h
@@ -112,6 +112,36 @@ typedef struct {
 	gchar *postal_code;
 } EwsAddress;
 
+typedef enum {
+	E_EWS_PERMISSION_BIT_FREE_BUSY_DETAILED	= 0x00001000,
+	E_EWS_PERMISSION_BIT_FREE_BUSY_SIMPLE	= 0x00000800,
+	E_EWS_PERMISSION_BIT_FOLDER_VISIBLE	= 0x00000400,
+	E_EWS_PERMISSION_BIT_FOLDER_CONTACT	= 0x00000200,
+	E_EWS_PERMISSION_BIT_FOLDER_OWNER	= 0x00000100,
+	E_EWS_PERMISSION_BIT_CREATE_SUBFOLDER	= 0x00000080,
+	E_EWS_PERMISSION_BIT_DELETE_ANY		= 0x00000040,
+	E_EWS_PERMISSION_BIT_EDIT_ANY		= 0x00000020,
+	E_EWS_PERMISSION_BIT_DELETE_OWNED	= 0x00000010,
+	E_EWS_PERMISSION_BIT_EDIT_OWNED		= 0x00000008,
+	E_EWS_PERMISSION_BIT_CREATE		= 0x00000002,
+	E_EWS_PERMISSION_BIT_READ_ANY		= 0x00000001
+} EEwsPermissionBits;
+
+typedef enum {
+	E_EWS_PERMISSION_USER_TYPE_NONE		= 0,
+	E_EWS_PERMISSION_USER_TYPE_ANONYMOUS	= 1 << 1, /* anonymous user */
+	E_EWS_PERMISSION_USER_TYPE_DEFAULT	= 1 << 2, /* default rights for any users */
+	E_EWS_PERMISSION_USER_TYPE_REGULAR	= 1 << 3  /* regular user, the EEwsPermission::user_smtp member is valid */
+} EEwsPermissionUserType;
+
+typedef struct {
+	EEwsPermissionUserType user_type;	/* whether is distinguished name, if 'true' */
+	gchar *display_name;			/* display name for a user */
+	gchar *primary_smtp;			/* valid only for E_EWS_PERMISSION_USER_TYPE_REGULAR */
+	gchar *sid;				/* security identifier (SID), if any */
+	guint32 rights;				/* EEwsPermissionBits for the user */
+} EEwsPermission;
+
 GType		e_ews_item_get_type (void);
 EEwsItem *	e_ews_item_new_from_soap_parameter
 						(ESoapParameter *param);
@@ -230,6 +260,23 @@ gboolean	e_ews_item_task_has_complete_date
 						 gboolean * has_date);
 const gchar *	e_ews_item_get_tzid		(EEwsItem *item);
 
+/* Folder Permissions */
+EEwsPermission *e_ews_permission_new		(EEwsPermissionUserType user_type,
+						 const gchar *display_name,
+						 const gchar *primary_smtp,
+						 const gchar *sid,
+						 guint32 rights);
+void		e_ews_permission_free		(EEwsPermission *perm);
+
+const gchar *	e_ews_permission_rights_to_level_name
+						(guint32 rights);
+guint32		e_ews_permission_level_name_to_rights
+						(const gchar *level_name);
+
+GSList *	e_ews_permissions_from_soap_param
+						(ESoapParameter *param);
+void		e_ews_permissions_free (GSList *permissions);
+
 G_END_DECLS
 
 #endif
diff --git a/src/server/e-source-ews-folder.c b/src/server/e-source-ews-folder.c
index 7a632dc..dcdc6b5 100644
--- a/src/server/e-source-ews-folder.c
+++ b/src/server/e-source-ews-folder.c
@@ -186,7 +186,7 @@ e_source_ews_folder_dup_change_key (ESourceEwsFolder *extension)
 
 	g_mutex_lock (extension->priv->property_lock);
 
-	protected = e_source_ews_folder_get_id (extension);
+	protected = e_source_ews_folder_get_change_key (extension);
 	duplicate = g_strdup (protected);
 
 	g_mutex_unlock (extension->priv->property_lock);
@@ -262,3 +262,19 @@ e_source_ews_folder_set_id (ESourceEwsFolder *extension,
 	g_object_notify (G_OBJECT (extension), "id");
 }
 
+/* free returned pointer with e_ews_folder_id_free() */
+EwsFolderId *
+e_source_ews_folder_dup_folder_id (ESourceEwsFolder *extension)
+{
+	EwsFolderId *folder_id;
+
+	g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), NULL);
+
+	g_mutex_lock (extension->priv->property_lock);
+
+	folder_id = e_ews_folder_id_new (extension->priv->id, extension->priv->change_key, FALSE);
+
+	g_mutex_unlock (extension->priv->property_lock);
+
+	return folder_id;
+}
diff --git a/src/server/e-source-ews-folder.h b/src/server/e-source-ews-folder.h
index 65e8035..f6202bd 100644
--- a/src/server/e-source-ews-folder.h
+++ b/src/server/e-source-ews-folder.h
@@ -20,6 +20,7 @@
 #define E_SOURCE_EWS_FOLDER_H
 
 #include <libedataserver/libedataserver.h>
+#include "server/e-ews-folder.h"
 
 /* Standard GObject macros */
 #define E_TYPE_SOURCE_EWS_FOLDER \
@@ -72,6 +73,9 @@ gchar *		e_source_ews_folder_dup_id	(ESourceEwsFolder *extension);
 void		e_source_ews_folder_set_id	(ESourceEwsFolder *extension,
 						 const gchar *id);
 
+EwsFolderId *	e_source_ews_folder_dup_folder_id
+						(ESourceEwsFolder *extension);
+
 G_END_DECLS
 
 #endif /* E_SOURCE_EWS_FOLDER_H */
diff --git a/src/server/tests/test-createfolder.c b/src/server/tests/test-createfolder.c
index 6742f95..9eb46b7 100644
--- a/src/server/tests/test-createfolder.c
+++ b/src/server/tests/test-createfolder.c
@@ -63,7 +63,7 @@ create_folder_cb (GObject *object,
 	folder_id->id = g_strdup (fid->id);
 	folder_id->change_key = g_strdup (fid->change_key);
 
-	e_ews_folder_free_fid (fid);
+	e_ews_folder_id_free (fid);
 
 quit:
 	g_main_loop_quit (main_loop);
diff --git a/src/server/tests/test-libews.c b/src/server/tests/test-libews.c
index 5fdced4..4675d58 100644
--- a/src/server/tests/test-libews.c
+++ b/src/server/tests/test-libews.c
@@ -23,7 +23,7 @@ static void
 finalize_test_data ()
 {
 	if (folder_id) {
-		e_ews_folder_free_fid (folder_id);
+		e_ews_folder_id_free (folder_id);
 		folder_id = NULL;
 	}
 }
diff --git a/src/utils/ews-test-finditem-query.c b/src/utils/ews-test-finditem-query.c
index 6d0a2ee..b6e6609 100644
--- a/src/utils/ews-test-finditem-query.c
+++ b/src/utils/ews-test-finditem-query.c
@@ -129,7 +129,7 @@ op_test_finditem_run (void)
 		"IdOnly", NULL, NULL, CONTACTS_QUERY,
 		folder_type, (EwsConvertQueryCallback) (e_ews_query_to_restriction),
 		cancellable, find_folder_item_callback, (gpointer) folder_name);
-	e_ews_folder_free_fid (fid);
+	e_ews_folder_id_free (fid);
 
 	/*Check for calendar folder*/
 	folder_name = "calendar";
@@ -143,7 +143,7 @@ op_test_finditem_run (void)
 		"IdOnly", NULL, NULL, CALENDAR_QUERY,
 		folder_type, (EwsConvertQueryCallback) (e_ews_query_to_restriction),
 		cancellable, find_folder_item_callback, (gpointer) folder_name);
-	e_ews_folder_free_fid (fid);
+	e_ews_folder_id_free (fid);
 
 	/*Check for mail folder*/
 	folder_name = "inbox";
@@ -157,7 +157,7 @@ op_test_finditem_run (void)
 		"IdOnly", NULL, NULL, MAIL_QUERY,
 		folder_type, (EwsConvertQueryCallback) (e_ews_query_to_restriction),
 		cancellable, find_folder_item_callback, (gpointer) folder_name);
-	e_ews_folder_free_fid (fid);
+	e_ews_folder_id_free (fid);
 }
 
 static gboolean



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