diff --git a/Makefile.am b/Makefile.am
index 28036bf..3e7b2e7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,5 @@
 SUBDIRS = \
+	eplugin \
 	camel mail \
 	addressbook calendar \
 	storage \
diff --git a/configure.ac b/configure.ac
index 9258041..abc26ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,8 +9,9 @@ AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 
 # Required Package Versions
 m4_define([glib_minimum_version], [2.16.0])
-m4_define([gtk_minimum_version], [2.10.0])
+m4_define([gtk_minimum_version], [2.16.0])
 m4_define([eds_minimum_version], [eex_version])
+m4_define([evo_minimum_version], [eex_version])
 m4_define([gconf_minimum_version], [2.0.0])             # XXX Just a Guess
 m4_define([libbonobo_minimum_version], [2.20.3])
 m4_define([libxml_minimum_version], [2.0.0])            # XXX Just a Guess
@@ -152,6 +153,17 @@ PKG_CHECK_MODULES(EVOLUTION_DATA_SERVER,
 	 libebackend-$EDS_API_VERSION >= eds_minimum_version
 	 libexchange-storage-$EDS_API_VERSION >= eds_minimum_version])
 
+dnl ****************************
+dnl Check for evolution plugins 
+dnl ****************************
+PKG_CHECK_MODULES(EVOLUTION_PLUGIN, evolution-plugin >= evo_minimum_version)
+
+dnl *******************
+dnl Special directories
+dnl *******************
+plugindir=`$PKG_CONFIG --variable=plugindir evolution-plugin`
+AC_SUBST(plugindir)
+
 dnl *************************
 dnl CFLAGS and LIBS and stuff
 dnl *************************
@@ -374,6 +386,7 @@ dnl ******************************
 AC_OUTPUT([
 Makefile
 evolution-exchange-zip
+eplugin/Makefile
 camel/Makefile
 mail/Makefile
 addressbook/Makefile
diff --git a/eplugin/Makefile.am b/eplugin/Makefile.am
new file mode 100644
index 0000000..aaf9522
--- /dev/null
+++ b/eplugin/Makefile.am
@@ -0,0 +1,79 @@
+AM_CPPFLAGS = -I .			\
+	-I$(top_srcdir)			\
+	$(LIBEXCHANGE_CFLAGS)		\
+	$(EXCHANGE_STORAGE_CFLAGS)	\
+	$(EVOLUTION_PLUGIN_CFLAGS)
+
+%.eplug: %.eplug.in
+	sed -e 's|\@PLUGINDIR\@|$(plugindir)|'		\
+	-e 's|\@SOEXT\@|$(SOEXT)|'			\
+	-e 's|\@GETTEXT_PACKAGE\@|$(GETTEXT_PACKAGE)|'	\
+	-e 's|\@LOCALEDIR\@|$(localedir)|' $< > $@
+
+%.eplug.in: %.eplug.xml
+	LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp $< $@
+
+%.error: %.error.xml
+	LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp $< $@
+
+plugin_DATA = org-gnome-exchange-operations.eplug 	\
+	org-gnome-folder-permissions.xml		\
+	org-gnome-folder-subscription.xml		\
+	org-gnome-exchange-tasks-subscription.xml	\
+	org-gnome-exchange-cal-subscription.xml		\
+	org-gnome-exchange-ab-subscription.xml
+
+plugin_LTLIBRARIES = liborg-gnome-exchange-operations.la
+
+liborg_gnome_exchange_operations_la_SOURCES = 		\
+	exchange-operations.c				\
+	exchange-operations.h				\
+	exchange-config-listener.c			\
+	exchange-config-listener.h			\
+	exchange-calendar.c				\
+	exchange-contacts.c				\
+	exchange-change-password.c			\
+	exchange-change-password.h			\
+	exchange-delegates-user.c			\
+	exchange-delegates-user.h			\
+	exchange-delegates.c				\
+	exchange-delegates.h				\
+	exchange-user-dialog.c				\
+	exchange-user-dialog.h				\
+	exchange-folder-size-display.c			\
+	exchange-folder-size-display.h			\
+	exchange-account-setup.c			\
+	exchange-permissions-dialog.c			\
+	exchange-permissions-dialog.h			\
+	exchange-folder-permission.c			\
+	exchange-folder-subscription.c			\
+	exchange-folder-subscription.h			\
+	exchange-folder.c				\
+	exchange-mail-send-options.c			\
+	exchange-send-options.c				\
+	exchange-send-options.h
+
+liborg_gnome_exchange_operations_la_LIBADD = 		\
+	$(LIBEXCHANGE_LIBS)				\
+	$(EXCHANGE_STORAGE_LIBS)			\
+	$(EVOLUTION_PLUGIN_LIBS)
+
+liborg_gnome_exchange_operations_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED)
+
+error_DATA = org-gnome-exchange-operations.error
+errordir = $(privdatadir)/errors
+
+EXTRA_DIST = 							\
+	org-gnome-exchange-operations.eplug.xml			\
+	org-gnome-exchange-operations.error.xml			\
+	org-gnome-folder-permissions.xml			\
+	org-gnome-folder-subscription.xml			\
+	org-gnome-exchange-tasks-subscription.xml		\
+	org-gnome-exchange-cal-subscription.xml			\
+	org-gnome-exchange-ab-subscription.xml
+
+BUILT_SOURCES = $(error_DATA) org-gnome-exchange-operations.eplug 
+
+CLEANFILES = $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/eplugin/exchange-account-setup.c b/eplugin/exchange-account-setup.c
new file mode 100644
index 0000000..e00d08d
--- /dev/null
+++ b/eplugin/exchange-account-setup.c
@@ -0,0 +1,1150 @@
+/*
+ * 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:
+ *		Sushma Rai <rsushma@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "libedataserver/e-account.h"
+#include "e-util/e-error.h"
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gconf/gconf-client.h>
+#include <camel/camel-provider.h>
+#include <camel/camel-url.h>
+#include <camel/camel-service.h>
+#include <camel/camel-folder.h>
+#include <e-util/e-dialog-utils.h>
+#include <e2k-validate.h>
+#include <exchange-oof.h>
+#include <exchange-account.h>
+#include "exchange-config-listener.h"
+#include "exchange-operations.h"
+#include "exchange-folder-size-display.h"
+#include "mail/em-account-editor.h"
+#include "mail/em-config.h"
+#include "exchange-delegates.h"
+#include "exchange-change-password.h"
+#include "exchange-folder-size-display.h"
+
+GtkWidget* org_gnome_exchange_settings(EPlugin *epl, EConfigHookItemFactoryData *data);
+GtkWidget *org_gnome_exchange_owa_url(EPlugin *epl, EConfigHookItemFactoryData *data);
+gboolean org_gnome_exchange_check_options(EPlugin *epl, EConfigHookPageCheckData *data);
+GtkWidget *org_gnome_exchange_auth_section (EPlugin *epl, EConfigHookItemFactoryData *data);
+void org_gnome_exchange_commit (EPlugin *epl, EConfigHookItemFactoryData *data);
+GtkWidget* org_gnome_exchange_show_folder_size_factory (EPlugin *epl, EConfigHookItemFactoryData *data);
+
+CamelServiceAuthType camel_exchange_ntlm_authtype = {
+	/* i18n: "Secure Password Authentication" is an Outlookism */
+	(gchar *) N_("Secure Password"),
+
+	/* i18n: "NTLM" probably doesn't translate */
+	(gchar *) N_("This option will connect to the Exchange server "
+	"using secure password (NTLM) authentication."),
+
+	(gchar *) "NTLM",
+	TRUE
+};
+
+CamelServiceAuthType camel_exchange_password_authtype = {
+	(gchar *) N_("Plaintext Password"),
+
+	(gchar *) N_("This option will connect to the Exchange server "
+	"using standard plaintext password authentication."),
+
+	(gchar *) "Basic",
+	TRUE
+};
+
+typedef struct {
+	gboolean state;
+	gchar *message;
+	GtkWidget *text_view;
+}OOFData;
+
+static OOFData *oof_data;
+
+static void
+update_state (GtkTextBuffer *buffer, gpointer data)
+{
+	if (gtk_text_buffer_get_modified (buffer)) {
+		GtkTextIter start, end;
+		if (oof_data->message)
+			g_free (oof_data->message);
+		gtk_text_buffer_get_bounds (buffer, &start, &end);
+		oof_data->message =  gtk_text_buffer_get_text (buffer, &start,
+							       &end, FALSE);
+		gtk_text_buffer_set_modified (buffer, FALSE);
+	}
+}
+
+static void
+toggled_state (GtkToggleButton *button, gpointer data)
+{
+	gboolean current_oof_state = gtk_toggle_button_get_active (button);
+
+	if (current_oof_state == oof_data->state)
+		return;
+	oof_data->state = current_oof_state;
+	gtk_widget_set_sensitive (oof_data->text_view, current_oof_state);
+}
+
+#ifdef HAVE_KRB5
+static void
+btn_chpass_clicked (GtkButton *button, gpointer data)
+{
+	ExchangeAccount *account;
+	gchar *old_password, *new_password;
+	ExchangeAccountResult result;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+
+	old_password = exchange_account_get_password (account);
+	if (!old_password) {
+		g_print ("Could not fetch old password\n");
+		return;
+	}
+	new_password = exchange_get_new_password (old_password, TRUE);
+	if (!new_password) {
+		/* "Cacel" button was hit */
+		return;
+	}
+	/* g_print ("Current password is \"%s\"\n", old_password); */
+	result = exchange_account_set_password (account, old_password, new_password);
+	if (result != EXCHANGE_ACCOUNT_CONNECT_SUCCESS)
+		exchange_operations_report_error (account, result);
+
+	g_free (old_password);
+	g_free (new_password);
+}
+#endif
+
+static void
+btn_dass_clicked (GtkButton *button, gpointer data)
+{
+	ExchangeAccount *account;
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+	exchange_delegates (account, gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_WINDOW));
+}
+
+static void
+btn_fsize_clicked (GtkButton *button, gpointer data)
+{
+	ExchangeAccount *account;
+	GtkListStore *model;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+
+	model = exchange_account_folder_size_get_model (account);
+	if (model)
+		exchange_folder_size_display (model, GTK_WIDGET (button));
+}
+
+/* only used in editor */
+GtkWidget *
+org_gnome_exchange_settings(EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	EMConfigTargetAccount *target_account;
+	ExchangeAccount *account = NULL;
+	CamelURL *url;
+	const gchar *source_url;
+	gchar *message = NULL, *txt = NULL, *oof_message;
+	gboolean oof_state = FALSE;
+	gint offline_status;
+
+	GtkVBox *vbox_settings;
+
+	/* OOF fields */
+	GtkFrame *frm_oof;
+	GtkVBox *vbox_oof;
+	GtkLabel *lbl_oof_desc;
+	GtkTable *tbl_oof_status;
+	GtkLabel *lbl_status;
+	GtkRadioButton *radio_iof, *radio_oof;
+	GtkScrolledWindow *scrwnd_oof;
+	GtkTextView *txtview_oof;
+
+	/* Authentication settings */
+	GtkFrame *frm_auth;
+	GtkVBox *vbox_auth;
+	GtkTable *tbl_auth;
+#ifdef HAVE_KRB5
+	GtkLabel *lbl_chpass;
+	GtkButton *btn_chpass;
+#endif
+	GtkLabel *lbl_dass;
+	GtkButton *btn_dass;
+
+	/* Miscelleneous setting */
+	GtkFrame *frm_misc;
+	GtkVBox *vbox_misc;
+	GtkTable *tbl_misc;
+	GtkLabel *lbl_fsize;
+	GtkButton *btn_fsize;
+
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+
+	target_account = (EMConfigTargetAccount *)data->config->target;
+	source_url = e_account_get_string (target_account->account,  E_ACCOUNT_SOURCE_URL);
+	url = camel_url_new(source_url, NULL);
+	if (url == NULL
+	    || strcmp(url->protocol, "exchange") != 0) {
+		if (url)
+			camel_url_free(url);
+		return NULL;
+	}
+
+	if (data->old) {
+		camel_url_free(url);
+		return data->old;
+	}
+	if (url)
+		camel_url_free (url);
+
+	account = exchange_operations_get_exchange_account ();
+
+	exchange_config_listener_get_offline_status (exchange_global_config_listener,
+								    &offline_status);
+	if (offline_status == OFFLINE_MODE) {
+		e_error_run (NULL, ERROR_DOMAIN ":exchange-settings-offline", NULL);
+
+		return NULL;
+	}
+
+	oof_data = g_new0 (OOFData, 1);
+
+	oof_data->state = FALSE;
+	oof_data->message = NULL;
+	oof_data->text_view = NULL;
+
+	/* See if oof info found already */
+
+	if (account && !exchange_oof_get (account, &oof_state, &message)) {
+
+		e_error_run (NULL, ERROR_DOMAIN ":state-read-error", NULL);
+
+                return NULL;
+        }
+
+	if (message && *message)
+		oof_data->message = g_strdup (message);
+	else
+		oof_data->message = NULL;
+	oof_data->state = oof_state;
+
+	/* construct page */
+
+	vbox_settings = (GtkVBox*) g_object_new (GTK_TYPE_VBOX, "homogeneous", FALSE, "spacing", 6, NULL);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox_settings), 12);
+
+	frm_oof = (GtkFrame*) g_object_new (GTK_TYPE_FRAME, "label", _("Out Of Office"), NULL);
+	gtk_box_pack_start (GTK_BOX (vbox_settings), GTK_WIDGET (frm_oof), FALSE, FALSE, 0);
+
+	vbox_oof = (GtkVBox*) g_object_new (GTK_TYPE_VBOX, NULL, "homogeneous", FALSE, "spacing", 12, NULL);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox_oof), 6);
+	gtk_container_add (GTK_CONTAINER (frm_oof), GTK_WIDGET (vbox_oof));
+
+	lbl_oof_desc = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("The message specified below will be automatically sent to \neach person who sends mail to you while you are out of the office."), "justify", GTK_JUSTIFY_LEFT, NULL);
+	gtk_misc_set_alignment (GTK_MISC (lbl_oof_desc), 0, 0.5);
+	gtk_box_pack_start (GTK_BOX (vbox_oof), GTK_WIDGET (lbl_oof_desc), FALSE, FALSE, 0);
+
+	tbl_oof_status = (GtkTable*) g_object_new (GTK_TYPE_TABLE, "n-rows", 2, "n-columns", 2, "homogeneous", FALSE, "row-spacing", 6, "column-spacing", 6, NULL);
+	txt = g_strdup_printf ("<b>%s</b>", _("Status:"));
+	lbl_status = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", txt, "use-markup", TRUE, NULL);
+	g_free (txt);
+	gtk_misc_set_alignment (GTK_MISC (lbl_status), 0, 0.5);
+	gtk_misc_set_padding (GTK_MISC (lbl_status), 0, 0);
+
+	if (oof_data->state) {
+		radio_oof = (GtkRadioButton*) g_object_new (GTK_TYPE_RADIO_BUTTON, "label", _("I am out of the office"), NULL);
+		radio_iof = (GtkRadioButton*) g_object_new (GTK_TYPE_RADIO_BUTTON, "label", _("I am in the office"), "group", radio_oof, NULL);
+	}
+	else {
+		radio_iof = (GtkRadioButton*) g_object_new (GTK_TYPE_RADIO_BUTTON, "label", _("I am in the office"), NULL);
+		radio_oof = (GtkRadioButton*) g_object_new (GTK_TYPE_RADIO_BUTTON, "label", _("I am out of the office"), "group", radio_iof, NULL);
+	}
+	g_signal_connect (radio_oof, "toggled", G_CALLBACK (toggled_state), NULL);
+
+	gtk_table_attach (tbl_oof_status, GTK_WIDGET (lbl_status), 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+	gtk_table_attach (tbl_oof_status, GTK_WIDGET (radio_iof), 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+	gtk_table_attach (tbl_oof_status, GTK_WIDGET (radio_oof), 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
+
+	gtk_box_pack_start (GTK_BOX (vbox_oof), GTK_WIDGET (tbl_oof_status), FALSE, FALSE, 0);
+
+	scrwnd_oof = (GtkScrolledWindow*) g_object_new (GTK_TYPE_SCROLLED_WINDOW, "hscrollbar-policy", GTK_POLICY_AUTOMATIC, "vscrollbar-policy", GTK_POLICY_AUTOMATIC, "shadow-type", GTK_SHADOW_IN, NULL);
+	gtk_box_pack_start (GTK_BOX (vbox_oof), GTK_WIDGET (scrwnd_oof), FALSE, FALSE, 0);
+	txtview_oof = (GtkTextView*) g_object_new (GTK_TYPE_TEXT_VIEW, "justification", GTK_JUSTIFY_LEFT, "wrap-mode", GTK_WRAP_WORD, "editable", TRUE, NULL);
+	buffer = gtk_text_view_get_buffer (txtview_oof);
+	gtk_text_buffer_get_bounds (buffer, &start, &end);
+	oof_message = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+	if (oof_message && *oof_message) {
+		/* Will this ever happen? */
+		oof_data->message = oof_message;
+	}
+	if (oof_data->message) {
+		/* previuosly set message */
+		gtk_text_buffer_set_text (buffer, oof_data->message, -1);
+		gtk_text_view_set_buffer (txtview_oof, buffer);
+
+	}
+	gtk_text_buffer_set_modified (buffer, FALSE);
+	if (!oof_data->state)
+		gtk_widget_set_sensitive (GTK_WIDGET (txtview_oof), FALSE);
+	oof_data->text_view = GTK_WIDGET (txtview_oof);
+	g_signal_connect (buffer, "changed", G_CALLBACK (update_state), NULL);
+	gtk_container_add (GTK_CONTAINER (scrwnd_oof), GTK_WIDGET (txtview_oof));
+
+	/* Security settings */
+	frm_auth = (GtkFrame*) g_object_new (GTK_TYPE_FRAME, "label", _("Security"), NULL);
+	gtk_box_pack_start (GTK_BOX (vbox_settings), GTK_WIDGET (frm_auth), FALSE, FALSE, 0);
+
+	vbox_auth = (GtkVBox*) g_object_new (GTK_TYPE_VBOX, "homogeneous", FALSE, "spacing", 6, NULL);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox_auth), 6);
+	gtk_container_add (GTK_CONTAINER (frm_auth), GTK_WIDGET (vbox_auth));
+
+	tbl_auth = (GtkTable*) g_object_new (GTK_TYPE_TABLE, "n-rows", 2, "n-columns", 2, "homogeneous", FALSE, "row-spacing", 6, "column-spacing", 6, NULL);
+
+#ifdef HAVE_KRB5
+	/* Change Password */
+	lbl_chpass = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("Change the password for Exchange account"), NULL);
+	gtk_misc_set_alignment (GTK_MISC (lbl_chpass), 0, 0.5);
+	btn_chpass = (GtkButton*) g_object_new (GTK_TYPE_BUTTON, "label", _("Change Password"), NULL);
+	g_signal_connect (GTK_OBJECT (btn_chpass), "clicked", G_CALLBACK (btn_chpass_clicked), NULL);
+#endif
+
+	/* Delegation Assistant */
+	lbl_dass = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("Manage the delegate settings for Exchange account"), NULL);
+	gtk_misc_set_alignment (GTK_MISC (lbl_dass), 0, 0.5);
+	btn_dass = (GtkButton*) g_object_new (GTK_TYPE_BUTTON, "label", _("Delegation Assistant"), NULL);
+	g_signal_connect (btn_dass, "clicked", G_CALLBACK (btn_dass_clicked), NULL);
+	/* Add items to the table */
+#ifdef HAVE_KRB5
+	gtk_table_attach_defaults (tbl_auth, GTK_WIDGET (lbl_chpass), 0, 1, 0, 1);
+	gtk_table_attach (tbl_auth, GTK_WIDGET (btn_chpass), 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+#endif
+	gtk_table_attach_defaults (tbl_auth, GTK_WIDGET (lbl_dass), 0, 1, 1, 2);
+	gtk_table_attach (tbl_auth, GTK_WIDGET (btn_dass), 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
+	gtk_box_pack_start (GTK_BOX (vbox_auth), GTK_WIDGET (tbl_auth), FALSE, FALSE, 0);
+
+	/* Miscelleneous settings */
+	frm_misc = (GtkFrame*) g_object_new (GTK_TYPE_FRAME, "label", _("Miscelleneous"), NULL);
+	gtk_box_pack_start (GTK_BOX (vbox_settings), GTK_WIDGET (frm_misc), FALSE, FALSE, 0);
+
+	vbox_misc = (GtkVBox*) g_object_new (GTK_TYPE_VBOX, "homogeneous", FALSE, "spacing", 6, NULL);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox_misc), 6);
+	gtk_container_add (GTK_CONTAINER (frm_misc), GTK_WIDGET (vbox_misc));
+
+	tbl_misc = (GtkTable*) g_object_new (GTK_TYPE_TABLE, "n-rows", 1, "n-columns", 1, "homogeneous", FALSE, "row-spacing", 6, "column-spacing", 6, NULL);
+
+	/* Folder Size */
+	lbl_fsize = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("View the size of all Exchange folders"), NULL);
+	gtk_misc_set_alignment (GTK_MISC (lbl_fsize), 0, 0.5);
+	btn_fsize = (GtkButton*) g_object_new (GTK_TYPE_BUTTON, "label", _("Folders Size"), NULL);
+	g_signal_connect (btn_fsize, "clicked", G_CALLBACK (btn_fsize_clicked), NULL);
+	gtk_table_attach_defaults (tbl_misc, GTK_WIDGET (lbl_fsize), 0, 1, 0, 1);
+	gtk_table_attach (tbl_misc, GTK_WIDGET (btn_fsize), 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+	gtk_box_pack_start (GTK_BOX (vbox_misc), GTK_WIDGET (tbl_misc), FALSE, FALSE, 0);
+
+	gtk_widget_show_all (GTK_WIDGET (vbox_settings));
+	gtk_notebook_insert_page (GTK_NOTEBOOK (data->parent), GTK_WIDGET (vbox_settings), gtk_label_new(_("Exchange Settings")), 4);
+	return GTK_WIDGET (vbox_settings);
+
+}
+
+static void
+print_error (const gchar *owa_url, E2kAutoconfigResult result)
+{
+	switch (result) {
+
+		case E2K_AUTOCONFIG_CANT_CONNECT:
+			e_error_run (NULL, ERROR_DOMAIN ":account-connect-error", "", NULL);
+			break;
+
+		case E2K_AUTOCONFIG_CANT_RESOLVE:
+			e_error_run (NULL, ERROR_DOMAIN ":account-resolve-error", "", NULL);
+			break;
+
+		case E2K_AUTOCONFIG_AUTH_ERROR:
+		case E2K_AUTOCONFIG_AUTH_ERROR_TRY_NTLM:
+		case E2K_AUTOCONFIG_AUTH_ERROR_TRY_BASIC:
+			e_error_run (NULL, ERROR_DOMAIN ":password-incorrect", NULL);
+			break;
+
+		case E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN:
+			e_error_run (NULL, ERROR_DOMAIN ":account-domain-error", NULL);
+			break;
+
+		case E2K_AUTOCONFIG_NO_OWA:
+		case E2K_AUTOCONFIG_NOT_EXCHANGE:
+			e_error_run (NULL, ERROR_DOMAIN ":account-wss-error", NULL);
+			break;
+
+		case E2K_AUTOCONFIG_CANT_BPROPFIND:
+			e_error_run (NULL, ERROR_DOMAIN ":connect-exchange-error",
+				     "http://support.novell.com/cgi-bin/search/searchtid.cgi?/ximian/ximian328.html",
+				     NULL);
+			break;
+
+		case E2K_AUTOCONFIG_EXCHANGE_5_5:
+			e_error_run (NULL, ERROR_DOMAIN ":account-version-error", NULL);
+			break;
+
+		default:
+			e_error_run (NULL, ERROR_DOMAIN ":configure-error", NULL);
+			break;
+
+	}
+}
+
+static const gchar *
+gal_auth_to_string (E2kAutoconfigGalAuthPref ad_auth)
+{
+	switch (ad_auth) {
+	case E2K_AUTOCONFIG_USE_GAL_DEFAULT: return "default";
+	case E2K_AUTOCONFIG_USE_GAL_BASIC:   return "basic";
+	case E2K_AUTOCONFIG_USE_GAL_NTLM:    return "ntlm";
+	}
+
+	return "default";
+}
+
+static void
+owa_authenticate_user(GtkWidget *button, EConfig *config)
+{
+	EMConfigTargetAccount *target_account = (EMConfigTargetAccount *)config->target;
+	E2kAutoconfigResult result;
+	CamelURL *url=NULL;
+	gboolean remember_password;
+	gchar *url_string, *key;
+	const gchar *source_url, *id_name, *owa_url;
+	gchar *at, *user;
+	gboolean valid = FALSE;
+	ExchangeParams *exchange_params;
+	GtkWidget *mailbox_entry = g_object_get_data (G_OBJECT (button), "mailbox-entry");
+
+	exchange_params = g_new0 (ExchangeParams, 1);
+	exchange_params->host = NULL;
+	exchange_params->ad_server = NULL;
+	exchange_params->ad_auth = E2K_AUTOCONFIG_USE_GAL_DEFAULT;
+	exchange_params->mailbox = NULL;
+	exchange_params->owa_path = NULL;
+	exchange_params->is_ntlm = TRUE;
+
+	source_url = e_account_get_string (target_account->account, E_ACCOUNT_SOURCE_URL);
+
+	if (source_url && source_url[0] != '\0')
+		url = camel_url_new(source_url, NULL);
+	if (url && url->user == NULL) {
+		id_name = e_account_get_string (target_account->account, E_ACCOUNT_ID_ADDRESS);
+		if (id_name) {
+			at = strchr(id_name, '@');
+			user = g_alloca(at-id_name+1);
+			memcpy(user, id_name, at-id_name);
+			user[at-id_name] = 0;
+			camel_url_set_user (url, user);
+		}
+	}
+
+	/* validate_user() CALLS GTK!!!
+
+	   THIS IS TOTALLY UNNACCEPTABLE!!!!!!!!
+
+	   It must use camel_session_ask_password, and it should return an exception for any problem,
+	   which should then be shown using e-error */
+
+	owa_url = camel_url_get_param (url, "owa_url");
+	if (camel_url_get_param (url, "authmech"))
+		exchange_params->is_ntlm = TRUE;
+	else
+		exchange_params->is_ntlm = FALSE;
+	camel_url_set_authmech (url, exchange_params->is_ntlm ? "NTLM" : "Basic");
+
+	key = camel_url_to_string (url, CAMEL_URL_HIDE_PASSWORD | CAMEL_URL_HIDE_PARAMS);
+	/* Supress the trailing slash */
+	key [strlen(key) -1] = 0;
+
+	/* set the mailbox before function call to let it use our, not create one */
+	exchange_params->mailbox = g_strdup (camel_url_get_param (url, "mailbox"));
+
+	valid =  e2k_validate_user (owa_url, key, &url->user, exchange_params,
+						&remember_password, &result,
+						GTK_WINDOW (gtk_widget_get_toplevel (button)));
+	g_free (key);
+
+	if (!valid && result != E2K_AUTOCONFIG_CANCELLED)
+		print_error (owa_url, result);
+
+	camel_url_set_host (url, valid ? exchange_params->host : "");
+
+	if (valid)
+		camel_url_set_param (url, "save-passwd", remember_password? "true" : "false");
+
+	camel_url_set_param (url, "ad_server", valid ? exchange_params->ad_server: NULL);
+	camel_url_set_param (url, "mailbox", valid ? exchange_params->mailbox : NULL);
+	camel_url_set_param (url, "owa_path", valid ? exchange_params->owa_path : NULL);
+	camel_url_set_param (url, "ad_auth", valid ? gal_auth_to_string (exchange_params->ad_auth) : NULL);
+
+	if (mailbox_entry) {
+		const gchar *par = camel_url_get_param (url, "mailbox");
+
+		gtk_entry_set_text (GTK_ENTRY (mailbox_entry), par ? par : "");
+	}
+
+	g_free (exchange_params->owa_path);
+	g_free (exchange_params->mailbox);
+	g_free (exchange_params->host);
+	g_free (exchange_params->ad_server);
+	g_free (exchange_params);
+
+	if (valid) {
+		url_string = camel_url_to_string (url, 0);
+		e_account_set_string (target_account->account, E_ACCOUNT_SOURCE_URL, url_string);
+		e_account_set_string (target_account->account, E_ACCOUNT_TRANSPORT_URL, url_string);
+		e_account_set_bool (target_account->account, E_ACCOUNT_SOURCE_SAVE_PASSWD, remember_password);
+		g_free (url_string);
+	}
+	camel_url_free (url);
+}
+
+static void
+owa_editor_entry_changed(GtkWidget *entry, EConfig *config)
+{
+	const gchar *uri, *ssl = NULL;
+	CamelURL *url, *owaurl = NULL;
+	gchar *url_string;
+	EMConfigTargetAccount *target = (EMConfigTargetAccount *)config->target;
+	GtkWidget *button = g_object_get_data((GObject *)entry, "authenticate-button");
+	gint active = FALSE;
+
+	/* NB: we set the button active only if we have a parsable uri entered */
+
+	const gchar * target_url = e_account_get_string(target->account, E_ACCOUNT_SOURCE_URL);
+	if (target_url && target_url[0] != '\0')
+		url = camel_url_new(target_url, NULL);
+	else url = NULL;
+	uri = gtk_entry_get_text((GtkEntry *)entry);
+	if (uri && uri[0]) {
+		camel_url_set_param(url, "owa_url", uri);
+		owaurl = camel_url_new(uri, NULL);
+		if (owaurl) {
+			active = TRUE;
+
+			/* Reading the owa url and setting use_ssl paramemter */
+			if (!strcmp(owaurl->protocol, "https"))
+				ssl = "always";
+			camel_url_free(owaurl);
+		}
+	} else {
+		camel_url_set_param(url, "owa_url", NULL);
+	}
+
+	camel_url_set_param(url, "use_ssl", ssl);
+	gtk_widget_set_sensitive(button, active);
+
+	url_string = camel_url_to_string(url, 0);
+	e_account_set_string(target->account, E_ACCOUNT_SOURCE_URL, url_string);
+	g_free(url_string);
+	camel_url_free (url);
+}
+
+static void
+update_mailbox_param_in_url (EAccount *account, e_account_item_t item, const gchar *mailbox)
+{
+	CamelURL *url;
+	gchar *url_string;
+	const gchar *target_url;
+
+	if (!account)
+		return;
+
+	target_url = e_account_get_string (account, item);
+	if (target_url && target_url[0] != '\0')
+		url = camel_url_new (target_url, NULL);
+	else
+		return;
+
+	if (mailbox && *mailbox)
+		camel_url_set_param (url, "mailbox", mailbox);
+	else
+		camel_url_set_param (url, "mailbox", NULL);
+
+	url_string = camel_url_to_string (url, 0);
+	e_account_set_string (account, item, url_string);
+	g_free (url_string);
+	camel_url_free (url);
+}
+
+static void
+mailbox_editor_entry_changed (GtkWidget *entry, EConfig *config)
+{
+	EMConfigTargetAccount *target;
+	const gchar *mailbox;
+
+	target = (EMConfigTargetAccount *)config->target;
+	mailbox = gtk_entry_get_text (GTK_ENTRY (entry));
+
+	update_mailbox_param_in_url (target->account, E_ACCOUNT_SOURCE_URL, mailbox);
+	update_mailbox_param_in_url (target->account, E_ACCOUNT_TRANSPORT_URL, mailbox);
+}
+
+static void
+want_mailbox_toggled (GtkWidget *toggle, EConfig *config)
+{
+	GtkWidget *entry;
+
+	g_return_if_fail (toggle != NULL);
+	g_return_if_fail (config != NULL);
+
+	entry = g_object_get_data (G_OBJECT (toggle), "mailbox-entry");
+	if (entry) {
+		gboolean is_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle));
+		EMConfigTargetAccount *target;
+		const gchar *mailbox;
+
+		gtk_widget_set_sensitive (entry, is_active);
+
+		target = (EMConfigTargetAccount *)config->target;
+		mailbox = gtk_entry_get_text (GTK_ENTRY (entry));
+
+		update_mailbox_param_in_url (target->account, E_ACCOUNT_SOURCE_URL, is_active ? mailbox : NULL);
+		update_mailbox_param_in_url (target->account, E_ACCOUNT_TRANSPORT_URL, is_active ? mailbox : NULL);
+	}
+}
+
+static gchar *
+construct_owa_url (CamelURL *url)
+{
+	const gchar *owa_path, *use_ssl = NULL;
+	const gchar *protocol = "http", *mailbox_name;
+	gchar *owa_url;
+
+	use_ssl = camel_url_get_param (url, "use_ssl");
+	if (use_ssl) {
+		if (!strcmp (use_ssl, "always"))
+			protocol = "https";
+	}
+
+	owa_path = camel_url_get_param (url, "owa_path");
+	if (!owa_path)
+		owa_path = "/exchange";
+	mailbox_name = camel_url_get_param (url, "mailbox");
+
+	if (mailbox_name)
+		owa_url = g_strdup_printf("%s://%s%s/%s", protocol, url->host, owa_path, mailbox_name);
+	else
+		owa_url = g_strdup_printf("%s://%s%s", protocol, url->host, owa_path );
+
+	return owa_url;
+}
+
+/* used by editor and druid - same code */
+GtkWidget *
+org_gnome_exchange_owa_url(EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	EMConfigTargetAccount *target_account;
+	const gchar *source_url;
+	gchar *owa_url = NULL, *mailbox_name, *username;
+	GtkWidget *owa_entry, *mailbox_entry, *want_mailbox_check;
+	CamelURL *url;
+	gint row;
+	GtkWidget *hbox, *label, *button;
+
+	target_account = (EMConfigTargetAccount *)data->config->target;
+	source_url = e_account_get_string (target_account->account,  E_ACCOUNT_SOURCE_URL);
+	if (source_url && source_url[0] != '\0')
+		url = camel_url_new(source_url, NULL);
+	else
+		url = NULL;
+	if (url == NULL
+	    || strcmp(url->protocol, "exchange") != 0) {
+		if (url)
+			camel_url_free(url);
+
+		if (data->old
+		    && (label = g_object_get_data((GObject *)data->old, "authenticate-label")))
+			gtk_widget_destroy(label);
+
+		/* TODO: we could remove 'owa-url' from the url,
+		   but that will lose it if we come back.  Maybe a commit callback could do it */
+
+		return NULL;
+	}
+
+	if (data->old) {
+		camel_url_free(url);
+		return data->old;
+	}
+
+	owa_url = g_strdup (camel_url_get_param(url, "owa_url"));
+	mailbox_name = g_strdup (camel_url_get_param (url, "mailbox"));
+	username = g_strdup (url->user);
+
+	/* if the host is null, then user+other info is dropped silently, force it to be kept */
+	if (url->host == NULL) {
+		gchar *uri;
+
+		camel_url_set_host(url, "");
+		uri = camel_url_to_string(url, 0);
+		e_account_set_string(target_account->account,  E_ACCOUNT_SOURCE_URL, uri);
+		g_free(uri);
+	}
+
+	row = ((GtkTable *)data->parent)->nrows;
+
+	hbox = gtk_hbox_new (FALSE, 6);
+	label = gtk_label_new_with_mnemonic(_("_OWA URL:"));
+	gtk_widget_show(label);
+
+	owa_entry = gtk_entry_new();
+
+	if (!owa_url) {
+		if (url->host[0] != 0) {
+			gchar *uri;
+
+			/* url has hostname but not owa_url.
+			 * Account has been created using x-c-s or evo is upgraded to 2.2
+			 * When invoked from druid, hostname will get set after validation,
+			 * so this condition will never be true during account creation.
+			 */
+			owa_url = construct_owa_url (url);
+			camel_url_set_param (url, "owa_url", owa_url);
+			uri = camel_url_to_string(url, 0);
+			e_account_set_string(target_account->account,  E_ACCOUNT_SOURCE_URL, uri);
+			g_free(uri);
+		}
+	}
+	camel_url_free (url);
+	if (owa_url)
+		gtk_entry_set_text(GTK_ENTRY (owa_entry), owa_url);
+	gtk_label_set_mnemonic_widget((GtkLabel *)label, owa_entry);
+
+	button = gtk_button_new_with_mnemonic (_("A_uthenticate"));
+	gtk_widget_set_sensitive (button, owa_url && owa_url[0]);
+
+	gtk_box_pack_start (GTK_BOX (hbox), owa_entry, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+	gtk_widget_show_all(hbox);
+
+	gtk_table_attach (GTK_TABLE (data->parent), label, 0, 1, row, row+1, 0, 0, 0, 0);
+	gtk_table_attach (GTK_TABLE (data->parent), hbox, 1, 2, row, row+1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
+
+	g_signal_connect (owa_entry, "changed", G_CALLBACK(owa_editor_entry_changed), data->config);
+	g_object_set_data((GObject *)owa_entry, "authenticate-button", button);
+	g_signal_connect (button, "clicked", G_CALLBACK(owa_authenticate_user), data->config);
+
+	/* Track the authenticate label, so we can destroy it if e-config is to destroy the hbox */
+	g_object_set_data((GObject *)hbox, "authenticate-label", label);
+
+	/* check for correctness of the input in the owa_entry */
+	owa_editor_entry_changed (owa_entry, data->config);
+
+	row++;
+	want_mailbox_check = gtk_check_button_new_with_mnemonic (
+		_("Mailbox name is _different than user name"));
+	gtk_widget_show (want_mailbox_check);
+	gtk_table_attach (GTK_TABLE (data->parent), want_mailbox_check, 1, 2, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
+	if (!username || !*username || !mailbox_name || !*mailbox_name ||
+	    g_ascii_strcasecmp (username, mailbox_name) == 0 ||
+	    (strchr (username, '/') && g_ascii_strcasecmp (strchr (username, '/') + 1, mailbox_name) == 0)) {
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (want_mailbox_check), FALSE);
+	} else {
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (want_mailbox_check), TRUE);
+	}
+	g_signal_connect (want_mailbox_check, "toggled", G_CALLBACK (want_mailbox_toggled), data->config);
+
+	row++;
+	label = gtk_label_new_with_mnemonic (_("_Mailbox:"));
+	gtk_widget_show (label);
+
+	mailbox_entry = gtk_entry_new ();
+	gtk_widget_show (mailbox_entry);
+	if (mailbox_name)
+		gtk_entry_set_text (GTK_ENTRY (mailbox_entry), mailbox_name);
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), mailbox_entry);
+
+	gtk_widget_set_sensitive (mailbox_entry, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (want_mailbox_check)));
+
+	g_signal_connect (mailbox_entry, "changed", G_CALLBACK (mailbox_editor_entry_changed), data->config);
+	g_object_set_data (G_OBJECT (button), "mailbox-entry", mailbox_entry);
+	g_object_set_data (G_OBJECT (want_mailbox_check), "mailbox-entry", mailbox_entry);
+
+	gtk_table_attach (GTK_TABLE (data->parent), label, 0, 1, row, row+1, 0, 0, 0, 0);
+	gtk_table_attach (GTK_TABLE (data->parent), mailbox_entry, 1, 2, row, row+1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
+
+	g_free (owa_url);
+	g_free (mailbox_name);
+	g_free (username);
+
+	return hbox;
+}
+
+gboolean
+org_gnome_exchange_check_options(EPlugin *epl, EConfigHookPageCheckData *data)
+{
+	EMConfigTargetAccount *target = (EMConfigTargetAccount *)data->config->target;
+	gint status = TRUE;
+
+	/* We assume that if the host is set, then the setting is valid.
+	   The host gets set when the provider validate() call is made */
+	/* We do this check for receive page also, so that user can
+	 * proceed with the account set up only after user is validated,
+	 * and host name is reset by validate() call
+	 */
+	if (data->pageid == NULL ||
+	    strcmp (data->pageid, "10.receive") == 0 ||
+	    strcmp (data->pageid, "20.receive_options") == 0) {
+		CamelURL *url;
+
+		const gchar * target_url = e_account_get_string(target->account,  E_ACCOUNT_SOURCE_URL);
+		if (target_url && target_url[0] != '\0')
+			url = camel_url_new(target_url, NULL);
+		else
+			url = NULL;
+		/* Note: we only care about exchange url's, we WILL get called on all other url's too. */
+		if (url != NULL
+		    && strcmp(url->protocol, "exchange") == 0
+		    && (url->host == NULL || url->host[0] == 0))
+			status = FALSE;
+
+		if (url)
+			camel_url_free(url);
+	}
+
+	return status;
+}
+
+static void
+set_oof_info (void)
+{
+	ExchangeAccount *account;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (account && !exchange_oof_set (account, oof_data->state, oof_data->message)) {
+
+		e_error_run (NULL, ERROR_DOMAIN ":state-update-error", NULL);
+	}
+}
+
+static void
+destroy_oof_data (void)
+{
+	if (oof_data->message)
+		g_free (oof_data->message);
+	if (oof_data)
+		g_free (oof_data);
+}
+
+void
+org_gnome_exchange_commit (EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	EMConfigTargetAccount *target_account;
+	const gchar *source_url;
+	CamelURL *url;
+	gint offline_status;
+
+	target_account = (EMConfigTargetAccount *)data->config->target;
+	source_url = e_account_get_string (target_account->account,  E_ACCOUNT_SOURCE_URL);
+	if (source_url && source_url[0] != '\0')
+		url = camel_url_new (source_url, NULL);
+	else
+		url = NULL;
+	if (url == NULL
+	    || strcmp (url->protocol, "exchange") != 0) {
+		if (url)
+			camel_url_free (url);
+
+		return;
+	}
+	if (data->old) {
+		camel_url_free(url);
+		return;
+	}
+
+	camel_url_free (url);
+
+	exchange_config_listener_get_offline_status (exchange_global_config_listener,
+								    &offline_status);
+
+	if (offline_status == OFFLINE_MODE) {
+                return;
+	}
+
+	/* Set oof data in exchange account */
+	set_oof_info ();
+	destroy_oof_data ();
+	return;
+}
+
+static void
+exchange_check_authtype (GtkWidget *w, EConfig *config)
+{
+	return;
+}
+
+static void
+exchange_authtype_changed (GtkComboBox *dropdown, EConfig *config)
+{
+	EMConfigTargetAccount *target = (EMConfigTargetAccount *)config->target;
+	gint id = gtk_combo_box_get_active(dropdown);
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	CamelServiceAuthType *authtype;
+	CamelURL *url_source, *url_transport;
+	const gchar *source_url, *transport_url;
+	gchar *source_url_string, *transport_url_string;
+
+	source_url = e_account_get_string (target->account,
+					   E_ACCOUNT_SOURCE_URL);
+	if (id == -1)
+		return;
+
+	url_source = camel_url_new (source_url, NULL);
+
+	transport_url = e_account_get_string (target->account,
+					      E_ACCOUNT_TRANSPORT_URL);
+	url_transport = camel_url_new (transport_url, NULL);
+
+	model = gtk_combo_box_get_model(dropdown);
+	if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) {
+		gtk_tree_model_get(model, &iter, 1, &authtype, -1);
+		if (authtype) {
+			camel_url_set_authmech(url_source, authtype->authproto);
+			camel_url_set_authmech(url_transport, authtype->authproto);
+		}
+		else {
+			camel_url_set_authmech(url_source, NULL);
+			camel_url_set_authmech(url_transport, NULL);
+		}
+
+		source_url_string = camel_url_to_string(url_source, 0);
+		transport_url_string = camel_url_to_string(url_transport, 0);
+		e_account_set_string(target->account, E_ACCOUNT_SOURCE_URL, source_url_string);
+		e_account_set_string(target->account, E_ACCOUNT_TRANSPORT_URL, transport_url_string);
+		g_free(source_url_string);
+		g_free(transport_url_string);
+	}
+	camel_url_free(url_source);
+	camel_url_free(url_transport);
+}
+
+GtkWidget *
+org_gnome_exchange_auth_section (EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	EMConfigTargetAccount *target_account;
+	const gchar *source_url;
+	gchar *label_text, *exchange_account_authtype = NULL;
+	CamelURL *url;
+	GtkWidget *hbox, *button, *auth_label, *vbox, *label_hide;
+	GtkComboBox *dropdown;
+	GtkTreeIter iter;
+	GtkListStore *store;
+	gint i, active=0, auth_changed_id = 0;
+	GList *authtypes, *l, *ll;
+	ExchangeAccount *account;
+
+	target_account = (EMConfigTargetAccount *)data->config->target;
+	source_url = e_account_get_string (target_account->account,
+					   E_ACCOUNT_SOURCE_URL);
+	url = camel_url_new (source_url, NULL);
+	if (url == NULL
+	    || strcmp (url->protocol, "exchange") != 0) {
+		if (url)
+			camel_url_free (url);
+
+		return NULL;
+	}
+
+	if (data->old) {
+		camel_url_free(url);
+		return data->old;
+	}
+
+	account = exchange_operations_get_exchange_account ();
+	if (account)
+		exchange_account_authtype = exchange_account_get_authtype (account);
+
+	vbox = gtk_vbox_new (FALSE, 6);
+
+	label_text = g_strdup_printf("<b>%s</b>", _("_Authentication Type"));
+	auth_label = gtk_label_new_with_mnemonic (label_text);
+	g_free (label_text);
+	gtk_label_set_justify (GTK_LABEL (auth_label), GTK_JUSTIFY_LEFT);
+	gtk_misc_set_alignment (GTK_MISC (auth_label), 0, 0.5);
+	gtk_misc_set_padding (GTK_MISC (auth_label), 0, 0);
+	gtk_label_set_use_markup (GTK_LABEL (auth_label), TRUE);
+
+	label_hide = gtk_label_new("\n");
+
+	hbox = gtk_hbox_new (FALSE, 6);
+	dropdown = (GtkComboBox * )gtk_combo_box_new ();
+	gtk_label_set_mnemonic_widget (GTK_LABEL (auth_label), GTK_WIDGET (dropdown));
+
+	button = gtk_button_new_with_mnemonic (_("Ch_eck for Supported Types"));
+
+	authtypes = g_list_prepend (g_list_prepend (NULL, &camel_exchange_password_authtype),
+				    &camel_exchange_ntlm_authtype);
+	store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
+
+	for (i=0, l=authtypes; l; l=l->next, i++) {
+		CamelServiceAuthType *authtype = l->data;
+		gint avail = TRUE;
+
+		if (authtypes) {
+			for (ll = authtypes; ll; ll = g_list_next(ll))
+				if (!strcmp(authtype->authproto,
+					((CamelServiceAuthType *)ll->data)->authproto))
+					break;
+			avail = ll != NULL;
+		}
+		gtk_list_store_append (store, &iter);
+		gtk_list_store_set (store, &iter, 0, authtype->name, 1,
+				    authtype, 2, !avail, -1);
+
+		if (url && url->authmech && !strcmp(url->authmech, authtype->authproto)) {
+			active = i;
+		}
+		else if (url && exchange_account_authtype &&
+			 !strcmp (exchange_account_authtype, authtype->authproto)) {
+			/* if the url doesn't contain authmech, read the value from
+			 * exchange account and set the tab selection and
+			 * also set the authmech back to url
+			 */
+			camel_url_set_authmech (url, exchange_account_authtype);
+			active = i;
+		}
+	}
+
+	gtk_combo_box_set_model (dropdown, (GtkTreeModel *)store);
+	gtk_combo_box_set_active (dropdown, -1);
+
+	if (auth_changed_id == 0) {
+		GtkCellRenderer *cell = gtk_cell_renderer_text_new();
+
+		gtk_cell_layout_pack_start ((GtkCellLayout *)dropdown, cell, TRUE);
+		gtk_cell_layout_set_attributes ((GtkCellLayout *)dropdown, cell,
+						"text", 0, "strikethrough", 2, NULL);
+
+		auth_changed_id = g_signal_connect (dropdown,
+						    "changed",
+						    G_CALLBACK (exchange_authtype_changed),
+						    data->config);
+		g_signal_connect (button,
+				  "clicked",
+				  G_CALLBACK(exchange_check_authtype),
+				  data->config);
+	}
+
+	gtk_combo_box_set_active(dropdown, active);
+
+	gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (dropdown), FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+	gtk_box_pack_start (GTK_BOX (vbox), auth_label, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), label_hide, TRUE, TRUE, 0);
+	gtk_widget_show_all (vbox);
+
+	gtk_box_pack_start (GTK_BOX (data->parent), vbox, TRUE, TRUE, 0);
+
+	if (url)
+		camel_url_free(url);
+	g_list_free (authtypes);
+	g_free (exchange_account_authtype);
+
+	return vbox;
+}
+
+GtkWidget *
+org_gnome_exchange_show_folder_size_factory (EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	EMConfigTargetFolder *target=  (EMConfigTargetFolder *)data->config->target;
+	CamelFolder *cml_folder = target->folder;
+	CamelService *service;
+	CamelProvider *provider;
+	ExchangeAccount *account;
+	GtkWidget *lbl_size, *lbl_size_val;
+	GtkListStore *model;
+	GtkVBox *vbx;
+	GtkHBox *hbx_size;
+	gchar *folder_name, *folder_size;
+	gint mode;
+
+	service = CAMEL_SERVICE (camel_folder_get_parent_store (cml_folder));
+	if (!service)
+		return NULL;
+
+	provider = camel_service_get_provider (service);
+	if (!provider)
+		return NULL;
+
+	if (g_ascii_strcasecmp (provider->protocol, "exchange"))
+		return NULL;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return NULL;
+
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return NULL;
+
+	folder_name = (gchar *) camel_folder_get_name (cml_folder);
+	if (!folder_name)
+		folder_name = g_strdup ("name");
+
+	model = exchange_account_folder_size_get_model (account);
+	if (model)
+		folder_size = g_strdup_printf (_("%s KB"), exchange_folder_size_get_val (model, folder_name));
+	else
+		folder_size = g_strdup (_("0 KB"));
+
+	hbx_size = (GtkHBox*) gtk_hbox_new (FALSE, 0);
+	vbx = (GtkVBox *)gtk_notebook_get_nth_page (GTK_NOTEBOOK (data->parent), 0);
+
+	lbl_size = gtk_label_new_with_mnemonic (_("Size:"));
+	lbl_size_val = gtk_label_new_with_mnemonic (_(folder_size));
+	gtk_widget_show (lbl_size);
+	gtk_widget_show (lbl_size_val);
+	gtk_misc_set_alignment (GTK_MISC (lbl_size), 0.0, 0.5);
+	gtk_misc_set_alignment (GTK_MISC (lbl_size_val), 0.0, 0.5);
+	gtk_box_pack_start (GTK_BOX (hbx_size), lbl_size, FALSE, TRUE, 12);
+	gtk_box_pack_start (GTK_BOX (hbx_size), lbl_size_val, FALSE, TRUE, 10);
+	gtk_widget_show_all (GTK_WIDGET (hbx_size));
+
+	gtk_box_pack_start (GTK_BOX (vbx), GTK_WIDGET (hbx_size), FALSE, FALSE, 0);
+	g_free (folder_size);
+
+	return GTK_WIDGET (hbx_size);
+}
diff --git a/eplugin/exchange-calendar.c b/eplugin/exchange-calendar.c
new file mode 100644
index 0000000..f9f7bd7
--- /dev/null
+++ b/eplugin/exchange-calendar.c
@@ -0,0 +1,539 @@
+/*
+ * 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:
+ *		Praveen Kumar <kpraveen@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <e-util/e-config.h>
+#include <calendar/gui/e-cal-config.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-url.h>
+#include <e-folder.h>
+#include <exchange-account.h>
+#include <libecal/e-cal.h>
+
+#include "calendar/gui/dialogs/calendar-setup.h"
+#include "mail/em-account-editor.h"
+#include "mail/em-config.h"
+#include "libedataserver/e-account.h"
+#include "e-util/e-error.h"
+
+#include "exchange-operations.h"
+#include "exchange-folder-size-display.h"
+
+enum {
+	CALENDARNAME_COL,
+	CALENDARRURI_COL,
+	NUM_COLS
+};
+
+gboolean calendar_src_exists = FALSE;
+gchar *calendar_old_source_uri = NULL;
+
+static GPtrArray *e_exchange_calendar_get_calendars (ECalSourceType ftype);
+void e_exchange_calendar_pcalendar_on_change (GtkTreeView *treeview, ESource *source);
+GtkWidget *e_exchange_calendar_pcalendar (EPlugin *epl, EConfigHookItemFactoryData *data);
+gboolean e_exchange_calendar_check (EPlugin *epl, EConfigHookPageCheckData *data);
+void e_exchange_calendar_commit (EPlugin *epl, EConfigTarget *target);
+
+/* FIXME: Reconsider the prototype of this function */
+static GPtrArray *
+e_exchange_calendar_get_calendars (ECalSourceType ftype)
+{
+	ExchangeAccount *account;
+	GPtrArray *folder_array;
+	GPtrArray *calendar_list;
+	EFolder *folder;
+	gint i, prefix_len;
+	gchar *type;
+	gchar *uri_prefix;
+	gchar *tmp, *ruri;
+	gchar *tstring;
+
+	/* FIXME: Compiler warns here; review needed */
+	if (ftype == E_CAL_SOURCE_TYPE_EVENT) { /* Calendars */
+		tstring = g_strdup ("calendar");
+	}
+	else if (ftype == E_CAL_SOURCE_TYPE_TODO) { /* Tasks */
+		tstring = g_strdup ("tasks");
+	}
+	else {
+		/* FIXME: Would this ever happen? If so, handle it wisely */
+		tstring = NULL;
+	}
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return NULL;
+
+	/* FIXME: Reconsider this hardcoding */
+	uri_prefix = g_strconcat ("exchange://", account->account_filename, "/;", NULL);
+	prefix_len = strlen (uri_prefix);
+
+	calendar_list = g_ptr_array_new ();
+
+	exchange_account_rescan_tree (account);
+	folder_array = exchange_account_get_folders (account);
+
+	for (i=0; i<folder_array->len; ++i) {
+		folder = g_ptr_array_index (folder_array, i);
+		type = (gchar *)e_folder_get_type_string (folder);
+
+		if (!strcmp (type, tstring)) {
+			tmp = (gchar *)e_folder_get_physical_uri (folder);
+			if (g_str_has_prefix (tmp, uri_prefix)) {
+				ruri = g_strdup (tmp+prefix_len);
+				g_ptr_array_add (calendar_list, ruri);
+			}
+		}
+	}
+
+	if (folder_array)
+		g_ptr_array_free (folder_array, TRUE);
+	g_free (uri_prefix);
+	g_free (tstring);
+	return calendar_list;
+}
+
+void
+e_exchange_calendar_pcalendar_on_change (GtkTreeView *treeview, ESource *source)
+{
+	GtkTreeSelection *selection;
+	GtkTreeModel     *model;
+	GtkTreeIter       iter;
+	ExchangeAccount *account;
+	gchar *es_ruri, *ruri;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+	gtk_tree_selection_get_selected(selection, &model, &iter);
+
+	gtk_tree_model_get (model, &iter, CALENDARRURI_COL, &ruri, -1);
+	es_ruri = g_strconcat (account->account_filename, "/;", ruri, NULL);
+	e_source_set_relative_uri (source, es_ruri);
+	g_free (ruri);
+	g_free (es_ruri);
+}
+
+GtkWidget *
+e_exchange_calendar_pcalendar (EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	static GtkWidget *lbl_pcalendar, *scrw_pcalendar, *tv_pcalendar, *lbl_size, *lbl_size_val;
+	static GtkWidget *hidden = NULL;
+	GtkWidget *parent;
+	GtkTreeStore *ts_pcalendar;
+	GtkCellRenderer *cr_calendar;
+	GtkTreeViewColumn *tvc_calendar;
+	GtkListStore *model;
+	GPtrArray *callist;
+	ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
+	ESource *source = t->source;
+	EUri *uri;
+	ExchangeAccount *account;
+	gchar *ruri;
+	gchar *account_name;
+        gchar *uri_text;
+	gchar *cal_name;
+	gchar *folder_size;
+	const gchar *rel_uri;
+	gint row, i;
+	gint offline_status;
+	gchar *offline_msg;
+	GtkWidget *lbl_offline_msg;
+	gboolean is_personal;
+
+	if (!hidden)
+		hidden = gtk_label_new ("");
+
+	if (data->old) {
+		/* FIXME: Review this */
+		gtk_widget_destroy (lbl_pcalendar);
+		gtk_widget_destroy (scrw_pcalendar);
+		gtk_widget_destroy (tv_pcalendar);
+	}
+
+	uri_text = e_source_get_uri (t->source);
+	uri = e_uri_new (uri_text);
+
+	if (uri && strcmp (uri->protocol, "exchange")) {
+		e_uri_free (uri);
+                g_free (uri_text);
+		return hidden;
+	}
+
+	e_uri_free (uri);
+
+	parent = data->parent;
+	row = ((GtkTable*)parent)->nrows;
+
+	exchange_config_listener_get_offline_status (exchange_global_config_listener,
+								    &offline_status);
+	if (offline_status == OFFLINE_MODE) {
+		/* Evolution is in offline mode; we will not be able to create
+		   new folders or modify existing folders. */
+		offline_msg = g_markup_printf_escaped ("<b>%s</b>",
+						       _("Evolution is in offline mode. You cannot create or modify folders now.\nPlease switch to online mode for such operations."));
+		lbl_offline_msg = gtk_label_new ("");
+		gtk_label_set_markup (GTK_LABEL (lbl_offline_msg), offline_msg);
+		g_free (offline_msg);
+		gtk_widget_show (lbl_offline_msg);
+		gtk_table_attach (GTK_TABLE (parent), lbl_offline_msg, 0, 2, row, row+1, GTK_FILL|GTK_EXPAND, 0, 0, 0);
+		g_free (uri_text);
+		return lbl_offline_msg;
+	}
+
+	rel_uri = e_source_peek_relative_uri (t->source);
+	if (rel_uri && strlen (rel_uri)) {
+		calendar_src_exists = TRUE;
+		g_free (calendar_old_source_uri);
+		calendar_old_source_uri = g_strdup (rel_uri);
+	}
+	else {
+		calendar_src_exists = FALSE;
+	}
+
+	/* REVIEW: Should this handle be freed? - Attn: surf */
+	account = exchange_operations_get_exchange_account ();
+	if (!account) {
+		g_free (calendar_old_source_uri);
+		g_free (uri_text);
+		return NULL;
+	}
+	account_name = account->account_name;
+	is_personal = is_exchange_personal_folder (account, uri_text);
+	g_free (uri_text);
+
+	if (calendar_src_exists && is_personal) {
+		cal_name = (gchar *) e_source_peek_name (source);
+		model = exchange_account_folder_size_get_model (account);
+		if (model)
+			folder_size = g_strdup_printf ("%s KB", exchange_folder_size_get_val (model, cal_name));
+		else
+			folder_size = g_strdup ("0 KB");
+
+		/* FIXME: Take care of i18n */
+		lbl_size = gtk_label_new_with_mnemonic (_("Size:"));
+		lbl_size_val = gtk_label_new_with_mnemonic (_(folder_size));
+		gtk_widget_show (lbl_size);
+		gtk_widget_show (lbl_size_val);
+		gtk_misc_set_alignment (GTK_MISC (lbl_size), 0.0, 0.5);
+		gtk_misc_set_alignment (GTK_MISC (lbl_size_val), 0.0, 0.5);
+		gtk_table_attach (GTK_TABLE (parent), lbl_size, 0, 2, row, row+1, GTK_FILL|GTK_EXPAND, 0, 0, 0);
+		gtk_table_attach (GTK_TABLE (parent), lbl_size_val, 1, 3, row, row+1, GTK_FILL|GTK_EXPAND, 0, 0, 0);
+		g_free (folder_size);
+	}
+
+	lbl_pcalendar = gtk_label_new_with_mnemonic (_("_Location:"));
+	gtk_widget_show (lbl_pcalendar);
+	gtk_misc_set_alignment (GTK_MISC (lbl_pcalendar), 0.0, 0.5);
+	gtk_table_attach (GTK_TABLE (parent), lbl_pcalendar, 0, 2, row+1, row+2, GTK_FILL|GTK_EXPAND, 0, 0, 0);
+
+	ts_pcalendar = gtk_tree_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
+
+	callist = e_exchange_calendar_get_calendars (t->source_type);
+
+	if (callist) {
+		for (i = 0; i < callist->len; i++) {
+			ruri = g_ptr_array_index (callist, i);
+			exchange_operations_cta_add_node_to_tree (ts_pcalendar, NULL, ruri);
+		}
+		g_ptr_array_free (callist, TRUE);
+	}
+
+	cr_calendar = gtk_cell_renderer_text_new ();
+	tvc_calendar = gtk_tree_view_column_new_with_attributes (account_name, cr_calendar, "text", CALENDARNAME_COL, NULL);
+	tv_pcalendar = gtk_tree_view_new_with_model (GTK_TREE_MODEL (ts_pcalendar));
+	gtk_tree_view_append_column (GTK_TREE_VIEW (tv_pcalendar), tvc_calendar);
+	g_object_set (tv_pcalendar, "expander-column", tvc_calendar, "headers-visible", TRUE, NULL);
+	gtk_tree_view_expand_all (GTK_TREE_VIEW (tv_pcalendar));
+
+	scrw_pcalendar = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrw_pcalendar), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrw_pcalendar), GTK_SHADOW_IN);
+	g_object_set (scrw_pcalendar, "height-request", 150, NULL);
+	gtk_container_add (GTK_CONTAINER (scrw_pcalendar), tv_pcalendar);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (lbl_pcalendar), tv_pcalendar);
+	g_signal_connect (G_OBJECT (tv_pcalendar), "cursor-changed", G_CALLBACK (e_exchange_calendar_pcalendar_on_change), t->source);
+
+	gtk_table_attach (GTK_TABLE (parent), scrw_pcalendar, 0, 2, row+2, row+3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
+	gtk_widget_show_all (scrw_pcalendar);
+
+	if (calendar_src_exists) {
+		gchar *uri_prefix, *sruri, *tmpruri;
+		gint prefix_len;
+		GtkTreeSelection *selection;
+
+		uri_prefix = g_strconcat (account->account_filename, "/;", NULL);
+		prefix_len = strlen (uri_prefix);
+
+		tmpruri = (gchar *) rel_uri;
+
+		if (g_str_has_prefix (tmpruri, uri_prefix)) {
+			sruri = g_strdup (tmpruri+prefix_len);
+		}
+		else {
+			sruri = NULL;
+		}
+
+		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv_pcalendar));
+		exchange_operations_cta_select_node_from_tree (ts_pcalendar, NULL, sruri, sruri, selection);
+		gtk_widget_set_sensitive (tv_pcalendar, FALSE);
+		g_free (uri_prefix);
+		g_free (sruri);
+	}
+
+	g_object_unref (ts_pcalendar);
+	return tv_pcalendar;
+}
+
+gboolean
+e_exchange_calendar_check (EPlugin *epl, EConfigHookPageCheckData *data)
+{
+	/* FIXME - check pageid */
+	ECalConfigTargetSource *t = (ECalConfigTargetSource *) data->target;
+	ESourceGroup *group;
+	const gchar *base_uri;
+	const gchar *rel_uri;
+	gint offline_status;
+	ExchangeAccount *account;
+	EUri *euri;
+	gint uri_len;
+	gchar *uri_text, *uri_string, *path, *folder_name;
+	gboolean is_personal;
+
+	rel_uri = e_source_peek_relative_uri (t->source);
+	group = e_source_peek_group (t->source);
+	base_uri = e_source_group_peek_base_uri (group);
+	exchange_config_listener_get_offline_status (exchange_global_config_listener,
+						     &offline_status);
+	if (base_uri && !strncmp (base_uri, "exchange", 8)) {
+		if (offline_status == OFFLINE_MODE)
+			return FALSE;
+		if (rel_uri && !strlen (rel_uri))
+			return FALSE;
+	}
+	else {
+		return TRUE;
+	}
+
+	if (!calendar_src_exists) {
+		/* new folder */
+                return TRUE;
+        }
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return FALSE;
+
+	uri_text = e_source_get_uri (t->source);
+	euri = e_uri_new (uri_text);
+	uri_string = e_uri_to_string (euri, FALSE);
+	e_uri_free (euri);
+
+	is_personal = is_exchange_personal_folder (account, uri_text);
+
+	uri_len = strlen (uri_string) + 1;
+	g_free (uri_string);
+	path = g_build_filename ("/", uri_text + uri_len, NULL);
+	g_free (uri_text);
+	folder_name = g_strdup (g_strrstr (path, "/") +1);
+	g_free (path);
+
+	if (strcmp (folder_name, e_source_peek_name (t->source))) {
+		/* rename */
+		if (exchange_account_get_standard_uri (account, folder_name) ||
+		    !is_personal) {
+			/* rename of standard/non-personal folder */
+			g_free (folder_name);
+			return FALSE;
+		}
+	}
+	g_free (folder_name);
+
+	return TRUE;
+}
+
+void
+e_exchange_calendar_commit (EPlugin *epl, EConfigTarget *target)
+{
+	ECalConfigTargetSource *t = (ECalConfigTargetSource *) target;
+	ESource *source = t->source;
+	gchar *uri_text, *gruri, *gname, *ruri, *ftype, *path, *path_prefix, *oldpath=NULL;
+	gchar *username, *windows_domain, *authtype;
+	gint prefix_len;
+	ExchangeAccount *account;
+	ExchangeAccountFolderResult result;
+	ExchangeConfigListenerStatus status;
+	gint offline_status;
+	gboolean rename = FALSE;
+
+	uri_text = e_source_get_uri (source);
+	if (uri_text && strncmp (uri_text, "exchange", 8)) {
+		g_free (uri_text);
+		return;
+	}
+
+	status = exchange_is_offline (&offline_status);
+	if (offline_status == OFFLINE_MODE || status != CONFIG_LISTENER_STATUS_OK) {
+		g_free (uri_text);
+		return;
+	}
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account || !is_exchange_personal_folder (account, uri_text))
+		return;
+
+	windows_domain = exchange_account_get_windows_domain (account);
+	if (windows_domain)
+		username = g_strdup_printf ("%s\\%s", windows_domain,
+					    exchange_account_get_username (account));
+	else
+		username = g_strdup (exchange_account_get_username (account));
+
+	authtype = exchange_account_get_authtype (account);
+
+	path_prefix = g_strconcat (account->account_filename, "/;", NULL);
+	prefix_len = strlen (path_prefix);
+	g_free (path_prefix);
+
+	/* FIXME: Compiler gives a warning here; review needed */
+	if (t->source_type == E_CAL_SOURCE_TYPE_EVENT) {
+		ftype = g_strdup ("calendar");
+	}
+	else if (t->source_type == E_CAL_SOURCE_TYPE_TODO) {
+		ftype = g_strdup ("tasks");
+	}
+	else {
+		/* FIXME: This one would ever occur? */
+		ftype = g_strdup ("mail");
+	}
+
+	gname = (gchar *) e_source_peek_name (source);
+	gruri = (gchar *) e_source_peek_relative_uri (source);
+
+	if (calendar_src_exists) {
+		gchar *tmpruri, *uri_string, *temp_path, *prefix;
+		EUri *euri;
+		gint uri_len;
+
+		/* sample uri_string: exchange://user;auth=NTLM@host/ */
+		/* sample uri_text: exchange://user;auth=NTLM@host/;personal/Calendar */
+
+		euri = e_uri_new (uri_text);
+		uri_string = e_uri_to_string (euri, FALSE);
+		e_uri_free (euri);
+
+		/* sample gruri: user;auth=NTLM@host/;personal/Calendar */
+		/* sample ruri: user;auth=NTLM@host/personal/Calendar */
+		/* sample path: /personal/Calendar */
+
+		uri_len = strlen (uri_string) + 1;
+		tmpruri = g_strdup (uri_string + strlen ("exchange://"));
+		temp_path = g_build_filename ("/", uri_text + uri_len, NULL);
+		prefix  = g_strndup (temp_path, strlen (temp_path) - strlen (g_strrstr (temp_path, "/")));
+		g_free (temp_path);
+		path = g_build_filename (prefix, "/", gname, NULL);
+		ruri = g_strconcat (tmpruri, ";", path+1, NULL);
+		oldpath = g_build_filename ("/", calendar_old_source_uri + prefix_len, NULL);
+		g_free (prefix);
+		g_free (uri_string);
+		g_free (tmpruri);
+	}
+	else {
+		/* new folder */
+		ruri = g_strconcat (gruri, "/", gname, NULL);
+		path = g_build_filename ("/", ruri+prefix_len, NULL);
+	}
+
+	if (!calendar_src_exists) {
+		/* Create the new folder */
+		result = exchange_account_create_folder (account, path, ftype);
+	}
+	else if (gruri && strcmp (path, oldpath)) {
+		/* Rename the folder */
+		rename = TRUE;
+		result = exchange_account_xfer_folder (account, oldpath, path, TRUE);
+	}
+	else {
+		/* Nothing happened specific to exchange; just return */
+		goto done;
+	}
+
+	switch (result) {
+	case EXCHANGE_ACCOUNT_FOLDER_OK:
+		if (result == EXCHANGE_ACCOUNT_FOLDER_OK) {
+			e_source_set_name (source, gname);
+			e_source_set_relative_uri (source, ruri);
+			e_source_set_property (source, "username", username);
+			e_source_set_property (source, "auth-domain", "Exchange");
+			if (authtype) {
+				e_source_set_property (source, "auth-type", authtype);
+				g_free (authtype);
+				authtype=NULL;
+			}
+			e_source_set_property (source, "auth", "1");
+			if (rename) {
+				exchange_operations_update_child_esources (source,
+							   calendar_old_source_uri,
+							   ruri);
+			}
+		}
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-exists-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-doesnt-exist-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_UNKNOWN_TYPE:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-unknown-type", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-perm-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_OFFLINE:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-offline-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_UNSUPPORTED_OPERATION:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-unsupported-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-generic-error", NULL);
+		break;
+	default:
+		break;
+	}
+
+done:
+	g_free (uri_text);
+	g_free (username);
+	if (authtype)
+		g_free (authtype);
+	g_free (ruri);
+	g_free (path);
+	g_free (ftype);
+	g_free (oldpath);
+	g_free (calendar_old_source_uri);
+	calendar_old_source_uri = NULL;
+}
diff --git a/eplugin/exchange-change-password.c b/eplugin/exchange-change-password.c
new file mode 100644
index 0000000..68e93ab
--- /dev/null
+++ b/eplugin/exchange-change-password.c
@@ -0,0 +1,194 @@
+/*
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* exchange-change-password: Change Password code */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "exchange-change-password.h"
+
+#include <exchange-account.h>
+#include <e2k-utils.h>
+
+#include <gtk/gtk.h>
+
+static void
+entry_changed (GtkEntry *entry, gpointer user_data)
+{
+	GtkEntry *new_entry, *confirm_entry;
+	GtkDialog *pass_dialog;
+	const gchar *text;
+
+        new_entry = GTK_ENTRY (entry);
+        confirm_entry = GTK_ENTRY (user_data);
+	pass_dialog = GTK_DIALOG (g_object_get_data (G_OBJECT (new_entry), "pass_dialog"));
+
+	text = gtk_entry_get_text (new_entry);
+	if (!text || !*text) {
+		gtk_dialog_set_response_sensitive (pass_dialog, GTK_RESPONSE_OK, FALSE);
+		return;
+	}
+
+	text = gtk_entry_get_text (confirm_entry);
+	if (!text || !*text) {
+		gtk_dialog_set_response_sensitive (pass_dialog, GTK_RESPONSE_OK, FALSE);
+		return;
+	}
+
+	gtk_dialog_set_response_sensitive (pass_dialog, GTK_RESPONSE_OK, TRUE);
+}
+
+/**
+ * exchange_get_new_password:
+ * @existing_password: The user's current password
+ * @voluntary: %TRUE if the user has chosen "Change Password",
+ * %FALSE if their old password has expired.
+ *
+ * Prompt the user for a new password.
+ */
+gchar *
+exchange_get_new_password (const gchar *existing_password, gboolean voluntary)
+{
+	GtkResponseType response;
+	gchar *new_pass;
+	GtkWidget *pass_dialog;
+	GtkWidget *dialog_vbox1;
+	GtkWidget *pass_label;
+	GtkWidget *table1;
+	GtkWidget *current_pass_label;
+	GtkWidget *new_pass_label;
+	GtkWidget *confirm_pass_label;
+	GtkWidget *current_pass_entry;
+	GtkWidget *new_pass_entry;
+	GtkWidget *confirm_pass_entry;
+
+	pass_dialog = gtk_dialog_new_with_buttons (
+		_("Change Password"),
+		NULL,
+		GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+
+	dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (pass_dialog));
+	gtk_widget_show (dialog_vbox1);
+
+	pass_label = gtk_label_new (_("Your current password has expired. Please change your password now."));
+	gtk_widget_show (pass_label);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), pass_label, FALSE, FALSE, 0);
+	gtk_label_set_justify (GTK_LABEL (pass_label), GTK_JUSTIFY_CENTER);
+	gtk_label_set_line_wrap (GTK_LABEL (pass_label), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (pass_label), 0.52, 0.5);
+	gtk_misc_set_padding (GTK_MISC (pass_label), 0, 6);
+
+	table1 = gtk_table_new (3, 2, FALSE);
+	gtk_widget_show (table1);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), table1, TRUE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (table1), 6);
+	gtk_table_set_row_spacings (GTK_TABLE (table1), 6);
+	gtk_table_set_col_spacings (GTK_TABLE (table1), 6);
+
+	current_pass_label = gtk_label_new_with_mnemonic (_("Current _Password:"));
+	gtk_widget_show (current_pass_label);
+	gtk_table_attach (GTK_TABLE (table1), current_pass_label, 0, 1, 0, 1,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (current_pass_label), 0, 0.5);
+
+	new_pass_label = gtk_label_new_with_mnemonic (_("_New Password:"));
+	gtk_widget_show (new_pass_label);
+	gtk_table_attach (GTK_TABLE (table1), new_pass_label, 0, 1, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (new_pass_label), 0, 0.5);
+
+	confirm_pass_label = gtk_label_new_with_mnemonic (_("_Confirm Password:"));
+	gtk_widget_show (confirm_pass_label);
+	gtk_table_attach (GTK_TABLE (table1), confirm_pass_label, 0, 1, 2, 3,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (confirm_pass_label), 0, 0.5);
+
+	new_pass_entry = gtk_entry_new ();
+	gtk_widget_show (new_pass_entry);
+	gtk_table_attach (GTK_TABLE (table1), new_pass_entry, 1, 2, 1, 2,
+			  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_entry_set_visibility (GTK_ENTRY (new_pass_entry), FALSE);
+
+	confirm_pass_entry = gtk_entry_new ();
+	gtk_widget_show (confirm_pass_entry);
+	gtk_table_attach (GTK_TABLE (table1), confirm_pass_entry, 1, 2, 2, 3,
+			  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_entry_set_visibility (GTK_ENTRY (confirm_pass_entry), FALSE);
+
+	current_pass_entry = gtk_entry_new ();
+	gtk_widget_show (current_pass_entry);
+	gtk_table_attach (GTK_TABLE (table1), current_pass_entry, 1, 2, 0, 1,
+			  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 12);
+	gtk_entry_set_visibility (GTK_ENTRY (current_pass_entry), FALSE);
+
+	g_object_set_data (G_OBJECT (new_pass_entry), "pass_dialog", pass_dialog);
+	g_object_set_data (G_OBJECT (confirm_pass_entry), "pass_dialog", pass_dialog);
+	g_signal_connect (new_pass_entry, "changed", G_CALLBACK (entry_changed), confirm_pass_entry);
+	g_signal_connect (confirm_pass_entry, "changed", G_CALLBACK (entry_changed), new_pass_entry);
+	entry_changed (GTK_ENTRY (new_pass_entry), confirm_pass_entry);
+
+	if (voluntary)
+		gtk_widget_hide (GTK_WIDGET (pass_label));
+
+run_dialog_again:
+	response = gtk_dialog_run (GTK_DIALOG (pass_dialog));
+	if (response == GTK_RESPONSE_OK) {
+		const gchar *cur_pass, *new_pass1, *new_pass2;
+
+		cur_pass = gtk_entry_get_text (GTK_ENTRY (current_pass_entry));
+		new_pass1 = gtk_entry_get_text (GTK_ENTRY (new_pass_entry));
+		new_pass2 = gtk_entry_get_text (GTK_ENTRY (confirm_pass_entry));
+
+		if (existing_password) {
+			if (strcmp (cur_pass, existing_password) != 0) {
+				/* User entered a wrong existing
+				 * password. Prompt him again.
+				 */
+				gtk_label_set_text (GTK_LABEL (pass_label), _("The current password does not match the existing password for your account. Please enter the correct password"));
+				gtk_widget_show (pass_label);
+				goto run_dialog_again;
+			}
+		}
+
+		if (strcmp (new_pass1, new_pass2) != 0) {
+			gtk_label_set_text (GTK_LABEL (pass_label), _("The two passwords do not match. Please re-enter the passwords."));
+			gtk_widget_show (pass_label);
+			goto run_dialog_again;
+		}
+
+		new_pass = g_strdup (new_pass1);
+	} else
+		new_pass = NULL;
+
+	gtk_widget_destroy (pass_dialog);
+
+	return new_pass;
+}
diff --git a/eplugin/exchange-change-password.h b/eplugin/exchange-change-password.h
new file mode 100644
index 0000000..c33a887
--- /dev/null
+++ b/eplugin/exchange-change-password.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_CHANGE_PASSWORD_H__
+#define __EXCHANGE_CHANGE_PASSWORD_H__
+
+#include <exchange-types.h>
+
+G_BEGIN_DECLS
+
+gchar *exchange_get_new_password (const gchar *existing_password,
+				 gboolean    voluntary);
+
+G_END_DECLS
+
+#endif /* __EXCHANGE_CHANGE_PASSWORD_H__ */
diff --git a/eplugin/exchange-config-listener.c b/eplugin/exchange-config-listener.c
new file mode 100644
index 0000000..dc6582b
--- /dev/null
+++ b/eplugin/exchange-config-listener.c
@@ -0,0 +1,1520 @@
+/*
+ * ExchangeConfigListener: a class that listens to the config database
+ * and handles creating the ExchangeAccount object and making sure that
+ * default folders are updated as needed.
+ *
+ * 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/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "exchange-config-listener.h"
+#include "exchange-operations.h"
+#include "exchange-change-password.h"
+
+#include <exchange-constants.h>
+#include <exchange-hierarchy.h>
+#include <exchange-oof.h>
+#include <e-folder-exchange.h>
+#include <e2k-marshal.h>
+#include <e2k-uri.h>
+#include <camel/camel-url.h>
+
+#include <e-util/e-error.h>
+
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-source-group.h>
+#include <libedataserverui/e-passwords.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+struct _ExchangeConfigListenerPrivate {
+	GConfClient *gconf;
+	guint idle_id;
+
+	gchar *configured_uri, *configured_name;
+	EAccount *configured_account;
+
+	ExchangeAccount *exchange_account;
+};
+
+typedef struct {
+	const gchar *name;
+	const gchar *uri;
+	gint type;
+}FolderInfo;
+
+enum {
+	EXCHANGE_ACCOUNT_CREATED,
+	EXCHANGE_ACCOUNT_REMOVED,
+	LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+#define PARENT_TYPE E_TYPE_ACCOUNT_LIST
+
+#define CONF_KEY_SELECTED_CAL_SOURCES "/apps/evolution/calendar/display/selected_calendars"
+#define CONF_KEY_SELECTED_TASKS_SOURCES "/apps/evolution/calendar/tasks/selected_tasks"
+
+static EAccountListClass *parent_class = NULL;
+
+static void dispose (GObject *object);
+static void finalize (GObject *object);
+
+static void account_added   (EAccountList *account_listener,
+			     EAccount     *account);
+static void account_changed (EAccountList *account_listener,
+			     EAccount     *account);
+static void account_removed (EAccountList *account_listener,
+			     EAccount     *account);
+#ifdef LDEAD
+static void exchange_add_autocompletion_folders (GConfClient *gc_client,
+						 ExchangeAccount *account);
+#endif
+static gboolean exchange_camel_urls_is_equal (const gchar *url1,
+					      const gchar *url2);
+static void remove_selected_non_offline_esources (ExchangeAccount *account,
+						  const gchar *gconf_key);
+static void
+class_init (GObjectClass *object_class)
+{
+	EAccountListClass *e_account_list_class =
+		E_ACCOUNT_LIST_CLASS (object_class);
+
+	parent_class = g_type_class_ref (PARENT_TYPE);
+
+	/* virtual method override */
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+
+	e_account_list_class->account_added   = account_added;
+	e_account_list_class->account_changed = account_changed;
+	e_account_list_class->account_removed = account_removed;
+
+	/* signals */
+	signals[EXCHANGE_ACCOUNT_CREATED] =
+		g_signal_new ("exchange_account_created",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (ExchangeConfigListenerClass, exchange_account_created),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_POINTER);
+	signals[EXCHANGE_ACCOUNT_REMOVED] =
+		g_signal_new ("exchange_account_removed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (ExchangeConfigListenerClass, exchange_account_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_POINTER);
+}
+
+static void
+init (GObject *object)
+{
+	ExchangeConfigListener *config_listener =
+		EXCHANGE_CONFIG_LISTENER (object);
+
+	config_listener->priv = g_new0 (ExchangeConfigListenerPrivate, 1);
+}
+
+static void
+dispose (GObject *object)
+{
+	ExchangeConfigListener *config_listener =
+		EXCHANGE_CONFIG_LISTENER (object);
+
+	if (config_listener->priv->idle_id) {
+		g_source_remove (config_listener->priv->idle_id);
+		config_listener->priv->idle_id = 0;
+	}
+
+	if (config_listener->priv->gconf) {
+		g_object_unref (config_listener->priv->gconf);
+		config_listener->priv->gconf = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+	ExchangeConfigListener *config_listener =
+		EXCHANGE_CONFIG_LISTENER (object);
+
+	g_free (config_listener->priv->configured_name);
+	g_free (config_listener->priv->configured_uri);
+	g_free (config_listener->priv);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+E2K_MAKE_TYPE (exchange_config_listener, ExchangeConfigListener, class_init, init, PARENT_TYPE)
+
+#define EVOLUTION_URI_PREFIX     "evolution:/"
+#define EVOLUTION_URI_PREFIX_LEN (sizeof (EVOLUTION_URI_PREFIX) - 1)
+
+static EFolder *
+standard_folder (ExchangeAccount *account, const gchar *folder_type)
+{
+	const gchar *uri;
+
+	uri = exchange_account_get_standard_uri (account, folder_type);
+	if (!uri)
+		return NULL;
+	return exchange_account_get_folder (account, uri);
+}
+
+static void
+set_special_mail_folder (ExchangeAccount *account, const gchar *folder_type,
+			 gchar **folder_uri)
+{
+	EFolder *folder;
+	const gchar *physical_uri;
+	gchar *url_string, *path;
+	CamelURL *camel_url;
+	gint uri_len;
+
+	folder = standard_folder (account, folder_type);
+	if (!folder)
+		return;
+	physical_uri = e_folder_get_physical_uri (folder);
+
+	/* remove; form the uri */
+	camel_url = camel_url_new (physical_uri, NULL);
+	url_string = camel_url_to_string (camel_url, CAMEL_URL_HIDE_ALL);
+	camel_url_free (camel_url);
+	/* sample physical uri: exchange://pnayak;auth=NTLM@164.99.168.136/;personal/Drafts */
+	/* sample url_string: exchange://pnayak;auth=NTLM@164.99.168.136/ */
+	/* sample path:  personal/Drafts */
+	uri_len = strlen (url_string) + 1;
+	path = g_build_filename (physical_uri + uri_len, NULL);
+	*folder_uri = g_strconcat (url_string, path, NULL);
+	g_free (path);
+	g_free (url_string);
+}
+
+static void
+add_defaults_for_account (ExchangeConfigListener *config_listener,
+			  E2kContext *ctx,
+			  ExchangeAccount *account)
+{
+	EAccount *eaccount;
+	gboolean save = FALSE;
+
+#ifdef LDEAD
+	exchange_add_autocompletion_folders (config_listener->priv->gconf, account);
+#endif
+
+	/* FIXME: set exchange account's sent items and drafts folders, by default */
+	eaccount = config_listener->priv->configured_account;
+	if (!e_account_get_string (eaccount, E_ACCOUNT_DRAFTS_FOLDER_URI)) {
+		set_special_mail_folder (account, "drafts",
+					 &eaccount->drafts_folder_uri);
+		save = TRUE;
+	}
+	if (!e_account_get_string (eaccount, E_ACCOUNT_SENT_FOLDER_URI)) {
+		set_special_mail_folder (account, "sentitems",
+					 &eaccount->sent_folder_uri);
+		save = TRUE;
+	}
+	if (save) {
+		e_account_list_change (E_ACCOUNT_LIST (config_listener), eaccount);
+		e_account_list_save (E_ACCOUNT_LIST (config_listener));
+	}
+}
+
+static gboolean
+is_active_exchange_account (EAccount *account)
+{
+	if (!account->enabled)
+		return FALSE;
+	if (!account->source || !account->source->url)
+		return FALSE;
+	return (strncmp (account->source->url, EXCHANGE_URI_PREFIX, 11) == 0);
+}
+
+#if 0 /* Not using the following code anywhere for the moment */
+static void
+add_account_esources (ExchangeAccount *account,
+		      GSList *folders)
+{
+	ESource *source = NULL;
+	ESourceGroup *cal_source_group = NULL;
+	ESourceGroup *tasks_source_group = NULL;
+	ESourceGroup *contacts_source_group = NULL;
+	gchar *relative_uri = NULL, *username = NULL;
+#if 0
+	GSList *ids;
+#endif
+	GConfClient *client;
+	gint mode;
+	ESourceList *cal_source_list, *tasks_source_list, *contacts_source_list;
+	FolderInfo *folder=NULL;
+	gboolean offline_mode = FALSE;
+
+	client = gconf_client_get_default ();
+
+	cal_source_list = e_source_list_new_for_gconf ( client, CONF_KEY_CAL);
+	tasks_source_list = e_source_list_new_for_gconf ( client, CONF_KEY_TASKS);
+	contacts_source_list = e_source_list_new_for_gconf ( client, CONF_KEY_CONTACTS);
+
+	exchange_account_is_offline_sync_set (account, &mode);
+	if (mode == OFFLINE_MODE) {
+		/* If account is marked for offline sync during account
+		 * creation, mark all the folders for offline sync
+		 */
+		offline_mode = TRUE;
+	}
+
+	username = exchange_account_get_username (account);
+
+	/* For each component create a source group */
+
+	cal_source_group = e_source_group_new (account->account_name,
+					       EXCHANGE_URI_PREFIX);
+	tasks_source_group = e_source_group_new (account->account_name,
+						 EXCHANGE_URI_PREFIX);
+	contacts_source_group = e_source_group_new (account->account_name,
+						    EXCHANGE_URI_PREFIX);
+
+	if (!e_source_list_add_group (contacts_source_list, contacts_source_group, -1) ||
+	    !e_source_list_add_group (cal_source_list, cal_source_group, -1) ||
+	    !e_source_list_add_group (tasks_source_list, tasks_source_group, -1)) {
+		goto done;
+	}
+	for (; folders != NULL; folders = g_slist_next (folders)) {
+		/* Create source for each folder and add to the group */
+
+		folder = folders->data;
+		if (folder->type == EXCHANGE_CONTACTS_FOLDER) {
+			source = e_source_new_with_absolute_uri (folder->name,
+								 folder->uri);
+			if (offline_mode)
+				e_source_set_property (source, "offline_sync", "1");
+			if (username)
+				e_source_set_property (source, "username", username);
+			e_source_set_property (source, "auth", "1");
+			e_source_set_property (source, "auth-domain", "Exchange");
+			e_source_group_add_source (contacts_source_group,
+						   source, -1);
+			g_object_unref (source);
+		}
+		else if (folder->type == EXCHANGE_CALENDAR_FOLDER) {
+			relative_uri = g_strdup (folder->uri +
+						 strlen (EXCHANGE_URI_PREFIX));
+			source = e_source_new (folder->name, relative_uri);
+			if (offline_mode)
+				e_source_set_property (source, "offline_sync", "1");
+			if (username)
+				e_source_set_property (source, "username", username);
+			e_source_set_property (source, "auth", "1");
+			e_source_set_property (source, "auth-domain", "Exchange");
+			e_source_group_add_source (cal_source_group,
+						   source, -1);
+#if 0
+			ids = gconf_client_get_list (client,
+						     CONF_KEY_SELECTED_CAL_SOURCES,
+						     GCONF_VALUE_STRING, NULL);
+			ids = g_slist_append (ids,
+					      g_strdup (e_source_peek_uid (source)));
+			gconf_client_set_list (client,
+					       CONF_KEY_SELECTED_CAL_SOURCES,
+					       GCONF_VALUE_STRING, ids, NULL);
+			g_slist_foreach (ids, (GFunc) g_free, NULL);
+			g_slist_free (ids);
+#endif
+			g_object_unref (source);
+			g_free (relative_uri);
+
+		}
+		else if (folder->type == EXCHANGE_TASKS_FOLDER) {
+			relative_uri = g_strdup (folder->uri +
+						 strlen (EXCHANGE_URI_PREFIX));
+			source = e_source_new (folder->name, relative_uri);
+			if (offline_mode == ONLINE_MODE)
+				e_source_set_property (source, "offline_sync", "1");
+			if (username)
+				e_source_set_property (source, "username", username);
+			e_source_set_property (source, "auth", "1");
+			e_source_set_property (source, "auth-domain", "Exchange");
+			e_source_group_add_source (tasks_source_group,
+						   source, -1);
+#if 0
+			ids = gconf_client_get_list (client,
+						     CONF_KEY_SELECTED_TASKS_SOURCES,
+						     GCONF_VALUE_STRING, NULL);
+			ids = g_slist_append (ids,
+					      g_strdup (e_source_peek_uid (source)));
+			gconf_client_set_list (client,
+					       CONF_KEY_SELECTED_TASKS_SOURCES,
+					       GCONF_VALUE_STRING, ids, NULL);
+			g_slist_foreach (ids, (GFunc) g_free, NULL);
+			g_slist_free (ids);
+#endif
+			g_object_unref (source);
+			g_free (relative_uri);
+		}
+	}
+
+	e_source_list_sync (cal_source_list, NULL);
+	e_source_list_sync (tasks_source_list, NULL);
+	e_source_list_sync (contacts_source_list, NULL);
+
+done:
+	g_object_unref (cal_source_group);
+	g_object_unref (tasks_source_group);
+	g_object_unref (contacts_source_group);
+
+	g_object_unref (cal_source_list);
+	g_object_unref (tasks_source_list);
+	g_object_unref (contacts_source_list);
+
+	g_object_unref (client);
+}
+
+static void
+add_new_sources (ExchangeAccount *account)
+{
+	GPtrArray *exchange_folders;
+
+	exchange_folders = exchange_account_get_folders (account);
+        if (exchange_folders && exchange_folders->len > 0) {
+		gint i;
+		const gchar *folder_type;
+		const gchar *folder_name;
+		const gchar *folder_uri;
+		gint type;
+		EFolder *folder;
+		ExchangeHierarchy *hier;
+		gboolean create_esource = FALSE;
+
+		for (i = 0; i < exchange_folders->len; i++) {
+
+			folder = exchange_folders->pdata[i];
+			hier = e_folder_exchange_get_hierarchy (folder);
+			if (hier->type != EXCHANGE_HIERARCHY_PUBLIC) {
+				folder_name = e_folder_get_name (folder);
+				folder_uri = e_folder_get_physical_uri (folder);
+				folder_type = e_folder_get_type_string (folder);
+
+				if (!(strcmp (folder_type, "calendar")) ||
+				    !(strcmp (folder_type, "calendar/public"))) {
+						type = EXCHANGE_CALENDAR_FOLDER;
+						create_esource = TRUE;
+				}
+				else if (!(strcmp (folder_type, "tasks")) ||
+					 !(strcmp (folder_type, "tasks/public"))) {
+						type = EXCHANGE_TASKS_FOLDER;
+						create_esource = TRUE;
+				}
+				else if (!(strcmp (folder_type, "contacts")) ||
+					 !(strcmp (folder_type, "contacts/public")) ||
+					 !(strcmp (folder_type, "contacts/ldap"))) {
+						type = EXCHANGE_CONTACTS_FOLDER;
+						create_esource = TRUE;
+				}
+				else {
+					create_esource = FALSE;
+				}
+
+				if (create_esource)
+					add_folder_esource (account, type,
+							folder_name, folder_uri);
+			} /* End hierarchy type check */
+		} /* End for loop */
+        } /* End check for a list of folders */
+}
+
+static void
+add_sources (ExchangeAccount *account)
+{
+	GPtrArray *exchange_folders;
+
+	exchange_folders = exchange_account_get_folders (account);
+        if (exchange_folders && exchange_folders->len > 0) {
+		gint i;
+		const gchar *folder_type;
+		EFolder *folder;
+		GSList *folders = NULL;
+
+		for (i = 0; i < exchange_folders->len; i++) {
+			FolderInfo *folder_info = g_new0 (FolderInfo, 1);
+
+			folder = exchange_folders->pdata[i];
+			folder_type = e_folder_get_type_string (folder);
+
+			if (!(strcmp (folder_type, "calendar")) ||
+			    !(strcmp (folder_type, "calendar/public"))) {
+				folder_info->name = e_folder_get_name (folder);
+				folder_info->uri = e_folder_get_physical_uri (folder);
+				folder_info->type = EXCHANGE_CALENDAR_FOLDER;
+				folders = g_slist_append (folders, folder_info);
+			}
+			else if (!(strcmp (folder_type, "tasks")) ||
+				 !(strcmp (folder_type, "tasks/public"))) {
+				folder_info->name = e_folder_get_name (folder);
+				folder_info->uri = e_folder_get_physical_uri (folder);
+				folder_info->type = EXCHANGE_TASKS_FOLDER;
+				folders = g_slist_append (folders, folder_info);
+			}
+			else if (!(strcmp (folder_type, "contacts")) ||
+				 !(strcmp (folder_type, "contacts/public")) ||
+				 !(strcmp (folder_type, "contacts/ldap"))) {
+				folder_info->name = e_folder_get_name (folder);
+				folder_info->uri = e_folder_get_physical_uri (folder);
+				folder_info->type = EXCHANGE_CONTACTS_FOLDER;
+				folders = g_slist_append (folders, folder_info);
+			}
+			else
+				g_free (folder_info);
+		}
+		/* Add e-sources for all the folders */
+		add_account_esources (account, folders);
+		g_slist_foreach (folders, (GFunc) g_free, NULL);
+		g_slist_free (folders);
+        }
+}
+#endif
+
+static void
+remove_account_esource (ExchangeAccount *account,
+			FolderType folder_type)
+{
+	ESourceGroup *group;
+	ESource *source = NULL;
+	GSList *groups;
+	GSList *sources;
+	GSList *ids, *node_to_be_deleted;
+	gboolean found_group;
+	const gchar *source_uid;
+	GConfClient *client;
+	ESourceList *source_list = NULL;
+
+	/* Remove the ESource group, to remove all the folders in a component */
+
+	client = gconf_client_get_default ();
+
+	if (folder_type == EXCHANGE_CONTACTS_FOLDER)
+		source_list = e_source_list_new_for_gconf ( client,
+							CONF_KEY_CONTACTS);
+	else if (folder_type == EXCHANGE_CALENDAR_FOLDER)
+		source_list = e_source_list_new_for_gconf ( client,
+							CONF_KEY_CAL);
+	else if (folder_type == EXCHANGE_TASKS_FOLDER)
+		source_list = e_source_list_new_for_gconf ( client,
+							CONF_KEY_TASKS);
+
+	groups = e_source_list_peek_groups (source_list);
+	found_group = FALSE;
+
+	for (; groups != NULL && !found_group; groups = g_slist_next (groups)) {
+		group = E_SOURCE_GROUP (groups->data);
+
+		if (strcmp (e_source_group_peek_name (group), account->account_name) == 0
+                    &&
+                    strcmp (e_source_group_peek_base_uri (group), EXCHANGE_URI_PREFIX) == 0) {
+			sources = e_source_group_peek_sources (group);
+
+			for (; sources != NULL; sources = g_slist_next (sources)) {
+				source = E_SOURCE (sources->data);
+				source_uid = e_source_peek_uid (source);
+
+				/* Remove from the selected folders */
+				if (folder_type == EXCHANGE_CALENDAR_FOLDER) {
+					ids = gconf_client_get_list (
+							client,
+							CONF_KEY_SELECTED_CAL_SOURCES ,
+							GCONF_VALUE_STRING, NULL);
+					if (ids) {
+						node_to_be_deleted = g_slist_find_custom (
+									ids,
+									source_uid,
+									(GCompareFunc) strcmp);
+						if (node_to_be_deleted) {
+							g_free (node_to_be_deleted->data);
+							ids = g_slist_delete_link (ids,
+									node_to_be_deleted);
+							gconf_client_set_list (client,
+								CONF_KEY_SELECTED_CAL_SOURCES,
+								GCONF_VALUE_STRING, ids, NULL);
+						}
+						g_slist_foreach (ids, (GFunc) g_free, NULL);
+						g_slist_free (ids);
+					}
+				}
+				else if (folder_type == EXCHANGE_TASKS_FOLDER) {
+					ids = gconf_client_get_list (client,
+								CONF_KEY_SELECTED_TASKS_SOURCES ,
+								GCONF_VALUE_STRING, NULL);
+					if (ids) {
+						node_to_be_deleted = g_slist_find_custom (
+									ids,
+									source_uid,
+									(GCompareFunc) strcmp);
+						if (node_to_be_deleted) {
+							g_free (node_to_be_deleted->data);
+							ids = g_slist_delete_link (ids,
+									node_to_be_deleted);
+							gconf_client_set_list (client,
+								CONF_KEY_SELECTED_TASKS_SOURCES,
+								GCONF_VALUE_STRING, ids, NULL);
+						}
+						g_slist_foreach (ids, (GFunc) g_free, NULL);
+						g_slist_free (ids);
+					}
+				}
+			}
+			e_source_list_remove_group (source_list, group);
+			e_source_list_sync (source_list, NULL);
+			found_group = TRUE;
+		}
+	}
+	g_object_unref (source_list);
+	g_object_unref (client);
+}
+
+static void
+remove_account_esources (ExchangeAccount *account)
+{
+	/* Remove ESources for all the folders in all the components */
+
+	remove_account_esource (account, EXCHANGE_CALENDAR_FOLDER);
+	remove_account_esource (account, EXCHANGE_TASKS_FOLDER);
+	remove_account_esource (account, EXCHANGE_CONTACTS_FOLDER);
+}
+
+#ifdef HAVE_KRB5
+static gchar *
+get_new_exchange_password (ExchangeAccount *account)
+{
+	gchar *old_password, *new_password;
+
+	old_password = exchange_account_get_password (account);
+	new_password = exchange_get_new_password (old_password, 0);
+
+	if (new_password) {
+		exchange_account_set_password (account,
+					       old_password,
+					       new_password);
+		g_free (old_password);
+		return new_password;
+	}
+	g_free (old_password);
+	return NULL;
+}
+#endif
+
+#ifdef HAVE_KRB5
+static void
+change_passwd_cb (GtkWidget *button, ExchangeAccount *account)
+{
+	gchar *current_passwd, *new_passwd;
+
+	gtk_widget_hide (gtk_widget_get_toplevel(button));
+	current_passwd = exchange_account_get_password (account);
+	new_passwd = exchange_get_new_password (current_passwd, TRUE);
+	exchange_account_set_password (account, current_passwd, new_passwd);
+	g_free (current_passwd);
+	g_free (new_passwd);
+}
+#endif
+
+static void
+display_passwd_expiry_message (gint max_passwd_age, ExchangeAccount *account)
+{
+	GtkResponseType response;
+	GtkWidget *passwd_exp_dialog;
+	GtkWidget *dialog_vbox1;
+	GtkWidget *dialog_action_area1;
+	GtkWidget *change_passwd_button;
+	GtkWidget *warning_msg_label;
+	GtkWidget *ok_button;
+	AtkObject *atko;
+	gchar *passwd_expiry_msg =
+		g_strdup_printf (_("Your password will expire in the next %d days"), max_passwd_age);
+
+
+	passwd_exp_dialog = gtk_dialog_new ();
+	gtk_window_set_title (GTK_WINDOW (passwd_exp_dialog), _("Password Expiry Warning..."));
+	gtk_window_set_position (GTK_WINDOW (passwd_exp_dialog), GTK_WIN_POS_CENTER_ON_PARENT);
+	gtk_window_set_type_hint (GTK_WINDOW (passwd_exp_dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+	dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (passwd_exp_dialog));
+	gtk_widget_show (dialog_vbox1);
+
+	warning_msg_label = gtk_label_new (passwd_expiry_msg);
+	gtk_widget_show (warning_msg_label);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), warning_msg_label, FALSE, FALSE, 0);
+	gtk_label_set_justify (GTK_LABEL (warning_msg_label), GTK_JUSTIFY_CENTER);
+	gtk_misc_set_padding (GTK_MISC (warning_msg_label), 0, 20);
+
+	dialog_action_area1 = gtk_dialog_get_action_area (GTK_DIALOG (passwd_exp_dialog));
+	gtk_widget_show (dialog_action_area1);
+	gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END);
+
+	change_passwd_button = gtk_button_new_with_mnemonic (_("_Change Password"));
+	gtk_widget_show (change_passwd_button);
+	gtk_dialog_add_action_widget (GTK_DIALOG (passwd_exp_dialog), change_passwd_button, 0);
+	GTK_WIDGET_SET_FLAGS (change_passwd_button, GTK_CAN_DEFAULT);
+
+	ok_button = gtk_button_new_from_stock ("gtk-ok");
+	gtk_widget_show (ok_button);
+	gtk_dialog_add_action_widget (GTK_DIALOG (passwd_exp_dialog), ok_button, GTK_RESPONSE_OK);
+	GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT);
+
+	atko = gtk_widget_get_accessible (ok_button);
+	atk_object_set_name (atko, "ok_button");
+
+	gtk_widget_grab_focus (change_passwd_button);
+	gtk_widget_grab_default (change_passwd_button);
+
+	gtk_widget_set_sensitive (change_passwd_button, TRUE);
+#ifdef HAVE_KRB5
+	g_signal_connect (change_passwd_button,
+			  "clicked",
+			  G_CALLBACK (change_passwd_cb),
+			  account);
+#endif
+	response = gtk_dialog_run (GTK_DIALOG (passwd_exp_dialog));
+
+	gtk_widget_destroy (passwd_exp_dialog);
+	g_free (passwd_expiry_msg);
+}
+
+static gint
+run_oof_dialog (void)
+{
+	GtkWidget *oof_dialog;
+	GtkWidget *dialog_vbox1;
+	GtkWidget *hbox9;
+	GtkWidget *image3;
+	GtkWidget *label7;
+	GtkWidget *dialog_action_area1;
+	GtkWidget *button3;
+	GtkWidget *alignment3;
+	GtkWidget *hbox6;
+	GtkWidget *image7;
+	GtkWidget *label10;
+	GtkWidget *button4;
+	GtkWidget *alignment4;
+	GtkWidget *hbox7;
+	GtkWidget *image8;
+	GtkWidget *label11;
+	gchar *tmp_str;
+	gint res;
+
+	oof_dialog = gtk_dialog_new ();
+	gtk_container_set_border_width (GTK_CONTAINER (oof_dialog), 6);
+	gtk_window_set_title (GTK_WINDOW (oof_dialog), _("Out of Office Assistant"));
+	gtk_window_set_position (GTK_WINDOW (oof_dialog), GTK_WIN_POS_CENTER_ON_PARENT);
+	gtk_window_set_resizable (GTK_WINDOW (oof_dialog), FALSE);
+	gtk_window_set_type_hint (GTK_WINDOW (oof_dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+	dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (oof_dialog));
+	gtk_widget_show (dialog_vbox1);
+
+	hbox9 = gtk_hbox_new (FALSE, 6);
+	gtk_widget_show (hbox9);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), hbox9, TRUE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox9), 6);
+
+	image3 = gtk_image_new_from_stock ("gtk-dialog-question", GTK_ICON_SIZE_DIALOG);
+	gtk_widget_show (image3);
+	gtk_box_pack_start (GTK_BOX (hbox9), image3, FALSE, TRUE, 0);
+
+	tmp_str = g_strconcat ("<b>", _("Currently, your status is \"Out of the Office\"."), "</b>\n\n", _("Would you like to change your status to \"In the Office\"?"), NULL);
+	label7 = gtk_label_new (tmp_str);
+	g_free (tmp_str);
+	gtk_widget_show (label7);
+	gtk_box_pack_start (GTK_BOX (hbox9), label7, TRUE, TRUE, 0);
+	gtk_label_set_use_markup (GTK_LABEL (label7), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (label7), 0, 0.5);
+
+	dialog_action_area1 = gtk_dialog_get_action_area (GTK_DIALOG (oof_dialog));
+	gtk_widget_show (dialog_action_area1);
+	gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END);
+
+	button3 = gtk_button_new ();
+	gtk_widget_show (button3);
+	gtk_dialog_add_action_widget (GTK_DIALOG (oof_dialog), button3, GTK_RESPONSE_NO);
+	GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT);
+
+	alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0);
+	gtk_widget_show (alignment3);
+	gtk_container_add (GTK_CONTAINER (button3), alignment3);
+
+	hbox6 = gtk_hbox_new (FALSE, 2);
+	gtk_widget_show (hbox6);
+	gtk_container_add (GTK_CONTAINER (alignment3), hbox6);
+
+	image7 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON);
+	gtk_widget_show (image7);
+	gtk_box_pack_start (GTK_BOX (hbox6), image7, FALSE, FALSE, 0);
+
+	label10 = gtk_label_new_with_mnemonic (_("_No, Don't Change Status"));
+	gtk_widget_show (label10);
+	gtk_box_pack_start (GTK_BOX (hbox6), label10, FALSE, FALSE, 0);
+
+	button4 = gtk_button_new ();
+	gtk_widget_show (button4);
+	gtk_dialog_add_action_widget (GTK_DIALOG (oof_dialog), button4, GTK_RESPONSE_YES);
+	GTK_WIDGET_SET_FLAGS (button4, GTK_CAN_DEFAULT);
+
+	alignment4 = gtk_alignment_new (0.5, 0.5, 0, 0);
+	gtk_widget_show (alignment4);
+	gtk_container_add (GTK_CONTAINER (button4), alignment4);
+
+	hbox7 = gtk_hbox_new (FALSE, 2);
+	gtk_widget_show (hbox7);
+	gtk_container_add (GTK_CONTAINER (alignment4), hbox7);
+
+	image8 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON);
+	gtk_widget_show (image8);
+	gtk_box_pack_start (GTK_BOX (hbox7), image8, FALSE, FALSE, 0);
+
+	label11 = gtk_label_new_with_mnemonic (_("_Yes, Change Status"));
+	gtk_widget_show (label11);
+	gtk_box_pack_start (GTK_BOX (hbox7), label11, FALSE, FALSE, 0);
+
+	res = gtk_dialog_run (GTK_DIALOG (oof_dialog));
+	gtk_widget_destroy (oof_dialog);
+
+	return res;
+}
+
+ExchangeAccountResult
+exchange_config_listener_authenticate (ExchangeConfigListener *ex_conf_listener, ExchangeAccount *account)
+{
+	ExchangeConfigListenerPrivate *priv;
+	ExchangeAccountResult result;
+	gchar *key, *password, *title, *url_string;
+#ifdef HAVE_KRB5
+	gchar *new_password;
+#endif
+	gboolean oldremember, remember = FALSE;
+	CamelURL *camel_url;
+	const gchar *remember_password;
+
+	g_return_val_if_fail (EXCHANGE_IS_CONFIG_LISTENER (ex_conf_listener), EXCHANGE_ACCOUNT_CONFIG_ERROR);
+	priv = ex_conf_listener->priv;
+
+	camel_url = camel_url_new (priv->configured_uri, NULL);
+	key = camel_url_to_string (camel_url, CAMEL_URL_HIDE_PASSWORD | CAMEL_URL_HIDE_PARAMS);
+	remember_password = camel_url_get_param (camel_url, "save-passwd");
+	password = e_passwords_get_password ("Exchange", key);
+	if (!password) {
+		oldremember = remember = exchange_account_is_save_password (account);
+		title = g_strdup_printf (_("Enter Password for %s"), account->account_name);
+		password = e_passwords_ask_password (title, "Exchange", key, title,
+						     E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET,
+						     &remember, NULL);
+		if (remember != oldremember) {
+			exchange_account_set_save_password (account, remember);
+			camel_url_set_param (camel_url, "save-passwd", remember? "true" : "false");
+			url_string = camel_url_to_string (camel_url, 0);
+			e_account_set_string (ex_conf_listener->priv->configured_account, E_ACCOUNT_SOURCE_URL, url_string);
+			e_account_set_string (ex_conf_listener->priv->configured_account, E_ACCOUNT_TRANSPORT_URL, url_string);
+			e_account_set_bool (ex_conf_listener->priv->configured_account, E_ACCOUNT_SOURCE_SAVE_PASSWD, remember);
+			e_account_list_change (E_ACCOUNT_LIST (ex_conf_listener), ex_conf_listener->priv->configured_account);
+			e_account_list_save (E_ACCOUNT_LIST (ex_conf_listener));
+			g_free (url_string);
+		}
+		g_free (title);
+	}
+	else if (remember_password && !g_ascii_strcasecmp (remember_password, "false")) {
+		/* get_password returns the password cached but user has not
+		 * selected remember password option, forget this password
+		 * whis is stored temporarily by e2k_validate_user(), to avoid
+		 * asking for password again, at the end of account creation.
+		 */
+		e_passwords_forget_password ("Exchange", key);
+		exchange_account_set_save_password (account, FALSE);
+	}
+
+	exchange_account_connect (account, password, &result);
+
+	g_free (password);
+	g_free (key);
+	camel_url_free (camel_url);
+
+	if (result == EXCHANGE_ACCOUNT_PASSWORD_EXPIRED) {
+#ifdef HAVE_KRB5
+		new_password = get_new_exchange_password (account);
+		if (new_password) {
+			/* try connecting with new password */
+			exchange_account_connect (account, new_password, &result);
+			g_free (new_password);
+		}
+#endif
+	}
+	else if (result == EXCHANGE_ACCOUNT_QUOTA_RECIEVE_ERROR ||
+		 result == EXCHANGE_ACCOUNT_QUOTA_SEND_ERROR ||
+		 result == EXCHANGE_ACCOUNT_QUOTA_WARN) {
+		gchar *current_quota_usage = NULL;
+		const gchar *error_code = NULL;
+		GtkWidget *widget;
+
+		switch (result) {
+			case EXCHANGE_ACCOUNT_QUOTA_RECIEVE_ERROR:
+				current_quota_usage = g_strdup_printf ("%.2f",
+							account->mbox_size);
+				error_code = "org-gnome-exchange-operations:account-quota-error";
+				break;
+			case EXCHANGE_ACCOUNT_QUOTA_SEND_ERROR:
+				current_quota_usage = g_strdup_printf ("%.2f",
+							account->mbox_size);
+				error_code = "org-gnome-exchange-operations:account-quota-send-error";
+				break;
+			case EXCHANGE_ACCOUNT_QUOTA_WARN:
+				current_quota_usage = g_strdup_printf ("%.2f",
+							account->mbox_size);
+				error_code = "org-gnome-exchange-operations:account-quota-warn";
+				break;
+			default:
+				break;
+		}
+
+		if (current_quota_usage) {
+			widget = e_error_new (NULL, error_code, current_quota_usage, NULL);
+			g_signal_connect ((GtkDialog *)widget, "response",
+					  G_CALLBACK (gtk_widget_destroy), widget);
+			gtk_widget_show (widget);
+			g_free (current_quota_usage);
+		}
+
+		/* reset result, so that we check if the password
+		 * expiry warning period
+		 */
+		result = EXCHANGE_ACCOUNT_CONNECT_SUCCESS;
+	}
+	if (result == EXCHANGE_ACCOUNT_CONNECT_SUCCESS) {
+		gint max_pwd_age_days;
+		gboolean oof;
+
+		/* check for password expiry warning */
+		max_pwd_age_days = exchange_account_check_password_expiry (account);
+		if (max_pwd_age_days >= 0) {
+			display_passwd_expiry_message (max_pwd_age_days, account);
+		}
+
+		/* check for oof state */
+		if (exchange_oof_get (account, &oof, NULL)) {
+			if (oof) {
+				/* OOF state is set, check if user wants to set it back to in-office */
+				if (run_oof_dialog () == GTK_RESPONSE_YES)
+					if (!exchange_oof_set (account, FALSE, NULL))
+						e_error_run (NULL, "org-gnome-exchange-operations:state-update-error", NULL);
+			}
+		}
+	}
+	return result;
+}
+
+static void
+account_added (EAccountList *account_list, EAccount *account)
+{
+	ExchangeConfigListener *config_listener;
+	ExchangeAccount *exchange_account;
+	gint is_offline;
+
+	if (!is_active_exchange_account (account))
+		return;
+
+	config_listener = EXCHANGE_CONFIG_LISTENER (account_list);
+	if (config_listener->priv->configured_account) {
+		/* Multiple accounts configured. */
+		e_error_run (NULL, "org-gnome-exchange-operations:single-account-error", NULL);
+		return;
+	}
+
+	/* New account! Yippee! */
+	exchange_account = exchange_account_new (account_list, account);
+	if (!exchange_account) {
+		g_warning ("Could not parse exchange uri '%s'",
+			   account->source->url);
+		return;
+	}
+
+	config_listener->priv->exchange_account = exchange_account;
+	config_listener->priv->configured_account = account;
+
+	g_free (config_listener->priv->configured_uri);
+	config_listener->priv->configured_uri = g_strdup (account->source->url);
+	g_free (config_listener->priv->configured_name);
+	config_listener->priv->configured_name = g_strdup (account->name);
+
+	g_signal_connect_swapped (config_listener->priv->exchange_account,
+				  "connected",
+				  G_CALLBACK (add_defaults_for_account),
+				  config_listener);
+
+	g_signal_emit (config_listener, signals[EXCHANGE_ACCOUNT_CREATED], 0,
+		       exchange_account);
+/*	add_sources (exchange_account); */
+
+	exchange_config_listener_get_offline_status (config_listener, &is_offline);
+
+	if (is_offline == OFFLINE_MODE) {
+		remove_selected_non_offline_esources (exchange_account, CONF_KEY_CAL);
+		remove_selected_non_offline_esources (exchange_account, CONF_KEY_TASKS);
+		return;
+	}
+	exchange_account_set_online (exchange_account);
+	exchange_config_listener_authenticate (config_listener, exchange_account);
+	exchange_account_set_online (exchange_account);
+}
+
+struct account_update_data {
+	EAccountList *account_list;
+	EAccount *account;
+};
+
+static void
+configured_account_destroyed (gpointer user_data, GObject *where_account_was)
+{
+	struct account_update_data *aud = user_data;
+
+	if (!EXCHANGE_CONFIG_LISTENER (aud->account_list)->priv->configured_account)
+		account_added (aud->account_list, aud->account);
+
+	g_object_unref (aud->account_list);
+	g_object_unref (aud->account);
+	g_free (aud);
+}
+
+static gboolean
+requires_relogin (gchar *current_url, gchar *new_url)
+{
+	E2kUri *current_uri, *new_uri;
+	const gchar *current_param_val, *new_param_val;
+	const gchar *params [] = { "owa_url", "ad_server", "use_ssl" };
+	const gint n_params = G_N_ELEMENTS (params);
+	gint i;
+	gboolean relogin = FALSE;
+
+	current_uri = e2k_uri_new (current_url);
+	new_uri = e2k_uri_new (new_url);
+
+	if (strcmp (current_uri->user, new_uri->user) ||
+	    strcmp (current_uri->host, new_uri->host)) {
+		relogin = TRUE;
+		goto end;
+	}
+
+	if (current_uri->authmech || new_uri->authmech) {
+		if (current_uri->authmech && new_uri->authmech) {
+			if (strcmp (current_uri->authmech, new_uri->authmech)) {
+				/* Auth mechanism has changed */
+				relogin = TRUE;
+				goto end;
+			}
+		}
+		else {
+			/* Auth mechanism is set for the first time */
+			relogin = TRUE;
+			goto end;
+		}
+	}
+
+	for (i=0; i<n_params; i++) {
+		current_param_val = e2k_uri_get_param (current_uri, params[i]);
+		new_param_val = e2k_uri_get_param (new_uri, params[i]);
+
+		if (current_param_val && new_param_val) {
+			/* both the urls have params to be compared */
+			if (strcmp (current_param_val, new_param_val)) {
+				relogin = TRUE;
+				break;
+			}
+		}
+		else if (current_param_val || new_param_val) {
+			/* check for added or deleted parameter */
+			relogin = TRUE;
+			break;
+		}
+	}
+end:
+	e2k_uri_free (new_uri);
+	e2k_uri_free (current_uri);
+	return relogin;
+}
+
+static void
+account_changed (EAccountList *account_list, EAccount *account)
+{
+	ExchangeConfigListener *config_listener =
+		EXCHANGE_CONFIG_LISTENER (account_list);
+	ExchangeConfigListenerPrivate *priv = config_listener->priv;
+
+	if (account != config_listener->priv->configured_account) {
+		if (!is_active_exchange_account (account))
+			return;
+
+		/* The user has converted an existing non-Exchange
+		 * account to an Exchange account, so treat it like an
+		 * add.
+		 */
+		account_added (account_list, account);
+		return;
+	} else if (!is_active_exchange_account (account)) {
+		/* The user has disabled the Exchange account or
+		 * converted it to non-Exchange, so treat it like a
+		 * remove.
+		 */
+		account_removed (account_list, account);
+		return;
+	}
+
+	/* FIXME: The order of the parameters in the Camel URL string is not in
+	 * order for the two given strings. So, we will not be able to use
+	 * plain string comparison. Instead compare the parameters one by one.
+	 */
+	if (exchange_camel_urls_is_equal (config_listener->priv->configured_uri,
+					  account->source->url) &&
+	    !strcmp (config_listener->priv->configured_name, account->name)) {
+		/* The user changed something we don't care about. */
+		return;
+	}
+
+	/* OK, so he modified the active account in a way we care
+	 * about. If the user hasn't connected yet, we're still ok.
+	 */
+	if (!exchange_account_get_context (config_listener->priv->exchange_account)) {
+		/* Good. Remove the current account, and wait for it
+		 * to actually go away (which may not happen immediately
+		 * since there may be a function higher up on the stack
+		 * still holding a ref on it). Then create the new one.
+		 * (We have to wait for it to go away because the new
+		 * storage probably still has the same name as the old
+		 * one, so trying to create it before the old one is
+		 * removed would fail.)
+		 */
+		struct account_update_data *aud;
+
+		aud = g_new (struct account_update_data, 1);
+		aud->account = g_object_ref (account);
+		aud->account_list = g_object_ref (account_list);
+		g_object_weak_ref (G_OBJECT (config_listener->priv->exchange_account), configured_account_destroyed, aud);
+
+		account_removed (account_list, account);
+		return;
+	}
+
+	/* If account name has changed, or the url value has changed, which
+	 * could be due to change in hostname or some parameter value,
+	 * remove old e-sources
+	 */
+	if (requires_relogin (config_listener->priv->configured_uri,
+			      account->source->url)) {
+		remove_account_esources (priv->exchange_account);
+		exchange_account_forget_password (priv->exchange_account);
+	} else if (strcmp (config_listener->priv->configured_name, account->name)) {
+/*		remove_account_esources (priv->exchange_account); */
+		exchange_config_listener_modify_esource_group_name (config_listener,
+								    config_listener->priv->configured_name,
+								    account->name);
+		g_free (config_listener->priv->configured_name);
+		config_listener->priv->configured_name = g_strdup (account->name);
+		return;
+	} else {
+		/* FIXME: Do ESources need to be modified? */
+		return;
+	}
+
+	/* Nope. Let the user know we're ignoring him. */
+	e_error_run (NULL, "org-gnome-exchange-operations:apply-restart",
+		     priv->configured_name, NULL);
+
+	/* But note the new URI so if he changes something else, we
+	 * only warn again if he changes again.
+	 */
+	g_free (config_listener->priv->configured_uri);
+	config_listener->priv->configured_uri = g_strdup (account->source->url);
+}
+
+static void
+account_removed (EAccountList *account_list, EAccount *account)
+{
+	ExchangeConfigListener *config_listener =
+		EXCHANGE_CONFIG_LISTENER (account_list);
+	ExchangeConfigListenerPrivate *priv = config_listener->priv;
+
+	if (account != priv->configured_account)
+		return;
+
+	/* Remove all ESources */
+	remove_account_esources (priv->exchange_account);
+
+	exchange_account_forget_password (priv->exchange_account);
+
+	if (!exchange_account_get_context (priv->exchange_account)) {
+		/* The account isn't connected yet, so we can destroy
+		 * it without problems.
+		 */
+		g_signal_emit (config_listener,
+			       signals[EXCHANGE_ACCOUNT_REMOVED], 0,
+			       priv->exchange_account);
+
+		priv->configured_account = NULL;
+		g_free (priv->configured_uri);
+		priv->configured_uri = NULL;
+		g_free (priv->configured_name);
+		priv->configured_name = NULL;
+	}
+}
+
+static gboolean
+idle_construct (gpointer data)
+{
+	ExchangeConfigListener *config_listener = data;
+
+	config_listener->priv->idle_id = 0;
+	e_account_list_construct (E_ACCOUNT_LIST (config_listener),
+				  config_listener->priv->gconf);
+	return FALSE;
+}
+
+ExchangeConfigListenerStatus
+exchange_config_listener_get_offline_status (ExchangeConfigListener *excl,
+					     gint *mode)
+{
+	ExchangeConfigListenerPrivate *priv;
+	GConfValue *value;
+	ExchangeConfigListenerStatus status = CONFIG_LISTENER_STATUS_OK;
+	gboolean offline = FALSE;
+
+	g_return_val_if_fail (excl != NULL, CONFIG_LISTENER_STATUS_NOT_FOUND);
+
+	priv = excl->priv;
+	value = gconf_client_get (priv->gconf,
+					"/apps/evolution/shell/start_offline", NULL);
+	if (value)
+		offline = gconf_value_get_bool (value);
+
+	if (offline)
+		*mode = OFFLINE_MODE;
+	else
+		*mode = ONLINE_MODE;
+
+	gconf_value_free (value);
+	return status;
+
+}
+
+/**
+ * exchange_config_listener_new:
+ *
+ * This creates and returns a new #ExchangeConfigListener, which
+ * monitors GConf and creates and (theoretically) destroys accounts
+ * accordingly. It will emit an %account_created signal when a new
+ * account is created (or shortly after the listener itself is created
+ * if an account already exists).
+ *
+ * Due to various constraints, the user is currently limited to a
+ * single account, and it is not possible to destroy an existing
+ * account. Thus, the %account_created signal will never be emitted
+ * more than once currently.
+ *
+ * Return value: the new config listener.
+ **/
+ExchangeConfigListener *
+exchange_config_listener_new (void)
+{
+	ExchangeConfigListener *config_listener;
+
+	config_listener = g_object_new (EXCHANGE_TYPE_CONFIG_LISTENER, NULL);
+	config_listener->priv->gconf = gconf_client_get_default ();
+
+	config_listener->priv->idle_id =
+		g_idle_add (idle_construct, config_listener);
+
+	return config_listener;
+}
+
+GSList *
+exchange_config_listener_get_accounts (ExchangeConfigListener *config_listener)
+{
+	g_return_val_if_fail (EXCHANGE_IS_CONFIG_LISTENER (config_listener), NULL);
+
+	if (config_listener->priv->exchange_account)
+		return g_slist_append (NULL, config_listener->priv->exchange_account);
+	else
+		return NULL;
+}
+
+/**
+ * exchange_config_listener_modify_esource_group_name
+ *
+ * @excl: Handle for Exchange Config Listener
+ * @old_name: Old name of the ESourceGroup
+ * @new_name: New name of the ESourceGroup
+ *
+ * This function modifies the old source group name to the specified new
+ * source group name
+ **/
+void
+exchange_config_listener_modify_esource_group_name (ExchangeConfigListener *excl,
+							 const gchar *old_name,
+							 const gchar *new_name)
+{
+	GConfClient *client;
+	ESourceGroup *group;
+	GSList *groups;
+	ESourceList *c_source_list = NULL, *t_source_list = NULL,
+		*a_source_list = NULL;
+
+	client = excl->priv->gconf;
+
+	c_source_list = e_source_list_new_for_gconf ( client, CONF_KEY_CAL);
+	t_source_list = e_source_list_new_for_gconf ( client, CONF_KEY_TASKS);
+	a_source_list = e_source_list_new_for_gconf ( client, CONF_KEY_CONTACTS);
+
+	groups = e_source_list_peek_groups (c_source_list);
+
+	for (; groups != NULL; groups = g_slist_next (groups)) {
+		group = E_SOURCE_GROUP (groups->data);
+		if (!strcmp (e_source_group_peek_name (group), old_name)) {
+			e_source_group_set_name (group, new_name);
+			break;
+		}
+	}
+
+	groups = e_source_list_peek_groups (t_source_list);
+
+	for (; groups != NULL; groups = g_slist_next (groups)) {
+		group = E_SOURCE_GROUP (groups->data);
+		if (!strcmp (e_source_group_peek_name (group), old_name)) {
+			e_source_group_set_name (group, new_name);
+			break;
+		}
+	}
+
+	groups = e_source_list_peek_groups (a_source_list);
+
+	for (; groups != NULL; groups = g_slist_next (groups)) {
+		group = E_SOURCE_GROUP (groups->data);
+		if (!strcmp (e_source_group_peek_name (group), old_name)) {
+			e_source_group_set_name (group, new_name);
+			break;
+		}
+	}
+
+	e_source_list_sync (c_source_list, NULL);
+	e_source_list_sync (t_source_list, NULL);
+	e_source_list_sync (a_source_list, NULL);
+
+	g_object_unref (c_source_list);
+	g_object_unref (t_source_list);
+	g_object_unref (a_source_list);
+}
+
+#ifdef LDEAD
+/**
+ * exchange_add_autocompletion_folders:
+ *
+ * @gc_client: GConfClient handle
+ * @account: ExchangeAccount handle
+ *
+ * This function adds the GAL of the Exchange account to the autocompletion list
+ * while configuring a new Exchange account
+ *
+ **/
+static void
+exchange_add_autocompletion_folders (GConfClient *gc_client, ExchangeAccount *account)
+{
+	ESourceList *sl=NULL;
+	ESource *source;
+	GSList *groups;
+	gboolean found_group=FALSE;
+
+	sl = e_source_list_new_for_gconf (gc_client, CONF_KEY_CONTACTS);
+	groups = e_source_list_peek_groups (sl);
+
+	for (; groups != NULL && !found_group; groups = g_slist_next (groups)) {
+		ESourceGroup *group = E_SOURCE_GROUP (groups->data);
+
+		if (strcmp (e_source_group_peek_name (group), account->account_name) == 0
+                    &&
+		    strcmp (e_source_group_peek_base_uri (group), EXCHANGE_URI_PREFIX) == 0) {
+			GSList *sources = e_source_group_peek_sources (group);
+
+			for (; sources != NULL; sources = g_slist_next (sources)) {
+				ESource *source = E_SOURCE (sources->data);
+				const gchar *absolute_uri;
+
+				absolute_uri = e_source_peek_absolute_uri (source);
+				if (absolute_uri == NULL)
+					continue;
+				if (g_str_has_prefix (absolute_uri, "gal://")) {
+					/* Set autocompletion on GAL alone by default */
+					e_source_set_property (source, "completion", "true");
+					break;
+				}
+			}
+			found_group = TRUE;
+		}
+	}
+
+	g_object_unref (sl);
+}
+#endif
+
+/**
+ * exchange_camel_urls_is_equal
+ *
+ * @url1: CAMEL URL string 1
+ * @url2: CAMEL URL string 2
+ *
+ * This function checks if the parameters present in two given CAMEL URLS are
+ * identical and returns the result.
+ *
+ * Return Value: Boolean result of the comparision.
+ *
+ **/
+static gboolean
+exchange_camel_urls_is_equal (const gchar *url1, const gchar *url2)
+{
+	CamelURL *curl1, *curl2;
+	gchar *param1, *param2;
+	const gchar *params[] = {
+		"auth",
+		"owa_url",
+		"owa_path",
+		"mailbox",
+		"ad_server",
+	};
+	const gint n_params = 5;
+	gint i;
+
+	curl1 = camel_url_new (url1, NULL);
+	curl2 = camel_url_new (url2, NULL);
+
+	for (i = 0; i < n_params; ++i) {
+		param1 = (gchar *) camel_url_get_param (curl1, params[i]);
+		param2 = (gchar *) camel_url_get_param (curl2, params[i]);
+		if ((param1 && !param2) || (!param1 && param2) || /* Missing */
+		    (param1 && param2 && strcmp (param1, param2))) { /* Differing */
+			g_free (param1);
+			g_free (param2);
+			g_free (curl1);
+			g_free (curl2);
+			return FALSE;
+		}
+		g_free (param1);
+		g_free (param2);
+	}
+	g_free (curl1);
+	g_free (curl2);
+	return TRUE;
+}
+
+/**
+ * remove_selected_non_offline_esources
+ *
+ * @account: Handle for Exchange Account
+ * @gconf_key: GConf key of the calendar or tasks
+ *
+ * This function removes the non-offline calendars and taks list from the
+ * selection list
+ **/
+static void
+remove_selected_non_offline_esources (ExchangeAccount *account, const gchar *gconf_key)
+{
+	ESourceGroup *group;
+	ESource *source = NULL;
+	GSList *groups;
+	GSList *sources;
+	GSList *ids, *node_to_be_deleted;
+	gboolean found_group;
+	const gchar *source_uid;
+	GConfClient *client;
+	ESourceList *source_list = NULL;
+	const gchar *offline_mode=NULL;
+	gchar *selected_gconf_key;
+
+	if (gconf_key && !strcmp (gconf_key, CONF_KEY_CAL)) {
+		selected_gconf_key = g_strdup (CONF_KEY_SELECTED_CAL_SOURCES);
+	} else if (gconf_key && !strcmp (gconf_key, CONF_KEY_TASKS)) {
+		selected_gconf_key = g_strdup (CONF_KEY_SELECTED_TASKS_SOURCES);
+	}
+	else {
+		return;
+	}
+
+	client = gconf_client_get_default ();
+	source_list = e_source_list_new_for_gconf ( client, gconf_key);
+
+	groups = e_source_list_peek_groups (source_list);
+	found_group = FALSE;
+
+	for (; groups != NULL && !found_group; groups = g_slist_next (groups)) {
+		group = E_SOURCE_GROUP (groups->data);
+
+		if (strcmp (e_source_group_peek_name (group), account->account_name) == 0
+                    &&
+                    strcmp (e_source_group_peek_base_uri (group), EXCHANGE_URI_PREFIX) == 0) {
+			sources = e_source_group_peek_sources (group);
+
+			for (; sources != NULL; sources = g_slist_next (sources)) {
+				source = E_SOURCE (sources->data);
+				source_uid = e_source_peek_uid (source);
+
+				/* Remove from the selected folders */
+				ids = gconf_client_get_list (client,
+							     selected_gconf_key,
+							     GCONF_VALUE_STRING, NULL);
+				if (ids) {
+					offline_mode = e_source_get_property (source, "offline_sync");
+					if (!offline_mode ||
+					    (offline_mode && strcmp (offline_mode, "1"))) {
+						while ((node_to_be_deleted =
+							g_slist_find_custom (ids,
+									     source_uid,
+									     (GCompareFunc) strcmp))) {
+							g_free (node_to_be_deleted->data);
+							ids = g_slist_delete_link (ids,
+										   node_to_be_deleted);
+							gconf_client_set_list (client,
+									       selected_gconf_key,
+									       GCONF_VALUE_STRING, ids, NULL);
+						}
+					}
+					g_slist_foreach (ids, (GFunc) g_free, NULL);
+					g_slist_free (ids);
+				}
+			}
+			found_group = TRUE;
+			e_source_list_sync (source_list, NULL);
+		}
+	}
+
+	g_free (selected_gconf_key);
+	g_object_unref (source_list);
+	g_object_unref (client);
+}
diff --git a/eplugin/exchange-config-listener.h b/eplugin/exchange-config-listener.h
new file mode 100644
index 0000000..07051bc
--- /dev/null
+++ b/eplugin/exchange-config-listener.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_CONFIG_LISTENER_H__
+#define __EXCHANGE_CONFIG_LISTENER_H__
+
+#include <exchange-constants.h>
+#include <exchange-account.h>
+
+#include "exchange-types.h"
+#include "libedataserver/e-account-list.h"
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-source-group.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+	CONFIG_LISTENER_STATUS_OK,
+	CONFIG_LISTENER_STATUS_NOT_FOUND
+} ExchangeConfigListenerStatus;
+
+#define EXCHANGE_TYPE_CONFIG_LISTENER            (exchange_config_listener_get_type ())
+#define EXCHANGE_CONFIG_LISTENER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_TYPE_CONFIG_LISTENER, ExchangeConfigListener))
+#define EXCHANGE_CONFIG_LISTENER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_TYPE_CONFIG_LISTENER, ExchangeConfigListenerClass))
+#define EXCHANGE_IS_CONFIG_LISTENER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_TYPE_CONFIG_LISTENER))
+#define EXCHANGE_IS_CONFIG_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EXCHANGE_TYPE_CONFIG_LISTENER))
+
+struct _ExchangeConfigListener {
+	EAccountList parent;
+
+	ExchangeConfigListenerPrivate *priv;
+};
+
+struct _ExchangeConfigListenerClass {
+	EAccountListClass parent_class;
+
+	/* signals */
+	void (*exchange_account_created) (ExchangeConfigListener *,
+					  ExchangeAccount *);
+	void (*exchange_account_removed) (ExchangeConfigListener *,
+					  ExchangeAccount *);
+};
+
+#define CONF_KEY_CAL "/apps/evolution/calendar/sources"
+#define CONF_KEY_TASKS "/apps/evolution/tasks/sources"
+#define CONF_KEY_CONTACTS "/apps/evolution/addressbook/sources"
+#define EXCHANGE_URI_PREFIX "exchange://"
+
+GType                   exchange_config_listener_get_type (void);
+ExchangeConfigListener *exchange_config_listener_new      (void);
+
+GSList                 *exchange_config_listener_get_accounts (ExchangeConfigListener *config_listener);
+
+void			add_folder_esource (ExchangeAccount *account, FolderType folder_type, const gchar *folder_name, const gchar *physical_uri);
+void			remove_folder_esource (ExchangeAccount *account, FolderType folder_type, const gchar *physical_uri);
+ExchangeConfigListenerStatus exchange_config_listener_get_offline_status (ExchangeConfigListener *excl, gint *mode);
+
+void exchange_config_listener_modify_esource_group_name (ExchangeConfigListener *excl,
+							 const gchar *old_name,
+							 const gchar *new_name);
+
+ExchangeAccountResult exchange_config_listener_authenticate (ExchangeConfigListener *excl,
+							ExchangeAccount *account);
+
+G_END_DECLS
+
+#endif /* __EXCHANGE_CONFIG_LISTENER_H__ */
diff --git a/eplugin/exchange-contacts.c b/eplugin/exchange-contacts.c
new file mode 100644
index 0000000..7fb9f85
--- /dev/null
+++ b/eplugin/exchange-contacts.c
@@ -0,0 +1,548 @@
+/*
+ * 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:
+ *		Praveen Kumar <kpraveen@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <e-util/e-config.h>
+#include <calendar/gui/e-cal-config.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-url.h>
+#include <e-folder.h>
+#include <exchange-account.h>
+
+#include <libebook/e-book.h>
+#include <libecal/e-cal.h>
+#include <addressbook/gui/widgets/eab-config.h>
+
+#include "mail/em-account-editor.h"
+#include "mail/em-config.h"
+#include "libedataserver/e-account.h"
+#include "e-util/e-error.h"
+
+#include "exchange-operations.h"
+#include "exchange-folder-size-display.h"
+
+enum {
+	CONTACTSNAME_COL,
+	CONTACTSRURI_COL,
+	NUM_COLS
+};
+
+gboolean contacts_src_exists = FALSE;
+gchar *contacts_old_src_uri = NULL;
+
+static GPtrArray *e_exchange_contacts_get_contacts (void);
+void e_exchange_contacts_pcontacts_on_change (GtkTreeView *treeview, ESource *source);
+GtkWidget *e_exchange_contacts_pcontacts (EPlugin *epl, EConfigHookItemFactoryData *data);
+gboolean e_exchange_contacts_check (EPlugin *epl, EConfigHookPageCheckData *data);
+void e_exchange_contacts_commit (EPlugin *epl, EConfigTarget *target);
+
+/* FIXME: Reconsider the prototype of this function */
+static GPtrArray *
+e_exchange_contacts_get_contacts (void)
+{
+	ExchangeAccount *account;
+	GPtrArray *folder_array;
+	GPtrArray *contacts_list;
+	EFolder *folder;
+
+	gint i, prefix_len;
+	gchar *uri_prefix, *ruri;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return NULL;
+
+	uri_prefix = g_strconcat ("exchange://", account->account_filename, "/;", NULL);
+	prefix_len = strlen (uri_prefix);
+
+	contacts_list = g_ptr_array_new ();
+	exchange_account_rescan_tree (account);
+	folder_array = exchange_account_get_folders (account);
+
+	for (i=0; i<folder_array->len; ++i) {
+		gchar *type, *tmp;
+		folder = g_ptr_array_index (folder_array, i);
+		type = (gchar *) e_folder_get_type_string (folder);
+		if (!strcmp (type, "contacts")) {
+			tmp = (gchar *) e_folder_get_physical_uri (folder);
+			if (g_str_has_prefix (tmp, uri_prefix)) {
+				ruri = g_strdup (tmp+prefix_len);
+				g_ptr_array_add (contacts_list, ruri);
+			}
+		}
+	}
+
+	g_free (uri_prefix);
+	if (folder_array)
+		g_ptr_array_free (folder_array, TRUE);
+	return contacts_list;
+}
+
+void
+e_exchange_contacts_pcontacts_on_change (GtkTreeView *treeview, ESource *source)
+{
+	GtkTreeSelection *selection;
+	GtkTreeModel     *model;
+	GtkTreeIter       iter;
+	ExchangeAccount *account;
+	gchar *es_ruri;
+	gchar *ruri;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+	gtk_tree_selection_get_selected(selection, &model, &iter);
+
+	gtk_tree_model_get (model, &iter, CONTACTSRURI_COL, &ruri, -1);
+	es_ruri = g_strconcat (account->account_filename, "/;", ruri, NULL);
+	e_source_set_relative_uri (source, es_ruri);
+
+	g_free (ruri);
+	g_free (es_ruri);
+}
+
+GtkWidget *
+e_exchange_contacts_pcontacts (EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	static GtkWidget *lbl_pcontacts, *scrw_pcontacts, *tv_pcontacts, *vb_pcontacts, *lbl_size, *lbl_size_val, *hbx_size;
+	GtkTreeStore *ts_pcontacts;
+	GtkCellRenderer *cr_contacts;
+	GtkTreeViewColumn *tvc_contacts;
+	GtkListStore *model;
+	GPtrArray *conlist;
+	gchar *ruri, *account_name, *uri_text;
+	ExchangeAccount *account;
+	gint i;
+	gchar *folder_size, *abook_name;
+	const gchar *rel_uri;
+	const gchar *uid;
+	EABConfigTargetSource *t = (EABConfigTargetSource *) data->target;
+	ESource *source = t->source;
+	GtkWidget *lbl_offline_msg, *vb_offline_msg;
+	gchar *offline_msg;
+	gint offline_status;
+	gboolean gal_folder = FALSE, is_personal;
+
+	if (data->old) {
+		gtk_widget_destroy (vb_pcontacts);
+	}
+
+	uri_text = e_source_get_uri (source);
+	if (uri_text && g_ascii_strncasecmp (uri_text, "exchange", 8)) {
+		if (g_ascii_strncasecmp (uri_text, "gal", 3)) {
+			g_free (uri_text);
+			return NULL;
+		}
+		else {
+			gal_folder = TRUE;
+		}
+	}
+
+	exchange_config_listener_get_offline_status (exchange_global_config_listener,
+								    &offline_status);
+	if (offline_status == OFFLINE_MODE) {
+		/* Evolution is in offline mode; we will not be able to create
+		   new folders or modify existing folders. */
+		offline_msg = g_markup_printf_escaped ("<b>%s</b>",
+						       _("Evolution is in offline mode. You cannot create or modify folders now.\nPlease switch to online mode for such operations."));
+		vb_offline_msg = gtk_vbox_new (FALSE, 6);
+		gtk_container_add (GTK_CONTAINER (data->parent), vb_offline_msg);
+		lbl_offline_msg = gtk_label_new ("");
+		gtk_label_set_markup (GTK_LABEL (lbl_offline_msg), offline_msg);
+		g_free (offline_msg);
+		gtk_box_pack_start (GTK_BOX (vb_offline_msg), lbl_offline_msg, FALSE, FALSE, 0);
+		gtk_widget_show_all (vb_offline_msg);
+		g_free (uri_text);
+		return vb_offline_msg;
+	}
+
+	if (gal_folder) {
+		contacts_src_exists = TRUE;
+		g_free (uri_text);
+		return NULL;
+	}
+
+	rel_uri = e_source_peek_relative_uri (source);
+	uid = e_source_peek_uid (source);
+	if (rel_uri && uid && (strcmp (rel_uri, uid))) {
+		contacts_src_exists = TRUE;
+		g_free (contacts_old_src_uri);
+		contacts_old_src_uri = g_strdup (rel_uri);
+	}
+	else {
+		/* new folder */
+		contacts_src_exists = FALSE;
+		e_source_set_relative_uri (source, ""); /* FIXME: Nasty hack */
+	}
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account) {
+		g_free (contacts_old_src_uri);
+		g_free (uri_text);
+		return NULL;
+	}
+	account_name = account->account_name;
+	hbx_size = NULL;
+
+	is_personal = is_exchange_personal_folder (account, uri_text);
+	g_free (uri_text);
+
+	if (contacts_src_exists && is_personal ) {
+		abook_name = (gchar *)e_source_peek_name (source);
+		model = exchange_account_folder_size_get_model (account);
+		if (model)
+			folder_size = g_strdup_printf (_("%s KB"), exchange_folder_size_get_val (model, abook_name));
+		else
+			folder_size = g_strdup_printf (_("0 KB"));
+
+		/* FIXME: Take care of i18n */
+		lbl_size = gtk_label_new_with_mnemonic (_("Size:"));
+		lbl_size_val = gtk_label_new_with_mnemonic (_(folder_size));
+		hbx_size = gtk_hbox_new (FALSE, 0);
+		gtk_box_pack_start (GTK_BOX (hbx_size), lbl_size, FALSE, TRUE, 0);
+		gtk_box_pack_start (GTK_BOX (hbx_size), lbl_size_val, FALSE, TRUE, 10);
+		gtk_widget_show (lbl_size);
+		gtk_widget_show (lbl_size_val);
+		gtk_misc_set_alignment (GTK_MISC (lbl_size), 0.0, 0.5);
+		gtk_misc_set_alignment (GTK_MISC (lbl_size_val), 0.0, 0.5);
+		g_free (folder_size);
+	}
+	vb_pcontacts = gtk_vbox_new (FALSE, 6);
+	gtk_container_add (GTK_CONTAINER (data->parent), vb_pcontacts);
+
+	if (hbx_size)
+		gtk_box_pack_start (GTK_BOX (vb_pcontacts), hbx_size, FALSE, FALSE, 0);
+
+	lbl_pcontacts = gtk_label_new_with_mnemonic (_("_Location:"));
+	gtk_widget_show (lbl_pcontacts);
+	gtk_misc_set_alignment (GTK_MISC (lbl_pcontacts), 0.0, 0.5);
+	gtk_box_pack_start (GTK_BOX (vb_pcontacts), lbl_pcontacts, FALSE, FALSE, 0);
+
+	ts_pcontacts = gtk_tree_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
+
+	conlist = e_exchange_contacts_get_contacts ();
+
+	if (conlist) {
+		for (i = 0; i < conlist->len; i++) {
+			ruri = g_ptr_array_index (conlist, i);
+			exchange_operations_cta_add_node_to_tree (ts_pcontacts, NULL, ruri);
+		}
+		g_ptr_array_free (conlist, TRUE);
+	}
+
+	cr_contacts = gtk_cell_renderer_text_new ();
+	tvc_contacts = gtk_tree_view_column_new_with_attributes (account_name, cr_contacts, "text", CONTACTSNAME_COL, NULL);
+	tv_pcontacts = gtk_tree_view_new_with_model (GTK_TREE_MODEL (ts_pcontacts));
+	gtk_tree_view_append_column (GTK_TREE_VIEW (tv_pcontacts), tvc_contacts);
+	g_object_set (tv_pcontacts,"expander-column", tvc_contacts, "headers-visible", TRUE, NULL);
+	gtk_tree_view_expand_all (GTK_TREE_VIEW (tv_pcontacts));
+
+	scrw_pcontacts = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrw_pcontacts), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrw_pcontacts), GTK_SHADOW_IN);
+	g_object_set (scrw_pcontacts, "height-request", 150, NULL);
+	gtk_container_add (GTK_CONTAINER (scrw_pcontacts), tv_pcontacts);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (lbl_pcontacts), tv_pcontacts);
+	g_signal_connect (G_OBJECT (tv_pcontacts), "cursor-changed", G_CALLBACK (e_exchange_contacts_pcontacts_on_change), t->source);
+	gtk_widget_show_all (scrw_pcontacts);
+
+	gtk_box_pack_start (GTK_BOX (vb_pcontacts), scrw_pcontacts, FALSE, FALSE, 0);
+	gtk_widget_show_all (vb_pcontacts);
+
+	if (contacts_src_exists) {
+		gchar *uri_prefix, *sruri, *tmpruri;
+		gint prefix_len;
+		GtkTreeSelection *selection;
+
+		tmpruri = (gchar *) rel_uri;
+		uri_prefix = g_strconcat (account->account_filename, "/;", NULL);
+		prefix_len = strlen (uri_prefix);
+
+		if (g_str_has_prefix (tmpruri, uri_prefix)) {
+			sruri = g_strdup (tmpruri+prefix_len);
+		}
+		else {
+			sruri = NULL;
+		}
+
+		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv_pcontacts));
+		exchange_operations_cta_select_node_from_tree (ts_pcontacts,
+							       NULL,
+							       sruri,
+							       sruri,
+							       selection);
+		gtk_widget_set_sensitive (tv_pcontacts, FALSE);
+
+		g_free (uri_prefix);
+		g_free (sruri);
+	}
+
+	g_object_unref (ts_pcontacts);
+	return vb_pcontacts;
+}
+
+gboolean
+e_exchange_contacts_check (EPlugin *epl, EConfigHookPageCheckData *data)
+{
+	/* FIXME - check pageid */
+	EABConfigTargetSource *t = (EABConfigTargetSource *) data->target;
+	ESourceGroup *group;
+	const gchar *base_uri;
+	const gchar *rel_uri;
+	gint offline_status;
+	ExchangeAccount *account;
+
+	rel_uri = e_source_peek_relative_uri (t->source);
+	group = e_source_peek_group (t->source);
+	base_uri = e_source_group_peek_base_uri (group);
+	exchange_config_listener_get_offline_status (exchange_global_config_listener,
+								    &offline_status);
+	if (base_uri && !g_ascii_strncasecmp (base_uri, "exchange", 8)) {
+		if (offline_status == OFFLINE_MODE)
+			return FALSE;
+		if (rel_uri && !strlen (rel_uri))
+			return FALSE;
+	}
+	else {
+		return TRUE;
+	}
+
+	if (!contacts_src_exists) {
+		return TRUE;
+	}
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return FALSE;
+
+	if (!rel_uri) {
+		GConfClient *client;
+		ESourceList *source_list = NULL;
+		ESourceGroup *source_group = NULL;
+		ESource *source;
+		EAccount *eaccount;
+
+		/* GAL folder */
+		client = gconf_client_get_default ();
+		source_list = e_source_list_new_for_gconf ( client, CONF_KEY_CONTACTS);
+		g_object_unref (client);
+
+		eaccount = exchange_account_fetch (account);
+		g_return_val_if_fail (eaccount != NULL, FALSE);
+		g_return_val_if_fail (eaccount->uid != NULL, FALSE);
+
+		if ((source_group = e_source_list_peek_group_by_properties (source_list, "account-uid", eaccount->uid, NULL))) {
+			source =  e_source_group_peek_source_by_name (source_group, e_source_peek_name (t->source));
+			if (e_source_group_peek_source_by_name (source_group,
+							e_source_peek_name (t->source))) {
+				/* not a rename of GAL */
+				g_object_unref (source_list);
+				return TRUE;
+			}
+			else {
+				g_object_unref (source_list);
+				return FALSE;
+			}
+		}
+		else {
+			g_object_unref (source_list);
+			return FALSE;
+		}
+	}
+	else {
+		EUri *euri;
+		gint uri_len;
+		gchar *uri_text, *uri_string, *path, *folder_name;
+		gboolean is_personal;
+
+		uri_text = e_source_get_uri (t->source);
+		euri = e_uri_new (uri_text);
+		uri_string = e_uri_to_string (euri, FALSE);
+		e_uri_free (euri);
+
+		is_personal = is_exchange_personal_folder (account, uri_text);
+
+		uri_len = strlen (uri_string) + 1;
+		g_free (uri_string);
+		path = g_build_filename ("/", uri_text + uri_len, NULL);
+		g_free (uri_text);
+		folder_name = g_strdup (g_strrstr (path, "/") +1);
+		g_free (path);
+
+		if (strcmp (folder_name, e_source_peek_name (t->source))) {
+			/* rename */
+			if (exchange_account_get_standard_uri (account, folder_name) ||
+			    !is_personal) {
+				/* rename of standard/non-personal folder */
+				g_free (folder_name);
+				return FALSE;
+			}
+			g_free (folder_name);
+		}
+	}
+	return TRUE;
+}
+
+void
+e_exchange_contacts_commit (EPlugin *epl, EConfigTarget *target)
+{
+	EABConfigTargetSource *t = (EABConfigTargetSource *) target;
+	ESource *source = t->source;
+	gchar *uri_text, *gname, *gruri, *ruri = NULL, *path = NULL, *path_prefix, *oldpath=NULL;
+	gchar *username, *windows_domain, *authtype;
+	gint prefix_len;
+	ExchangeAccount *account;
+	ExchangeAccountFolderResult result;
+	gint offline_status;
+	gboolean rename = FALSE;
+
+	uri_text = e_source_get_uri (source);
+	if (uri_text && strncmp (uri_text, "exchange", 8)) {
+		/* here no need of checking for gal */
+		g_free (uri_text);
+		return;
+	}
+
+	exchange_config_listener_get_offline_status (exchange_global_config_listener,
+								    &offline_status);
+	if (offline_status == OFFLINE_MODE) {
+		g_free (uri_text);
+		return;
+	}
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account || !is_exchange_personal_folder (account, uri_text))
+		return;
+
+	windows_domain = exchange_account_get_windows_domain (account);
+	if (windows_domain)
+		username = g_strdup_printf ("%s\\%s", windows_domain,
+					    exchange_account_get_username (account));
+	else
+		username = g_strdup (exchange_account_get_username (account));
+
+	authtype = exchange_account_get_authtype (account);
+
+	path_prefix = g_strconcat (account->account_filename, "/;", NULL);
+	prefix_len = strlen (path_prefix);
+	g_free (path_prefix);
+
+	gname = (gchar *) e_source_peek_name (source);
+	gruri = (gchar *) e_source_peek_relative_uri (source);
+
+	if (contacts_src_exists) {
+		gchar *tmpruri, *uri_string, *temp_path, *prefix;
+		EUri *euri;
+		gint uri_len;
+
+		euri = e_uri_new (uri_text);
+		uri_string = e_uri_to_string (euri, FALSE);
+		e_uri_free (euri);
+
+		uri_len = strlen (uri_string) + 1;
+		tmpruri = g_strdup (uri_string + strlen ("exchange://"));
+		temp_path = g_build_filename ("/", uri_text + uri_len, NULL);
+		prefix	= g_strndup (temp_path, strlen (temp_path) - strlen (g_strrstr (temp_path, "/")));
+		g_free (temp_path);
+		path = g_build_filename (prefix, "/", gname, NULL);
+		ruri = g_strconcat (tmpruri, ";", path+1, NULL);
+		oldpath = g_build_filename ("/", contacts_old_src_uri + prefix_len, NULL);
+		g_free (prefix);
+		g_free (uri_string);
+		g_free (tmpruri);
+	}
+	else {
+		/* new folder */
+		ruri = g_strconcat (gruri, "/", gname, NULL);
+		path = g_build_filename ("/", ruri+prefix_len, NULL);
+	}
+
+	if (!contacts_src_exists) {
+		/* Create the new folder */
+		result = exchange_account_create_folder (account, path, "contacts");
+	}
+	else if (gruri && strcmp (path, oldpath )) {
+		/* Rename the folder */
+		rename = TRUE;
+		result = exchange_account_xfer_folder (account, oldpath, path, TRUE);
+	}
+	else {
+		/* Nothing happened specific to exchange; just return */
+		goto done;
+	}
+	switch (result) {
+	case EXCHANGE_ACCOUNT_FOLDER_OK:
+		e_source_set_name (source, gname);
+		e_source_set_relative_uri (source, ruri);
+		e_source_set_property (source, "username", username);
+		e_source_set_property (source, "auth-domain", "Exchange");
+		if (authtype) {
+			e_source_set_property (source, "auth-type", authtype);
+			g_free (authtype);
+			authtype=NULL;
+		}
+		e_source_set_property (source, "auth", "plain/password");
+		if (rename) {
+			exchange_operations_update_child_esources (source,
+							contacts_old_src_uri,
+							ruri);
+		}
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-exists-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-doesnt-exist-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_UNKNOWN_TYPE:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-unknown-type", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-perm-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_OFFLINE:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-offline-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_UNSUPPORTED_OPERATION:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-unsupported-error", NULL);
+		break;
+	case EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR:
+		e_error_run (NULL, ERROR_DOMAIN ":folder-generic-error", NULL);
+		break;
+	default:
+		break;
+	}
+done:
+	g_free (ruri);
+	g_free (username);
+	if (authtype)
+		g_free (authtype);
+	g_free (path);
+	g_free (oldpath);
+	g_free (contacts_old_src_uri);
+	g_free (uri_text);
+	contacts_old_src_uri = NULL;
+}
diff --git a/eplugin/exchange-delegates-user.c b/eplugin/exchange-delegates-user.c
new file mode 100644
index 0000000..c856bb2
--- /dev/null
+++ b/eplugin/exchange-delegates-user.c
@@ -0,0 +1,626 @@
+/*
+ * 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:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* ExchangeDelegatesUser: A single delegate */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "exchange-delegates.h"
+#include "exchange-delegates-user.h"
+
+#include <mail/mail-ops.h>
+#include <mail/mail-component.h>
+#include <mail/mail-send-recv.h>
+#include <camel/camel-multipart.h>
+#include <camel/camel-mime-utils.h>
+#include <camel/camel-stream-mem.h>
+#include <exchange-account.h>
+#include "exchange-delegates.h"
+#include <exchange/exchange-account.h>
+#include <e2k-global-catalog.h>
+#include <e2k-marshal.h>
+#include <e2k-sid.h>
+#include <e2k-utils.h>
+
+#include <e-util/e-dialog-utils.h>
+#include <e-util/e-dialog-widgets.h>
+
+#include <string.h>
+
+#define EXCHANGE_DELEGATES_USER_CUSTOM    -3
+/* Can't use E2K_PERMISSIONS_ROLE_CUSTOM, because it's -1, which
+ * means "end of list" to e_dialog_combo_box_get/set
+ */
+
+static const gint exchange_perm_map[] = {
+	E2K_PERMISSIONS_ROLE_NONE,
+	E2K_PERMISSIONS_ROLE_REVIEWER,
+	E2K_PERMISSIONS_ROLE_AUTHOR,
+	E2K_PERMISSIONS_ROLE_EDITOR,
+
+	EXCHANGE_DELEGATES_USER_CUSTOM,
+
+	-1
+};
+
+const gchar *exchange_delegates_user_folder_names[] = {
+	"calendar", "tasks", "inbox", "contacts"
+};
+
+/* To translators: The folder names to be displayed in the message being
+   sent to the delegatee.
+*/
+static const gchar *folder_names_for_display[] = {
+	N_("Calendar"), N_("Tasks"), N_("Inbox"), N_("Contacts")
+};
+
+enum {
+	EDITED,
+	LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+#define PARENT_TYPE G_TYPE_OBJECT
+static GObjectClass *parent_class = NULL;
+
+static void
+finalize (GObject *object)
+{
+	ExchangeDelegatesUser *user = EXCHANGE_DELEGATES_USER (object);
+
+	if (user->display_name)
+		g_free (user->display_name);
+	if (user->dn)
+		g_free (user->dn);
+	if (user->entryid)
+		g_byte_array_free (user->entryid, TRUE);
+	if (user->sid)
+		g_object_unref (user->sid);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+class_init (GObjectClass *object_class)
+{
+	parent_class = g_type_class_ref (PARENT_TYPE);
+
+	object_class->finalize = finalize;
+
+	/* signals */
+	signals[EDITED] =
+		g_signal_new ("edited",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (ExchangeDelegatesUserClass, edited),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+}
+
+E2K_MAKE_TYPE (exchange_delegates_user, ExchangeDelegatesUser, class_init, NULL, PARENT_TYPE)
+
+static inline gboolean
+is_delegate_role (E2kPermissionsRole role)
+{
+	return (role == E2K_PERMISSIONS_ROLE_NONE ||
+		role == E2K_PERMISSIONS_ROLE_REVIEWER ||
+		role == E2K_PERMISSIONS_ROLE_AUTHOR ||
+		role == E2K_PERMISSIONS_ROLE_EDITOR);
+}
+
+static void
+set_perms (GtkWidget *combobox, E2kPermissionsRole role)
+{
+	if (!is_delegate_role (role)) {
+		gtk_combo_box_append_text (GTK_COMBO_BOX (combobox), _("Custom"));
+		role = EXCHANGE_DELEGATES_USER_CUSTOM;
+	}
+
+	e_dialog_combo_box_set (combobox, role, exchange_perm_map);
+}
+
+static void
+parent_window_destroyed (gpointer dialog, GObject *where_parent_window_was)
+{
+	gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
+}
+
+/* Maps the role_nam parameter to their corresponding Full role name
+*/
+static const gchar *
+map_to_full_role_name (E2kPermissionsRole role_nam)
+{
+	const gchar *role_name;
+
+	switch (role_nam)
+	{
+	/* To translators: The following are the various types of permissions that can
+	   assigned by an user to his folders.
+	*/
+		case E2K_PERMISSIONS_ROLE_EDITOR: role_name = g_strdup (
+							_("Editor (read, create, edit)"));
+						  break;
+
+		case E2K_PERMISSIONS_ROLE_AUTHOR: role_name = g_strdup (
+							_("Author (read, create)"));
+						  break;
+
+		case E2K_PERMISSIONS_ROLE_REVIEWER: role_name = g_strdup (
+							_("Reviewer (read-only)"));
+						    break;
+
+		default: role_name = g_strdup (_("None"));
+			 break;
+	}
+
+	return role_name;
+}
+
+static void
+em_utils_delegates_done (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *info,
+		       gint queued, const gchar *appended_uid, gpointer data)
+{
+	camel_message_info_free (info);
+	mail_send ();
+}
+
+/**
+ * exchange_delegates_user_edit:
+ * @user: a delegate
+ * @parent_window: parent window for the editor dialog
+ *
+ * Brings up a dialog to edit @user's permissions as a delegate.
+ * An %edited signal will be emitted if anything changed.
+ *
+ * Return value: %TRUE for "OK", %FALSE for "Cancel".
+ **/
+gboolean
+exchange_delegates_user_edit (ExchangeAccount *account,
+			     ExchangeDelegatesUser *user,
+			     GtkWidget *parent_window)
+{
+	gchar *title;
+	gint button, i;
+	E2kPermissionsRole role;
+	gboolean modified;
+	GtkWidget *delegate_permissions;
+	GtkWidget *dialog_vbox1;
+	GtkWidget *vbox3;
+	GtkWidget *delegate_label;
+	GtkWidget *folders_table;
+	GtkWidget *calendar_label;
+	GtkWidget *task_label;
+	GtkWidget *inbox_label;
+	GtkWidget *contact_label;
+	GtkWidget *calendar_perms_combobox;
+	GtkWidget *task_perms_combobox;
+	GtkWidget *inbox_perms_combobox;
+	GtkWidget *contact_perms_combobox;
+	GtkWidget *delegate_mail;
+	GtkWidget *see_private_checkbox;
+	GtkWidget *combobox, *comboboxes[EXCHANGE_DELEGATES_LAST];
+
+	g_return_val_if_fail (EXCHANGE_IS_DELEGATES_USER (user), FALSE);
+	g_return_val_if_fail (E2K_IS_SID (user->sid), FALSE);
+
+	delegate_permissions = gtk_dialog_new_with_buttons (
+		_("Delegate Permissions"),
+		NULL,
+		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+
+	dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (delegate_permissions));
+	gtk_widget_show (dialog_vbox1);
+
+	vbox3 = gtk_vbox_new (FALSE, 12);
+	gtk_widget_show (vbox3);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox3, TRUE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox3), 12);
+
+	delegate_label = gtk_label_new (_("Permissions for"));
+	gtk_widget_show (delegate_label);
+	gtk_box_pack_start (GTK_BOX (vbox3), delegate_label, FALSE, FALSE, 0);
+	gtk_label_set_justify (GTK_LABEL (delegate_label), GTK_JUSTIFY_CENTER);
+
+	folders_table = gtk_table_new (4, 2, FALSE);
+	gtk_widget_show (folders_table);
+	gtk_box_pack_start (GTK_BOX (vbox3), folders_table, FALSE, FALSE, 0);
+	gtk_table_set_row_spacings (GTK_TABLE (folders_table), 6);
+	gtk_table_set_col_spacings (GTK_TABLE (folders_table), 6);
+
+	/* Translators: This is used for permissions for <user> for the folder Calendar. */
+	calendar_label = gtk_label_new_with_mnemonic (_("C_alendar:"));
+	gtk_widget_show (calendar_label);
+	gtk_table_attach (GTK_TABLE (folders_table), calendar_label, 0, 1, 0, 1,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_label_set_justify (GTK_LABEL (calendar_label), GTK_JUSTIFY_CENTER);
+	gtk_misc_set_alignment (GTK_MISC (calendar_label), 0, 0.5);
+
+	/* Translators: This is used for permissions for <user> for the folder Tasks. */
+	task_label = gtk_label_new_with_mnemonic (_("_Tasks:"));
+	gtk_widget_show (task_label);
+	gtk_table_attach (GTK_TABLE (folders_table), task_label, 0, 1, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_label_set_justify (GTK_LABEL (task_label), GTK_JUSTIFY_CENTER);
+	gtk_misc_set_alignment (GTK_MISC (task_label), 0, 0.5);
+
+	/* Translators: This is used for permissions for <user> for the folder Inbox. */
+	inbox_label = gtk_label_new_with_mnemonic (_("_Inbox:"));
+	gtk_widget_show (inbox_label);
+	gtk_table_attach (GTK_TABLE (folders_table), inbox_label, 0, 1, 2, 3,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_label_set_justify (GTK_LABEL (inbox_label), GTK_JUSTIFY_CENTER);
+	gtk_misc_set_alignment (GTK_MISC (inbox_label), 0, 0.5);
+
+	/* Translators: This is used for permissions for <user> for the folder Contacts. */
+	contact_label = gtk_label_new_with_mnemonic (_("Co_ntacts:"));
+	gtk_widget_show (contact_label);
+	gtk_table_attach (GTK_TABLE (folders_table), contact_label, 0, 1, 3, 4,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_label_set_justify (GTK_LABEL (contact_label), GTK_JUSTIFY_CENTER);
+	gtk_misc_set_alignment (GTK_MISC (contact_label), 0, 0.5);
+
+	calendar_perms_combobox = gtk_combo_box_new_text ();
+	gtk_widget_show (calendar_perms_combobox);
+	gtk_table_attach (GTK_TABLE (folders_table), calendar_perms_combobox, 1, 2, 0, 1,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+	gtk_combo_box_append_text (GTK_COMBO_BOX (calendar_perms_combobox), _("None"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (calendar_perms_combobox), _("Reviewer (read-only)"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (calendar_perms_combobox), _("Author (read, create)"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (calendar_perms_combobox), _("Editor (read, create, edit)"));
+
+	task_perms_combobox = gtk_combo_box_new_text ();
+	gtk_widget_show (task_perms_combobox);
+	gtk_table_attach (GTK_TABLE (folders_table), task_perms_combobox, 1, 2, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+	gtk_combo_box_append_text (GTK_COMBO_BOX (task_perms_combobox), _("None"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (task_perms_combobox), _("Reviewer (read-only)"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (task_perms_combobox), _("Author (read, create)"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (task_perms_combobox), _("Editor (read, create, edit)"));
+
+	inbox_perms_combobox = gtk_combo_box_new_text ();
+	gtk_widget_show (inbox_perms_combobox);
+	gtk_table_attach (GTK_TABLE (folders_table), inbox_perms_combobox, 1, 2, 2, 3,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+	gtk_combo_box_append_text (GTK_COMBO_BOX (inbox_perms_combobox), _("None"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (inbox_perms_combobox), _("Reviewer (read-only)"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (inbox_perms_combobox), _("Author (read, create)"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (inbox_perms_combobox), _("Editor (read, create, edit)"));
+
+	contact_perms_combobox = gtk_combo_box_new_text ();
+	gtk_widget_show (contact_perms_combobox);
+	gtk_table_attach (GTK_TABLE (folders_table), contact_perms_combobox, 1, 2, 3, 4,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+	gtk_combo_box_append_text (GTK_COMBO_BOX (contact_perms_combobox), _("None"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (contact_perms_combobox), _("Reviewer (read-only)"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (contact_perms_combobox), _("Author (read, create)"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (contact_perms_combobox), _("Editor (read, create, edit)"));
+
+	delegate_mail = gtk_check_button_new_with_mnemonic (_("_Summarize permissions"));
+	gtk_widget_show (delegate_mail);
+	gtk_box_pack_start (GTK_BOX (vbox3), delegate_mail, FALSE, FALSE, 0);
+
+	see_private_checkbox = gtk_check_button_new_with_mnemonic (_("_Delegate can see private items"));
+	gtk_widget_show (see_private_checkbox);
+	gtk_box_pack_start (GTK_BOX (vbox3), see_private_checkbox, FALSE, FALSE, 0);
+
+	e_dialog_set_transient_for (GTK_WINDOW (delegate_permissions), parent_window);
+	gtk_box_set_spacing (GTK_BOX (dialog_vbox1), 6);
+
+	title = g_strdup_printf (_("Permissions for %s"), user->display_name);
+	gtk_label_set_text (GTK_LABEL (delegate_label), title);
+	g_free (title);
+
+	comboboxes[0] = calendar_perms_combobox;
+	comboboxes[1] = task_perms_combobox;
+	comboboxes[2] = inbox_perms_combobox;
+	comboboxes[3] = contact_perms_combobox;
+
+	/* Set up the permissions */
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		combobox = comboboxes[i];
+		set_perms (combobox, user->role[i]);
+	}
+
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (see_private_checkbox),
+				      user->see_private);
+
+	/* Run the dialog, while watching its parent. */
+	g_object_weak_ref (G_OBJECT (parent_window),
+			   parent_window_destroyed, delegate_permissions);
+	g_object_add_weak_pointer (G_OBJECT (parent_window),
+				   (gpointer*)&parent_window);
+	button = gtk_dialog_run (GTK_DIALOG (delegate_permissions));
+	if (parent_window) {
+		g_object_remove_weak_pointer (G_OBJECT (parent_window),
+					      (gpointer *)&parent_window);
+		g_object_weak_unref (G_OBJECT (parent_window),
+				     parent_window_destroyed, delegate_permissions);
+	}
+
+	if (button != GTK_RESPONSE_OK) {
+		gtk_widget_destroy (delegate_permissions);
+		return FALSE;
+	}
+
+	/* And update */
+	modified = FALSE;
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		combobox = comboboxes[i];
+		role = e_dialog_combo_box_get (combobox, exchange_perm_map);
+
+		if (is_delegate_role (user->role[i]) &&
+		    user->role[i] != role) {
+			user->role[i] = role;
+			modified = TRUE;
+		}
+	}
+
+	/* The following piece of code is used to construct a mail message to be sent to a Delegate
+	   summarizing all the permissions set for him on the user's various folders.
+	*/
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (delegate_mail)) == TRUE) {
+		if (button == GTK_RESPONSE_OK) {
+
+			EAccount *eaccount;
+			CamelMimeMessage *delegate_mail = camel_mime_message_new ();
+			CamelMultipart *body = camel_multipart_new ();
+			CamelMimePart *part;
+			CamelDataWrapper *delegate_mail_text, *delegate_mail_data;
+			CamelContentType *type;
+			CamelInternetAddress *addr;
+			CamelStream *stream;
+			CamelFolder *out_folder;
+			CamelMessageInfo *info;
+			gchar *self_address, *delegate_mail_subject;
+			gchar *role_name;
+			GString *role_name_final;
+
+			const gchar *recipient_address;
+			const gchar *delegate_exchange_dn;
+			const gchar *msg_part1 = NULL, *msg_part2 = NULL;
+
+			role_name_final = g_string_new ("");
+
+			self_address = g_strdup (exchange_account_get_email_id (account));
+
+			/* Create toplevel container */
+			camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (body),
+					"multipart/alternative;");
+			camel_multipart_set_boundary (body, NULL);
+
+			/* Create textual receipt */
+			delegate_mail_text = camel_data_wrapper_new ();
+			type = camel_content_type_new ("text", "html");
+			camel_content_type_set_param (type, "format", "flowed");
+			camel_data_wrapper_set_mime_type_field (delegate_mail_text, type);
+			camel_content_type_unref (type);
+			stream = camel_stream_mem_new ();
+
+			/* To translators: This is a part of the message to be sent to the delegatee
+			   summarizing the permissions assigned to him.
+			*/
+			msg_part1 = _("This message was sent automatically by Evolution to inform you that you have been "
+					"designated as a delegate. You can now send messages on my behalf.");
+
+			/* To translators: Another chunk of the same message.
+			*/
+			msg_part2 = _("You have been given the following permissions on my folders:");
+
+			camel_stream_printf (stream,
+				"<html><body><p>%s<br><br>%s</p><table border = 0 width=\"40%%\">", msg_part1, msg_part2);
+			for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+				combobox = comboboxes[i];
+				role = e_dialog_combo_box_get (combobox, exchange_perm_map);
+				role_name = g_strdup (map_to_full_role_name(role));
+				g_string_append_printf (
+					role_name_final,
+					"<tr><td>%s:</td><td>%s</td></tr>",
+					folder_names_for_display[i], role_name);
+			}
+
+			camel_stream_printf (stream, "%s</table>", role_name_final->str);
+
+			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (see_private_checkbox)) == TRUE) {
+				/* To translators: This message is included if the delegatee has been given access
+				   to the private items.
+				*/
+				camel_stream_printf (stream, "<br>%s", _("You are also permitted "
+							"to see my private items."));
+			}
+			else
+				/* To translators: This message is included if the delegatee has not been given access
+				   to the private items.
+				*/
+				camel_stream_printf (stream, "<br>%s", _("However you are not permitted "
+							 "to see my private items."));
+			camel_data_wrapper_construct_from_stream (delegate_mail_text, stream);
+			g_free (role_name);
+			g_string_free (role_name_final, TRUE);
+			camel_object_unref (stream);
+
+			part = camel_mime_part_new ();
+			camel_medium_set_content_object (CAMEL_MEDIUM (part), delegate_mail_text);
+			camel_object_unref (delegate_mail_text);
+			camel_multipart_add_part (body, part);
+			camel_object_unref (part);
+
+			/* Create the machine-readable receipt */
+			delegate_mail_data = camel_data_wrapper_new ();
+			type = camel_content_type_new ("message", "disposition-notification");
+			camel_data_wrapper_set_mime_type_field (delegate_mail_data, type);
+			camel_content_type_unref (type);
+			stream = camel_stream_mem_new ();
+			part = camel_mime_part_new ();
+
+			camel_data_wrapper_construct_from_stream (delegate_mail_data, stream);
+			camel_object_unref (stream);
+			camel_medium_set_content_object (CAMEL_MEDIUM (part), delegate_mail_data);
+			camel_object_unref (delegate_mail_data);
+			camel_multipart_add_part (body, part);
+			camel_object_unref (part);
+
+			/* Finish creating the message */
+			camel_medium_set_content_object (CAMEL_MEDIUM (delegate_mail), CAMEL_DATA_WRAPPER (body));
+			camel_object_unref (body);
+
+			delegate_mail_subject = g_strdup_printf (_("You have been designated "
+						"as a delegate for %s"), exchange_account_get_username (account));
+			camel_mime_message_set_subject (delegate_mail, delegate_mail_subject);
+			g_free (delegate_mail_subject);
+
+			addr = camel_internet_address_new ();
+			camel_address_decode (CAMEL_ADDRESS (addr), self_address);
+			camel_mime_message_set_from (delegate_mail, addr);
+			g_free (self_address);
+			camel_object_unref (addr);
+
+			delegate_exchange_dn = e2k_entryid_to_dn (user->entryid);
+			recipient_address = email_look_up (delegate_exchange_dn,account);
+
+			if (recipient_address) {
+				addr = camel_internet_address_new ();
+				camel_address_decode (CAMEL_ADDRESS (addr), recipient_address);
+				camel_mime_message_set_recipients (delegate_mail, CAMEL_RECIPIENT_TYPE_TO, addr);
+				camel_object_unref (addr);
+			}
+
+			eaccount = exchange_account_fetch (account);
+			if (eaccount) {
+				camel_medium_set_header (CAMEL_MEDIUM (delegate_mail),
+							 "X-Evolution-Account", eaccount->uid);
+				camel_medium_set_header (CAMEL_MEDIUM (delegate_mail),
+							 "X-Evolution-Transport", eaccount->transport->url);
+				camel_medium_set_header (CAMEL_MEDIUM (delegate_mail),
+							 "X-Evolution-Fcc", eaccount->sent_folder_uri);
+			}
+
+			/* Send the permissions summarizing mail */
+			out_folder = mail_component_get_folder (NULL, MAIL_COMPONENT_FOLDER_OUTBOX);
+			info = camel_message_info_new (NULL);
+			camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
+			mail_append_mail (out_folder, delegate_mail, info, em_utils_delegates_done, NULL);
+
+		}
+
+	}
+
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (see_private_checkbox)) !=
+	    user->see_private) {
+		user->see_private = !user->see_private;
+		modified = TRUE;
+	}
+
+	gtk_widget_destroy (delegate_permissions);
+
+	if (modified)
+		g_signal_emit (user, signals[EDITED], 0);
+
+	return TRUE;
+}
+
+/**
+ * exchange_delegates_user_new:
+ * @display_name: the delegate's (UTF8) display name
+ *
+ * Return value: a new delegate user with default permissions (but
+ * with most of the internal data blank).
+ **/
+ExchangeDelegatesUser *
+exchange_delegates_user_new (const gchar *display_name)
+{
+	ExchangeDelegatesUser *user;
+	gint i;
+
+	user = g_object_new (EXCHANGE_TYPE_DELEGATES_USER, NULL);
+	user->display_name = g_strdup (display_name);
+
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		if (i == EXCHANGE_DELEGATES_CALENDAR ||
+		    i == EXCHANGE_DELEGATES_TASKS)
+			user->role[i] = E2K_PERMISSIONS_ROLE_EDITOR;
+		else
+			user->role[i] = E2K_PERMISSIONS_ROLE_NONE;
+	}
+
+	return user;
+}
+
+/**
+ * exchange_delegates_user_new_from_gc:
+ * @gc: the global catalog object
+ * @email: email address of the new delegate
+ * @creator_entryid: The value of the PR_CREATOR_ENTRYID property
+ * on the LocalFreebusy file.
+ *
+ * Return value: a new delegate user with default permissions and
+ * internal data filled in from the global catalog.
+ **/
+ExchangeDelegatesUser *
+exchange_delegates_user_new_from_gc (E2kGlobalCatalog *gc,
+				    const gchar *email,
+				    GByteArray *creator_entryid)
+{
+	E2kGlobalCatalogStatus status;
+	E2kGlobalCatalogEntry *entry;
+	ExchangeDelegatesUser *user;
+	guint8 *p;
+
+	status = e2k_global_catalog_lookup (
+		gc, NULL, /* FIXME: cancellable */
+		E2K_GLOBAL_CATALOG_LOOKUP_BY_EMAIL, email,
+		(E2K_GLOBAL_CATALOG_LOOKUP_SID |
+		 E2K_GLOBAL_CATALOG_LOOKUP_LEGACY_EXCHANGE_DN),
+		&entry);
+	if (status != E2K_GLOBAL_CATALOG_OK)
+		return NULL;
+
+	user = exchange_delegates_user_new (e2k_sid_get_display_name (entry->sid));
+	user->dn = g_strdup (entry->dn);
+	user->sid = entry->sid;
+	g_object_ref (user->sid);
+
+	user->entryid = g_byte_array_new ();
+	p = creator_entryid->data + creator_entryid->len - 2;
+	while (p > creator_entryid->data && *p)
+		p--;
+	g_byte_array_append (user->entryid, creator_entryid->data,
+			     p - creator_entryid->data + 1);
+	g_byte_array_append (user->entryid, (guint8*)entry->legacy_exchange_dn,
+			     strlen (entry->legacy_exchange_dn));
+	g_byte_array_append (user->entryid, (guint8*)"", 1);
+
+	return user;
+}
diff --git a/eplugin/exchange-delegates-user.h b/eplugin/exchange-delegates-user.h
new file mode 100644
index 0000000..3d886d7
--- /dev/null
+++ b/eplugin/exchange-delegates-user.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_DELEGATES_USER_H__
+#define __EXCHANGE_DELEGATES_USER_H__
+
+#include <exchange-types.h>
+#include <e2k-security-descriptor.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EXCHANGE_TYPE_DELEGATES_USER			(exchange_delegates_user_get_type ())
+#define EXCHANGE_DELEGATES_USER(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_TYPE_DELEGATES_USER, ExchangeDelegatesUser))
+#define EXCHANGE_DELEGATES_USER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_TYPE_DELEGATES_USER, ExchangeDelegatesUserClass))
+#define EXCHANGE_IS_DELEGATES_USER(obj)			(G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_TYPE_DELEGATES_USER))
+#define EXCHANGE_IS_DELEGATES_USER_CLASS(klass)		(G_TYPE_CHECK_CLASS_TYPE ((obj), EXCHANGE_TYPE_DELEGATES_USER))
+
+
+typedef struct _ExchangeDelegatesUser        ExchangeDelegatesUser;
+typedef struct _ExchangeDelegatesUserPrivate ExchangeDelegatesUserPrivate;
+typedef struct _ExchangeDelegatesUserClass   ExchangeDelegatesUserClass;
+
+enum {
+	EXCHANGE_DELEGATES_CALENDAR,
+	EXCHANGE_DELEGATES_TASKS,
+	EXCHANGE_DELEGATES_INBOX,
+	EXCHANGE_DELEGATES_CONTACTS,
+	EXCHANGE_DELEGATES_LAST
+};
+
+struct _ExchangeDelegatesUser {
+	GObject parent;
+
+	gchar *display_name, *dn;
+	GByteArray *entryid;
+
+	E2kSid *sid;
+	E2kPermissionsRole role[EXCHANGE_DELEGATES_LAST];
+	gboolean see_private;
+};
+
+struct _ExchangeDelegatesUserClass {
+	GObjectClass parent_class;
+
+	/* signals */
+	void (*edited) (ExchangeDelegatesUser *, gpointer);
+};
+
+
+
+GType    exchange_delegates_user_get_type (void);
+
+ExchangeDelegatesUser *exchange_delegates_user_new         (const gchar            *display_name);
+ExchangeDelegatesUser *exchange_delegates_user_new_from_gc (E2kGlobalCatalog      *gc,
+							    const gchar            *email,
+							    GByteArray            *creator_entryid);
+
+gboolean  exchange_delegates_user_edit (ExchangeAccount  *account, ExchangeDelegatesUser *user,
+					GtkWidget *parent_window);
+
+G_END_DECLS
+
+#endif /* __EXCHANGE_DELEGATES_USER_H__ */
diff --git a/eplugin/exchange-delegates.c b/eplugin/exchange-delegates.c
new file mode 100644
index 0000000..ce38acf
--- /dev/null
+++ b/eplugin/exchange-delegates.c
@@ -0,0 +1,1026 @@
+/*
+ * 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:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* ExchangeDelegates: Exchange delegate handling.
+ *
+ * FIXME: make this instant-apply
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "exchange-delegates.h"
+#include "exchange-delegates-user.h"
+#include "exchange-user-dialog.h"
+#include "exchange-operations.h"
+
+#include <exchange-account.h>
+#include <e2k-propnames.h>
+#include <e2k-security-descriptor.h>
+#include <e2k-sid.h>
+#include <e2k-uri.h>
+#include <e2k-utils.h>
+
+#include <e-util/e-dialog-utils.h>
+#include <e-util/e-error.h>
+
+typedef struct {
+	const gchar *uri;
+	E2kSecurityDescriptor *sd;
+	gboolean changed;
+} ExchangeDelegatesFolder;
+
+typedef struct {
+	ExchangeAccount *account;
+	gchar *self_dn;
+
+	GtkWidget *dialog, *parent;
+
+	GtkListStore *model;
+	GtkWidget *table;
+
+	GByteArray *creator_entryid;
+	GPtrArray *users, *added_users, *removed_users;
+	gboolean loaded_folders;
+	ExchangeDelegatesFolder folder[EXCHANGE_DELEGATES_LAST];
+	ExchangeDelegatesFolder freebusy_folder;
+} ExchangeDelegates;
+
+extern const gchar *exchange_delegates_user_folder_names[];
+
+const gchar *exchange_localfreebusy_path = "NON_IPM_SUBTREE/Freebusy%20Data/LocalFreebusy.EML";
+
+static void set_perms_for_user (ExchangeDelegatesUser *user, gpointer user_data);
+
+static void
+set_sd_for_href (ExchangeDelegates *delegates,
+		 const gchar *href,
+		 E2kSecurityDescriptor *sd)
+{
+	gint i;
+
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		if (!delegates->folder[i].uri)
+			continue;
+
+		if (!strcmp (href, delegates->folder[i].uri)) {
+			delegates->folder[i].sd = sd;
+			return;
+		}
+	}
+
+	/* else, it's the freebusy folder */
+	delegates->freebusy_folder.uri = g_strdup (href);
+	delegates->freebusy_folder.sd = sd;
+}
+
+/* Given an array of ExchangeDelegatesUser containing display names
+ * and entryids, and an array of E2kSecurityDescriptors containing
+ * SIDs (which contain display names), add SIDs to the delegates. In
+ * the easy case, we can just match the SIDs up with their
+ * corresponding user by display name. However, there are two things
+ * that can go wrong:
+ *
+ *   1. Some users may have been removed from the SDs
+ *   2. Two users may have the same display name
+ *
+ * In both cases, we fall back to using the GC.
+ */
+static gboolean
+fill_in_sids (ExchangeDelegates *delegates)
+{
+	gint u, u2, sd, needed_sids;
+	ExchangeDelegatesUser *user, *user2;
+	GList *sids, *s;
+	E2kSid *sid;
+	E2kGlobalCatalog *gc;
+	E2kGlobalCatalogStatus status;
+	E2kGlobalCatalogEntry *entry;
+	gboolean ok = TRUE;
+
+	needed_sids = 0;
+
+	/* Mark users with duplicate names and count the number of
+	 * non-duplicate names.
+	 */
+	for (u = 0; u < delegates->users->len; u++) {
+		user = delegates->users->pdata[u];
+		if (user->sid == (E2kSid *)-1)
+			continue;
+		for (u2 = u + 1; u2 < delegates->users->len; u2++) {
+			user2 = delegates->users->pdata[u2];
+			if (!strcmp (user->display_name, user2->display_name))
+				user->sid = user2->sid = (E2kSid *)-1;
+		}
+		if (!user->sid)
+			needed_sids++;
+	}
+
+	/* Scan security descriptors trying to match SIDs until we're
+	 * not expecting to find any more.
+	 */
+	for (sd = 0; sd < EXCHANGE_DELEGATES_LAST && needed_sids; sd++) {
+		sids = e2k_security_descriptor_get_sids (delegates->folder[sd].sd);
+		for (s = sids; s && needed_sids; s = s->next) {
+			sid = s->data;
+			for (u = 0; u < delegates->users->len; u++) {
+				user = delegates->users->pdata[u];
+				if (user->sid)
+					continue;
+				if (!strcmp (user->display_name,
+					     e2k_sid_get_display_name (sid))) {
+					user->sid = sid;
+					g_object_ref (sid);
+					needed_sids--;
+				}
+			}
+		}
+		g_list_free (sids);
+	}
+
+	/* Now for each user whose SID hasn't yet been found, look it up. */
+	gc = exchange_account_get_global_catalog (delegates->account);
+	for (u = 0; u < delegates->users->len; u++) {
+		user = delegates->users->pdata[u];
+		if (user->sid && user->sid != (E2kSid *)-1)
+			continue;
+
+		status = e2k_global_catalog_lookup (
+			gc, NULL, /* FIXME: cancellable */
+			E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
+			e2k_entryid_to_dn (user->entryid),
+			E2K_GLOBAL_CATALOG_LOOKUP_SID, &entry);
+		if (status != E2K_GLOBAL_CATALOG_OK) {
+			user->sid = NULL;
+			ok = FALSE;
+			continue;
+		}
+		user->sid = entry->sid;
+		g_object_ref (user->sid);
+		e2k_global_catalog_entry_free (gc, entry);
+	}
+
+	return ok;
+}
+
+static const gchar *sd_props[] = {
+	E2K_PR_EXCHANGE_SD_BINARY,
+	E2K_PR_EXCHANGE_SD_XML
+};
+static const gint n_sd_props = sizeof (sd_props) / sizeof (sd_props[0]);
+
+/* Read the folder security descriptors and match them up with the
+ * list of delegates.
+ */
+static gboolean
+get_folder_security (ExchangeDelegates *delegates)
+{
+	GPtrArray *hrefs;
+	E2kContext *ctx;
+	E2kHTTPStatus status;
+	E2kResultIter *iter;
+	E2kResult *result;
+	xmlNode *xml_form;
+	GByteArray *binary_form;
+	ExchangeDelegatesUser *user;
+	guint32 perms;
+	gint i, u;
+
+	/* If we've been here before, just return the success or
+	 * failure result from last time.
+	 */
+	if (delegates->freebusy_folder.uri)
+		return delegates->loaded_folders;
+
+	if (!exchange_account_get_global_catalog (delegates->account)) {
+		e_error_run (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegates-no-gcs-error",
+			     NULL);
+		return FALSE;
+	}
+
+	ctx = exchange_account_get_context (delegates->account);
+
+	hrefs = g_ptr_array_new ();
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		delegates->folder[i].uri = exchange_account_get_standard_uri (
+			delegates->account, exchange_delegates_user_folder_names[i]);
+		if (delegates->folder[i].uri) {
+			g_ptr_array_add (hrefs, (gchar *)e2k_uri_relative (
+						 delegates->account->home_uri,
+						 delegates->folder[i].uri));
+		}
+	}
+	g_ptr_array_add (hrefs, (gchar *)exchange_localfreebusy_path);
+
+	iter = e2k_context_bpropfind_start (
+		ctx, NULL, delegates->account->home_uri,
+		(const gchar **)hrefs->pdata, hrefs->len,
+		sd_props, n_sd_props);
+	g_ptr_array_free (hrefs, TRUE);
+
+	while ((result = e2k_result_iter_next (iter))) {
+		xml_form = e2k_properties_get_prop (result->props,
+						    E2K_PR_EXCHANGE_SD_XML);
+		binary_form = e2k_properties_get_prop (result->props,
+						       E2K_PR_EXCHANGE_SD_BINARY);
+
+		if (xml_form && binary_form) {
+			set_sd_for_href (delegates, result->href,
+					 e2k_security_descriptor_new (xml_form, binary_form));
+		}
+	}
+	status = e2k_result_iter_free (iter);
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		e_error_run (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegates-perm-read-error",
+			     NULL);
+		return FALSE;
+	}
+
+	if (!fill_in_sids (delegates)) {
+		delegates->loaded_folders = FALSE;
+		e_error_run (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":perm-deter-error", NULL);
+		return FALSE;
+	}
+
+	/* Fill in delegate structures from the security descriptors */
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		for (u = 0; u < delegates->users->len; u++) {
+			user = delegates->users->pdata[u];
+			perms = e2k_security_descriptor_get_permissions (
+				delegates->folder[i].sd, user->sid);
+			user->role[i] = e2k_permissions_role_find (perms);
+		}
+	}
+
+	delegates->loaded_folders = TRUE;
+	return TRUE;
+}
+
+static const gchar *delegation_props[] = {
+	PR_DELEGATES_DISPLAY_NAMES,
+	PR_DELEGATES_ENTRYIDS,
+	PR_DELEGATES_SEE_PRIVATE,
+	PR_CREATOR_ENTRYID
+};
+static const gint n_delegation_props = sizeof (delegation_props) / sizeof (delegation_props[0]);
+
+/* Fetch the list of delegates from the freebusy message. */
+static gboolean
+get_user_list (ExchangeDelegates *delegates)
+{
+	E2kContext *ctx;
+	E2kResultIter *iter;
+	E2kResult *result;
+	GPtrArray *display_names, *entryids, *privflags;
+	GByteArray *entryid;
+	ExchangeDelegatesUser *user;
+	gint i;
+
+	ctx = exchange_account_get_context (delegates->account);
+	iter = e2k_context_bpropfind_start (ctx, NULL,
+					    delegates->account->home_uri,
+					    &exchange_localfreebusy_path, 1,
+					    delegation_props, n_delegation_props);
+	result = e2k_result_iter_next (iter);
+	if (!result || !E2K_HTTP_STATUS_IS_SUCCESSFUL (result->status)) {
+		e2k_result_iter_free (iter);
+		return FALSE;
+	}
+
+	delegates->users = g_ptr_array_new ();
+	delegates->added_users = g_ptr_array_new ();
+	delegates->removed_users = g_ptr_array_new ();
+
+	display_names = e2k_properties_get_prop (result->props, PR_DELEGATES_DISPLAY_NAMES);
+	entryids      = e2k_properties_get_prop (result->props, PR_DELEGATES_ENTRYIDS);
+	privflags     = e2k_properties_get_prop (result->props, PR_DELEGATES_SEE_PRIVATE);
+
+	entryid       = e2k_properties_get_prop (result->props, PR_CREATOR_ENTRYID);
+	delegates->creator_entryid = g_byte_array_new ();
+	g_byte_array_append (delegates->creator_entryid, entryid->data, entryid->len);
+
+	if (!display_names || !entryids || !privflags) {
+		e2k_result_iter_free (iter);
+		return TRUE;
+	}
+
+	for (i = 0; i < display_names->len && i < entryids->len && i < privflags->len; i++) {
+		user = exchange_delegates_user_new (display_names->pdata[i]);
+		user->see_private  = privflags->pdata[i] && atoi (privflags->pdata[i]);
+		entryid            = entryids->pdata[i];
+		user->entryid      = g_byte_array_new ();
+		g_byte_array_append (user->entryid, entryid->data, entryid->len);
+
+		g_signal_connect (user, "edited", G_CALLBACK (set_perms_for_user), delegates);
+
+		g_ptr_array_add (delegates->users, user);
+	}
+
+	e2k_result_iter_free (iter);
+	return TRUE;
+}
+
+/* Add or remove a delegate. Everyone must be in one of three states:
+ *   1. only in users (because they started and ended there)
+ *   2. in users and added_users (because they weren't in
+ *      users to begin with, but got added)
+ *   3. only in removed_users (because they were in users to
+ *      begin with and got removed).
+ * If you're added and then removed, or removed and then added, you have
+ * to end up in state 1. That's what this is for.
+ */
+static void
+add_remove_user (ExchangeDelegatesUser *user,
+		 GPtrArray *to_array, GPtrArray *from_array)
+{
+	ExchangeDelegatesUser *match;
+	gint i;
+
+	for (i = 0; i < from_array->len; i++) {
+		match = from_array->pdata[i];
+		if (e2k_sid_binary_sid_equal (e2k_sid_get_binary_sid (match->sid),
+					      e2k_sid_get_binary_sid (user->sid))) {
+			g_ptr_array_remove_index_fast (from_array, i);
+			g_object_unref (match);
+			return;
+		}
+	}
+
+	g_ptr_array_add (to_array, user);
+	g_object_ref (user);
+}
+
+static void
+set_perms_for_user (ExchangeDelegatesUser *user, gpointer user_data)
+{
+	ExchangeDelegates *delegates = user_data;
+	gint i, role;
+	guint32 perms;
+
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		perms = e2k_permissions_role_get_perms (user->role[i]);
+		e2k_security_descriptor_set_permissions (delegates->folder[i].sd,
+							 user->sid, perms);
+	}
+	role = user->role[EXCHANGE_DELEGATES_CALENDAR];
+	if (role == E2K_PERMISSIONS_ROLE_AUTHOR)
+		role = E2K_PERMISSIONS_ROLE_EDITOR;
+	perms = e2k_permissions_role_get_perms (role);
+	e2k_security_descriptor_set_permissions (delegates->freebusy_folder.sd,
+						 user->sid, perms);
+}
+
+static void
+add_button_clicked_cb (GtkWidget *widget, gpointer data)
+{
+	ExchangeDelegates *delegates = data;
+	E2kGlobalCatalog *gc;
+	GtkWidget *dialog, *parent_window;
+	const gchar *delegate_exchange_dn;
+	gchar *email;
+	ExchangeDelegatesUser *user, *match;
+	gint response, u;
+	GtkTreeIter iter;
+
+	if (!get_folder_security (delegates))
+		return;
+
+	gc = exchange_account_get_global_catalog (delegates->account);
+
+	parent_window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
+	dialog = e2k_user_dialog_new (parent_window,
+				      _("Delegate To:"), _("Delegate To"));
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	if (response != GTK_RESPONSE_OK) {
+		gtk_widget_destroy (dialog);
+		return;
+	}
+	email = e2k_user_dialog_get_user (E2K_USER_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+
+	if (email == NULL)
+		return;
+
+	user = exchange_delegates_user_new_from_gc (gc, email,
+						    delegates->creator_entryid);
+	if (!user) {
+		e_error_run (GTK_WINDOW (parent_window), ERROR_DOMAIN ":delegate-error", email, NULL);
+		g_free (email);
+		return;
+	}
+	g_free (email);
+
+	delegate_exchange_dn = e2k_entryid_to_dn (user->entryid);
+	if (delegate_exchange_dn && !g_ascii_strcasecmp (delegate_exchange_dn, delegates->account->legacy_exchange_dn)) {
+		g_object_unref (user);
+		e_error_run (GTK_WINDOW (parent_window), ERROR_DOMAIN ":delegate-own-error", NULL);
+		return;
+	}
+
+	for (u = 0; u < delegates->users->len; u++) {
+		match = delegates->users->pdata[u];
+		if (e2k_sid_binary_sid_equal (e2k_sid_get_binary_sid (user->sid),
+					      e2k_sid_get_binary_sid (match->sid))) {
+			e_error_run (GTK_WINDOW (parent_window), ERROR_DOMAIN ":delegate-existing",
+				     user->display_name, NULL);
+			g_object_unref (user);
+			exchange_delegates_user_edit (delegates->account, match, parent_window);
+			return;
+		}
+	}
+
+	if (!exchange_delegates_user_edit (delegates->account, user, parent_window)) {
+		g_object_unref (user);
+		return;
+	}
+	set_perms_for_user (user, delegates);
+	g_signal_connect (user, "edited",
+			  G_CALLBACK (set_perms_for_user), delegates);
+
+	add_remove_user (user, delegates->added_users, delegates->removed_users);
+	g_ptr_array_add (delegates->users, user);
+
+	/* Add the user to the table */
+	gtk_list_store_append (delegates->model, &iter);
+	gtk_list_store_set (delegates->model, &iter,
+			    0, user->display_name,
+			    -1);
+}
+
+static gint
+get_selected_row (GtkWidget *tree_view, GtkTreeIter *iter)
+{
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	gint *indices, row;
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+	if (!gtk_tree_selection_get_selected (selection, &model, iter))
+		return -1;
+
+	path = gtk_tree_model_get_path (model, iter);
+	indices = gtk_tree_path_get_indices (path);
+	row = indices[0];
+	gtk_tree_path_free (path);
+
+	return row;
+}
+
+static void
+edit_button_clicked_cb (GtkWidget *widget, gpointer data)
+{
+	ExchangeDelegates *delegates = data;
+	GtkWidget *parent_window;
+	GtkTreeIter iter;
+	gint row;
+
+	if (!get_folder_security (delegates))
+		return;
+
+	row = get_selected_row (delegates->table, &iter);
+	g_return_if_fail (row >= 0 && row < delegates->users->len);
+
+	parent_window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
+
+	exchange_delegates_user_edit (delegates->account, delegates->users->pdata[row],
+				      parent_window);
+}
+
+const gchar *
+email_look_up (const gchar *delegate_legacy, ExchangeAccount *account)
+{
+	E2kGlobalCatalog *gc;
+	E2kGlobalCatalogEntry *entry;
+	E2kGlobalCatalogStatus status;
+
+	const gchar *email_id;
+
+	gc = exchange_account_get_global_catalog (account);
+
+	if (!gc)
+		return NULL;
+
+	status = e2k_global_catalog_lookup (
+			gc, NULL, E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
+			delegate_legacy, 0, &entry);
+
+	email_id = g_strdup (entry->email);
+	e2k_global_catalog_entry_free (gc, entry);
+	return email_id;
+}
+
+static gboolean
+table_click_cb (GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+	ExchangeDelegates *delegates = data;
+	GtkWidget *parent_window;
+	GtkTreeIter iter;
+	gint row;
+
+	if (event->type != GDK_2BUTTON_PRESS)
+		return FALSE;
+
+	row = get_selected_row (delegates->table, &iter);
+	if (row < 0 || row >= delegates->users->len)
+		return FALSE;
+
+	if (!get_folder_security (delegates))
+		return FALSE;
+
+	parent_window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
+	exchange_delegates_user_edit (delegates->account, delegates->users->pdata[row],
+				      parent_window);
+	return TRUE;
+}
+
+static void
+remove_button_clicked_cb (GtkWidget *widget, gpointer data)
+{
+	ExchangeDelegates *delegates = data;
+	ExchangeDelegatesUser *user;
+	GtkWidget *dialog;
+	gint row, btn, i;
+	GtkTreeIter iter;
+
+	if (!get_folder_security (delegates))
+		return;
+
+	row = get_selected_row (delegates->table, &iter);
+	g_return_if_fail (row >= 0 && row < delegates->users->len);
+
+	user = delegates->users->pdata[row];
+
+	dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+					 GTK_MESSAGE_QUESTION,
+					 GTK_BUTTONS_YES_NO,
+					 _("Remove the delegate %s?"),
+					 user->display_name);
+	e_dialog_set_transient_for (GTK_WINDOW (dialog), widget);
+
+	btn = gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+	if (btn != GTK_RESPONSE_YES)
+		return;
+
+	add_remove_user (user, delegates->removed_users, delegates->added_users);
+
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		e2k_security_descriptor_remove_sid (delegates->folder[i].sd,
+						    user->sid);
+	}
+	e2k_security_descriptor_remove_sid (delegates->freebusy_folder.sd,
+					    user->sid);
+
+	/* Remove the user from the table */
+	gtk_list_store_remove (delegates->model, &iter);
+	g_ptr_array_remove_index (delegates->users, row);
+	g_object_unref (user);
+}
+
+static gboolean
+proppatch_sd (E2kContext *ctx, ExchangeDelegatesFolder *folder)
+{
+	GByteArray *binsd;
+	E2kProperties *props;
+	const gchar *href = "";
+	E2kResultIter *iter;
+	E2kResult *result;
+	E2kHTTPStatus status;
+
+	binsd = e2k_security_descriptor_to_binary (folder->sd);
+	if (!binsd)
+		return FALSE;
+
+	props = e2k_properties_new ();
+	e2k_properties_set_binary (props, E2K_PR_EXCHANGE_SD_BINARY, binsd);
+
+	iter = e2k_context_bproppatch_start (ctx, NULL, folder->uri,
+					     &href, 1, props, FALSE);
+	e2k_properties_free (props);
+
+	result = e2k_result_iter_next (iter);
+	if (result) {
+		status = result->status;
+		e2k_result_iter_free (iter);
+	} else
+		status = e2k_result_iter_free (iter);
+
+	return E2K_HTTP_STATUS_IS_SUCCESSFUL (status);
+}
+
+static gboolean
+get_user_dn (E2kGlobalCatalog *gc, ExchangeDelegatesUser *user)
+{
+	E2kGlobalCatalogEntry *entry;
+	E2kGlobalCatalogStatus status;
+	const gchar *exchange_dn;
+
+	exchange_dn = e2k_entryid_to_dn (user->entryid);
+	status = e2k_global_catalog_lookup (
+		gc, NULL, /* FIXME: cancellable */
+		E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
+		exchange_dn, 0, &entry);
+	if (status != E2K_GLOBAL_CATALOG_OK)
+		return FALSE;
+
+	user->dn = g_strdup (entry->dn);
+	e2k_global_catalog_entry_free (gc, entry);
+	return TRUE;
+}
+
+static void
+delegates_apply (ExchangeDelegates *delegates)
+{
+	ExchangeDelegatesUser *user;
+	E2kGlobalCatalog *gc;
+	E2kContext *ctx;
+	GPtrArray *display_names, *entryids, *privflags;
+	GByteArray *entryid_dup;
+	gchar *error = NULL;
+	E2kProperties *props;
+	gint i;
+	E2kGlobalCatalogStatus status;
+
+	if (!delegates->loaded_folders)
+		return;
+
+	/* We can't do this atomically/transactionally, so we need to
+	 * make sure that if we fail at any step, things are still in
+	 * a semi-consistent state. So we do:
+	 *
+	 *   1. Remove old delegates from AD
+	 *   2. Update LocalFreebusy.EML (the canonical list of delegates)
+	 *   3. Add new delegates to AD
+	 *   4. Update security descriptors
+	 *
+	 * If step 1 fails, nothing is changed.
+	 *
+	 * If step 2 fails, delegates who should have been removed
+	 * will have been removed from AD but nothing else, so they
+	 * will still show up as being delegates and the user can try
+	 * to remove them again later.
+	 *
+	 * If step 3 fails, delegates who should have been added will
+	 * not be in AD, but will be listed as delegates, so the user
+	 * can remove them and try adding them again later.
+	 *
+	 * If step 4 fails, the user can still correct the folder
+	 * permissions by hand.
+	 */
+
+	gc = exchange_account_get_global_catalog (delegates->account);
+	if (!gc) {
+		error = g_strdup (_("Could not access Active Directory"));
+		goto done;
+	}
+
+	if ((delegates->removed_users || delegates->added_users) && !delegates->self_dn) {
+		E2kGlobalCatalogEntry *entry;
+
+		status = e2k_global_catalog_lookup (
+			gc, NULL, /* FIXME: cancellable */
+			E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
+			delegates->account->legacy_exchange_dn, 0, &entry);
+		if (status != E2K_GLOBAL_CATALOG_OK) {
+			error = g_strdup (_("Could not find self in Active Directory"));
+			goto done;
+		}
+
+		delegates->self_dn = g_strdup (entry->dn);
+		e2k_global_catalog_entry_free (gc, entry);
+	}
+
+	/* 1. Remove old delegates from AD */
+	while (delegates->removed_users && delegates->removed_users->len) {
+		user = delegates->removed_users->pdata[0];
+		if (!user->dn && !get_user_dn (gc, user)) {
+			error = g_strdup_printf (
+				_("Could not find delegate %s in Active Directory"),
+				user->display_name);
+			goto done;
+		}
+
+		/* FIXME: cancellable */
+		status = e2k_global_catalog_remove_delegate (gc, NULL,
+							     delegates->self_dn,
+							     user->dn);
+		if (status != E2K_GLOBAL_CATALOG_OK &&
+		    status != E2K_GLOBAL_CATALOG_NO_DATA) {
+			error = g_strdup_printf (
+				_("Could not remove delegate %s"),
+				user->display_name);
+			goto done;
+		}
+
+		g_object_unref (user);
+		g_ptr_array_remove_index_fast (delegates->removed_users, 0);
+	}
+
+	/* 2. Update LocalFreebusy.EML */
+	ctx = exchange_account_get_context (delegates->account);
+
+	if (delegates->users->len) {
+		display_names = g_ptr_array_new ();
+		entryids = g_ptr_array_new ();
+		privflags = g_ptr_array_new ();
+
+		for (i = 0; i < delegates->users->len; i++) {
+			user = delegates->users->pdata[i];
+			g_ptr_array_add (display_names, g_strdup (user->display_name));
+			entryid_dup = g_byte_array_new ();
+			g_byte_array_append (entryid_dup, user->entryid->data,
+					     user->entryid->len);
+			g_ptr_array_add (entryids, entryid_dup);
+			g_ptr_array_add (privflags, g_strdup_printf ("%d", user->see_private));
+		}
+
+		props = e2k_properties_new ();
+		e2k_properties_set_string_array (
+			props, PR_DELEGATES_DISPLAY_NAMES, display_names);
+		e2k_properties_set_binary_array (
+			props, PR_DELEGATES_ENTRYIDS, entryids);
+		e2k_properties_set_int_array (
+			props, PR_DELEGATES_SEE_PRIVATE, privflags);
+	} else if (delegates->removed_users) {
+		props = e2k_properties_new ();
+		e2k_properties_remove (props, PR_DELEGATES_DISPLAY_NAMES);
+		e2k_properties_remove (props, PR_DELEGATES_ENTRYIDS);
+		e2k_properties_remove (props, PR_DELEGATES_SEE_PRIVATE);
+	} else
+		props = NULL;
+
+	if (props) {
+		E2kResultIter *iter;
+		E2kResult *result;
+
+		iter = e2k_context_bproppatch_start (
+			ctx, NULL, delegates->account->home_uri,
+			&exchange_localfreebusy_path, 1,
+			props, FALSE);
+		e2k_properties_free (props);
+
+		result = e2k_result_iter_next (iter);
+		if (result) {
+			status = result->status;
+			e2k_result_iter_free (iter);
+		} else
+			status = e2k_result_iter_free (iter);
+
+		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+			error = g_strdup (_("Could not update list of delegates."));
+			goto done;
+		}
+	}
+
+	/* 3. Add new delegates to AD */
+	while (delegates->added_users && delegates->added_users->len) {
+		user = delegates->added_users->pdata[0];
+		/* An added user must have come from the GC so
+		 * we know user->dn is set.
+		 */
+		/* FIXME: cancellable */
+		status = e2k_global_catalog_add_delegate (gc, NULL,
+							  delegates->self_dn,
+							  user->dn);
+		if (status != E2K_GLOBAL_CATALOG_OK &&
+		    status != E2K_GLOBAL_CATALOG_EXISTS) {
+			error = g_strdup_printf (
+				_("Could not add delegate %s"),
+				user->display_name);
+			goto done;
+		}
+		g_ptr_array_remove_index_fast (delegates->added_users, 0);
+		g_object_unref (user);
+	}
+
+	/* 4. Update security descriptors */
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++)
+		proppatch_sd (ctx, &delegates->folder[i]);
+	proppatch_sd (ctx, &delegates->freebusy_folder);
+
+ done:
+	if (error) {
+		e_error_run (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegate-fail-error", error, NULL);
+		g_free (error);
+	}
+}
+
+static void parent_destroyed (gpointer user_data, GObject *ex_parent);
+
+static void
+delegates_destroy (ExchangeDelegates *delegates)
+{
+	gint i;
+
+	g_object_unref (delegates->account);
+
+	if (delegates->parent) {
+		g_object_weak_unref (G_OBJECT (delegates->parent),
+				     parent_destroyed, delegates);
+	}
+	if (delegates->dialog)
+		gtk_widget_destroy (delegates->dialog);
+
+	if (delegates->model)
+		g_object_unref (delegates->model);
+
+	if (delegates->self_dn)
+		g_free (delegates->self_dn);
+	if (delegates->creator_entryid)
+		g_byte_array_free (delegates->creator_entryid, TRUE);
+
+	if (delegates->users) {
+		for (i = 0; i < delegates->users->len; i++)
+			g_object_unref (delegates->users->pdata[i]);
+		g_ptr_array_free (delegates->users, TRUE);
+	}
+	if (delegates->added_users) {
+		for (i = 0; i < delegates->added_users->len; i++)
+			g_object_unref (delegates->added_users->pdata[i]);
+		g_ptr_array_free (delegates->added_users, TRUE);
+	}
+	if (delegates->removed_users) {
+		for (i = 0; i < delegates->removed_users->len; i++)
+			g_object_unref (delegates->removed_users->pdata[i]);
+		g_ptr_array_free (delegates->removed_users, TRUE);
+	}
+
+	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
+		if (delegates->folder[i].sd)
+			g_object_unref (delegates->folder[i].sd);
+	}
+	if (delegates->freebusy_folder.sd)
+		g_object_unref (delegates->freebusy_folder.sd);
+	if (delegates->freebusy_folder.uri)
+		g_free ((gchar *)delegates->freebusy_folder.uri);
+
+	g_free (delegates);
+}
+
+static void
+dialog_response (GtkDialog *dialog, gint response, gpointer user_data)
+{
+	ExchangeDelegates *delegates = user_data;
+
+	if (response == GTK_RESPONSE_OK)
+		delegates_apply (delegates);
+	delegates_destroy (delegates);
+}
+
+static void
+parent_destroyed (gpointer user_data, GObject *ex_parent)
+{
+	ExchangeDelegates *delegates = user_data;
+
+	gtk_widget_destroy (delegates->dialog);
+	delegates_destroy (delegates);
+}
+
+void
+exchange_delegates (ExchangeAccount *account, GtkWidget *parent)
+{
+	GtkWidget *dialog_vbox1;
+	GtkWidget *vbox2;
+	GtkWidget *label3;
+	GtkWidget *delegate_hbox;
+	GtkWidget *delegates_table;
+	GtkWidget *vbuttonbox1;
+	GtkWidget *add_button;
+	GtkWidget *edit_button;
+	GtkWidget *remove_button;
+	ExchangeDelegates *delegates;
+	ExchangeDelegatesUser *user;
+	GtkTreeViewColumn *column;
+	GtkTreeIter iter;
+	gint i;
+
+	g_return_if_fail (GTK_IS_WIDGET (parent));
+	g_return_if_fail (EXCHANGE_IS_ACCOUNT (account));
+
+	delegates = g_new0 (ExchangeDelegates, 1);
+	delegates->account = g_object_ref (account);
+
+	delegates->dialog = gtk_dialog_new_with_buttons (
+		_("Delegates"),
+		NULL,
+		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+
+	dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (delegates->dialog));
+	gtk_widget_show (dialog_vbox1);
+
+	vbox2 = gtk_vbox_new (FALSE, 6);
+	gtk_widget_show (vbox2);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox2, TRUE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox2), 6);
+
+	label3 = gtk_label_new (_("These users will be able to send mail on your behalf\nand access your folders with the permissions you give them."));
+	gtk_widget_show (label3);
+	gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0);
+
+	delegate_hbox = gtk_hbox_new (FALSE, 6);
+	gtk_widget_show (delegate_hbox);
+	gtk_box_pack_start (GTK_BOX (vbox2), delegate_hbox, TRUE, TRUE, 0);
+
+	delegates_table = gtk_tree_view_new ();
+	gtk_widget_show (delegates_table);
+	gtk_box_pack_start (GTK_BOX (delegate_hbox), delegates_table, TRUE, TRUE, 0);
+	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (delegates_table), FALSE);
+
+	vbuttonbox1 = gtk_vbutton_box_new ();
+	gtk_widget_show (vbuttonbox1);
+	gtk_box_pack_end (GTK_BOX (delegate_hbox), vbuttonbox1, FALSE, TRUE, 0);
+	gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox1), GTK_BUTTONBOX_START);
+	gtk_box_set_spacing (GTK_BOX (vbuttonbox1), 6);
+
+	add_button = gtk_button_new_from_stock ("gtk-add");
+	gtk_widget_show (add_button);
+	gtk_container_add (GTK_CONTAINER (vbuttonbox1), add_button);
+	GTK_WIDGET_SET_FLAGS (add_button, GTK_CAN_DEFAULT);
+
+	edit_button = gtk_button_new_with_mnemonic (_("_Edit"));
+	gtk_widget_show (edit_button);
+	gtk_container_add (GTK_CONTAINER (vbuttonbox1), edit_button);
+	GTK_WIDGET_SET_FLAGS (edit_button, GTK_CAN_DEFAULT);
+
+	remove_button = gtk_button_new_from_stock ("gtk-remove");
+	gtk_widget_show (remove_button);
+	gtk_container_add (GTK_CONTAINER (vbuttonbox1), remove_button);
+	GTK_WIDGET_SET_FLAGS (remove_button, GTK_CAN_DEFAULT);
+
+	g_signal_connect (delegates->dialog, "response",
+			  G_CALLBACK (dialog_response), delegates);
+
+	e_dialog_set_transient_for (GTK_WINDOW (delegates->dialog), parent);
+	delegates->parent = parent;
+	g_object_weak_ref (G_OBJECT (parent), parent_destroyed, delegates);
+
+	/* Set up the buttons */
+	g_signal_connect (add_button, "clicked",
+			  G_CALLBACK (add_button_clicked_cb), delegates);
+	g_signal_connect (edit_button, "clicked",
+			  G_CALLBACK (edit_button_clicked_cb), delegates);
+	g_signal_connect (remove_button, "clicked",
+			  G_CALLBACK (remove_button_clicked_cb), delegates);
+
+	/* Set up the table */
+	delegates->model = gtk_list_store_new (1, G_TYPE_STRING);
+	delegates->table = delegates_table;
+	column = gtk_tree_view_column_new_with_attributes (
+		_("Name"), gtk_cell_renderer_text_new (), "text", 0, NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (delegates->table),
+				     column);
+	gtk_tree_view_set_model (GTK_TREE_VIEW (delegates->table),
+				 GTK_TREE_MODEL (delegates->model));
+
+	/* Get list of delegate users */
+	if (get_user_list (delegates)) {
+		for (i = 0; i < delegates->users->len; i++) {
+			user = delegates->users->pdata[i];
+
+			gtk_list_store_append (delegates->model, &iter);
+			gtk_list_store_set (delegates->model, &iter,
+					    0, user->display_name,
+					    -1);
+		}
+		g_signal_connect (delegates->table,
+				  "button_press_event",
+				  G_CALLBACK (table_click_cb), delegates);
+	} else {
+		gtk_widget_set_sensitive (add_button, FALSE);
+		gtk_widget_set_sensitive (edit_button, FALSE);
+		gtk_widget_set_sensitive (remove_button, FALSE);
+
+		gtk_list_store_append (delegates->model, &iter);
+		gtk_list_store_set (delegates->model, &iter,
+				    0, _("Error reading delegates list."),
+				    -1);
+	}
+
+	gtk_widget_show (delegates->dialog);
+}
diff --git a/eplugin/exchange-delegates.h b/eplugin/exchange-delegates.h
new file mode 100644
index 0000000..ae89047
--- /dev/null
+++ b/eplugin/exchange-delegates.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_DELEGATES_H__
+#define __EXCHANGE_DELEGATES_H__
+
+#include <exchange-types.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void exchange_delegates (ExchangeAccount *account, GtkWidget *parent);
+const gchar *email_look_up (const gchar *delegate_legacy, ExchangeAccount *account);
+
+G_END_DECLS
+
+#endif /* __EXCHANGE_DELEGATES_CONTROL_H__ */
diff --git a/eplugin/exchange-folder-permission.c b/eplugin/exchange-folder-permission.c
new file mode 100644
index 0000000..149454a
--- /dev/null
+++ b/eplugin/exchange-folder-permission.c
@@ -0,0 +1,340 @@
+/*
+ *
+ * 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:
+ *		Shakti Sen <shprasad@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <exchange-account.h>
+#include <e-util/e-dialog-utils.h>
+#include <calendar/gui/e-cal-popup.h>
+#include <libedataserverui/e-source-selector.h>
+#include <camel/camel-url.h>
+#include <mail/em-popup.h>
+#include <mail/em-menu.h>
+#include <libebook/e-book.h>
+#include "exchange-config-listener.h"
+#include "exchange-operations.h"
+#include "exchange-permissions-dialog.h"
+#include "addressbook/gui/widgets/eab-popup.h"
+#include "calendar/gui/e-cal-menu.h"
+#include "calendar/gui/e-cal-model.h"
+#include "addressbook/gui/widgets/eab-menu.h"
+
+#define d(x)
+
+static void org_folder_permissions_cb (EPopup *ep, EPopupItem *p, gpointer data);
+void org_gnome_exchange_folder_permissions (EPlugin *ep, EMPopupTargetFolder *t);
+void org_gnome_exchange_menu_folder_permissions (EPlugin *ep, EMMenuTargetSelect *target);
+void org_gnome_exchange_calendar_permissions (EPlugin *ep, ECalPopupTargetSource *target);
+void org_gnome_exchange_addressbook_permissions (EPlugin *ep, EABPopupTargetSource *target);
+void org_gnome_exchange_menu_ab_permissions (EPlugin *ep, EABMenuTargetSelect *target);
+void org_gnome_exchange_menu_tasks_permissions (EPlugin *ep, ECalMenuTargetSelect *target);
+void org_gnome_exchange_menu_cal_permissions (EPlugin *ep, ECalMenuTargetSelect *target);
+
+gchar *selected_exchange_folder_uri = NULL;
+
+static EPopupItem popup_items[] = {
+	{ E_POPUP_ITEM, (gchar *) "30.emc.10", (gchar *) N_("Permissions..."), org_folder_permissions_cb, NULL, (gchar *) "folder-new", 0, EM_POPUP_FOLDER_INFERIORS }
+};
+
+static void
+popup_free (EPopup *ep, GSList *items, gpointer data)
+{
+       g_slist_free (items);
+}
+
+void
+org_gnome_exchange_calendar_permissions (EPlugin *ep, ECalPopupTargetSource *target)
+{
+	GSList *menus = NULL;
+	gint i = 0, mode;
+	static gint first =0;
+	ExchangeAccount *account = NULL;
+	ESource *source = NULL;
+	gchar *uri = NULL;
+
+	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (target->selector));
+	uri = (gchar *) e_source_get_uri (source);
+	if (uri && ! g_strrstr (uri, "exchange://"))	{
+		return;
+	}
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return;
+	if (!exchange_account_get_folder (account, uri))
+		return;
+
+	selected_exchange_folder_uri = uri;
+
+	/* for translation*/
+	if (!first) {
+		popup_items[0].label =  _(popup_items[0].label);
+		first++;
+
+	}
+
+	for (i = 0; i < sizeof (popup_items) / sizeof (popup_items[0]); i++)
+		menus = g_slist_prepend (menus, &popup_items[i]);
+
+	e_popup_add_items (target->target.popup, menus, NULL, popup_free, NULL);
+
+}
+
+void
+org_gnome_exchange_addressbook_permissions (EPlugin *ep, EABPopupTargetSource *target)
+{
+	GSList *menus = NULL;
+	gint i = 0, mode;
+	static gint first =0;
+	ExchangeAccount *account = NULL;
+	ESource *source = NULL;
+	gchar *uri = NULL;
+
+	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (target->selector));
+	uri = (gchar *) e_source_get_uri (source);
+	if (!g_strrstr (uri, "exchange://"))
+		return;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return;
+
+	if (!exchange_account_get_folder (account, uri))
+		return;
+
+	selected_exchange_folder_uri = uri;
+
+	/* for translation*/
+	if (!first) {
+		popup_items[0].label =  _(popup_items[0].label);
+		first++;
+	}
+
+	for (i = 0; i < sizeof (popup_items) / sizeof (popup_items[0]); i++)
+		menus = g_slist_prepend (menus, &popup_items[i]);
+
+	e_popup_add_items (target->target.popup, menus, NULL, popup_free, NULL);
+}
+
+void
+org_gnome_exchange_folder_permissions (EPlugin *ep, EMPopupTargetFolder *target)
+{
+	GSList *menus = NULL;
+	gint i = 0, mode;
+	static gint first =0;
+	gchar *path = NULL;
+	gchar *fixed_path = NULL;
+	ExchangeAccount *account = NULL;
+
+	d(g_print ("exchange-folder-permission.c: entry\n"));
+
+	if (!g_strrstr (target->uri, "exchange://"))
+		return;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account )
+		return;
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return;
+
+	path = target->uri + strlen ("exchange://") + strlen (account->account_filename);
+
+	if (!path || !*path)
+		return;
+
+	fixed_path = camel_url_decode_path (path);
+	d(g_print ("exchange-folder-permission.c: path=[%s], fixed_path=[%s]\n", path, fixed_path));
+
+	if (! g_strrstr (target->uri, "exchange://") ||
+	    !exchange_account_get_folder (account, fixed_path)) {
+		g_free (fixed_path);
+		return;
+	}
+
+	g_free (fixed_path);
+
+	selected_exchange_folder_uri = path;
+	/* for translation*/
+	if (!first) {
+		popup_items[0].label =  _(popup_items[0].label);
+		first++;
+	}
+
+	for (i = 0; i < sizeof (popup_items) / sizeof (popup_items[0]); i++)
+		menus = g_slist_prepend (menus, &popup_items[i]);
+
+	e_popup_add_items (target->target.popup, menus, NULL, popup_free, NULL);
+
+}
+
+static void
+org_folder_permissions_cb (EPopup *ep, EPopupItem *p, gpointer data)
+{
+	ExchangeAccount *account = NULL;
+	EFolder *folder = NULL;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (!account)
+		return;
+
+	folder = exchange_account_get_folder (account, selected_exchange_folder_uri);
+	if (folder)
+		exchange_permissions_dialog_new (account, folder, NULL);
+
+}
+
+void
+org_gnome_exchange_menu_folder_permissions (EPlugin *ep, EMMenuTargetSelect *target)
+{
+	ExchangeAccount *account = NULL;
+	EFolder *folder = NULL;
+	gchar *path = NULL;
+	gint mode;
+
+	if (!g_str_has_prefix (target->uri, "exchange://"))
+		return;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return;
+
+	path = target->uri + strlen ("exchange://") + strlen (account->account_filename);
+	folder = exchange_account_get_folder (account, path);
+	if (folder)
+		exchange_permissions_dialog_new (account, folder, NULL);
+}
+
+void
+org_gnome_exchange_menu_cal_permissions (EPlugin *ep, ECalMenuTargetSelect *target)
+{
+	ExchangeAccount *account = NULL;
+	EFolder *folder = NULL;
+	ECalModel *model = NULL;
+	ECal *ecal = NULL;
+	gchar *uri = NULL;
+	gint mode;
+
+	if (!target)
+		return;
+	if (target->model)
+		model = E_CAL_MODEL (target->model);
+
+	ecal = e_cal_model_get_default_client (model);
+	uri = (gchar *) e_cal_get_uri (ecal);
+	if (!uri)
+		return;
+	else
+		if (!g_str_has_prefix (uri, "exchange://"))
+			return;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return;
+
+	folder = exchange_account_get_folder (account, uri);
+	exchange_permissions_dialog_new (account, folder, NULL);
+}
+
+void
+org_gnome_exchange_menu_tasks_permissions (EPlugin *ep, ECalMenuTargetSelect *target)
+{
+	ExchangeAccount *account = NULL;
+	EFolder *folder = NULL;
+	ECalModel *model = NULL;
+	ECal *ecal = NULL;
+	gchar *uri = NULL;
+	gint mode;
+
+	if (!target)
+		return;
+	if (target->model)
+		model = E_CAL_MODEL (target->model);
+
+	ecal = e_cal_model_get_default_client (model);
+	uri = (gchar *) e_cal_get_uri (ecal);
+	if (!uri)
+		return;
+	else
+		if (!g_str_has_prefix (uri, "exchange://"))
+			return;
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return;
+
+	folder = exchange_account_get_folder (account, uri);
+	exchange_permissions_dialog_new (account, folder, NULL);
+}
+
+void
+org_gnome_exchange_menu_ab_permissions (EPlugin *ep, EABMenuTargetSelect *target)
+{
+	ExchangeAccount *account = NULL;
+	EFolder *folder = NULL;
+	EBook *ebook = NULL;
+	gchar *uri = NULL;
+	gint mode;
+
+	if (!target)
+		return;
+	if (target->book)
+		ebook = E_BOOK (target->book);
+
+	uri = (gchar *) e_book_get_uri (ebook);
+	if (!uri)
+		return;
+	else
+		if (!g_str_has_prefix (uri, "exchange://"))
+			return;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return;
+
+	folder = exchange_account_get_folder (account, uri);
+	exchange_permissions_dialog_new (account, folder, NULL);
+}
diff --git a/eplugin/exchange-folder-size-display.c b/eplugin/exchange-folder-size-display.c
new file mode 100644
index 0000000..1b61b84
--- /dev/null
+++ b/eplugin/exchange-folder-size-display.c
@@ -0,0 +1,170 @@
+/*
+ * 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:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* ExchangeFolderSize: Display the folder tree with the folder sizes */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <e-util/e-dialog-utils.h>
+#include <gtk/gtk.h>
+#include "exchange-folder-size-display.h"
+
+enum {
+        COLUMN_NAME,
+        COLUMN_SIZE,
+        NUM_COLUMNS
+};
+
+static gboolean
+get_folder_size_func (GtkTreeModel *model,
+		  GtkTreePath	    *path,
+                  GtkTreeIter       *iter,
+                 gpointer           user_data)
+{
+	GHashTable *info = (GHashTable *) user_data;
+	gdouble folder_size;
+	gchar *folder_name;
+
+	gtk_tree_model_get(model, iter, COLUMN_SIZE, &folder_size, COLUMN_NAME, &folder_name, -1);
+
+	g_hash_table_insert (info, g_strdup (folder_name), g_strdup_printf ("%.2f", folder_size));
+	return FALSE;
+}
+
+gchar *
+exchange_folder_size_get_val (GtkListStore *model, const gchar *folder_name)
+{
+	GHashTable *finfo;
+	gchar *folder_size, *fsize;
+
+	finfo = g_hash_table_new_full (
+		g_str_hash, g_str_equal,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) g_free);
+
+	gtk_tree_model_foreach (GTK_TREE_MODEL (model), get_folder_size_func, finfo);
+
+	if ((fsize = g_hash_table_lookup (finfo, folder_name)) != NULL)
+		folder_size = g_strdup (fsize);
+	else
+		folder_size = g_strdup ("0");
+
+	g_hash_table_destroy (finfo);
+
+	return folder_size;
+}
+
+static void
+format_size_func (GtkTreeViewColumn *col,
+                  GtkCellRenderer   *renderer,
+                  GtkTreeModel      *model,
+                  GtkTreeIter       *iter,
+                 gpointer           user_data)
+{
+	GtkCellRendererText *cell = (GtkCellRendererText *)renderer;
+	gdouble folder_size;
+	gchar * new_text;
+
+	gtk_tree_model_get(model, iter, COLUMN_SIZE, &folder_size, -1);
+
+	if (folder_size)
+		new_text = g_strdup_printf ("%.2f", folder_size);
+	else
+		new_text = g_strdup ("0");
+
+	g_object_set (cell, "text", new_text, NULL);
+	g_free (new_text);
+}
+
+void
+exchange_folder_size_display (GtkListStore *model, GtkWidget *parent)
+{
+        GtkTreeViewColumn *column;
+	GtkTreeSortable *sortable;
+	GtkCellRenderer *cell;
+	GtkWidget *folder_tree;
+	GtkWidget *dialog_vbox1;
+	GtkWidget *folder_tree_hbox;
+	GtkWidget *scrolledwindow1;
+	GtkWidget *folder_treeview;
+	GList *l;
+	gchar *col_name;
+
+        g_return_if_fail (GTK_IS_WIDGET (parent));
+
+	folder_tree = gtk_dialog_new_with_buttons (
+		_("Exchange Folder Tree"),
+		NULL,
+		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+	gtk_window_set_position (GTK_WINDOW (folder_tree), GTK_WIN_POS_CENTER_ON_PARENT);
+	gtk_window_set_default_size (GTK_WINDOW (folder_tree), 250, 300);
+
+	dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (folder_tree));
+	gtk_widget_show (dialog_vbox1);
+
+	folder_tree_hbox = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (folder_tree_hbox);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), folder_tree_hbox, TRUE, TRUE, 0);
+
+	scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
+	gtk_widget_show (scrolledwindow1);
+	gtk_box_pack_start (GTK_BOX (folder_tree_hbox), scrolledwindow1, TRUE, TRUE, 0);
+
+	folder_treeview = gtk_tree_view_new ();
+	gtk_widget_show (folder_treeview);
+	gtk_container_add (GTK_CONTAINER (scrolledwindow1), folder_treeview);
+
+        e_dialog_set_transient_for (GTK_WINDOW (folder_tree), parent);
+	/* fsize->parent = parent; */
+
+        /* Set up the table */
+	sortable = GTK_TREE_SORTABLE (model);
+	gtk_tree_sortable_set_sort_column_id (sortable, COLUMN_SIZE, GTK_SORT_DESCENDING);
+
+        column = gtk_tree_view_column_new_with_attributes (
+                _("Folder Name"), gtk_cell_renderer_text_new (), "text", COLUMN_NAME, NULL);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (folder_treeview),
+                                     column);
+
+	col_name = g_strdup_printf ("%s (KB)", _("Folder Size"));
+        column = gtk_tree_view_column_new_with_attributes (
+                col_name, gtk_cell_renderer_text_new (), "text", COLUMN_SIZE, NULL);
+	g_free (col_name);
+
+	l = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+	cell = (GtkCellRenderer *)l->data;
+	gtk_tree_view_column_set_cell_data_func (column, cell, format_size_func, NULL, NULL );
+	g_list_free (l);
+
+        gtk_tree_view_append_column (GTK_TREE_VIEW (folder_treeview),
+                                     column);
+        gtk_tree_view_set_model (GTK_TREE_VIEW (folder_treeview),
+                                 GTK_TREE_MODEL (model));
+	gtk_dialog_run (GTK_DIALOG (folder_tree));
+        gtk_widget_destroy (folder_tree);
+}
diff --git a/eplugin/exchange-folder-size-display.h b/eplugin/exchange-folder-size-display.h
new file mode 100644
index 0000000..13d112c
--- /dev/null
+++ b/eplugin/exchange-folder-size-display.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_FOLDER_SIZE_DISPLAY_H__
+#define __EXCHANGE_FOLDER_SIZE_DISPLAY_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void exchange_folder_size_display (GtkListStore *model, GtkWidget *parent);
+gchar * exchange_folder_size_get_val (GtkListStore *model, const gchar *folder_name);
+
+G_END_DECLS
+
+#endif /* __EXCHANGE_FOLDER_SIZE_DISPLAY_H__ */
diff --git a/eplugin/exchange-folder-subscription.c b/eplugin/exchange-folder-subscription.c
new file mode 100644
index 0000000..63d2fb2
--- /dev/null
+++ b/eplugin/exchange-folder-subscription.c
@@ -0,0 +1,380 @@
+/*
+ *
+ * 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:
+ *		Shakti Sen <shprasad@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+#include <e-util/e-error.h>
+#include <e-folder.h>
+#include <exchange-account.h>
+#include <exchange-hierarchy.h>
+#include "exchange-hierarchy-foreign.h"
+#include <e2k-types.h>
+#include <exchange-types.h>
+#include <e2k-propnames.h>
+#include <libedataserverui/e-name-selector.h>
+#include "exchange-config-listener.h"
+#include "exchange-folder-subscription.h"
+#include "exchange-operations.h"
+
+static void
+user_response (ENameSelectorDialog *name_selector_dialog, gint response, gpointer data)
+{
+	gtk_widget_hide (GTK_WIDGET (name_selector_dialog));
+}
+
+static void
+user_clicked (GtkWidget *button, ENameSelector *name_selector)
+{
+	ENameSelectorDialog *name_selector_dialog;
+
+	name_selector_dialog = e_name_selector_peek_dialog (name_selector);
+	gtk_window_set_modal (GTK_WINDOW (name_selector_dialog), TRUE);
+	gtk_widget_show (GTK_WIDGET (name_selector_dialog));
+}
+
+static GtkWidget *
+setup_name_selector (GtkWidget *placeholder, GtkWidget *button_user, ENameSelector **name_selector_ret)
+{
+	ENameSelector *name_selector;
+	ENameSelectorModel *name_selector_model;
+	ENameSelectorDialog *name_selector_dialog;
+	GtkWidget *widget;
+
+	g_assert (GTK_IS_CONTAINER (placeholder));
+
+	name_selector = e_name_selector_new ();
+
+	name_selector_model = e_name_selector_peek_model (name_selector);
+	/* FIXME Limit to one user */
+	e_name_selector_model_add_section (name_selector_model, "User", _("User"), NULL);
+
+	/* Listen for responses whenever the dialog is shown */
+	name_selector_dialog = e_name_selector_peek_dialog (name_selector);
+	g_signal_connect (name_selector_dialog, "response",
+			  G_CALLBACK (user_response), name_selector);
+
+	widget = GTK_WIDGET (e_name_selector_peek_section_entry (name_selector, "User"));
+	gtk_widget_show (widget);
+
+	g_signal_connect (button_user, "clicked", G_CALLBACK (user_clicked), name_selector);
+	gtk_box_pack_start (GTK_BOX (placeholder), widget, TRUE, TRUE, 6);
+	*name_selector_ret = name_selector;
+
+	return widget;
+}
+
+static void
+setup_folder_name_combo (GtkWidget *widget, const gchar *fname)
+{
+	GtkComboBox *combo;
+	const gchar *strings[] = {
+		"Calendar",
+		"Inbox",
+		"Contacts",
+		"Tasks",
+		NULL
+		/* FIXME: Should these be translated?  */
+	};
+	gint i;
+
+	combo = GTK_COMBO_BOX (widget);
+	g_assert (GTK_IS_COMBO_BOX_ENTRY (combo));
+
+	gtk_list_store_clear (GTK_LIST_STORE (gtk_combo_box_get_model (combo)));
+
+	for (i = 0; strings[i] != NULL; i ++)
+		gtk_combo_box_append_text (combo, strings[i]);
+
+	gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo))), fname);
+}
+
+static void
+folder_name_entry_changed_callback (GtkEditable *editable,
+                                    gpointer data)
+{
+	GtkDialog *dialog = GTK_DIALOG (data);
+	const gchar *folder_name_text = gtk_entry_get_text (GTK_ENTRY (editable));
+
+	if (*folder_name_text == '\0')
+		gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, FALSE);
+	else
+		gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, TRUE);
+}
+
+static void
+user_name_entry_changed_callback (GtkEditable *editable, gpointer data)
+{
+	GtkDialog *dialog = GTK_DIALOG (data);
+	const gchar *user_name_text = gtk_entry_get_text (GTK_ENTRY (editable));
+
+	if (*user_name_text == '\0')
+		gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, FALSE);
+	else
+		gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, TRUE);
+}
+
+static void
+setup_server_combobox (GtkWidget *widget, gchar *mail_account)
+{
+	g_return_if_fail (GTK_IS_COMBO_BOX (widget));
+
+	gtk_list_store_clear (GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (widget))));
+
+	gtk_combo_box_append_text (GTK_COMBO_BOX (widget), mail_account);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+
+	/* FIXME: Default to the current storage in the shell view.  */
+}
+
+typedef struct {
+	ExchangeAccount *account;
+	ENameSelector *name_selector;
+	GtkWidget *name_selector_widget;
+	GtkWidget *folder_name_entry;
+}SubscriptionInfo;
+
+static void
+destroy_subscription_info (SubscriptionInfo *subscription_info)
+{
+	if (subscription_info->name_selector) {
+		g_object_unref (subscription_info->name_selector);
+		subscription_info->name_selector = NULL;
+	}
+	g_free (subscription_info);
+}
+
+static void
+subscribe_to_folder (GtkWidget *dialog, gint response, gpointer data)
+{
+	SubscriptionInfo *subscription_info = data;
+	gchar *user_email_address = NULL, *folder_name = NULL, *path = NULL;
+	gchar *subscriber_email;
+	EFolder *folder = NULL;
+	EDestinationStore *destination_store;
+	GList *destinations;
+	EDestination *destination;
+	ExchangeAccountFolderResult result;
+
+	if (response == GTK_RESPONSE_CANCEL) {
+		gtk_widget_destroy (dialog);
+		destroy_subscription_info (subscription_info);
+	}
+	else if (response == GTK_RESPONSE_OK) {
+		while (TRUE) {
+			destination_store = e_name_selector_entry_peek_destination_store (
+						E_NAME_SELECTOR_ENTRY (GTK_ENTRY (subscription_info->name_selector_widget)));
+			destinations = e_destination_store_list_destinations (destination_store);
+			if (!destinations)
+				break;
+			destination = destinations->data;
+			user_email_address = g_strdup (e_destination_get_email (destination));
+			g_list_free (destinations);
+
+			if (user_email_address != NULL && *user_email_address != '\0')
+				break;
+
+			/* check if user is trying to subscribe to his own folder */
+			subscriber_email = exchange_account_get_email_id (subscription_info->account);
+			if (subscriber_email != NULL && *subscriber_email != '\0') {
+				if (g_str_equal (subscriber_email, user_email_address)) {
+					e_error_run (NULL, ERROR_DOMAIN ":folder-exists-error", NULL);
+					g_free (user_email_address);
+					gtk_widget_destroy (dialog);
+					destroy_subscription_info (subscription_info);
+					return;
+				}
+			}
+
+			/* It would be nice to insensitivize the OK button appropriately
+			instead of doing this, but unfortunately we can't do this for the
+			Bonobo control.  */
+			e_error_run (GTK_WINDOW (dialog), ERROR_DOMAIN ":select-user", NULL);
+		}
+
+		folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (subscription_info->folder_name_entry)));
+		if (user_email_address && folder_name) {
+			result = exchange_account_discover_shared_folder (subscription_info->account,
+									  user_email_address,
+									  folder_name, &folder);
+			g_free (folder_name);
+			gtk_widget_hide (dialog);
+			switch (result) {
+				case EXCHANGE_ACCOUNT_FOLDER_OK:
+					exchange_account_rescan_tree (subscription_info->account);
+					if (!g_ascii_strcasecmp (e_folder_get_type_string (folder), "mail"))
+						e_error_run (NULL, ERROR_DOMAIN ":folder-restart-evo", NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS:
+					e_error_run (NULL, ERROR_DOMAIN ":folder-exists-error", NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
+					e_error_run (NULL, ERROR_DOMAIN ":folder-doesnt-exist-error", NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_UNKNOWN_TYPE:
+					e_error_run (NULL, ERROR_DOMAIN ":folder-unknown-type", NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
+					e_error_run (NULL, ERROR_DOMAIN ":folder-perm-error", NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_OFFLINE:
+					e_error_run (NULL, ERROR_DOMAIN ":folder-offline-error", NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_UNSUPPORTED_OPERATION:
+					e_error_run (NULL, ERROR_DOMAIN ":folder-unsupported-error", NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_GC_NOTREACHABLE:
+					e_error_run (NULL, ERROR_DOMAIN ":folder-no-gc-error", NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_NO_SUCH_USER:
+					e_error_run (NULL, ERROR_DOMAIN ":no-user-error", user_email_address, NULL);
+					break;
+				case EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR:
+					e_error_run (NULL, ERROR_DOMAIN ":folder-generic-error", NULL);
+					break;
+				default:
+					break;
+			}
+		}
+
+		if (!folder) {
+			g_free (user_email_address);
+			gtk_widget_destroy (dialog);
+			return;
+		}
+
+		g_object_unref (folder);
+		path = g_strdup_printf ("/%s", user_email_address);
+		exchange_account_open_folder (subscription_info->account, path);
+		g_free (path);
+		g_free (user_email_address);
+		gtk_widget_destroy (dialog);
+		destroy_subscription_info (subscription_info);
+	}
+}
+
+gboolean
+create_folder_subscription_dialog (ExchangeAccount *account, const gchar *fname)
+{
+	ENameSelector *name_selector;
+	GtkWidget *dialog;
+	GtkWidget *dialog_vbox1;
+	GtkWidget *table1;
+	GtkWidget *label1;
+	GtkWidget *label3;
+	GtkWidget *user_picker_placeholder;
+	GtkWidget *button_user;
+	GtkWidget *folder_name_combo;
+	GtkWidget *server_combobox;
+	SubscriptionInfo *subscription_info;
+	gint mode;
+
+	exchange_account_is_offline (account, &mode);
+	if (mode == OFFLINE_MODE)
+		return FALSE;
+
+	subscription_info = g_new0 (SubscriptionInfo, 1);
+	subscription_info->account = account;
+
+	dialog = gtk_dialog_new_with_buttons (
+		_("Subscribe to Other User's Folder"),
+		NULL,
+		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+
+	dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+	gtk_widget_show (dialog_vbox1);
+
+	table1 = gtk_table_new (3, 2, FALSE);
+	gtk_widget_show (table1);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), table1, TRUE, TRUE, 2);
+	gtk_table_set_row_spacings (GTK_TABLE (table1), 3);
+	gtk_table_set_col_spacings (GTK_TABLE (table1), 3);
+
+	label1 = gtk_label_new_with_mnemonic (_("_Account:"));
+	gtk_widget_show (label1);
+	gtk_table_attach (GTK_TABLE (table1), label1, 0, 1, 0, 1,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_CENTER);
+
+	label3 = gtk_label_new_with_mnemonic (_("_Folder Name:"));
+	gtk_widget_show (label3);
+	gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 2, 3,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_CENTER);
+
+	user_picker_placeholder = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (user_picker_placeholder);
+	gtk_table_attach (GTK_TABLE (table1), user_picker_placeholder, 1, 2, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+
+	button_user = gtk_button_new_with_mnemonic (_("_User:"));
+	gtk_widget_show (button_user);
+	gtk_table_attach (GTK_TABLE (table1), button_user, 0, 1, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+
+	folder_name_combo = gtk_combo_box_entry_new_text ();
+	gtk_widget_show (folder_name_combo);
+	gtk_table_attach (GTK_TABLE (table1), folder_name_combo, 1, 2, 2, 3,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+
+	server_combobox = gtk_combo_box_new_text ();
+	gtk_widget_show (server_combobox);
+	gtk_table_attach (GTK_TABLE (table1), server_combobox, 1, 2, 0, 1,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+
+	gtk_window_set_modal (GTK_WINDOW (dialog), FALSE);
+
+	subscription_info->name_selector_widget = setup_name_selector (user_picker_placeholder, button_user, &name_selector);
+	subscription_info->name_selector = name_selector;
+	gtk_widget_grab_focus (subscription_info->name_selector_widget);
+
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
+	g_signal_connect (subscription_info->name_selector_widget, "changed",
+			  G_CALLBACK (user_name_entry_changed_callback), dialog);
+
+	setup_server_combobox (server_combobox, account->account_name);
+	setup_folder_name_combo (folder_name_combo, fname);
+	subscription_info->folder_name_entry = gtk_bin_get_child (GTK_BIN (folder_name_combo));
+	g_signal_connect (dialog, "response", G_CALLBACK (subscribe_to_folder), subscription_info);
+	gtk_widget_show (dialog);
+
+	/* Connect the callback to set the OK button insensitive when there is
+	   no text in the folder_name_entry.  Notice that we put a value there
+	   by default so the OK button is sensitive by default.  */
+	g_signal_connect (subscription_info->folder_name_entry, "changed",
+			  G_CALLBACK (folder_name_entry_changed_callback), dialog);
+
+	return TRUE;
+}
+
diff --git a/eplugin/exchange-folder-subscription.h b/eplugin/exchange-folder-subscription.h
new file mode 100644
index 0000000..15323ca
--- /dev/null
+++ b/eplugin/exchange-folder-subscription.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_FOLDER_SUBSCRIPTION_H__
+#define __EXCHANGE_FOLDER_SUBSCRIPTION_H__
+
+gboolean
+create_folder_subscription_dialog (ExchangeAccount *account, const gchar *fname);
+
+#endif
diff --git a/eplugin/exchange-folder.c b/eplugin/exchange-folder.c
new file mode 100644
index 0000000..7c9f1bf
--- /dev/null
+++ b/eplugin/exchange-folder.c
@@ -0,0 +1,595 @@
+/*
+ * 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:
+ *		Shakti Sen <shprasad@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <e-folder-exchange.h>
+#include <exchange-hierarchy.h>
+#include <calendar/gui/e-cal-popup.h>
+#include <mail/em-popup.h>
+#include <mail/em-menu.h>
+#include <libedataserverui/e-source-selector.h>
+#include <e-util/e-error.h>
+#include <camel/camel-store.h>
+#include <camel/camel-folder.h>
+#include <mail/mail-mt.h>
+#include <mail/mail-ops.h>
+
+#include "exchange-operations.h"
+#include "addressbook/gui/widgets/eab-popup.h"
+#include "exchange-folder-subscription.h"
+
+void org_gnome_exchange_folder_subscription (EPlugin *ep, EMMenuTargetSelect *target, const gchar *fname);
+void org_gnome_exchange_inbox_subscription (EPlugin *ep, EMMenuTargetSelect *target);
+void org_gnome_exchange_addressbook_subscription (EPlugin *ep, EMMenuTargetSelect *target);
+void org_gnome_exchange_calendar_subscription (EPlugin *ep, EMMenuTargetSelect *target);
+void org_gnome_exchange_tasks_subscription (EPlugin *ep, EMMenuTargetSelect *target);
+void org_gnome_exchange_check_subscribed (EPlugin *ep, ECalPopupTargetSource *target);
+void org_gnome_exchange_folder_unsubscribe (EPopup *ep, EPopupItem *p, gpointer data);
+void org_gnome_exchange_check_address_book_subscribed (EPlugin *ep, EABPopupTargetSource *target);
+void org_gnome_exchange_folder_ab_unsubscribe (EPopup *ep, EPopupItem *p, gpointer data);
+void org_gnome_exchange_check_inbox_subscribed (EPlugin *ep, EMPopupTargetFolder *target);
+void org_gnome_exchange_folder_inbox_unsubscribe (EPopup *ep, EPopupItem *p, gpointer data);
+void popup_free (EPopup *ep, GSList *items, gpointer data);
+void popup_inbox_free (EPopup *ep, GSList *items, gpointer data);
+void popup_ab_free (EPopup *ep, GSList *items, gpointer data);
+static void exchange_get_folder (gchar *uri, CamelFolder *folder, gpointer data);
+
+#define CONF_KEY_SELECTED_CAL_SOURCES "/apps/evolution/calendar/display/selected_calendars"
+
+static EPopupItem popup_inbox_items[] = {
+	{ E_POPUP_ITEM, (gchar *) "29.inbox_unsubscribe", (gchar *) N_("Unsubscribe Folder..."), org_gnome_exchange_folder_inbox_unsubscribe, NULL, (gchar *) "folder-new", 0, EM_POPUP_FOLDER_INFERIORS }
+};
+
+void
+popup_inbox_free (EPopup *ep, GSList *items, gpointer data)
+{
+	g_slist_free (items);
+}
+
+void
+org_gnome_exchange_folder_inbox_unsubscribe (EPopup *ep, EPopupItem *p, gpointer data)
+{
+	ExchangeAccount *account = NULL;
+	EMPopupTargetFolder *target = data;
+	gchar *path = NULL;
+	gchar *stored_path = NULL;
+	const gchar *inbox_uri = NULL;
+	const gchar *inbox_physical_uri = NULL;
+	gchar *target_uri = NULL;
+	EFolder *inbox;
+	ExchangeAccountFolderResult result;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (!account)
+		return;
+
+	target_uri = g_strdup (target->uri);
+	path = target->uri + strlen ("exchange://") + strlen (account->account_filename);
+	/* User will be able to unsubscribe by doing a right click on
+	   any one of this two-<other user's>Inbox or the
+	   <other user's folder> tree.
+	  */
+	stored_path = strrchr (path + 1, '/');
+
+	if (stored_path)
+		path[stored_path - path] = '\0';
+
+	result = exchange_account_remove_shared_folder (account, path);
+	switch (result) {
+		case EXCHANGE_ACCOUNT_FOLDER_OK:
+			break;
+		case EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS:
+			e_error_run (NULL, ERROR_DOMAIN ":folder-exists-error", NULL);
+			return;
+		case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
+			e_error_run (NULL, ERROR_DOMAIN ":folder-doesnt-exist-error", NULL);
+			return;
+		case EXCHANGE_ACCOUNT_FOLDER_UNKNOWN_TYPE:
+			e_error_run (NULL, ERROR_DOMAIN ":folder-unknown-type", NULL);
+			return;
+		case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
+			e_error_run (NULL, ERROR_DOMAIN ":folder-perm-error", NULL);
+			return;
+		case EXCHANGE_ACCOUNT_FOLDER_OFFLINE:
+			e_error_run (NULL, ERROR_DOMAIN ":folder-offline-error", NULL);
+			return;
+		case EXCHANGE_ACCOUNT_FOLDER_UNSUPPORTED_OPERATION:
+			e_error_run (NULL, ERROR_DOMAIN ":folder-unsupported-error", NULL);
+			return;
+		case EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR:
+			e_error_run (NULL, ERROR_DOMAIN ":folder-generic-error", NULL);
+			return;
+		case EXCHANGE_ACCOUNT_FOLDER_GC_NOTREACHABLE:
+			e_error_run (NULL, ERROR_DOMAIN ":folder-no-gc-error", NULL);
+			return;
+		case EXCHANGE_ACCOUNT_FOLDER_NO_SUCH_USER:
+			e_error_run (NULL, ERROR_DOMAIN ":no-user-error", NULL);
+			return;
+	}
+
+	/* We need to get the physical uri for the Inbox */
+	inbox_uri = exchange_account_get_standard_uri (account, "inbox");
+	inbox = exchange_account_get_folder (account, inbox_uri);
+	inbox_physical_uri = e_folder_get_physical_uri (inbox);
+
+	/* To get the CamelStore/Folder */
+	mail_get_folder (inbox_physical_uri, 0, exchange_get_folder, target_uri, mail_msg_unordered_push);
+
+}
+
+static CamelFolderInfo *
+ex_create_folder_info (CamelStore *store, gchar *name, gchar *uri,
+                  gint unread_count, gint flags)
+{
+        CamelFolderInfo *info;
+        const gchar *path;
+
+        path = strstr (uri, "://");
+        if (!path)
+                return NULL;
+        path = strchr (path + 3, '/');
+        if (!path)
+                return NULL;
+
+        info = camel_folder_info_new ();
+        info->name = name;
+        info->uri = uri;
+        info->full_name = g_strdup (path + 1);
+        info->unread = unread_count;
+
+        return info;
+}
+
+static void
+exchange_get_folder (gchar *uri, CamelFolder *folder, gpointer data)
+{
+	CamelStore *store;
+	CamelException ex;
+	CamelFolderInfo *info;
+	gchar *name = NULL;
+	gchar *stored_name = NULL;
+	gchar *target_uri = (gchar *)data;
+	ExchangeAccount *account = NULL;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (!account)
+		return;
+
+	/* Get the subscribed folder name. */
+	name = target_uri + strlen ("exchange://") + strlen (account->account_filename);
+	stored_name = strrchr (name + 1, '/');
+
+	if (stored_name)
+		name[stored_name - name] = '\0';
+
+	camel_exception_init (&ex);
+	store = camel_folder_get_parent_store (folder);
+
+	/* Construct the CamelFolderInfo */
+	info = ex_create_folder_info (store, name, target_uri, -1, 0);
+	camel_object_trigger_event (CAMEL_OBJECT (store),
+				    "folder_unsubscribed", info);
+	g_free (target_uri);
+}
+
+void
+org_gnome_exchange_check_inbox_subscribed (EPlugin *ep, EMPopupTargetFolder *target)
+{
+	GSList *menus = NULL;
+	gint i = 0;
+	ExchangeAccount *account = NULL;
+	gchar *path = NULL;
+	gchar *sub_folder = NULL;
+
+	if (!g_strrstr (target->uri, "exchange://"))
+		return;
+
+	account = exchange_operations_get_exchange_account ();
+	if (!account)
+		return;
+
+	path = g_strdup (target->uri + strlen ("exchange://") + strlen (account->account_filename));
+	sub_folder = strchr (path, '@');
+
+	g_free (path);
+
+	if (!sub_folder || !g_strrstr(sub_folder, "/"))
+		return;
+
+        for (i = 0; i < sizeof (popup_inbox_items) / sizeof (popup_inbox_items[0]); i++)
+                menus = g_slist_prepend (menus, &popup_inbox_items[i]);
+
+        e_popup_add_items (target->target.popup, menus, NULL, popup_inbox_free, target);
+}
+
+static EPopupItem popup_items[] = {
+	{ E_POPUP_ITEM, (gchar *) "29.calendar_unsubscribe", (gchar *) N_("Unsubscribe Folder..."), org_gnome_exchange_folder_unsubscribe, NULL, (gchar *) "folder-new", 0, EM_POPUP_FOLDER_INFERIORS }
+};
+
+void
+popup_free (EPopup *ep, GSList *items, gpointer data)
+{
+	g_slist_free (items);
+}
+
+static EPopupItem popup_ab_items[] = {
+	{ E_POPUP_ITEM, (gchar *) "29.address_book_unsubscribe", (gchar *) N_("Unsubscribe Folder..."), org_gnome_exchange_folder_ab_unsubscribe, NULL, (gchar *) "folder-new", 0, EM_POPUP_FOLDER_INFERIORS }
+};
+
+void
+popup_ab_free (EPopup *ep, GSList *items, gpointer data)
+{
+	g_slist_free (items);
+}
+
+void
+org_gnome_exchange_check_address_book_subscribed (EPlugin *ep, EABPopupTargetSource *target)
+{
+	GSList *menus = NULL;
+	gint i = 0;
+	ESource *source = NULL;
+	gchar *uri = NULL;
+	gchar *path = NULL;
+	gchar *sub_folder = NULL;
+	const gchar *base_uri;
+	ExchangeAccount *account = NULL;
+	ESourceGroup *group;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (!account)
+		return;
+
+	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (target->selector));
+	group = e_source_peek_group (source);
+	base_uri = e_source_group_peek_base_uri (group);
+	if (!base_uri || strcmp (base_uri, "exchange://"))
+		return;
+
+	uri = e_source_get_uri (source);
+	path = g_strdup (uri + strlen ("exchange://") + strlen (account->account_filename) + strlen ("/;"));
+	g_free (uri);
+	sub_folder = strchr (path, '@');
+
+	if (!sub_folder) {
+		g_free (path);
+		return;
+	}
+
+	for (i = 0; i < sizeof (popup_ab_items) / sizeof (popup_ab_items[0]); i++)
+		menus = g_slist_prepend (menus, &popup_ab_items[i]);
+
+	e_popup_add_items (target->target.popup, menus, NULL, popup_ab_free, target);
+	g_free (path);
+
+}
+
+void
+org_gnome_exchange_check_subscribed (EPlugin *ep, ECalPopupTargetSource *target)
+{
+	GSList *menus = NULL;
+	gint i = 0;
+	ESource *source = NULL;
+	gchar *ruri = NULL;
+	gchar *path = NULL;
+	gchar *sub_folder = NULL;
+	const gchar *base_uri;
+	ExchangeAccount *account = NULL;
+	ESourceGroup *group;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (!account)
+		return;
+
+	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (target->selector));
+	group = e_source_peek_group (source);
+	base_uri = e_source_group_peek_base_uri (group);
+	if (!base_uri || strcmp (base_uri, "exchange://"))
+		return;
+
+	ruri = (gchar *) e_source_peek_relative_uri (source);
+	path = g_strdup (ruri + strlen (account->account_filename) + strlen ("/;"));
+	sub_folder = strchr (path, '@');
+
+	if (!sub_folder) {
+		g_free (path);
+		return;
+	}
+
+	for (i = 0; i < sizeof (popup_items) / sizeof (popup_items[0]); i++)
+		menus = g_slist_prepend (menus, &popup_items[i]);
+
+	e_popup_add_items (target->target.popup, menus, NULL, popup_free, target);
+	g_free (path);
+}
+
+static void
+unsubscribe_dialog_ab_response (GtkDialog *dialog, gint response, gpointer data)
+{
+
+	if (response == GTK_RESPONSE_OK) {
+		ExchangeAccount *account = NULL;
+		gchar *path = NULL;
+		gchar *uri = NULL;
+		const gchar *source_uid = NULL;
+		ESourceGroup *source_group = NULL;
+		ESource *source = NULL;
+		EABPopupTargetSource *target = data;
+
+		account = exchange_operations_get_exchange_account ();
+
+		if (!account)
+			return;
+
+		source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (target->selector));
+		uri = e_source_get_uri (source);
+		path = g_strdup (uri + strlen ("exchange://") + strlen (account->account_filename));
+		source_uid = e_source_peek_uid (source);
+
+		exchange_account_remove_shared_folder (account, path);
+
+		source_group = e_source_peek_group (source);
+		e_source_group_remove_source_by_uid (source_group, source_uid);
+		g_free (path);
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+	}
+	if (response == GTK_RESPONSE_CANCEL)
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+	if (response == GTK_RESPONSE_DELETE_EVENT)
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+unsubscribe_dialog_response (GtkDialog *dialog, gint response, gpointer data)
+{
+
+	if (response == GTK_RESPONSE_OK) {
+		GSList *ids, *node_to_be_deleted;
+		ExchangeAccount *account = NULL;
+		gchar *path = NULL;
+		gchar *ruri = NULL;
+		const gchar *source_uid = NULL;
+		GConfClient *client;
+		ESourceGroup *source_group = NULL;
+		ESource *source = NULL;
+		ECalPopupTargetSource *target = data;
+
+		client = gconf_client_get_default ();
+
+		account = exchange_operations_get_exchange_account ();
+
+		if (!account)
+			return;
+
+		source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (target->selector));
+		ruri = (gchar *) e_source_peek_relative_uri (source);
+		source_uid = e_source_peek_uid (source);
+
+		path = g_strdup (ruri + strlen (account->account_filename));
+		exchange_account_remove_shared_folder (account, path);
+		ids = gconf_client_get_list (client,
+					     CONF_KEY_SELECTED_CAL_SOURCES,
+					     GCONF_VALUE_STRING, NULL);
+		if (ids) {
+			node_to_be_deleted = g_slist_find_custom (
+						ids,
+						source_uid,
+						(GCompareFunc) strcmp);
+			if (node_to_be_deleted) {
+				g_free (node_to_be_deleted->data);
+				ids = g_slist_delete_link (ids,
+						node_to_be_deleted);
+				gconf_client_set_list (client,
+					CONF_KEY_SELECTED_CAL_SOURCES,
+					GCONF_VALUE_STRING, ids, NULL);
+			}
+			g_slist_foreach (ids, (GFunc) g_free, NULL);
+			g_slist_free (ids);
+		}
+
+		source_group = e_source_peek_group (source);
+		e_source_group_remove_source_by_uid (source_group, source_uid);
+		g_free (path);
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+	}
+	if (response == GTK_RESPONSE_CANCEL)
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+	if (response == GTK_RESPONSE_DELETE_EVENT)
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+void
+org_gnome_exchange_folder_ab_unsubscribe (EPopup *ep, EPopupItem *p, gpointer data)
+{
+	GtkWidget *dialog = NULL;
+	EABPopupTargetSource *target = data;
+	ESource *source = NULL;
+	ExchangeAccount *account = NULL;
+	gchar *title = NULL;
+	gchar *displayed_folder_name = NULL;
+	gint response;
+	gint mode;
+	ExchangeConfigListenerStatus status;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (!account)
+		return;
+
+	status = exchange_is_offline (&mode);
+
+	if (status != CONFIG_LISTENER_STATUS_OK) {
+		g_warning ("Config listener not found");
+		return;
+	} else if (mode == OFFLINE_MODE) {
+		e_error_run (NULL, ERROR_DOMAIN ":account-offline-generic", NULL);
+		return;
+	}
+
+	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (target->selector));
+	displayed_folder_name = (gchar *) e_source_peek_name (source);
+	dialog = gtk_message_dialog_new (NULL,
+					 GTK_DIALOG_MODAL,
+					 GTK_MESSAGE_QUESTION,
+					 GTK_BUTTONS_NONE,
+					 _("Really unsubscribe from folder \"%s\"?"),
+					 displayed_folder_name);
+
+	gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+	gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_REMOVE, GTK_RESPONSE_OK);
+
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
+
+	title = g_strdup_printf (_("Unsubscribe from \"%s\""), displayed_folder_name);
+	gtk_window_set_title (GTK_WINDOW (dialog), title);
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	g_free (title);
+	g_free (displayed_folder_name);
+
+	gtk_widget_show (dialog);
+	unsubscribe_dialog_ab_response (GTK_DIALOG (dialog), response, data);
+}
+void
+org_gnome_exchange_folder_unsubscribe (EPopup *ep, EPopupItem *p, gpointer data)
+{
+	GtkWidget *dialog = NULL;
+	ECalPopupTargetSource *target = data;
+	ESource *source = NULL;
+	ExchangeAccount *account = NULL;
+	gchar *title = NULL;
+	const gchar *displayed_folder_name;
+	gint response;
+	gint mode;
+	ExchangeConfigListenerStatus status;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (!account)
+		return;
+
+	status = exchange_is_offline (&mode);
+
+	if (status != CONFIG_LISTENER_STATUS_OK) {
+		g_warning ("Config listener not found");
+		return;
+	} else if (mode == OFFLINE_MODE) {
+		e_error_run (NULL, ERROR_DOMAIN ":account-offline-generic", NULL);
+		return;
+	}
+
+	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (target->selector));
+	displayed_folder_name =  e_source_peek_name (source);
+	dialog = gtk_message_dialog_new (NULL,
+					 GTK_DIALOG_MODAL,
+					 GTK_MESSAGE_QUESTION,
+					 GTK_BUTTONS_NONE,
+					 _("Really unsubscribe from folder \"%s\"?"),
+					 displayed_folder_name);
+
+	gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+	gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_REMOVE, GTK_RESPONSE_OK);
+
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
+
+	title = g_strdup_printf (_("Unsubscribe from \"%s\""), displayed_folder_name);
+	gtk_window_set_title (GTK_WINDOW (dialog), title);
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	g_free (title);
+
+	gtk_widget_show (dialog);
+	unsubscribe_dialog_response (GTK_DIALOG (dialog), response, data);
+}
+
+void
+org_gnome_exchange_folder_subscription (EPlugin *ep, EMMenuTargetSelect *target, const gchar *fname)
+{
+	ExchangeAccount *account = NULL;
+	gint mode;
+	ExchangeConfigListenerStatus status;
+
+	account = exchange_operations_get_exchange_account ();
+
+	if (!account)
+		return;
+
+	status = exchange_is_offline (&mode);
+
+	if (status != CONFIG_LISTENER_STATUS_OK) {
+		g_warning ("Config listener not found");
+		return;
+	}
+	else if (mode == OFFLINE_MODE) {
+		/* Translators: this error code can be used for any operation
+		 * (like subscribing to other user's folders, unsubscribing
+		 * etc,) which can not be performed in offline mode
+		 */
+		e_error_run (NULL, ERROR_DOMAIN ":account-offline-generic", NULL);
+		return;
+	}
+
+	create_folder_subscription_dialog (account, fname);
+}
+
+void
+org_gnome_exchange_calendar_subscription (EPlugin *ep, EMMenuTargetSelect *target)
+{
+	const gchar *folder_name = N_("Calendar");
+	org_gnome_exchange_folder_subscription (ep, target, folder_name);
+}
+
+void
+org_gnome_exchange_addressbook_subscription (EPlugin *ep, EMMenuTargetSelect *target)
+{
+	const gchar *folder_name = N_("Contacts");
+	org_gnome_exchange_folder_subscription (ep, target, folder_name);
+}
+
+void
+org_gnome_exchange_tasks_subscription (EPlugin *ep, EMMenuTargetSelect *target)
+{
+	const gchar *folder_name = N_("Tasks");
+	org_gnome_exchange_folder_subscription (ep, target, folder_name);
+}
+
+void
+org_gnome_exchange_inbox_subscription (EPlugin *ep, EMMenuTargetSelect *target)
+{
+	const gchar *folder_name = N_("Inbox");
+	org_gnome_exchange_folder_subscription (ep, target, folder_name);
+}
diff --git a/eplugin/exchange-mail-send-options.c b/eplugin/exchange-mail-send-options.c
new file mode 100644
index 0000000..04065e4
--- /dev/null
+++ b/eplugin/exchange-mail-send-options.c
@@ -0,0 +1,196 @@
+/*
+ * 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:
+ *		R.Raghavendran <raghavguru7@gmail.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <camel/camel-mime-message.h>
+#include <camel/camel-address.h>
+#include "mail/em-event.h"
+
+#include "composer/e-msg-composer.h"
+#include "libedataserver/e-account.h"
+
+#include "exchange-send-options.h"
+
+void org_gnome_exchange_send_options (EPlugin *ep, EMEventTargetComposer *t);
+
+static ExchangeSendOptionsDialog *dialog=NULL;
+
+static void
+append_to_header (ExchangeSendOptionsDialog *dialog, gint state, gpointer data)
+{
+	EMsgComposer *composer;
+	CamelAddress *sender_address;
+	const gchar *sender_id, *recipient_id;
+	struct _camel_header_address *addr;
+	struct _camel_header_address *sender_addr;
+
+	composer = (EMsgComposer *)data;
+	if (state == GTK_RESPONSE_OK) {
+		if (dialog->options->importance) {
+			switch (dialog->options->importance) {
+				case E_IMP_HIGH :
+					e_msg_composer_modify_header (composer, "Importance", "high");
+					break;
+				case E_IMP_LOW :
+					e_msg_composer_modify_header (composer, "Importance", "low");
+					break;
+				default :
+					g_print ("\nNo importance set");
+					break;
+			}
+		}
+		else
+			e_msg_composer_remove_header (composer, "Importance");
+
+		if (dialog->options->sensitivity) {
+			switch (dialog->options->sensitivity) {
+				case E_SENSITIVITY_CONFIDENTIAL :
+					e_msg_composer_modify_header (composer, "Sensitivity", "Company-Confidential");
+					break;
+				case E_SENSITIVITY_PERSONAL :
+					e_msg_composer_modify_header (composer, "Sensitivity", "Personal");
+					break;
+				case E_SENSITIVITY_PRIVATE :
+					e_msg_composer_modify_header (composer, "Sensitivity", "Private");
+					break;
+				default :
+					g_print ("\nNo importance set");
+					break;
+			}
+		}
+		else
+			e_msg_composer_remove_header (composer, "Sensitivity");
+
+		sender_address = (CamelAddress *) e_msg_composer_get_from (composer);
+		sender_id = (const gchar *) camel_address_encode (sender_address);
+
+		addr = camel_header_address_decode (dialog->options->delegate_address, NULL);
+		sender_addr = camel_header_address_decode (sender_id, NULL);
+
+		if (dialog->options->send_as_del_enabled &&
+			dialog->options->delegate_address &&
+				g_ascii_strcasecmp(addr->v.addr, sender_addr->v.addr)) {
+
+			e_msg_composer_modify_header (composer, "Sender" , sender_id);
+
+			/* This block handles the case wherein the address to be added
+			 * in the "From" field has no name associated with it.
+			 * So for cases where there is no name we append the address
+			 * (only email) within angular braces.
+			 */
+			if (!g_ascii_strcasecmp (addr->name, "")) {
+				recipient_id = g_strdup_printf ("<%s>",
+						dialog->options->delegate_address);
+				e_msg_composer_add_header (composer, "From", recipient_id);
+			}
+
+			else
+				e_msg_composer_add_header (composer, "From",
+							dialog->options->delegate_address);
+		}
+
+		else {
+			e_msg_composer_remove_header (composer, "Sender");
+			e_msg_composer_add_header (composer, "From", sender_id);
+		}
+
+		if (dialog->options->delivery_enabled) {
+			EComposerHeaderTable *table;
+			EAccount *account;
+			gchar *mdn_address;
+
+			table = e_msg_composer_get_header_table (composer);
+			account = e_composer_header_table_get_account (table);
+			mdn_address = account->id->reply_to;
+			if (!mdn_address || !*mdn_address)
+				mdn_address = account->id->address;
+			e_msg_composer_modify_header (composer, "Return-Receipt-To", mdn_address);
+		}
+		else
+			e_msg_composer_remove_header (composer, "Return-Receipt-To");
+
+		if (dialog->options->read_enabled) {
+			EComposerHeaderTable *table;
+			EAccount *account;
+			gchar *mdn_address;
+
+			table = e_msg_composer_get_header_table (composer);
+			account = e_composer_header_table_get_account (table);
+			mdn_address = account->id->reply_to;
+			if (!mdn_address || !*mdn_address)
+				mdn_address = account->id->address;
+
+			e_msg_composer_modify_header (composer, "Disposition-Notification-To", mdn_address);
+		}
+		else
+			e_msg_composer_remove_header (composer, "Disposition-Notification-To");
+	}
+}
+
+static void
+send_options_commit (EMsgComposer *comp, gpointer user_data)
+{
+	if (!user_data && !EXCHANGE_IS_SENDOPTIONS_DIALOG (user_data))
+		return;
+
+	if (dialog) {
+		g_print ("\nDialog getting unreferenced ");
+		g_object_unref (dialog);
+		dialog = NULL;
+	}
+}
+
+void
+org_gnome_exchange_send_options (EPlugin *ep, EMEventTargetComposer *target)
+{
+	EMsgComposer *composer = target->composer;
+	EComposerHeaderTable *table;
+	EAccount *account = NULL;
+	gchar *temp = NULL;
+
+	table = e_msg_composer_get_header_table (composer);
+	account = e_composer_header_table_get_account (table);
+	if (!account)
+		return;
+
+	temp = strstr (account->transport->url, "exchange");
+	if (!temp) {
+		return;
+	}
+	e_msg_composer_set_send_options (composer, TRUE);
+	/*disply the send options dialog*/
+	if (!dialog) {
+		g_print ("New dialog\n\n");
+		dialog = exchange_sendoptions_dialog_new ();
+	}
+	exchange_sendoptions_dialog_run (dialog, GTK_WIDGET (composer));
+	g_signal_connect (dialog, "sod_response", G_CALLBACK (append_to_header), GTK_WIDGET (composer));
+
+	g_signal_connect (GTK_WIDGET (composer), "destroy",
+				  G_CALLBACK (send_options_commit), dialog);
+
+}
diff --git a/eplugin/exchange-operations.c b/eplugin/exchange-operations.c
new file mode 100644
index 0000000..7d53ee1
--- /dev/null
+++ b/eplugin/exchange-operations.c
@@ -0,0 +1,306 @@
+/*
+ * 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:
+ *		Praveen Kumar <kpraveen@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "exchange-operations.h"
+#include <e-folder-exchange.h>
+#include <exchange-hierarchy.h>
+#include <e-util/e-error.h>
+
+ExchangeConfigListener *exchange_global_config_listener=NULL;
+
+static const gchar *error_ids[] = {
+	"config-error",
+	"password-weak-error",
+	"password-change-error",
+	"password-change-success",
+	"account-offline",
+	"password-incorrect",
+	"account-domain-error",
+	"account-mailbox-na",
+	"account-version-error",
+	"account-wss-error",
+	"account-no-mailbox",
+	"account-resolve-error",
+	"account-connect-error",
+	"password-expired",
+	"account-unknown-error",
+	"account-quota-error",
+	"account-quota-send-error",
+	"account-quota-warn"
+};
+
+static void
+free_exchange_listener (void)
+{
+	g_object_unref (exchange_global_config_listener);
+}
+
+gint
+e_plugin_lib_enable (EPluginLib *eplib, gint enable)
+{
+	if (!exchange_global_config_listener) {
+		exchange_global_config_listener = exchange_config_listener_new ();
+		g_atexit (free_exchange_listener);
+	}
+
+	return 0;
+}
+
+ExchangeConfigListenerStatus
+exchange_is_offline (gint *mode)
+{
+	return exchange_config_listener_get_offline_status (exchange_global_config_listener, mode);
+}
+
+/* FIXME: See if a GLib variant of this function available */
+gboolean
+exchange_operations_tokenize_string (gchar **string, gchar *token, gchar delimit, guint maxsize)
+{
+	guint i=0;
+	gchar *str=*string;
+	while (*str!=delimit && *str!='\0' && i<maxsize-1) {
+		token[i++]=*str++;
+	}
+	while (*str==delimit)
+		str++;
+	token[i]='\0';
+	*string = str;
+	if (i==0)
+		return FALSE;
+	return TRUE;
+}
+
+gboolean
+exchange_operations_cta_add_node_to_tree (GtkTreeStore *store, GtkTreeIter *parent, const gchar *ruri)
+{
+	GtkTreeIter iter;
+	gchar *luri=(gchar *)ruri;
+	gchar nodename[80];
+	gchar *uri;
+	gboolean status, found;
+
+	exchange_operations_tokenize_string (&luri, nodename, '/', sizeof(nodename));
+
+	if (!nodename[0]) {
+		return TRUE;
+	}
+
+	if (!parent) {
+	  uri = g_strdup (nodename);
+	}
+	else {
+	  gchar *tmpuri;
+	  gtk_tree_model_get (GTK_TREE_MODEL (store), parent, 1, &tmpuri, -1);
+	  uri = g_strconcat (tmpuri, "/", nodename, NULL);
+	  g_free (tmpuri);
+	}
+
+	if (!strcmp (nodename, "personal") && !parent) {
+		/* FIXME: Don't hardcode this */
+		strcpy (nodename, _("Personal Folders"));
+	}
+
+	found = FALSE;
+	status = gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &iter, parent);
+	while (status) {
+	  gchar *readname;
+	  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &readname, -1);
+	  if (!strcmp (nodename, readname)) {
+	    found = TRUE;
+	    exchange_operations_cta_add_node_to_tree (store, &iter, luri);
+	    g_free (readname);
+	    break;
+	  }
+	  status = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+	}
+
+	if (!found) {
+	  gtk_tree_store_append (store, &iter, parent);
+	  gtk_tree_store_set (store, &iter, 0, nodename, 1, uri, -1);
+	  exchange_operations_cta_add_node_to_tree (store, &iter, luri);
+	}
+
+	g_free (uri);
+	return TRUE;
+}
+
+void
+exchange_operations_cta_select_node_from_tree (GtkTreeStore *store, GtkTreeIter *parent, const gchar *nuri, const gchar *ruri, GtkTreeSelection *selection)
+{
+	gchar *luri=(gchar *)nuri;
+	gchar nodename[80];
+	GtkTreeIter iter;
+	gboolean status;
+
+	if (!luri)
+		return;
+
+	exchange_operations_tokenize_string (&luri, nodename, '/', sizeof(nodename));
+	if (!nodename[0]) {
+		return;
+	}
+
+	if (!strcmp (nodename, "personal") && !parent) {
+		/* FIXME: Don't hardcode this */
+		strcpy (nodename, _("Personal Folders"));
+	}
+
+	status = gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &iter, parent);
+	while (status) {
+		gchar *readname;
+		gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &readname, -1);
+		if (!strcmp (nodename, readname)) {
+			gchar *readruri;
+			gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 1, &readruri, -1);
+			if (!strcmp (ruri, readruri)) {
+				gtk_tree_selection_select_iter (selection, &iter);
+				return;
+			}
+			g_free (readname);
+			g_free (readruri);
+			exchange_operations_cta_select_node_from_tree (store, &iter, luri, ruri, selection);
+			break;
+		}
+		status = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+	}
+	return;
+}
+
+ExchangeAccount *
+exchange_operations_get_exchange_account (void)
+{
+	ExchangeAccount *account = NULL;
+	ExchangeAccountResult result;
+	GSList *acclist;
+	gint mode;
+
+	acclist = exchange_config_listener_get_accounts (exchange_global_config_listener);
+	/* FIXME: Need to be changed for handling multiple accounts */
+	if (acclist) {
+		account = acclist->data;
+
+		exchange_config_listener_get_offline_status (exchange_global_config_listener,
+							     &mode);
+
+		if (mode == OFFLINE_MODE) {
+			return account;
+		}
+		else if (exchange_account_get_context (account)) {
+			return account;
+		} else {
+			/* Try authenticating */
+			result = exchange_config_listener_authenticate(exchange_global_config_listener, account);
+			if (result != EXCHANGE_ACCOUNT_CONNECT_SUCCESS) {
+				exchange_operations_report_error (account, result);
+				return NULL;
+			}
+			if (exchange_account_get_context (account))
+				return account;
+		}
+	}
+
+	return NULL;
+}
+
+void
+exchange_operations_report_error (ExchangeAccount *account, ExchangeAccountResult result)
+{
+	gchar *error_string;
+	gchar *quota_value;
+	GtkWidget *widget;
+
+	g_return_if_fail (account != NULL);
+
+	if (result == EXCHANGE_ACCOUNT_CONNECT_SUCCESS)
+		return;
+
+	error_string = g_strconcat ("org-gnome-exchange-operations:", error_ids[result], NULL);
+
+	switch (result) {
+		case EXCHANGE_ACCOUNT_MAILBOX_NA:
+			widget = e_error_new (NULL, error_string, exchange_account_get_username (account), NULL);
+			break;
+		case EXCHANGE_ACCOUNT_NO_MAILBOX:
+			widget = e_error_new (NULL, error_string, exchange_account_get_username (account),
+					      account->exchange_server, NULL);
+			break;
+		case EXCHANGE_ACCOUNT_RESOLVE_ERROR:
+		case EXCHANGE_ACCOUNT_CONNECT_ERROR:
+		case EXCHANGE_ACCOUNT_UNKNOWN_ERROR:
+			widget = e_error_new (NULL, error_string, account->exchange_server, NULL);
+			break;
+		case EXCHANGE_ACCOUNT_QUOTA_RECIEVE_ERROR:
+		case EXCHANGE_ACCOUNT_QUOTA_SEND_ERROR:
+		case EXCHANGE_ACCOUNT_QUOTA_WARN:
+			quota_value = g_strdup_printf ("%.2f", account->mbox_size);
+			widget = e_error_new (NULL, error_string, quota_value, NULL);
+			g_free (quota_value);
+			break;
+		default:
+			widget = e_error_new (NULL, error_string, NULL);
+	}
+	g_signal_connect ((GtkDialog *)widget, "response", G_CALLBACK (gtk_widget_destroy), widget);
+	gtk_widget_show (widget);
+	g_free (error_string);
+}
+
+void exchange_operations_update_child_esources (ESource *source, const gchar *old_path, const gchar *new_path)
+{
+	ESourceGroup *group;
+	GSList *sources, *tsource;
+	group = e_source_peek_group (source);
+	sources = e_source_group_peek_sources (group);
+	for (tsource = sources; tsource != NULL; tsource = tsource->next) {
+		gchar *ruri;
+		ruri = (gchar *) e_source_peek_relative_uri (tsource->data);
+		if (ruri && g_strrstr (ruri, old_path)) {
+			/* This ESource points to one of the child folders */
+			gchar **tmpv, *truri;
+			/* A nasty search and replace */
+			tmpv = g_strsplit (ruri, old_path, -1);
+			truri = g_strjoinv (new_path, tmpv);
+			e_source_set_relative_uri (tsource->data, truri);
+			g_strfreev (tmpv);
+			g_free (truri);
+		}
+	}
+}
+
+gboolean
+is_exchange_personal_folder (ExchangeAccount *account, gchar *uri)
+{
+	ExchangeHierarchy *hier;
+	EFolder *folder;
+
+	folder = exchange_account_get_folder (account, uri);
+	if (folder) {
+		hier = e_folder_exchange_get_hierarchy (folder);
+		if (hier->type != EXCHANGE_HIERARCHY_PERSONAL)
+			return FALSE;
+		else
+			return TRUE;
+	}
+	return FALSE;
+}
diff --git a/eplugin/exchange-operations.h b/eplugin/exchange-operations.h
new file mode 100644
index 0000000..d735ff8
--- /dev/null
+++ b/eplugin/exchange-operations.h
@@ -0,0 +1,56 @@
+/*
+ * 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:
+ *		Praveen Kumar <kpraveen@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_OPERATIONS_H__
+#define __EXCHANGE_OPERATIONS_H__
+
+#include <gtk/gtk.h>
+
+#include "e-util/e-plugin.h"
+#include "exchange-config-listener.h"
+#include <exchange-account.h>
+
+G_BEGIN_DECLS
+
+#define ERROR_DOMAIN "org-gnome-exchange-operations"
+
+extern ExchangeConfigListener *exchange_global_config_listener;
+
+gint e_plugin_lib_enable (EPluginLib *eplib, gint enable);
+
+ExchangeAccount *exchange_operations_get_exchange_account (void);
+ExchangeConfigListenerStatus exchange_is_offline (gint *mode);
+
+gboolean exchange_operations_tokenize_string (gchar **string, gchar *token, gchar delimit, guint maxsize);
+
+gboolean exchange_operations_cta_add_node_to_tree (GtkTreeStore *store, GtkTreeIter *parent, const gchar *nuri);
+void exchange_operations_cta_select_node_from_tree (GtkTreeStore *store, GtkTreeIter *parent, const gchar *nuri, const gchar *ruri, GtkTreeSelection *selection);
+
+void exchange_operations_report_error (ExchangeAccount *account, ExchangeAccountResult result);
+
+void exchange_operations_update_child_esources (ESource *source, const gchar *old_path, const gchar *new_path);
+
+gboolean is_exchange_personal_folder (ExchangeAccount *account, gchar *uri);
+
+G_END_DECLS
+
+#endif
diff --git a/eplugin/exchange-permissions-dialog.c b/eplugin/exchange-permissions-dialog.c
new file mode 100644
index 0000000..20af66e
--- /dev/null
+++ b/eplugin/exchange-permissions-dialog.c
@@ -0,0 +1,984 @@
+/*
+ * 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:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "exchange-permissions-dialog.h"
+#include "exchange-hierarchy.h"
+#include "exchange-user-dialog.h"
+
+#include "e2k-context.h"
+#include "e2k-global-catalog.h"
+#include "e2k-propnames.h"
+#include "e2k-sid.h"
+#include "e2k-security-descriptor.h"
+
+#include "e2k-uri.h"
+#include "e2k-utils.h"
+#include "e-folder-exchange.h"
+#include "exchange-account.h"
+#include "exchange-operations.h"
+
+#include <e-util/e-dialog-utils.h>
+#include <e-util/e-error.h>
+
+struct _ExchangePermissionsDialogPrivate {
+	ExchangeAccount *account;
+	gchar *base_uri, *folder_path;
+	E2kSecurityDescriptor *sd;
+	gboolean changed;
+	gboolean frozen;
+
+	/* The user list */
+	GtkTreeView *list_view;
+	GtkListStore *list_store;
+	GtkTreeSelection *list_selection;
+	E2kSid *selected_sid;
+
+	/* The Role menu */
+	GtkComboBox *role_optionmenu;
+
+	/* Custom label is added or not */
+	gboolean custom_added;
+
+	GtkWidget *separator, *custom;
+	E2kPermissionsRole selected_role;
+
+	/* The toggles */
+	GtkToggleButton *read_items_check, *create_items_check;
+	GtkToggleButton *create_subfolders_check, *folder_visible_check;
+	GtkToggleButton *folder_owner_check, *folder_contact_check;
+	GtkToggleButton *edit_none_radio, *edit_own_radio, *edit_all_radio;
+	GtkToggleButton *delete_none_radio, *delete_own_radio, *delete_all_radio;
+	guint32 selected_perms;
+};
+
+enum {
+	EXCHANGE_PERMISSIONS_DIALOG_NAME_COLUMN,
+	EXCHANGE_PERMISSIONS_DIALOG_ROLE_COLUMN,
+	EXCHANGE_PERMISSIONS_DIALOG_SID_COLUMN,
+
+	EXCHANGE_PERMISSIONS_DIALOG_NUM_COLUMNS
+};
+
+#define PARENT_TYPE GTK_TYPE_DIALOG
+static GtkDialogClass *parent_class = NULL;
+
+static void
+finalize (GObject *object)
+{
+	ExchangePermissionsDialog *dialog =
+		EXCHANGE_PERMISSIONS_DIALOG (object);
+
+	g_free (dialog->priv->base_uri);
+	g_free (dialog->priv->folder_path);
+
+	if (dialog->priv->sd)
+		g_object_unref (dialog->priv->sd);
+
+	g_free (dialog->priv);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+class_init (GObjectClass *object_class)
+{
+	parent_class = g_type_class_ref (PARENT_TYPE);
+
+	/* virtual method override */
+	object_class->finalize = finalize;
+}
+
+static void
+init (GObject *object)
+{
+	ExchangePermissionsDialog *dialog =
+		EXCHANGE_PERMISSIONS_DIALOG (object);
+
+	dialog->priv = g_new0 (ExchangePermissionsDialogPrivate, 1);
+}
+
+E2K_MAKE_TYPE (exchange_permissions_dialog, ExchangePermissionsDialog, class_init, init, PARENT_TYPE)
+
+static GtkWidget *create_permissions_vbox (ExchangePermissionsDialog *dialog);
+static void setup_user_list     (ExchangePermissionsDialog *dialog);
+static void display_permissions (ExchangePermissionsDialog *dialog);
+static void dialog_response     (ExchangePermissionsDialog *dialog,
+				 gint response, gpointer user_data);
+
+static const gchar *sd_props[] = {
+	E2K_PR_EXCHANGE_SD_BINARY,
+	E2K_PR_EXCHANGE_SD_XML
+};
+static const gint n_sd_props = sizeof (sd_props) / sizeof (sd_props[0]);
+
+/**
+ * exchange_permissions_dialog_new:
+ * @account: an account
+ * @folder: the folder whose permissions are to be editted
+ * @parent: a widget in the dialog's parent window
+ *
+ * Creates and displays a modeless permissions editor dialog for @folder.
+ **/
+void
+exchange_permissions_dialog_new (ExchangeAccount *account,
+				 EFolder *folder,
+				 GtkWidget *parent)
+{
+	ExchangePermissionsDialog *dialog;
+	const gchar *base_uri, *folder_uri, *folder_path;
+	E2kContext *ctx;
+	ExchangeHierarchy *hier;
+	GtkWidget *box;
+	gchar *title;
+	E2kHTTPStatus status;
+	E2kResult *results;
+	gint nresults = 0;
+	xmlNode *xml_form;
+	GByteArray *binary_form;
+
+	g_return_if_fail (folder);
+
+	ctx = exchange_account_get_context (account);
+	g_return_if_fail (ctx);
+
+	/* Create the dialog */
+	dialog = g_object_new (EXCHANGE_TYPE_PERMISSIONS_DIALOG, NULL);
+
+	title = g_strdup_printf (_("Permissions for %s"),
+				 e_folder_get_name (folder));
+	gtk_window_set_title (GTK_WINDOW (dialog), title);
+	g_free (title);
+
+	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+				GTK_STOCK_OK, GTK_RESPONSE_OK,
+				NULL);
+
+	g_signal_connect (dialog, "response",
+			  G_CALLBACK (dialog_response), NULL);
+
+	dialog->priv->changed = FALSE;
+
+	box = create_permissions_vbox (dialog);
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+			    box, TRUE, TRUE, 0);
+
+	dialog->priv->account = account;
+	g_object_ref (account);
+
+	hier = e_folder_exchange_get_hierarchy (folder);
+	base_uri = e_folder_exchange_get_internal_uri (hier->toplevel);
+	dialog->priv->base_uri = g_strdup (base_uri);
+	folder_uri = e_folder_exchange_get_internal_uri (folder);
+	folder_path = e2k_uri_relative (dialog->priv->base_uri, folder_uri);
+	dialog->priv->folder_path = g_strdup (folder_path);
+
+	/* And fetch the security descriptor */
+	status = e2k_context_propfind (ctx, NULL, folder_uri,
+				       sd_props, n_sd_props,
+				       &results, &nresults);
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status) || nresults < 1) {
+	lose:
+		e_error_run (GTK_WINDOW (parent), ERROR_DOMAIN ":perm-read-error", NULL);
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+		if (nresults)
+			e2k_results_free (results, nresults);
+		return;
+	}
+
+	xml_form = e2k_properties_get_prop (results[0].props,
+					    E2K_PR_EXCHANGE_SD_XML);
+	binary_form = e2k_properties_get_prop (results[0].props,
+					       E2K_PR_EXCHANGE_SD_BINARY);
+	if (!xml_form || !binary_form)
+		goto lose;
+
+	dialog->priv->sd = e2k_security_descriptor_new (xml_form, binary_form);
+	if (!dialog->priv->sd)
+		goto lose;
+
+	setup_user_list (dialog);
+	gtk_widget_show (GTK_WIDGET (dialog));
+	if (nresults)
+		e2k_results_free (results, nresults);
+}
+
+static void
+dialog_response (ExchangePermissionsDialog *dialog, gint response,
+		 gpointer user_data)
+{
+	E2kContext *ctx;
+	GByteArray *binsd;
+	E2kProperties *props;
+	E2kResultIter *iter;
+	E2kResult *result;
+	E2kHTTPStatus status;
+
+	if (response != GTK_RESPONSE_OK || !dialog->priv->changed) {
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+		return;
+	}
+
+	ctx = exchange_account_get_context (dialog->priv->account);
+	g_return_if_fail (ctx != NULL);
+
+	binsd = e2k_security_descriptor_to_binary (dialog->priv->sd);
+	if (!binsd) {
+		e_error_run (GTK_WINDOW (dialog), ERROR_DOMAIN ":perm-update-error", "", NULL);
+		return;
+	}
+
+	gtk_widget_set_sensitive (GTK_WIDGET (dialog), FALSE);
+
+	props = e2k_properties_new ();
+	e2k_properties_set_binary (props, E2K_PR_EXCHANGE_SD_BINARY, binsd);
+
+	/* We use BPROPPATCH here instead of PROPPATCH, because
+	 * PROPPATCH seems to mysteriously fail in someone else's
+	 * folder hierarchy. #29726
+	 */
+	iter = e2k_context_bproppatch_start (ctx, NULL, dialog->priv->base_uri,
+					     (const gchar **)&dialog->priv->folder_path, 1,
+					     props, FALSE);
+	e2k_properties_free (props);
+
+	result = e2k_result_iter_next (iter);
+	if (result) {
+		status = result->status;
+		e2k_result_iter_free (iter);
+	} else
+		status = e2k_result_iter_free (iter);
+
+	gtk_widget_set_sensitive (GTK_WIDGET (dialog), TRUE);
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
+		e_error_run (GTK_WINDOW (dialog), ERROR_DOMAIN ":perm-update-error",
+			     status == E2K_HTTP_UNAUTHORIZED ?
+			     _("(Permission denied.)") : "", NULL);
+		return;
+	}
+
+	if (response == GTK_RESPONSE_OK)
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+set_permissions (ExchangePermissionsDialog *dialog, guint32 perms)
+{
+	dialog->priv->selected_perms = perms;
+	dialog->priv->selected_role = e2k_permissions_role_find (perms);
+	e2k_security_descriptor_set_permissions (dialog->priv->sd,
+						 dialog->priv->selected_sid,
+						 dialog->priv->selected_perms);
+
+	dialog->priv->changed = TRUE;
+}
+
+/* User list functions */
+
+static void
+list_view_selection_changed (GtkTreeSelection *selection, gpointer user_data)
+{
+	ExchangePermissionsDialog *dialog = user_data;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	E2kSid *sid;
+
+	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+		return;
+	gtk_tree_model_get (model, &iter,
+			    EXCHANGE_PERMISSIONS_DIALOG_SID_COLUMN, &sid,
+			    -1);
+
+	dialog->priv->selected_sid = sid;
+	dialog->priv->selected_perms =
+		e2k_security_descriptor_get_permissions (dialog->priv->sd, sid);
+	dialog->priv->selected_role =
+		e2k_permissions_role_find (dialog->priv->selected_perms);
+
+	/* "Default" or "Anonymous" can't be a Folder contact, but any
+	 * real person can.
+	 */
+	gtk_widget_set_sensitive (GTK_WIDGET (dialog->priv->folder_contact_check),
+				  e2k_sid_get_sid_type (sid) != E2K_SID_TYPE_WELL_KNOWN_GROUP);
+
+	/* Update role menu and permissions checkboxes */
+	display_permissions (dialog);
+}
+
+static void
+add_user_to_list (ExchangePermissionsDialog *dialog, E2kSid *sid, gboolean select)
+{
+	guint32 perms;
+	E2kPermissionsRole role;
+	GtkTreeIter iter;
+
+	perms = e2k_security_descriptor_get_permissions (dialog->priv->sd,
+							 sid);
+	role = e2k_permissions_role_find (perms);
+
+	if (e2k_sid_get_sid_type (sid) == E2K_SID_TYPE_WELL_KNOWN_GROUP)
+		gtk_list_store_insert (dialog->priv->list_store, &iter, 1);
+	else
+		gtk_list_store_append (dialog->priv->list_store, &iter);
+
+	gtk_list_store_set (dialog->priv->list_store, &iter,
+			    EXCHANGE_PERMISSIONS_DIALOG_NAME_COLUMN,
+			    e2k_sid_get_display_name (sid),
+			    EXCHANGE_PERMISSIONS_DIALOG_ROLE_COLUMN,
+			    e2k_permissions_role_get_name (role),
+			    EXCHANGE_PERMISSIONS_DIALOG_SID_COLUMN,
+			    sid,
+			    -1);
+
+	if (select)
+		gtk_tree_selection_select_iter (dialog->priv->list_selection, &iter);
+}
+
+static void
+add_clicked (GtkButton *button, gpointer user_data)
+{
+	ExchangePermissionsDialog *dialog = user_data;
+	E2kGlobalCatalog *gc;
+	E2kGlobalCatalogStatus status;
+	E2kGlobalCatalogEntry *entry;
+	E2kSid *sid2;
+	GtkTreeIter iter;
+	GtkWidget *user_dialog;
+	const guint8 *bsid, *bsid2;
+	GList *email_list = NULL;
+	GList *l = NULL;
+	gchar *email = NULL;
+	gboolean valid;
+	gint result;
+
+	gc = exchange_account_get_global_catalog (dialog->priv->account);
+
+	if (!gc) {
+		e_error_run (GTK_WINDOW (dialog), ERROR_DOMAIN ":acl-no-gcs-error",
+			     NULL);
+		return;
+	}
+
+	user_dialog = e2k_user_dialog_new (GTK_WIDGET (dialog), _("Add User:"), _("Add User"));
+	result = gtk_dialog_run (GTK_DIALOG (user_dialog));
+
+	if (result == GTK_RESPONSE_OK)
+		email_list = e2k_user_dialog_get_user_list (E2K_USER_DIALOG (user_dialog));
+	gtk_widget_destroy (user_dialog);
+
+	if (email_list == NULL)
+		return;
+
+	for (l = email_list; l; l = g_list_next (l)) {
+		email = l->data;
+		status = e2k_global_catalog_lookup (
+			gc, NULL, /* FIXME: cancellable */
+			E2K_GLOBAL_CATALOG_LOOKUP_BY_EMAIL, email,
+			E2K_GLOBAL_CATALOG_LOOKUP_SID, &entry);
+		switch (status) {
+			case E2K_GLOBAL_CATALOG_OK:
+				break;
+			case E2K_GLOBAL_CATALOG_NO_SUCH_USER:
+				e_error_run (GTK_WINDOW (dialog), ERROR_DOMAIN ":no-user-error", email, NULL);
+				break;
+			case E2K_GLOBAL_CATALOG_NO_DATA:
+				e_error_run (GTK_WINDOW (dialog), ERROR_DOMAIN ":acl-add-error", email, NULL);
+				break;
+			default:
+				e_error_run (GTK_WINDOW (dialog), ERROR_DOMAIN ":perm-unknown-error", email, NULL);
+				break;
+		}
+		if (status != E2K_GLOBAL_CATALOG_OK)
+			return;
+
+		/* Make sure the user isn't already there. */
+		bsid = e2k_sid_get_binary_sid (entry->sid);
+		valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->list_store), &iter);
+		while (valid) {
+			gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->list_store), &iter,
+					    EXCHANGE_PERMISSIONS_DIALOG_SID_COLUMN, &sid2,
+					    -1);
+			bsid2 = e2k_sid_get_binary_sid (sid2);
+			if (e2k_sid_binary_sid_equal (bsid, bsid2)) {
+				e_error_run (GTK_WINDOW (dialog), ERROR_DOMAIN ":perm-existing-error",
+					     entry->display_name, NULL);
+				e2k_global_catalog_entry_free (gc, entry);
+				gtk_tree_selection_select_iter (dialog->priv->list_selection, &iter);
+				return;
+			}
+
+			valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (dialog->priv->list_store), &iter);
+		}
+
+		add_user_to_list (dialog, entry->sid, TRUE);
+
+		/* Calling set_permissions will cause the sd to take a
+		 * ref on the sid, allowing us to unref it.
+		 */
+		set_permissions (dialog, 0);
+		e2k_global_catalog_entry_free (gc, entry);
+	}
+	g_list_free (email_list);
+}
+
+static void
+remove_clicked (GtkButton *button, gpointer user_data)
+{
+	ExchangePermissionsDialog *dialog = user_data;
+	E2kSid *sid;
+	GdkModifierType modifiers;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	if (!gtk_tree_selection_get_selected (dialog->priv->list_selection,
+					      &model, &iter))
+		return;
+	gtk_tree_model_get (model, &iter,
+			    EXCHANGE_PERMISSIONS_DIALOG_SID_COLUMN, &sid,
+			    -1);
+	gdk_window_get_pointer (NULL, NULL, NULL, &modifiers);
+
+	if (e2k_sid_get_sid_type (sid) == E2K_SID_TYPE_WELL_KNOWN_GROUP &&
+	    !(modifiers & GDK_SHIFT_MASK)) {
+		/* You shouldn't normally delete "Default" or "Anonymous". */
+		set_permissions (dialog, 0);
+	} else {
+		gtk_list_store_remove (dialog->priv->list_store, &iter);
+		e2k_security_descriptor_remove_sid (dialog->priv->sd, sid);
+
+		if (!gtk_list_store_iter_is_valid (dialog->priv->list_store, &iter)) {
+			/* Select the new last row. Love that API... */
+			gtk_tree_model_iter_nth_child (model, &iter, NULL,
+						       gtk_tree_model_iter_n_children (model, NULL) - 1);
+		}
+		gtk_tree_selection_select_iter (dialog->priv->list_selection, &iter);
+
+		dialog->priv->changed = TRUE;
+	}
+}
+
+static void
+setup_user_list (ExchangePermissionsDialog *dialog)
+{
+	E2kSecurityDescriptor *sd = dialog->priv->sd;
+	E2kSid *default_entry;
+	GList *sids;
+
+	/* Always put "Default" first. */
+	default_entry = e2k_security_descriptor_get_default (sd);
+	add_user_to_list (dialog, default_entry, TRUE);
+
+	sids = e2k_security_descriptor_get_sids (sd);
+	while (sids) {
+		if (sids->data != default_entry)
+			add_user_to_list (dialog, sids->data, FALSE);
+		sids = sids->next;
+	}
+	g_list_free (sids);
+}
+
+/* Role option menu functions */
+
+static void
+role_changed (GtkWidget *role_combo, gpointer user_data)
+{
+	ExchangePermissionsDialog *dialog = user_data;
+	gint role;
+
+	if (dialog->priv->frozen)
+		return;
+
+	role = gtk_combo_box_get_active (GTK_COMBO_BOX (role_combo));
+	if (role == dialog->priv->selected_role)
+		return;
+	if (role >= E2K_PERMISSIONS_ROLE_NUM_ROLES) {
+		/* The user selected "Custom". Since "Custom" will
+		 * only be there to select when it's already
+		 * selected, this is a no-op.
+		 */
+		return;
+	}
+
+	set_permissions (dialog, e2k_permissions_role_get_perms (role));
+	display_permissions (dialog);
+}
+
+static void
+display_role (ExchangePermissionsDialog *dialog)
+{
+	gint role = dialog->priv->selected_role;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	if (!gtk_tree_selection_get_selected (dialog->priv->list_selection,
+					      &model, &iter))
+		return;
+	gtk_list_store_set (dialog->priv->list_store, &iter,
+			    EXCHANGE_PERMISSIONS_DIALOG_ROLE_COLUMN,
+			    e2k_permissions_role_get_name (role),
+			    -1);
+
+	if (role == E2K_PERMISSIONS_ROLE_CUSTOM) {
+		if (dialog->priv->custom_added == FALSE) {
+			gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->priv->role_optionmenu), _("Custom"));
+			dialog->priv->custom_added = TRUE;
+		}
+		role = E2K_PERMISSIONS_ROLE_NUM_ROLES;
+	}
+	else	{
+		if (dialog->priv->custom_added) {
+			gtk_combo_box_remove_text (GTK_COMBO_BOX (dialog->priv->role_optionmenu), E2K_PERMISSIONS_ROLE_NUM_ROLES);
+			dialog->priv->custom_added = FALSE;
+		}
+	}
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->role_optionmenu), role);
+}
+
+/* Toggle buttons */
+static void
+check_toggled (GtkToggleButton *toggle, gpointer user_data)
+{
+	ExchangePermissionsDialog *dialog = user_data;
+	ExchangePermissionsDialogPrivate *priv = dialog->priv;
+	guint32 new_perms, value;
+
+	if (dialog->priv->frozen)
+		return;
+
+	value = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (toggle), "mapi_permission"));
+
+	if (gtk_toggle_button_get_active (toggle))
+		new_perms = priv->selected_perms | value;
+	else
+		new_perms = priv->selected_perms & ~value;
+
+	if (new_perms == priv->selected_perms)
+		return;
+
+	set_permissions (dialog, new_perms);
+	display_role (dialog);
+}
+
+static void
+radio_toggled (GtkToggleButton *toggle, gpointer user_data)
+{
+	ExchangePermissionsDialog *dialog = user_data;
+	ExchangePermissionsDialogPrivate *priv = dialog->priv;
+	guint32 new_perms, value, mask;
+
+	if (dialog->priv->frozen || !gtk_toggle_button_get_active (toggle))
+		return;
+
+	value = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (toggle), "mapi_permission"));
+	mask = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (toggle), "mapi_mask"));
+
+	new_perms = (priv->selected_perms & ~mask) | value;
+	if (new_perms == priv->selected_perms)
+		return;
+
+	set_permissions (dialog, new_perms);
+	display_role (dialog);
+}
+
+static void
+rv_toggle (GtkToggleButton *toggled, gpointer user_data)
+{
+	ExchangePermissionsDialog *dialog = user_data;
+	GtkToggleButton *visible = dialog->priv->folder_visible_check;
+	GtkToggleButton *read = dialog->priv->read_items_check;
+
+	if (dialog->priv->frozen)
+		return;
+
+	/* If you turn off "Folder visible", then "Read items" turns
+	 * off too. Contrariwise, if you turn on "Read items", then
+	 * "Folder visible" turns on too.
+	 */
+	if (toggled == visible && !gtk_toggle_button_get_active (toggled))
+		gtk_toggle_button_set_active (read, FALSE);
+	else if (toggled == read && gtk_toggle_button_get_active (toggled))
+		gtk_toggle_button_set_active (visible, TRUE);
+}
+
+static void
+display_permissions (ExchangePermissionsDialog *dialog)
+{
+	GtkToggleButton *radio;
+	guint32 perms = dialog->priv->selected_perms;
+
+	dialog->priv->frozen = TRUE;
+
+	/* Set up check boxes */
+	gtk_toggle_button_set_active (dialog->priv->read_items_check,
+				      perms & E2K_PERMISSION_READ_ANY);
+	gtk_toggle_button_set_active (dialog->priv->create_items_check,
+				      perms & E2K_PERMISSION_CREATE);
+	gtk_toggle_button_set_active (dialog->priv->create_subfolders_check,
+				      perms & E2K_PERMISSION_CREATE_SUBFOLDER);
+	gtk_toggle_button_set_active (dialog->priv->folder_owner_check,
+				      perms & E2K_PERMISSION_OWNER);
+	gtk_toggle_button_set_active (dialog->priv->folder_contact_check,
+				      (perms & E2K_PERMISSION_CONTACT) &&
+				      GTK_WIDGET_SENSITIVE (dialog->priv->folder_contact_check));
+	gtk_toggle_button_set_active (dialog->priv->folder_visible_check,
+				      perms & E2K_PERMISSION_FOLDER_VISIBLE);
+
+	/* Set up radio buttons */
+	if (perms & E2K_PERMISSION_EDIT_ANY)
+		radio = dialog->priv->edit_all_radio;
+	else if (perms & E2K_PERMISSION_EDIT_OWNED)
+		radio = dialog->priv->edit_own_radio;
+	else
+		radio = dialog->priv->edit_none_radio;
+	gtk_toggle_button_set_active (radio, TRUE);
+
+	if (perms & E2K_PERMISSION_DELETE_ANY)
+		radio = dialog->priv->delete_all_radio;
+	else if (perms & E2K_PERMISSION_DELETE_OWNED)
+		radio = dialog->priv->delete_own_radio;
+	else
+		radio = dialog->priv->delete_none_radio;
+	gtk_toggle_button_set_active (radio, TRUE);
+
+	/* And role menu */
+	display_role (dialog);
+
+	dialog->priv->frozen = FALSE;
+}
+
+static GtkWidget *
+exchange_permissions_role_optionmenu_new (void)
+{
+	GtkWidget *menu;
+	const gchar **roles;
+	gint role;
+
+	menu = gtk_combo_box_new_text ();
+	roles = g_new (const gchar *, E2K_PERMISSIONS_ROLE_NUM_ROLES + 1);
+	for (role = 0; role < E2K_PERMISSIONS_ROLE_NUM_ROLES; role++) {
+		roles[role] = e2k_permissions_role_get_name (role);
+		gtk_combo_box_append_text (GTK_COMBO_BOX (menu), roles[role]);
+	}
+
+	roles[role] = NULL;
+
+	g_free (roles);
+
+	gtk_widget_show (menu);
+	return menu;
+}
+
+static GtkWidget *
+create_permissions_vbox (ExchangePermissionsDialog *dialog)
+{
+	GtkWidget *permissions_vbox;
+	GtkWidget *hbox1;
+	GtkWidget *scrolledwindow1;
+	GtkWidget *list_view;
+	GtkWidget *vbuttonbox1;
+	GtkWidget *add_button;
+	GtkWidget *remove_button;
+	GtkWidget *table2;
+	GtkWidget *label6;
+	GtkWidget *label7;
+	GtkWidget *label3;
+	GtkWidget *hbox3;
+	GtkWidget *label4;
+	GtkWidget *role_optionmenu;
+	GtkWidget *hbox2;
+	GtkWidget *vbox6;
+	GtkWidget *vbox8;
+	GtkWidget *create_items_check;
+	GtkWidget *read_items_check;
+	GtkWidget *create_subfolders_check;
+	GtkWidget *vbox9;
+	GtkWidget *edit_none_radio;
+	GSList *edit_none_radio_group = NULL;
+	GtkWidget *edit_own_radio;
+	GtkWidget *edit_all_radio;
+	GtkWidget *vbox7;
+	GtkWidget *vbox10;
+	GtkWidget *folder_owner_check;
+	GtkWidget *folder_contact_check;
+	GtkWidget *folder_visible_check;
+	GtkWidget *vbox11;
+	GtkWidget *delete_none_radio;
+	GSList *delete_none_radio_group = NULL;
+	GtkWidget *delete_own_radio;
+	GtkWidget *delete_all_radio;
+	gchar *tmp_str;
+	GtkTreeViewColumn *column;
+
+	permissions_vbox = gtk_vbox_new (FALSE, 0);
+	gtk_widget_show (permissions_vbox);
+	gtk_container_set_border_width (GTK_CONTAINER (permissions_vbox), 6);
+
+	hbox1 = gtk_hbox_new (FALSE, 6);
+	gtk_widget_show (hbox1);
+	gtk_box_pack_start (GTK_BOX (permissions_vbox), hbox1, TRUE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox1), 6);
+
+	scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
+	gtk_widget_show (scrolledwindow1);
+	gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow1, TRUE, TRUE, 0);
+	GTK_WIDGET_UNSET_FLAGS (scrolledwindow1, GTK_CAN_FOCUS);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN);
+
+	list_view = gtk_tree_view_new ();
+	gtk_widget_show (list_view);
+	gtk_container_add (GTK_CONTAINER (scrolledwindow1), list_view);
+
+	vbuttonbox1 = gtk_vbutton_box_new ();
+	gtk_widget_show (vbuttonbox1);
+	gtk_box_pack_start (GTK_BOX (hbox1), vbuttonbox1, FALSE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (vbuttonbox1), 4);
+	gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox1), GTK_BUTTONBOX_SPREAD);
+	gtk_box_set_spacing (GTK_BOX (vbuttonbox1), 10);
+
+	add_button = gtk_button_new_from_stock ("gtk-add");
+	gtk_widget_show (add_button);
+	gtk_container_add (GTK_CONTAINER (vbuttonbox1), add_button);
+	GTK_WIDGET_SET_FLAGS (add_button, GTK_CAN_DEFAULT);
+
+	remove_button = gtk_button_new_from_stock ("gtk-remove");
+	gtk_widget_show (remove_button);
+	gtk_container_add (GTK_CONTAINER (vbuttonbox1), remove_button);
+	GTK_WIDGET_SET_FLAGS (remove_button, GTK_CAN_DEFAULT);
+
+	table2 = gtk_table_new (3, 2, FALSE);
+	gtk_widget_show (table2);
+	gtk_box_pack_start (GTK_BOX (permissions_vbox), table2, FALSE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (table2), 6);
+	gtk_table_set_row_spacings (GTK_TABLE (table2), 6);
+
+	label6 = gtk_label_new ("    ");
+	gtk_widget_show (label6);
+	gtk_table_attach (GTK_TABLE (table2), label6, 0, 1, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (label6), 0, 0.5);
+
+	label7 = gtk_label_new ("    ");
+	gtk_widget_show (label7);
+	gtk_table_attach (GTK_TABLE (table2), label7, 0, 1, 2, 3,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (label7), 0, 0.5);
+
+	tmp_str = g_strconcat ("<b>", _("Permissions"), "</b>", NULL);
+	label3 = gtk_label_new (tmp_str);
+	g_free (tmp_str);
+	gtk_widget_show (label3);
+	gtk_table_attach (GTK_TABLE (table2), label3, 0, 2, 0, 1,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_label_set_use_markup (GTK_LABEL (label3), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5);
+
+	hbox3 = gtk_hbox_new (FALSE, 6);
+	gtk_widget_show (hbox3);
+	gtk_table_attach (GTK_TABLE (table2), hbox3, 1, 2, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox3), 6);
+
+	label4 = gtk_label_new (_("Role: "));
+	gtk_widget_show (label4);
+	gtk_box_pack_start (GTK_BOX (hbox3), label4, FALSE, FALSE, 0);
+	gtk_label_set_justify (GTK_LABEL (label4), GTK_JUSTIFY_CENTER);
+
+	role_optionmenu = exchange_permissions_role_optionmenu_new ();
+	gtk_widget_show (role_optionmenu);
+	gtk_box_pack_start (GTK_BOX (hbox3), role_optionmenu, TRUE, TRUE, 0);
+	GTK_WIDGET_UNSET_FLAGS (role_optionmenu, GTK_CAN_FOCUS);
+	GTK_WIDGET_UNSET_FLAGS (role_optionmenu, GTK_CAN_DEFAULT);
+
+	hbox2 = gtk_hbox_new (TRUE, 6);
+	gtk_widget_show (hbox2);
+	gtk_table_attach (GTK_TABLE (table2), hbox2, 1, 2, 2, 3,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox2), 6);
+
+	vbox6 = gtk_vbox_new (FALSE, 12);
+	gtk_widget_show (vbox6);
+	gtk_box_pack_start (GTK_BOX (hbox2), vbox6, TRUE, TRUE, 0);
+
+	vbox8 = gtk_vbox_new (FALSE, 6);
+	gtk_widget_show (vbox8);
+	gtk_box_pack_start (GTK_BOX (vbox6), vbox8, TRUE, TRUE, 0);
+
+	create_items_check = gtk_check_button_new_with_mnemonic (_("Create items"));
+	gtk_widget_show (create_items_check);
+	gtk_box_pack_start (GTK_BOX (vbox8), create_items_check, FALSE, FALSE, 0);
+
+	read_items_check = gtk_check_button_new_with_mnemonic (_("Read items"));
+	gtk_widget_show (read_items_check);
+	gtk_box_pack_start (GTK_BOX (vbox8), read_items_check, FALSE, FALSE, 0);
+
+	create_subfolders_check = gtk_check_button_new_with_mnemonic (_("Create subfolders"));
+	gtk_widget_show (create_subfolders_check);
+	gtk_box_pack_start (GTK_BOX (vbox8), create_subfolders_check, FALSE, FALSE, 0);
+
+	vbox9 = gtk_vbox_new (FALSE, 6);
+	gtk_widget_show (vbox9);
+	gtk_box_pack_start (GTK_BOX (vbox6), vbox9, TRUE, TRUE, 0);
+
+	edit_none_radio = gtk_radio_button_new_with_mnemonic (NULL, _("Cannot Edit"));
+	gtk_widget_show (edit_none_radio);
+	gtk_box_pack_start (GTK_BOX (vbox9), edit_none_radio, FALSE, FALSE, 0);
+	gtk_radio_button_set_group (GTK_RADIO_BUTTON (edit_none_radio), edit_none_radio_group);
+	edit_none_radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (edit_none_radio));
+
+	edit_own_radio = gtk_radio_button_new_with_mnemonic (NULL, _("Edit Own Items"));
+	gtk_widget_show (edit_own_radio);
+	gtk_box_pack_start (GTK_BOX (vbox9), edit_own_radio, FALSE, FALSE, 0);
+	gtk_radio_button_set_group (GTK_RADIO_BUTTON (edit_own_radio), edit_none_radio_group);
+	edit_none_radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (edit_own_radio));
+
+	edit_all_radio = gtk_radio_button_new_with_mnemonic (NULL, _("Edit Any Items"));
+	gtk_widget_show (edit_all_radio);
+	gtk_box_pack_start (GTK_BOX (vbox9), edit_all_radio, FALSE, FALSE, 0);
+	gtk_radio_button_set_group (GTK_RADIO_BUTTON (edit_all_radio), edit_none_radio_group);
+	edit_none_radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (edit_all_radio));
+
+	vbox7 = gtk_vbox_new (FALSE, 12);
+	gtk_widget_show (vbox7);
+	gtk_box_pack_start (GTK_BOX (hbox2), vbox7, TRUE, TRUE, 0);
+
+	vbox10 = gtk_vbox_new (FALSE, 6);
+	gtk_widget_show (vbox10);
+	gtk_box_pack_start (GTK_BOX (vbox7), vbox10, TRUE, TRUE, 0);
+
+	folder_owner_check = gtk_check_button_new_with_mnemonic (_("Folder owner"));
+	gtk_widget_show (folder_owner_check);
+	gtk_box_pack_start (GTK_BOX (vbox10), folder_owner_check, FALSE, FALSE, 0);
+
+	folder_contact_check = gtk_check_button_new_with_mnemonic (_("Folder contact"));
+	gtk_widget_show (folder_contact_check);
+	gtk_box_pack_start (GTK_BOX (vbox10), folder_contact_check, FALSE, FALSE, 0);
+
+	folder_visible_check = gtk_check_button_new_with_mnemonic (_("Folder visible"));
+	gtk_widget_show (folder_visible_check);
+	gtk_box_pack_start (GTK_BOX (vbox10), folder_visible_check, FALSE, FALSE, 0);
+
+	vbox11 = gtk_vbox_new (FALSE, 6);
+	gtk_widget_show (vbox11);
+	gtk_box_pack_start (GTK_BOX (vbox7), vbox11, TRUE, TRUE, 0);
+
+	delete_none_radio = gtk_radio_button_new_with_mnemonic (NULL, _("Cannot Delete"));
+	gtk_widget_show (delete_none_radio);
+	gtk_box_pack_start (GTK_BOX (vbox11), delete_none_radio, FALSE, FALSE, 0);
+	gtk_radio_button_set_group (GTK_RADIO_BUTTON (delete_none_radio), delete_none_radio_group);
+	delete_none_radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (delete_none_radio));
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (delete_none_radio), TRUE);
+
+	delete_own_radio = gtk_radio_button_new_with_mnemonic (NULL, _("Delete Own Items"));
+	gtk_widget_show (delete_own_radio);
+	gtk_box_pack_start (GTK_BOX (vbox11), delete_own_radio, FALSE, FALSE, 0);
+	gtk_radio_button_set_group (GTK_RADIO_BUTTON (delete_own_radio), delete_none_radio_group);
+	delete_none_radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (delete_own_radio));
+
+	delete_all_radio = gtk_radio_button_new_with_mnemonic (NULL, _("Delete Any Items"));
+	gtk_widget_show (delete_all_radio);
+	gtk_box_pack_start (GTK_BOX (vbox11), delete_all_radio, FALSE, FALSE, 0);
+	gtk_radio_button_set_group (GTK_RADIO_BUTTON (delete_all_radio), delete_none_radio_group);
+	delete_none_radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (delete_all_radio));
+
+#define GET_WIDGET(name, type) dialog->priv->name = type (name)
+
+	GET_WIDGET (list_view, GTK_TREE_VIEW);
+	column = gtk_tree_view_column_new_with_attributes (
+		_("Name"), gtk_cell_renderer_text_new (),
+		"text", EXCHANGE_PERMISSIONS_DIALOG_NAME_COLUMN, NULL);
+	gtk_tree_view_append_column (dialog->priv->list_view, column);
+	column = gtk_tree_view_column_new_with_attributes (
+		_("Role"), gtk_cell_renderer_text_new (),
+		"text", EXCHANGE_PERMISSIONS_DIALOG_ROLE_COLUMN, NULL);
+	gtk_tree_view_append_column (dialog->priv->list_view, column);
+
+	dialog->priv->list_selection = gtk_tree_view_get_selection (dialog->priv->list_view);
+	gtk_tree_selection_set_mode (dialog->priv->list_selection,
+				     GTK_SELECTION_SINGLE);
+	g_signal_connect (dialog->priv->list_selection, "changed",
+			  G_CALLBACK (list_view_selection_changed), dialog);
+
+	dialog->priv->list_store = gtk_list_store_new (
+		EXCHANGE_PERMISSIONS_DIALOG_NUM_COLUMNS,
+		G_TYPE_STRING, G_TYPE_STRING, E2K_TYPE_SID);
+	gtk_tree_view_set_model (dialog->priv->list_view,
+				 GTK_TREE_MODEL (dialog->priv->list_store));
+
+	g_signal_connect (add_button, "clicked",
+			  G_CALLBACK (add_clicked), dialog);
+	g_signal_connect (remove_button, "clicked",
+			  G_CALLBACK (remove_clicked), dialog);
+
+	GET_WIDGET (role_optionmenu, GTK_COMBO_BOX);
+	g_signal_connect (dialog->priv->role_optionmenu, "changed",
+			  G_CALLBACK (role_changed), dialog);
+
+	dialog->priv->custom_added = FALSE;
+
+#define GET_TOGGLE(name, value, callback) \
+	GET_WIDGET (name, GTK_TOGGLE_BUTTON); \
+	g_object_set_data (G_OBJECT (dialog->priv->name), \
+			   "mapi_permission", \
+			   GUINT_TO_POINTER (value)); \
+	g_signal_connect (dialog->priv->name, "toggled", \
+			  G_CALLBACK (callback), dialog)
+
+#define GET_CHECK(name, value) \
+	GET_TOGGLE (name, value, check_toggled)
+
+#define GET_RADIO(name, value, mask) \
+	GET_TOGGLE (name, value, radio_toggled); \
+	g_object_set_data (G_OBJECT (dialog->priv->name), \
+			   "mapi_mask", \
+			   GUINT_TO_POINTER (mask))
+
+	GET_CHECK (read_items_check, E2K_PERMISSION_READ_ANY);
+	GET_CHECK (create_items_check, E2K_PERMISSION_CREATE);
+	GET_RADIO (edit_none_radio, 0, E2K_PERMISSION_EDIT_MASK);
+	GET_RADIO (delete_none_radio, 0, E2K_PERMISSION_DELETE_MASK);
+	GET_RADIO (edit_own_radio, E2K_PERMISSION_EDIT_OWNED, E2K_PERMISSION_EDIT_MASK);
+	GET_RADIO (delete_own_radio, E2K_PERMISSION_DELETE_OWNED, E2K_PERMISSION_DELETE_MASK);
+	GET_RADIO (edit_all_radio, (E2K_PERMISSION_EDIT_ANY | E2K_PERMISSION_EDIT_OWNED), E2K_PERMISSION_EDIT_MASK);
+	GET_RADIO (delete_all_radio, (E2K_PERMISSION_DELETE_ANY | E2K_PERMISSION_DELETE_OWNED), E2K_PERMISSION_DELETE_MASK);
+	GET_CHECK (create_subfolders_check, E2K_PERMISSION_CREATE_SUBFOLDER);
+	GET_CHECK (folder_owner_check, E2K_PERMISSION_OWNER);
+	GET_CHECK (folder_contact_check, E2K_PERMISSION_CONTACT);
+	GET_CHECK (folder_visible_check, E2K_PERMISSION_FOLDER_VISIBLE);
+
+	g_signal_connect (dialog->priv->folder_visible_check,
+			  "toggled", G_CALLBACK (rv_toggle), dialog);
+	g_signal_connect (dialog->priv->read_items_check,
+			  "toggled", G_CALLBACK (rv_toggle), dialog);
+
+	return permissions_vbox;
+}
diff --git a/eplugin/exchange-permissions-dialog.h b/eplugin/exchange-permissions-dialog.h
new file mode 100644
index 0000000..ad2f47d
--- /dev/null
+++ b/eplugin/exchange-permissions-dialog.h
@@ -0,0 +1,56 @@
+/*
+ * 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:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_PERMISSIONS_DIALOG_H__
+#define __EXCHANGE_PERMISSIONS_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "e-folder.h"
+#include "exchange-types.h"
+
+G_BEGIN_DECLS
+
+#define EXCHANGE_TYPE_PERMISSIONS_DIALOG            (exchange_permissions_dialog_get_type ())
+#define EXCHANGE_PERMISSIONS_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_TYPE_PERMISSIONS_DIALOG, ExchangePermissionsDialog))
+#define EXCHANGE_PERMISSIONS_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_TYPE_PERMISSIONS_DIALOG, ExchangePermissionsDialogClass))
+#define EXCHANGE_IS_PERMISSIONS_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_TYPE_PERMISSIONS_DIALOG))
+#define EXCHANGE_IS_PERMISSIONS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EXCHANGE_TYPE_PERMISSIONS_DIALOG))
+
+struct _ExchangePermissionsDialog {
+	GtkDialog parent;
+
+	ExchangePermissionsDialogPrivate *priv;
+};
+
+struct _ExchangePermissionsDialogClass {
+	GtkDialogClass parent_class;
+
+};
+
+GType      exchange_permissions_dialog_get_type (void);
+
+void       exchange_permissions_dialog_new      (ExchangeAccount *account,
+						 EFolder         *folder,
+						 GtkWidget       *parent);
+
+G_END_DECLS
+
+#endif /* __EXCHANGE_PERMISSIONS_DIALOG_H__ */
diff --git a/eplugin/exchange-send-options.c b/eplugin/exchange-send-options.c
new file mode 100644
index 0000000..ecc0f03
--- /dev/null
+++ b/eplugin/exchange-send-options.c
@@ -0,0 +1,623 @@
+/*
+ * 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:
+ *		R.Raghavendran <raghavguru7@gmail.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <libedataserverui/e-name-selector.h>
+#include <libedataserverui/e-contact-store.h>
+#include "exchange-operations.h"
+#include <e-util/e-util.h>
+#include <e-util/e-error.h>
+
+#include "e-util/e-util-private.h"
+
+#include "exchange-send-options.h"
+
+struct _ExchangeSendOptionsDialogPrivate {
+	/*Widgets*/
+	GtkWidget *main;
+
+	/*name selector dialog*/
+	ENameSelector *proxy_name_selector;
+
+	/*Importance*/
+	GtkWidget *importance;
+
+	/*Sensitivity*/
+	GtkWidget *sensitivity;
+
+	/*Send_as_delegate_enabled*/
+	GtkWidget *delegate_enabled;
+
+	/*Read Receipt*/
+	GtkWidget *read_receipt;
+
+	/*Delivery Receipt*/
+	GtkWidget *delivery_receipt;
+
+	/*User button*/
+	GtkWidget *button_user;
+
+	/*Label Widgets*/
+	GtkWidget *importance_label;
+	GtkWidget *sensitivity_label;
+	gchar *help_section;
+};
+
+static void exchange_sendoptions_dialog_class_init (GObjectClass *object_class);
+static void exchange_sendoptions_dialog_finalize (GObject *object);
+static void exchange_sendoptions_dialog_init (GObject *object);
+static void exchange_sendoptions_dialog_dispose (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+enum {
+	SOD_RESPONSE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+/* exchange_send_options_get_widgets_data(ExchangeSendOptionsDialog *sod)
+   Return Value:This function returns a -1 if an error occurs. In case of error-free operation a 1 is returned.
+*/
+static gint
+exchange_send_options_get_widgets_data (ExchangeSendOptionsDialog *sod)
+{
+	ExchangeSendOptionsDialogPrivate *priv;
+	ExchangeSendOptions *options;
+	const gchar *address, *email, *name;
+
+	guint count=0;
+	ENameSelectorEntry *name_selector_entry;
+	EDestinationStore *destination_store;
+	GList *destinations, *tmp;
+
+	priv = sod->priv;
+	options = sod->options;
+
+	/* This block helps us fetch the address of the delegator(s). If no delegator is selected or more
+	   than one delegatee has been selected then an info dialog is popped up to help the user.
+	*/
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->delegate_enabled))) {
+
+		name_selector_entry = e_name_selector_peek_section_entry (priv->proxy_name_selector, "Add User");
+		destination_store = e_name_selector_entry_peek_destination_store (E_NAME_SELECTOR_ENTRY									       (name_selector_entry));
+		destinations = e_destination_store_list_destinations (destination_store);
+		tmp = destinations;
+
+		email = NULL;
+
+		/* The temporary variables address, email, and name are needed to fetch the list items.
+		   Only the valid one is then copied into the storage variables. The "count" variable
+		   helps us keep a count of the exact number of items in the list. The g_list_length(GList *)
+		   produced ambiguous results. Hence count is used :)
+		*/
+		for (; tmp != NULL; tmp = g_list_next (tmp)) {
+			address = g_strdup ((gchar *) e_destination_get_address (tmp->data));
+			email = g_strdup ((gchar *) e_destination_get_email (tmp->data));
+			name = g_strdup (e_destination_get_name (tmp->data));
+			if (g_str_equal (email, ""))
+				continue;
+			count++;
+
+			options->delegate_address = address;
+			options->delegate_name = name;
+			options->delegate_email = email;
+		}
+
+		if (count == 0) {
+			e_error_run ((GtkWindow *) priv->main,
+				"org-gnome-exchange-operations:no-delegate-selected", NULL, NULL);
+			gtk_widget_grab_focus ((GtkWidget *) name_selector_entry);
+			options->delegate_address = NULL;
+			options->delegate_name = NULL;
+			options->delegate_email = NULL;
+			return -1;
+		}
+
+		if (count > 1) {
+			e_error_run ((GtkWindow *)priv->main,
+				"org-gnome-exchange-operations:more-delegates-selected", NULL, NULL);
+			gtk_widget_grab_focus ((GtkWidget *) name_selector_entry);
+			options->delegate_address = NULL;
+			options->delegate_name = NULL;
+			options->delegate_email = NULL;
+			return -1;
+		}
+	}
+
+	options->importance = gtk_combo_box_get_active ((GtkComboBox *)priv->importance);
+	options->sensitivity = gtk_combo_box_get_active ((GtkComboBox *)priv->sensitivity);
+
+	options->send_as_del_enabled = gtk_toggle_button_get_active (
+					GTK_TOGGLE_BUTTON (priv->delegate_enabled));
+
+	options->delivery_enabled = gtk_toggle_button_get_active (
+					GTK_TOGGLE_BUTTON (priv->delivery_receipt));
+
+	options->read_enabled = gtk_toggle_button_get_active (
+					GTK_TOGGLE_BUTTON (priv->read_receipt));
+
+	return 1;
+}
+
+static void
+exchange_send_options_fill_widgets_with_data (ExchangeSendOptionsDialog *sod)
+{
+	ExchangeSendOptionsDialogPrivate *priv;
+	ExchangeSendOptions *options;
+	ENameSelectorEntry *name_selector_entry;
+
+	priv = sod->priv;
+	options = sod->options;
+
+	priv->help_section = g_strdup ("usage-mail");
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (priv->importance_label), priv->importance);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (priv->sensitivity_label), priv->sensitivity);
+
+	gtk_combo_box_set_active ((GtkComboBox *) priv->importance, options->importance);
+	gtk_combo_box_set_active ((GtkComboBox *) priv->sensitivity, options->sensitivity);
+
+	name_selector_entry = e_name_selector_peek_section_entry (priv->proxy_name_selector, "Add User");
+
+	if (options->send_as_del_enabled) {
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->delegate_enabled), TRUE);
+		gtk_widget_set_sensitive ((GtkWidget *)name_selector_entry, TRUE);
+		gtk_widget_set_sensitive ((GtkWidget *)priv->button_user, TRUE);
+	}
+
+	else {
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->delegate_enabled), FALSE);
+		gtk_widget_set_sensitive ((GtkWidget *)name_selector_entry, FALSE);
+		gtk_widget_set_sensitive ((GtkWidget *)priv->button_user, FALSE);
+	}
+
+	if (options->read_enabled)
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->read_receipt), TRUE);
+	else
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->read_receipt), FALSE);
+
+	if (options->delivery_enabled)
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->delivery_receipt), TRUE);
+	else
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->delivery_receipt), FALSE);
+}
+
+ExchangeSendOptionsDialog *
+exchange_sendoptions_dialog_new (void) {
+	ExchangeSendOptionsDialog *sod;
+
+	sod = g_object_new (EXCHANGE_TYPE_SENDOPTIONS_DIALOG, NULL);
+
+	return sod;
+}
+
+GType exchange_sendoptions_dialog_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (ExchangeSendOptionsDialogClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc) exchange_sendoptions_dialog_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (ExchangeSendOptionsDialog),
+     0,      /* n_preallocs */
+     (GInstanceInitFunc) exchange_sendoptions_dialog_init,
+	NULL    /* instance_init */
+    };
+    type = g_type_register_static (G_TYPE_OBJECT,
+                                   "ExchangeSendOptionsDialogType",
+                                   &info, 0);
+  }
+  return type;
+}
+
+static void exchange_send_options_cb (GtkDialog *dialog, gint state, gpointer func_data)
+{
+	ExchangeSendOptionsDialogPrivate *priv;
+	ExchangeSendOptionsDialog *sod;
+
+	sod = func_data;
+        priv = sod->priv;
+
+	switch (state) {
+		case GTK_RESPONSE_OK:
+		     if (exchange_send_options_get_widgets_data (sod) < 0)
+			return;
+		case GTK_RESPONSE_CANCEL:
+			gtk_widget_hide (priv->main);
+			gtk_widget_destroy (priv->main);
+			break;
+		case GTK_RESPONSE_HELP:
+			e_display_help (
+				GTK_WINDOW (priv->main),
+				priv->help_section);
+			break;
+	}
+	g_signal_emit (G_OBJECT (func_data), signals[SOD_RESPONSE], 0, state);
+
+}
+
+/* This function acts as a listener for the toggling of "send_as_a_delegate" button. This is needed to
+   sensitize the name_selector_entry and the User Button
+*/
+static void
+delegate_option_toggled (GtkCheckButton *button, gpointer func_data)
+{
+	ExchangeSendOptionsDialogPrivate *priv;
+	ExchangeSendOptionsDialog *sod;
+	ENameSelectorEntry *name_selector_entry;
+	ExchangeSendOptions *options;
+
+	sod=func_data;
+	priv=sod->priv;
+	options=sod->options;
+
+	name_selector_entry = e_name_selector_peek_section_entry (priv->proxy_name_selector, "Add User");
+
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->delegate_enabled))) {
+		gtk_widget_set_sensitive ((GtkWidget *) name_selector_entry, TRUE);
+		gtk_widget_set_sensitive ((GtkWidget *) priv->button_user, TRUE);
+	}
+
+	else {
+		gtk_widget_set_sensitive ((GtkWidget *) name_selector_entry, FALSE);
+		gtk_widget_set_sensitive ((GtkWidget *) priv->button_user, FALSE);
+	}
+
+}
+
+static void
+addressbook_dialog_response (ENameSelectorDialog *name_selector_dialog, gint response, gpointer user_data)
+{
+	gtk_widget_hide (GTK_WIDGET (name_selector_dialog));
+}
+
+static void
+addressbook_entry_changed (GtkWidget *entry, gpointer user_data)
+{
+}
+
+/* This function invokes the name selector dialog
+*/
+static void
+address_button_clicked (GtkButton *button, gpointer func_data)
+{
+
+	ExchangeSendOptionsDialogPrivate *priv;
+	ExchangeSendOptionsDialog *sod;
+	ENameSelectorDialog *name_selector_dialog;
+
+	sod=func_data;
+	priv=sod->priv;
+
+	name_selector_dialog = e_name_selector_peek_dialog (priv->proxy_name_selector);
+	gtk_widget_show (GTK_WIDGET (name_selector_dialog));
+}
+
+gboolean
+exchange_sendoptions_dialog_run (ExchangeSendOptionsDialog *sod, GtkWidget *parent)
+{
+	ExchangeSendOptionsDialogPrivate *priv;
+	ExchangeSendOptions *options;
+
+	EDestinationStore *destination_store;
+	ENameSelectorDialog *name_selector_dialog;
+	ENameSelectorModel *name_selector_model;
+	ENameSelectorEntry *name_selector_entry;
+	EDestination *des;
+	GtkWidget *send_options;
+	GtkWidget *send_options_vbox;
+	GtkWidget *options_vbox;
+	GtkWidget *message_settings_vbox;
+	GtkWidget *msg_settings_label;
+	GtkWidget *msg_settings_table;
+	GtkWidget *importance_label;
+	GtkWidget *sensitivity_label;
+	GtkWidget *sensitivity_combo_box;
+	GtkWidget *imp_combo_box;
+	GtkWidget *del_enabled_check;
+	GtkWidget *hbox1;
+	GtkWidget *hbox2;
+	GtkWidget *del_name_box;
+	GtkWidget *button_user;
+	GtkWidget *track_option_vbox;
+	GtkWidget *track_options_label;
+	GtkWidget *delivery_check_button;
+	GtkWidget *read_check_button;
+	gchar *tmp_str;
+
+	g_return_val_if_fail (sod != NULL || EXCHANGE_IS_SENDOPTIONS_DIALOG (sod), FALSE);
+
+	priv = sod->priv;
+	options = sod->options;
+
+	send_options = gtk_dialog_new_with_buttons (
+		_("Exchange - Send Options"),
+		NULL,
+		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+		GTK_STOCK_HELP, GTK_RESPONSE_HELP,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+	gtk_window_set_type_hint (GTK_WINDOW (send_options), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+	send_options_vbox = gtk_dialog_get_content_area (GTK_DIALOG (send_options));
+	gtk_widget_show (send_options_vbox);
+
+	options_vbox = gtk_vbox_new (FALSE, 0);
+	gtk_widget_show (options_vbox);
+	gtk_box_pack_start (GTK_BOX (send_options_vbox), options_vbox, TRUE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (options_vbox), 6);
+
+	message_settings_vbox = gtk_vbox_new (FALSE, 0);
+	gtk_widget_show (message_settings_vbox);
+	gtk_box_pack_start (GTK_BOX (options_vbox), message_settings_vbox, FALSE, FALSE, 0);
+
+	tmp_str = g_strconcat ("<b>", _("Message Settings"), "</b>", NULL);
+	msg_settings_label = gtk_label_new (tmp_str);
+	g_free (tmp_str);
+	gtk_widget_show (msg_settings_label);
+	gtk_box_pack_start (GTK_BOX (message_settings_vbox), msg_settings_label, FALSE, FALSE, 0);
+	gtk_label_set_use_markup (GTK_LABEL (msg_settings_label), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (msg_settings_label), 0, 0.49);
+
+	msg_settings_table = gtk_table_new (2, 2, FALSE);
+	gtk_widget_show (msg_settings_table);
+	gtk_box_pack_start (GTK_BOX (message_settings_vbox), msg_settings_table, FALSE, FALSE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (msg_settings_table), 6);
+	gtk_table_set_row_spacings (GTK_TABLE (msg_settings_table), 6);
+
+	importance_label = gtk_label_new_with_mnemonic (_("I_mportance: "));
+	gtk_widget_show (importance_label);
+	gtk_table_attach (GTK_TABLE (msg_settings_table), importance_label, 0, 1, 0, 1,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (importance_label), 0, 0.49);
+
+	sensitivity_label = gtk_label_new_with_mnemonic (_("_Sensitivity: "));
+	gtk_widget_show (sensitivity_label);
+	gtk_table_attach (GTK_TABLE (msg_settings_table), sensitivity_label, 0, 1, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (sensitivity_label), 0, 0.5);
+
+	sensitivity_combo_box = gtk_combo_box_new_text ();
+	gtk_widget_show (sensitivity_combo_box);
+	gtk_table_attach (GTK_TABLE (msg_settings_table), sensitivity_combo_box, 1, 2, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+	gtk_combo_box_append_text (GTK_COMBO_BOX (sensitivity_combo_box), _("Normal"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (sensitivity_combo_box), _("Personal"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (sensitivity_combo_box), _("Private"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (sensitivity_combo_box), _("Confidential"));
+
+	imp_combo_box = gtk_combo_box_new_text ();
+	gtk_widget_show (imp_combo_box);
+	gtk_table_attach (GTK_TABLE (msg_settings_table), imp_combo_box, 1, 2, 0, 1,
+			  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			  (GtkAttachOptions) (GTK_FILL), 0, 0);
+	gtk_combo_box_append_text (GTK_COMBO_BOX (imp_combo_box), _("Normal"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (imp_combo_box), _("High"));
+	gtk_combo_box_append_text (GTK_COMBO_BOX (imp_combo_box), _("Low"));
+
+	del_enabled_check = gtk_check_button_new_with_mnemonic (_("Send as Delegate"));
+	gtk_widget_show (del_enabled_check);
+	gtk_box_pack_start (GTK_BOX (options_vbox), del_enabled_check, FALSE, FALSE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (del_enabled_check), 6);
+
+	hbox1 = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (hbox1);
+	gtk_box_pack_start (GTK_BOX (options_vbox), hbox1, TRUE, TRUE, 0);
+
+	hbox2 = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (hbox2);
+	gtk_box_pack_start (GTK_BOX (hbox1), hbox2, TRUE, TRUE, 0);
+
+	del_name_box = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (del_name_box);
+	gtk_box_pack_start (GTK_BOX (hbox2), del_name_box, TRUE, TRUE, 0);
+
+	button_user = gtk_button_new_with_mnemonic (_("_User"));
+	gtk_widget_show (button_user);
+	gtk_box_pack_start (GTK_BOX (hbox1), button_user, FALSE, FALSE, 0);
+
+	track_option_vbox = gtk_vbox_new (FALSE, 0);
+	gtk_widget_show (track_option_vbox);
+	gtk_box_pack_start (GTK_BOX (options_vbox), track_option_vbox, TRUE, TRUE, 0);
+
+	tmp_str = g_strconcat ("<b>", _("Tracking Options"), "</b>", NULL);
+	track_options_label = gtk_label_new (tmp_str);
+	g_free (tmp_str);
+	gtk_widget_show (track_options_label);
+	gtk_box_pack_start (GTK_BOX (track_option_vbox), track_options_label, FALSE, FALSE, 6);
+	gtk_label_set_use_markup (GTK_LABEL (track_options_label), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (track_options_label), 0, 0.5);
+
+	delivery_check_button = gtk_check_button_new_with_mnemonic (_("Request a _delivery receipt for this message"));
+	gtk_widget_show (delivery_check_button);
+	gtk_box_pack_start (GTK_BOX (track_option_vbox), delivery_check_button, FALSE, FALSE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (delivery_check_button), 6);
+
+	read_check_button = gtk_check_button_new_with_mnemonic (_("Request a _read receipt for this message"));
+	gtk_widget_show (read_check_button);
+	gtk_box_pack_start (GTK_BOX (track_option_vbox), read_check_button, FALSE, FALSE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (read_check_button), 6);
+
+	priv->main = send_options;
+	priv->importance = imp_combo_box;
+	priv->sensitivity = sensitivity_combo_box;
+	priv->button_user = button_user;
+	priv->delegate_enabled = del_enabled_check;
+	priv->read_receipt = read_check_button;
+	priv->delivery_receipt = delivery_check_button;
+	priv->importance_label = importance_label;
+	priv->sensitivity_label = sensitivity_label;
+
+	send_options =  gtk_widget_get_toplevel (priv->main);
+	if (parent)
+		gtk_window_set_transient_for (GTK_WINDOW (send_options),
+				      GTK_WINDOW (parent));
+
+	priv->proxy_name_selector = e_name_selector_new ();
+	name_selector_dialog = e_name_selector_peek_dialog (priv->proxy_name_selector);
+
+	name_selector_model = e_name_selector_peek_model (priv->proxy_name_selector);
+	e_name_selector_model_add_section (name_selector_model, "Add User", _("Add User"), NULL);
+
+	exchange_send_options_fill_widgets_with_data (sod);
+
+	if (options->delegate_address) {
+		e_name_selector_model_peek_section (name_selector_model, "Add User", NULL, &destination_store);
+		des = e_destination_new ();
+		e_destination_set_email (des, options->delegate_email);
+		e_destination_set_name (des, options->delegate_name);
+		e_destination_store_append_destination (destination_store, des);
+		g_object_unref (des);
+	}
+
+	g_signal_connect ((GtkButton *) priv->button_user, "clicked",
+				G_CALLBACK (address_button_clicked), sod);
+	g_signal_connect (name_selector_dialog, "response",
+				G_CALLBACK (addressbook_dialog_response), sod);
+	g_signal_connect (GTK_DIALOG (priv->main), "response",
+				G_CALLBACK(exchange_send_options_cb), sod);
+	g_signal_connect ((GtkCheckButton *) priv->delegate_enabled, "toggled",
+				G_CALLBACK(delegate_option_toggled), sod);
+
+	name_selector_entry = e_name_selector_peek_section_entry (priv->proxy_name_selector,
+									"Add User");
+	g_signal_connect (name_selector_entry, "changed", G_CALLBACK (addressbook_entry_changed), sod);
+
+	/* The name box is just a container. The name_selector_entry is added to it. This Widget
+	   is created dynamically*/
+	gtk_container_add ((GtkContainer *) del_name_box, (GtkWidget *) name_selector_entry);
+	gtk_widget_show ((GtkWidget *) name_selector_entry);
+	gtk_widget_grab_focus ((GtkWidget *) name_selector_entry);
+
+	gtk_window_set_modal ((GtkWindow *) priv->main, TRUE);
+	gtk_widget_show (priv->main);
+
+	return TRUE;
+}
+
+static void
+exchange_sendoptions_dialog_class_init (GObjectClass *object)
+{
+	ExchangeSendOptionsDialogClass *klass;
+	GObjectClass *object_class;
+
+	klass = EXCHANGE_SENDOPTIONS_DIALOG_CLASS (object);
+	parent_class = g_type_class_peek_parent (klass);
+	object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = exchange_sendoptions_dialog_finalize;
+	object_class->dispose = exchange_sendoptions_dialog_dispose;
+	signals[SOD_RESPONSE] = g_signal_new ("sod_response",
+			G_TYPE_FROM_CLASS (klass),
+			G_SIGNAL_RUN_FIRST,
+			G_STRUCT_OFFSET (ExchangeSendOptionsDialogClass, esod_response),
+			NULL, NULL,
+			g_cclosure_marshal_VOID__INT,
+			G_TYPE_NONE, 1,
+			G_TYPE_INT);
+
+}
+
+static void
+exchange_sendoptions_dialog_init (GObject *object)
+{
+
+	ExchangeSendOptionsDialog *sod;
+	ExchangeSendOptionsDialogPrivate *priv;
+	ExchangeSendOptions *new;
+
+	sod = EXCHANGE_SENDOPTIONS_DIALOG (object);
+	new = g_new0 (ExchangeSendOptions, 1);
+
+	priv = g_new0 (ExchangeSendOptionsDialogPrivate, 1);
+
+	sod->priv = priv;
+	sod->options = new;
+	sod->options->send_as_del_enabled = FALSE;
+	sod->options->delivery_enabled = FALSE;
+	sod->options->read_enabled = FALSE;
+	sod->options->importance = E_IMP_NORMAL;
+	sod->options->sensitivity = E_SENSITIVITY_NORMAL;
+
+	priv->main = NULL;
+	priv->importance = NULL;
+	priv->sensitivity = NULL;
+	priv->sensitivity_label = NULL;
+	priv->importance_label = NULL;
+	priv->button_user = NULL;
+	priv->proxy_name_selector = NULL;
+	priv->read_receipt = NULL;
+	priv->delivery_receipt = NULL;
+
+}
+
+static void
+exchange_sendoptions_dialog_finalize (GObject *object)
+{
+	ExchangeSendOptionsDialog *sod = (ExchangeSendOptionsDialog *)object;
+	ExchangeSendOptionsDialogPrivate *priv;
+
+	g_return_if_fail (EXCHANGE_IS_SENDOPTIONS_DIALOG (sod));
+	priv = sod->priv;
+
+	g_free (priv->help_section);
+
+	if (sod->options) {
+		g_free (sod->options);
+		sod->options = NULL;
+	}
+
+	if (sod->priv) {
+		g_free (sod->priv);
+		sod->priv = NULL;
+	}
+
+	if (parent_class->finalize)
+		(* parent_class->finalize) (object);
+
+}
+
+static void
+exchange_sendoptions_dialog_dispose (GObject *object)
+{
+	ExchangeSendOptionsDialog *sod = (ExchangeSendOptionsDialog *) object;
+
+	g_return_if_fail (EXCHANGE_IS_SENDOPTIONS_DIALOG (sod));
+
+	if (parent_class->dispose)
+		(* parent_class->dispose) (object);
+
+}
+
diff --git a/eplugin/exchange-send-options.h b/eplugin/exchange-send-options.h
new file mode 100644
index 0000000..131fee0
--- /dev/null
+++ b/eplugin/exchange-send-options.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * 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:
+ *		Raghavendran R <raghavguru7@gmail.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __EXCHANGE_SENDOPTIONS_DIALOG_H__
+#define __EXCHANGE_SENDOPTIONS_DIALOG_H__
+
+#include <gtk/gtk.h>
+
+#define EXCHANGE_TYPE_SENDOPTIONS_DIALOG       (exchange_sendoptions_dialog_get_type ())
+#define EXCHANGE_SENDOPTIONS_DIALOG(obj)       (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_TYPE_SENDOPTIONS_DIALOG, ExchangeSendOptionsDialog))
+#define EXCHANGE_SENDOPTIONS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_TYPE_SENDOPTIONS_DIALOG, ExchangeSendOptionsDialogClass))
+#define EXCHANGE_IS_SENDOPTIONS_DIALOG(obj)    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_TYPE_SENDOPTIONS_DIALOG))
+#define EXCHANGE_IS_SENDOPTIONS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EXCHANGE_TYPE_SENDOPTIONS_DIALOG))
+
+typedef struct _ExchangeSendOptionsDialog		ExchangeSendOptionsDialog;
+typedef struct _ExchangeSendOptionsDialogClass		ExchangeSendOptionsDialogClass;
+typedef struct _ExchangeSendOptionsDialogPrivate	ExchangeSendOptionsDialogPrivate;
+
+typedef enum {
+	E_IMP_NORMAL,
+	E_IMP_HIGH,
+	E_IMP_LOW
+} ExchangeSendOptionsImp;
+
+typedef enum {
+	E_SENSITIVITY_NORMAL,
+	E_SENSITIVITY_PERSONAL,
+	E_SENSITIVITY_PRIVATE,
+	E_SENSITIVITY_CONFIDENTIAL
+} ExchangeSendOptionsSensitivity;
+
+/* We require the delegate_email and delegate_name to store the address of the delegator selected into
+   the destination store.
+*/
+typedef struct {
+	ExchangeSendOptionsImp importance;
+	ExchangeSendOptionsSensitivity sensitivity;
+	gboolean send_as_del_enabled;
+	gboolean delivery_enabled;
+	gboolean read_enabled;
+	const gchar *delegate_name;
+	const gchar *delegate_email;
+	const gchar *delegate_address;
+} ExchangeSendOptions;
+
+struct _ExchangeSendOptionsDialog {
+	GObject object;
+
+	ExchangeSendOptions *options;
+	/* Private data */
+	ExchangeSendOptionsDialogPrivate *priv;
+};
+
+struct _ExchangeSendOptionsDialogClass {
+	GObjectClass parent_class;
+	void (* esod_response) (ExchangeSendOptionsDialog *esd, gint status);
+};
+
+GType  exchange_sendoptions_dialog_get_type     (void);
+ExchangeSendOptionsDialog *exchange_sendoptions_dialog_new (void);
+gboolean exchange_sendoptions_dialog_run (ExchangeSendOptionsDialog *sod, GtkWidget *parent);
+#endif
+
diff --git a/eplugin/exchange-user-dialog.c b/eplugin/exchange-user-dialog.c
new file mode 100644
index 0000000..6cb20e6
--- /dev/null
+++ b/eplugin/exchange-user-dialog.c
@@ -0,0 +1,287 @@
+/*
+ * 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/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "exchange-user-dialog.h"
+#include "e2k-types.h"
+
+#include <bonobo-activation/bonobo-activation.h>
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-widget.h>
+#include <e-util/e-dialog-utils.h>
+#include <libedataserverui/e-name-selector.h>
+#include "e2k-xml-utils.h"
+
+struct _E2kUserDialogPrivate {
+	gchar *section_name;
+	ENameSelector *name_selector;
+	GtkWidget *entry, *parent_window;
+};
+
+#define PARENT_TYPE GTK_TYPE_DIALOG
+static GtkDialogClass *parent_class;
+
+static void parent_window_destroyed (gpointer dialog, GObject *where_parent_window_was);
+
+static void
+finalize (GObject *object)
+{
+	E2kUserDialog *dialog = E2K_USER_DIALOG (object);
+
+	g_free (dialog->priv->section_name);
+	g_free (dialog->priv);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+dispose (GObject *object)
+{
+	E2kUserDialog *dialog = E2K_USER_DIALOG (object);
+
+	if (dialog->priv->name_selector != NULL) {
+		g_object_unref (dialog->priv->name_selector);
+		dialog->priv->name_selector = NULL;
+	}
+
+	if (dialog->priv->parent_window) {
+		g_object_weak_unref (G_OBJECT (dialog->priv->parent_window),
+				     parent_window_destroyed, dialog);
+		dialog->priv->parent_window = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+class_init (E2kUserDialogClass *class)
+{
+	GObjectClass *object_class = (GObjectClass *) class;
+
+	parent_class = g_type_class_ref (GTK_TYPE_DIALOG);
+
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+}
+
+static void
+init (E2kUserDialog *dialog)
+{
+	dialog->priv = g_new0 (E2kUserDialogPrivate, 1);
+
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 6);
+}
+
+E2K_MAKE_TYPE (e2k_user_dialog, E2kUserDialog, class_init, init, PARENT_TYPE)
+
+static void
+parent_window_destroyed (gpointer user_data, GObject *where_parent_window_was)
+{
+	E2kUserDialog *dialog = user_data;
+
+	dialog->priv->parent_window = NULL;
+	gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
+}
+
+static void
+addressbook_dialog_response (ENameSelectorDialog *name_selector_dialog, gint response, gpointer data)
+{
+	gtk_widget_hide (GTK_WIDGET (name_selector_dialog));
+}
+
+static void
+addressbook_clicked_cb (GtkWidget *widget, gpointer data)
+{
+	E2kUserDialog *dialog = data;
+	E2kUserDialogPrivate *priv;
+	ENameSelectorDialog *name_selector_dialog;
+
+	priv = dialog->priv;
+
+	name_selector_dialog = e_name_selector_peek_dialog (priv->name_selector);
+	gtk_window_set_modal (GTK_WINDOW (dialog), FALSE);
+	gtk_widget_show (GTK_WIDGET (name_selector_dialog));
+}
+
+static gboolean
+e2k_user_dialog_construct (E2kUserDialog *dialog,
+			   GtkWidget *parent_window,
+			   const gchar *label_text,
+			   const gchar *section_name)
+{
+	E2kUserDialogPrivate *priv;
+	GtkWidget *hbox, *vbox, *label, *button;
+	ENameSelectorModel *name_selector_model;
+	ENameSelectorDialog *name_selector_dialog;
+
+	gtk_window_set_title (GTK_WINDOW (dialog), _("Select User"));
+	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+				GTK_STOCK_OK, GTK_RESPONSE_OK,
+				NULL);
+
+	e_dialog_set_transient_for (GTK_WINDOW (dialog), parent_window);
+
+	priv = dialog->priv;
+	priv->section_name = g_strdup (section_name);
+
+	priv->parent_window = parent_window;
+	g_object_weak_ref (G_OBJECT (parent_window),
+			   parent_window_destroyed, dialog);
+
+	/* Set up the actual select names bits */
+	priv->name_selector = e_name_selector_new ();
+
+	/* Listen for responses whenever the dialog is shown */
+	name_selector_dialog = e_name_selector_peek_dialog (priv->name_selector);
+	g_signal_connect (name_selector_dialog, "response",
+			  G_CALLBACK (addressbook_dialog_response), dialog);
+
+	name_selector_model = e_name_selector_peek_model (priv->name_selector);
+	/* FIXME Limit to one user */
+	e_name_selector_model_add_section (name_selector_model, section_name, section_name, NULL);
+
+	hbox = gtk_hbox_new (FALSE, 6);
+
+	label = gtk_label_new (label_text);
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6);
+
+	/* The vbox is a workaround for bug 43315 */
+	vbox = gtk_vbox_new (FALSE, 0);
+	priv->entry = GTK_WIDGET (e_name_selector_peek_section_entry (priv->name_selector, section_name));
+	gtk_box_pack_start (GTK_BOX (vbox), priv->entry, TRUE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 6);
+
+	button = gtk_button_new_with_label (_("Address Book..."));
+	g_signal_connect (button, "clicked",
+			  G_CALLBACK (addressbook_clicked_cb),
+			  dialog);
+	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 6);
+
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
+			    TRUE, TRUE, 6);
+	gtk_widget_show_all (hbox);
+
+	return TRUE;
+}
+
+/**
+ * e2k_user_dialog_new:
+ * @parent_window: The window invoking the dialog.
+ * @label_text: Text to label the entry in the initial dialog with
+ * @section_name: The section name for the select-names dialog
+ *
+ * Creates a new user selection dialog.
+ *
+ * Return value: A newly-created user selection dialog, or %NULL if
+ * the dialog could not be created.
+ **/
+GtkWidget *
+e2k_user_dialog_new (GtkWidget *parent_window,
+		     const gchar *label_text, const gchar *section_name)
+{
+	E2kUserDialog *dialog;
+
+	g_return_val_if_fail (GTK_IS_WINDOW (parent_window), NULL);
+	g_return_val_if_fail (label_text != NULL, NULL);
+	g_return_val_if_fail (section_name != NULL, NULL);
+
+	dialog = g_object_new (E2K_TYPE_USER_DIALOG, NULL);
+	if (!e2k_user_dialog_construct (dialog, parent_window,
+					label_text, section_name)) {
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+		return NULL;
+	}
+
+	return GTK_WIDGET (dialog);
+}
+
+/**
+ * e2k_user_dialog_get_user_list:
+ * @dialog: the dialog
+ *
+ * Gets the email addresses of the selected user from the dialog.
+ *
+ * Return value: the email addresses.
+ **/
+GList *
+e2k_user_dialog_get_user_list (E2kUserDialog *dialog)
+{
+	E2kUserDialogPrivate *priv;
+	EDestinationStore *destination_store;
+	GList *destinations;
+	GList *l;
+	GList *email_list = NULL;
+	EDestination *destination;
+
+	g_return_val_if_fail (E2K_IS_USER_DIALOG (dialog), NULL);
+
+	priv = dialog->priv;
+
+	destination_store = e_name_selector_entry_peek_destination_store (E_NAME_SELECTOR_ENTRY (priv->entry));
+	destinations = e_destination_store_list_destinations (destination_store);
+	if (!destinations)
+		return NULL;
+
+	for (l = destinations; l; l = g_list_next (l)) {
+		const gchar *mail;
+		destination = l->data;
+
+		mail = e_destination_get_email (destination);
+		if (mail && *mail)
+			email_list = g_list_prepend (email_list, g_strdup (mail));
+	}
+	g_list_free (destinations);
+
+	return email_list;
+}
+
+/**
+ * e2k_user_dialog_get_user:
+ * @dialog: the dialog
+ *
+ * Gets the email address of the selected user from the dialog.
+ *
+ * Return value: the email address, which must be freed with g_free().
+ **/
+gchar *
+e2k_user_dialog_get_user (E2kUserDialog *dialog)
+{
+	E2kUserDialogPrivate *priv;
+	EDestinationStore *destination_store;
+	GList *destinations;
+	EDestination *destination;
+	gchar *result = NULL;
+
+	g_return_val_if_fail (E2K_IS_USER_DIALOG (dialog), NULL);
+
+	priv = dialog->priv;
+
+	destination_store = e_name_selector_entry_peek_destination_store (E_NAME_SELECTOR_ENTRY (priv->entry));
+	destinations = e_destination_store_list_destinations (destination_store);
+	if (!destinations)
+		return NULL;
+
+	destination = destinations->data;
+	result = g_strdup (e_destination_get_email (destination));
+	g_list_free (destinations);
+
+	return result;
+}
diff --git a/eplugin/exchange-user-dialog.h b/eplugin/exchange-user-dialog.h
new file mode 100644
index 0000000..8b6134b
--- /dev/null
+++ b/eplugin/exchange-user-dialog.h
@@ -0,0 +1,56 @@
+/*
+ * 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:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __E2K_USER_DIALOG_H__
+#define __E2K_USER_DIALOG_H__
+
+#include <gtk/gtk.h>
+
+#define E2K_TYPE_USER_DIALOG		(e2k_user_dialog_get_type ())
+#define E2K_USER_DIALOG(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), E2K_TYPE_USER_DIALOG, E2kUserDialog))
+#define E2K_USER_DIALOG_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), E2K_TYPE_USER_DIALOG,	\
+					 E2kUserDialogClass))
+#define E2K_IS_USER_DIALOG(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), E2K_TYPE_USER_DIALOG))
+#define E2K_IS_USER_DIALOG_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), E2K_TYPE_USER_DIALOG))
+
+typedef struct _E2kUserDialog		E2kUserDialog;
+typedef struct _E2kUserDialogClass	E2kUserDialogClass;
+typedef struct _E2kUserDialogPrivate	E2kUserDialogPrivate;
+
+struct _E2kUserDialog {
+	GtkDialog parent;
+
+	/* Private data */
+	E2kUserDialogPrivate *priv;
+};
+
+struct _E2kUserDialogClass {
+	GtkDialogClass parent_class;
+};
+
+GType      e2k_user_dialog_get_type (void);
+GtkWidget *e2k_user_dialog_new      (GtkWidget     *parent_window,
+				     const gchar    *label_text,
+				     const gchar    *section_name);
+gchar      *e2k_user_dialog_get_user (E2kUserDialog *dialog);
+GList      *e2k_user_dialog_get_user_list (E2kUserDialog *dialog);
+
+#endif /* __E2K_USER_DIALOG_H__ */
diff --git a/eplugin/org-gnome-exchange-ab-subscription.xml b/eplugin/org-gnome-exchange-ab-subscription.xml
new file mode 100644
index 0000000..81181ca
--- /dev/null
+++ b/eplugin/org-gnome-exchange-ab-subscription.xml
@@ -0,0 +1,15 @@
+<Root>
+  <commands>
+    <cmd name="FolderSubscription" _label="Subscribe to Other User's Contacts"
+      _tip="Subscribe to Other User's Contacts"/>
+  </commands>
+
+  <menu>
+    <submenu name="File">
+      <placeholder name="FileOps">
+        <menuitem name="FolderSubscription" verb=""/>
+      </placeholder>
+    </submenu>
+  </menu>
+
+</Root>
diff --git a/eplugin/org-gnome-exchange-cal-subscription.xml b/eplugin/org-gnome-exchange-cal-subscription.xml
new file mode 100644
index 0000000..3b11479
--- /dev/null
+++ b/eplugin/org-gnome-exchange-cal-subscription.xml
@@ -0,0 +1,15 @@
+<Root>
+  <commands>
+    <cmd name="FolderSubscription" _label="Subscribe to Other User's Calendar"
+      _tip="Subscribe to Other User's Calendar"/>
+  </commands>
+
+  <menu>
+    <submenu name="File">
+      <placeholder name="FileOps">
+        <menuitem name="FolderSubscription" verb=""/>
+      </placeholder>
+    </submenu>
+  </menu>
+
+</Root>
diff --git a/eplugin/org-gnome-exchange-operations.eplug.xml b/eplugin/org-gnome-exchange-operations.eplug.xml
new file mode 100644
index 0000000..381ac94
--- /dev/null
+++ b/eplugin/org-gnome-exchange-operations.eplug.xml
@@ -0,0 +1,230 @@
+<?xml version="1.0"?>
+<e-plugin-list>
+  <e-plugin
+    type="shlib"
+    id="org.gnome.evolution.plugin.exchange-operations"
+    location="@PLUGINDIR@/liborg-gnome-exchange-operations@SOEXT@"
+    load-on-startup="true"
+    _name="Exchange Operations"
+    system_plugin="true">
+    <author name="Sushma Rai" email="rsushma@novell.com"/>
+    <author name="Praveen Kumar" email="kpraveen@novell.com"/>
+    <author name="Shakti Sen" email="shprasad@novell.com"/>
+    <author name="Raghavendran R" email="raghavguru7@gmail.com"/>	
+    <_description>Activates the Evolution-Exchange extension package.</_description>
+	
+    <hook class="org.gnome.evolution.mail.config:1.0">
+      	<group 
+		target="account" 
+		id="org.gnome.evolution.mail.config.accountEditor"
+		check="org_gnome_exchange_check_options"
+		commit="org_gnome_exchange_commit">
+		<item type="page" 
+	      		path="40.oof" 
+	      		_label="Exchange Settings"
+	      		factory="org_gnome_exchange_settings"/>
+                <item type="item_table"
+                        path="10.receive/10.config/20.owa"
+			factory="org_gnome_exchange_owa_url"/>
+		<item type="section"
+			path="10.receive/30.auth/00.exchange_auth"
+			factory="org_gnome_exchange_auth_section"/>
+      	</group>
+
+        <group
+                target="account"
+                id="org.gnome.evolution.mail.config.accountDruid"
+		check="org_gnome_exchange_check_options">
+                <item type="item_table"
+                        path="10.receive/10.config/20.owa"
+			factory="org_gnome_exchange_owa_url"/>
+		<item type="section"
+			path="10.receive/30.auth/00.exchange_auth"
+			factory="org_gnome_exchange_auth_section"/>
+	</group>
+
+        <group
+                target="account"
+                id="org.gnome.evolution.mail.config.accountWizard"
+		check="org_gnome_exchange_check_options">
+                <item type="item_table"
+                        path="10.receive/10.config/20.owa"
+			factory="org_gnome_exchange_owa_url"/>
+	</group>
+    </hook>
+
+    <hook class="org.gnome.evolution.calendar.config:1.0">
+	<group
+	     target="source"
+	     id="org.gnome.evolution.calendar.calendarProperties"
+	     check="e_exchange_calendar_check"
+	     commit="e_exchange_calendar_commit">
+                <item
+		 type="item_table"
+		 path="00.general/00.source/40.pcalendar"
+		 factory="e_exchange_calendar_pcalendar"/>
+        </group>
+    </hook>
+
+    <hook class="org.gnome.evolution.addressbook.config:1.0">
+        <group
+	     target="source"
+	     id="com.novell.evolution.addressbook.config.accountEditor"
+	     check="e_exchange_contacts_check"
+	     commit="e_exchange_contacts_commit">
+             <item
+		 type="item"
+		 path="00.general/10.display/40.pcontacts"
+		 factory="e_exchange_contacts_pcontacts"/>
+	</group>
+    </hook>
+
+	<hook class="org.gnome.evolution.mail.popup:1.0">
+		<menu id="org.gnome.evolution.mail.foldertree.popup" target="folder" factory = "org_gnome_exchange_folder_permissions">
+		</menu>
+	</hook> 
+	<hook class="org.gnome.evolution.calendar.popup:1.0">
+		<menu id="org.gnome.evolution.calendar.source.popup" target="source" factory="org_gnome_exchange_calendar_permissions">
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.calendar.popup:1.0">
+		<menu id="org.gnome.evolution.tasks.source.popup" target="source" factory="org_gnome_exchange_calendar_permissions">
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.addressbook.popup:1.0">
+		<menu id="org.gnome.evolution.addressbook.source.popup" target="source" factory="org_gnome_exchange_addressbook_permissions">
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.mail.bonobomenu:1.0">
+	<menu id="org.gnome.evolution.mail.browser" target="select">
+	<ui file="@PLUGINDIR@/org-gnome-folder-permissions.xml"/>
+	<item
+		type="item"
+		verb="CheckFolderPermission"
+		path="/commands/CheckFolderPermission"
+		enable="all"
+		activate="org_gnome_exchange_menu_folder_permissions"/>
+	</menu>
+	</hook>
+	<hook class="org.gnome.evolution.calendar.bonobomenu:1.0">
+	<menu id="org.gnome.evolution.calendar.view" target="select">
+	<ui file="@PLUGINDIR@/org-gnome-folder-permissions.xml"/>
+	<item
+		type="item"
+		verb="CheckFolderPermission"
+		path="/commands/CheckFolderPermission"
+		enable="all"
+		activate="org_gnome_exchange_menu_cal_permissions"/>
+	</menu>
+	</hook>
+	<hook class="org.gnome.evolution.calendar.bonobomenu:1.0">
+	<menu id="org.gnome.evolution.tasks.view" target="select">
+	<ui file="@PLUGINDIR@/org-gnome-folder-permissions.xml"/>
+	<item
+		type="item"
+		verb="CheckFolderPermission"
+		path="/commands/CheckFolderPermission"
+		enable="all"
+		activate="org_gnome_exchange_menu_tasks_permissions"/>
+	</menu>
+	</hook>
+	<hook class="org.gnome.evolution.addressbook.bonobomenu:1.0">
+	<menu id="org.gnome.evolution.addressbook.view" target="select">
+	<ui file="@PLUGINDIR@/org-gnome-folder-permissions.xml"/>
+	<item
+		type="item"
+		verb="CheckFolderPermission"
+		path="/commands/CheckFolderPermission"
+		enable="all"
+		activate="org_gnome_exchange_menu_ab_permissions"/>
+	</menu>
+	</hook>
+	<hook class="org.gnome.evolution.mail.bonobomenu:1.0">
+		<menu id="org.gnome.evolution.mail.browser" target="select">
+		<ui file="@PLUGINDIR@/org-gnome-folder-subscription.xml"/>
+		<item
+			type="item"
+			verb="FolderSubscription"
+			path="/commands/FolderSubscription"
+			enable="all"
+			activate="org_gnome_exchange_inbox_subscription"/>
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.calendar.bonobomenu:1.0">
+		<menu id="org.gnome.evolution.calendar.view" target="select">
+		<ui file="@PLUGINDIR@/org-gnome-exchange-cal-subscription.xml"/>
+		<item
+			type="item"
+			verb="FolderSubscription"
+			path="/commands/FolderSubscription"
+			enable="all"
+			activate="org_gnome_exchange_calendar_subscription"/>
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.calendar.bonobomenu:1.0">
+		<menu id="org.gnome.evolution.tasks.view" target="select">
+		<ui file="@PLUGINDIR@/org-gnome-exchange-tasks-subscription.xml"/>
+		<item
+			type="item"
+			verb="FolderSubscription"
+			path="/commands/FolderSubscription"
+			enable="all"
+			activate="org_gnome_exchange_tasks_subscription"/>
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.addressbook.bonobomenu:1.0">
+		<menu id="org.gnome.evolution.addressbook.view" target="select">
+		<ui file="@PLUGINDIR@/org-gnome-exchange-ab-subscription.xml"/>
+		<item
+			type="item"
+			verb="FolderSubscription"
+			path="/commands/FolderSubscription"
+			enable="all"
+			activate="org_gnome_exchange_addressbook_subscription"/>
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.calendar.popup:1.0">
+		<menu id="org.gnome.evolution.calendar.source.popup" 
+			target="source" 
+			factory="org_gnome_exchange_check_subscribed">
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.calendar.popup:1.0">
+		<menu id="org.gnome.evolution.tasks.source.popup" 
+			target="source" 
+			factory="org_gnome_exchange_check_subscribed">
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.addressbook.popup:1.0">
+		<menu id="org.gnome.evolution.addressbook.source.popup" 
+			target="source" 
+			factory="org_gnome_exchange_check_address_book_subscribed">
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.mail.popup:1.0">
+		<menu id="org.gnome.evolution.mail.foldertree.popup" 
+			target="folder" 
+			factory = "org_gnome_exchange_check_inbox_subscribed">
+		</menu>
+	</hook>
+	<hook class="org.gnome.evolution.mail.config:1.0">
+		<group id="org.gnome.evolution.mail.folderConfig" 
+			target="folder"
+			check= "exchange_show_folder_size_check">
+		<item 
+			type="page" 
+			path="10.size" 
+			_label="Size" 
+			factory="org_gnome_exchange_show_folder_size_factory"/>
+		</group>
+	</hook>
+	<hook class="org.gnome.evolution.mail.events:1.0">
+			<event
+			   id="composer.selectsendoption"
+			   handle="org_gnome_exchange_send_options"
+			   target="composer"
+			   enable="sendoption"
+			/>
+	</hook>
+  </e-plugin>
+</e-plugin-list>
diff --git a/eplugin/org-gnome-exchange-operations.error.xml b/eplugin/org-gnome-exchange-operations.error.xml
new file mode 100644
index 0000000..37ed0aa
--- /dev/null
+++ b/eplugin/org-gnome-exchange-operations.error.xml
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<error-list domain="org-gnome-exchange-operations">
+
+ <error id="single-account-error" type="error">
+  <_primary>You may only configure a single Exchange account.</_primary>
+ </error>
+
+ <error id="apply-restart" type="info">
+  <_primary>Please restart Evolution for changes to take effect</_primary>
+  <_secondary>Changes to options for Exchange account "{0}" will only take effect after restarting Evolution.</_secondary>
+ </error>
+
+ <error id="remove-quit" type="info">
+  <_primary>The Exchange account will be removed when you quit Evolution</_primary>
+ </error>
+
+ <error id="disable-quit" type="info">
+  <_primary>The Exchange account will be disabled when you quit Evolution</_primary>
+ </error>
+
+ <error id="state-read-error" type="error">
+  <_primary>Could not read out-of-office state</_primary>
+ </error>
+
+ <error id="state-update-error" type="error">
+  <_primary>Could not update out-of-office state</_primary>
+ </error>
+
+ <error id="config-error" type="error">
+  <_primary>Cannot change password due to configuration problems.</_primary>
+ </error>
+ 
+ <error id="password-weak-error" type="error">
+  <_primary>Server rejected password because it is too weak.</_primary>
+  <_secondary>Try again with a different password.</_secondary>
+ </error>
+
+ <error id="password-change-error" type="error">
+  <_primary>Could not change password.</_primary>
+ </error>
+
+ <error id="password-change-success" type="info">
+  <_primary>Password successfully changed.</_primary>
+ </error>
+
+ <error id="account-offline" type="info">
+  <_primary>Exchange Account is offline.</_primary>
+  <_secondary>Cannot display folders.</_secondary>
+ </error>
+
+ <error id="exchange-settings-offline" type="info">
+  <_primary>Exchange Account is offline.</_primary>
+  <_secondary>Cannot access the "Exchange settings" tab in offline mode.</_secondary>
+ </error>
+
+ <error id="account-offline-generic" type="info">
+  <_primary>Exchange Account is offline.</_primary>
+  <_secondary>Cannot perform the operation.</_secondary>
+ </error>
+
+ <error id="password-incorrect" type="error">
+  <_primary>Could not authenticate to server.</_primary>
+  <_secondary>Make sure the username and password are correct and try again.</_secondary>
+ </error>
+
+ <error id="account-domain-error" type="error">
+  <_primary>Could not authenticate to server.</_primary>
+  <_secondary xml:space="preserve">This probably means that your server requires 
+you to specify the Windows domain name 
+as part of your username (eg, &quot;DOMAIN\user&quot;).
+
+Or you might have just typed your password wrong.</_secondary>
+ </error>
+
+ <error id="account-mailbox-na" type="error">
+  <_primary>Mailbox for {0} is not on this server.</_primary>
+ </error>
+
+ <error id="account-version-error" type="error">
+  <_primary>The Exchange server is not compatible with Exchange Connector.</_primary>
+  <_secondary xml:space="preserve">The server is running Exchange 5.5. Exchange Connector 
+supports Microsoft Exchange 2000 and 2003 only.</_secondary>
+ </error>
+
+ <error id="account-wss-error" type="error">
+  <_primary>Could not find Exchange Web Storage System.</_primary>
+  <_secondary>If OWA is running on a different path, you must specify that in the account configuration dialog.</_secondary>
+ </error>
+
+ <error id="account-no-mailbox" type="info">
+  <_primary>No mailbox for user {0} on {1}.</_primary>
+ </error>
+
+ <error id="account-resolve-error" type="error">
+  <_primary>Could not locate server {0}.</_primary>
+  <_secondary>Make sure the server name is spelled correctly and try again.</_secondary>
+ </error>
+
+ <error id="account-connect-error" type="error">
+  <_primary>Could not connect to server {0}.</_primary>
+  <_secondary>Make sure the URL is correct and try again.</_secondary>
+ </error>
+
+ <error id="password-expired" type="error">
+  <_primary>Your password has expired.</_primary>
+ </error>
+
+ <error id="account-unknown-error" type="error">
+  <_primary>Could not connect to server {0}.</_primary>
+  <_secondary>Unknown error.</_secondary>
+ </error>
+
+ <error id="account-quota-error" type="error">
+  <_primary>You have exceeded your quota for storing mail on this server.</_primary>
+  <_secondary>Your current usage is: {0} KB. You will not be able to either send or receive mail now.</_secondary>
+ </error>
+
+ <error id="account-quota-send-error" type="warning">
+  <_primary>You are nearing your quota available for storing mail on this server.</_primary>
+  <_secondary>Your current usage is: {0} KB. You will not be able to send mail until you clear up some space by deleting some mail.</_secondary>
+ </error>
+
+ <error id="account-quota-warn" type="warning">
+  <_primary>You are nearing your quota available for storing mail on this server.</_primary>
+  <_secondary>Your current usage is: {0} KB. Try to clear up some space by deleting some mail.</_secondary>
+ </error>
+
+ <error id="connect-exchange-error" type="error">
+  <_primary>Could not connect to Exchange server.</_primary>
+  <_secondary xml:space="preserve">Exchange Connector requires access to certain
+functionality on the Exchange Server that appears
+to be disabled or blocked. (This is usually 
+unintentional.) Your Exchange Administrator will 
+need to enable this functionality in order for 
+you to be able to use Evolution Exchange Connector.
+
+For information to provide to your Exchange 
+administrator, please follow the link below:
+
+{0}
+  </_secondary>
+ </error>
+
+ <error id="configure-error" type="error">
+  <_secondary xml:space="preserve">Could not configure Exchange account because 
+an unknown error occurred. Check the URL, 
+username, and password, and try again.</_secondary>
+ </error>
+
+ <error id="delegates-no-gcs-error" type="error">
+  <_primary>No Global Catalog server configured for this account.</_primary>
+  <_secondary>Unable to edit delegates.</_secondary>
+ </error>
+
+ <error id="acl-no-gcs-error" type="error">
+  <_primary>Unable to add user to access control list:</_primary>
+  <_secondary>No Global Catalog server configured for this account.</_secondary>
+ </error>
+
+ <error id="delegates-perm-read-error" type="error">
+  <_primary>Could not read folder permissions.</_primary>
+  <_secondary>Unable to edit delegates.</_secondary>
+ </error>
+
+ <error id="perm-read-error" type="error">
+  <_primary>Could not read folder permissions</_primary>
+ </error>
+
+ <error id="perm-deter-error" type="error">
+  <_primary>Unable to edit delegates.</_primary>
+  <_secondary>Could not determine folder permissions for delegates.</_secondary>
+ </error>
+
+ <error id="delegate-error" type="error">
+  <_primary>Could not make {0} a delegate</_primary>
+ </error>
+
+ <error id="delegate-own-error" type="error">
+  <_primary>You cannot make yourself your own delegate</_primary>
+ </error>
+
+ <error id="delegate-existing" type="info">
+  <_primary>{0} is already a delegate</_primary>
+ </error>
+
+ <error id="delegate-fail-error" type="error">
+  <_primary>Failed to update delegates:</_primary>
+  <_secondary>{0}</_secondary>
+ </error>
+
+<error id="no-delegate-selected" type="info">
+  <_primary>Please enter a Delegate's ID or deselect the Send as a Delegate option.</_primary>
+ </error>
+
+<error id="more-delegates-selected" type="info">
+  <_primary>You are permitted to send a message on behalf of only one delegator at a time.</_primary>
+ </error>
+
+
+ <error id="select-user" type="info">
+  <_primary>Please select a user.</_primary>
+ </error>
+
+ <error id="perm-update-error" type="error">
+  <_primary>Could not update folder permissions.</_primary>
+  <_secondary>{0}</_secondary>
+ </error>
+
+ <error id="no-user-error" type="error">
+  <_primary>No such user {0}</_primary>
+ </error>
+
+ <error id="acl-add-error" type="error">
+  <_primary>{0} cannot be added to an access control list</_primary>
+ </error>
+
+ <error id="perm-unknown-error" type="error">
+  <_primary>Unknown error looking up {0}</_primary>
+ </error>
+
+ <error id="perm-existing-error" type="error">
+  <_primary>{0} is already in the list</_primary>
+ </error>
+
+ <error id="folder-exists-error" type="error">
+  <_primary>Folder already exists</_primary>
+ </error>
+
+ <error id="folder-restart-evo" type="error">
+  <_primary>Evolution requires a restart to load the subscribed user's mailbox</_primary>
+ </error>
+
+ <error id="folder-doesnt-exist-error" type="error">
+  <_primary>Folder does not exist</_primary>
+ </error>
+
+ <error id="folder-perm-error" type="error">
+  <_primary>Permission denied</_primary>
+ </error>
+
+ <error id="folder-unknown-type" type="error">
+  <_primary>Unknown type</_primary>
+ </error>
+
+ <error id="folder-offline-error" type="error">
+  <_primary>Folder offline</_primary>
+ </error>
+
+ <error id="folder-unsupported-error" type="error">
+  <_primary>Unsupported operation</_primary>
+ </error>
+
+ <error id="folder-no-gc-error" type="error">
+  <_primary>Global Catalog Server is not reachable</_primary>
+  <_secondary>Please make sure the Global Catalog Server name is correct.</_secondary> 
+ </error>
+
+ <error id="folder-generic-error" type="error">
+  <_primary>Generic error</_primary>
+ </error>
+
+</error-list>
+
diff --git a/eplugin/org-gnome-exchange-tasks-subscription.xml b/eplugin/org-gnome-exchange-tasks-subscription.xml
new file mode 100644
index 0000000..bb63c93
--- /dev/null
+++ b/eplugin/org-gnome-exchange-tasks-subscription.xml
@@ -0,0 +1,15 @@
+<Root>
+  <commands>
+    <cmd name="FolderSubscription" _label="Subscribe to Other User's Tasks"
+      _tip="Subscribe to Other User's Tasks"/>
+  </commands>
+
+  <menu>
+    <submenu name="File">
+      <placeholder name="FileOps">
+        <menuitem name="FolderSubscription" verb=""/>
+      </placeholder>
+    </submenu>
+  </menu>
+
+</Root>
diff --git a/eplugin/org-gnome-folder-permissions.xml b/eplugin/org-gnome-folder-permissions.xml
new file mode 100644
index 0000000..785034d
--- /dev/null
+++ b/eplugin/org-gnome-folder-permissions.xml
@@ -0,0 +1,14 @@
+<Root>
+  <commands>
+    <cmd name="CheckFolderPermission" _label="Permissions..."
+      _tip="Check folder permissions"/>
+  </commands>
+
+  <menu>
+    <submenu name="File">
+      <placeholder name="FileOps">
+        <menuitem name="CheckFolderPermission" verb=""/>
+      </placeholder>
+    </submenu>
+  </menu>
+</Root>
diff --git a/eplugin/org-gnome-folder-subscription.xml b/eplugin/org-gnome-folder-subscription.xml
new file mode 100644
index 0000000..3f65e94
--- /dev/null
+++ b/eplugin/org-gnome-folder-subscription.xml
@@ -0,0 +1,16 @@
+<Root>
+  <commands>
+    <cmd name="FolderSubscription" _label="Subscribe to Other User's Folder"
+      _tip="Subscribe to Other User's Folder"/>
+  </commands>
+
+  <menu>
+    <submenu name="File">
+      <placeholder name="FileOps">
+        <menuitem name="FolderSubscription" verb=""/>
+      </placeholder>
+    </submenu>
+
+
+  </menu>
+</Root>
