[evolution-patches] patch for 'Subscribe/Unsubscribe Folder' operation in exchange component



Hi,

I am sending a patch for 'Subscribe/Unsubscribe Folder' of exchange component. Please review it.

I have created a menu-item named 'Subscribe to other user's Folder' in 'Folder' menu. Also, if a folder is subscribed, the right click of that folder will display a menu-item named 'Unsubscribe Folder' which will remove the subscribed folder.

I have attached 2 patches 1) for e-d-s changes and 2) for changes in evolution/plugins/.

Please have a look at the patches.

Thanks,
Shakti


? Makefile
? Makefile.in
? exchange-folder-subscription.c
? exchange-folder-subscription.h
? exchange-folder.c
? org-gnome-exchange-operations.eplug
? org-gnome-folder-subscription.xml
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/plugins/exchange-operations/Makefile.am,v
retrieving revision 1.3
diff -u -p -r1.3 Makefile.am
--- Makefile.am	1 Jul 2005 10:06:24 -0000	1.3
+++ Makefile.am	7 Jul 2005 05:49:22 -0000
@@ -10,7 +10,7 @@ INCLUDES = -I .						\
 
 @EVO_PLUGIN_RULE@
 
-plugin_DATA = org-gnome-exchange-operations.eplug
+plugin_DATA = org-gnome-exchange-operations.eplug org-gnome-folder-subscription.xml
 plugin_LTLIBRARIES = liborg-gnome-exchange-operations.la
 
 liborg_gnome_exchange_operations_la_SOURCES = 		\
@@ -22,7 +22,10 @@ liborg_gnome_exchange_operations_la_SOUR
 	exchange-contacts.c				\
 	exchange-change-password.c			\
 	exchange-change-password.h			\
-	exchange-account-setup.c				
+	exchange-account-setup.c			\	
+	exchange-folder-subscription.c			\
+	exchange-folder-subscription.h			\
+	exchange-folder.c
 
 liborg_gnome_exchange_operations_la_LIBADD = 		\
 	$(top_builddir)/e-util/libeutil.la 			\
@@ -39,5 +42,6 @@ glade_DATA =							\
 
 EXTRA_DIST = 							\
 	org-gnome-exchange-operations.eplug.in			\
+	org-gnome-folder-subscription.xml			\
 	$(glade_DATA)
 
Index: exchange-account-setup.c
===================================================================
RCS file: /cvs/gnome/evolution/plugins/exchange-operations/exchange-account-setup.c,v
retrieving revision 1.6
diff -u -p -r1.6 exchange-account-setup.c
--- exchange-account-setup.c	1 Jul 2005 10:06:24 -0000	1.6
+++ exchange-account-setup.c	7 Jul 2005 05:49:23 -0000
@@ -124,7 +124,7 @@ btn_chpass_clicked (GtkButton *button, g
 	}
 	new_password = exchange_get_new_password (old_password, TRUE);
 	g_print ("Current password is \"%s\"\n", old_password);
-	exchange_account_set_password (account, old_password, new_password);
+	//exchange_account_set_password (account, old_password, new_password);
 	
 	g_free (old_password);
 	g_free (new_password);	
Index: org-gnome-exchange-operations.eplug.in
===================================================================
RCS file: /cvs/gnome/evolution/plugins/exchange-operations/org-gnome-exchange-operations.eplug.in,v
retrieving revision 1.1
diff -u -p -r1.1 org-gnome-exchange-operations.eplug.in
--- org-gnome-exchange-operations.eplug.in	13 Jun 2005 12:39:20 -0000	1.1
+++ org-gnome-exchange-operations.eplug.in	7 Jul 2005 05:49:25 -0000
@@ -8,6 +8,7 @@
     name="Exchange Operations">
     <author name="Sushma Rai" email="rsushma novell com"/>
     <author name="Praveen Kumar" email="kpraveen novell com"/>
+    <author name="Shakti Sen" email="shprasad novell com"/>
     <description>A plugin that handles a collection of Exchange account specific operations and features.</description>
 	
     <hook class="org.gnome.evolution.mail.config:1.0">
@@ -70,6 +71,33 @@
 		 factory="e_exchange_contacts_pcontacts"/>
             </group>
      </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_folder_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_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_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_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_check_inbox_subscribed">
+		</menu>
+	</hook>
 
   </e-plugin>
 </e-plugin-list>
--- /dev/null	2004-08-25 23:04:59.000000000 +0530
+++ exchange-folder-subscription.c	2005-07-07 11:12:01.177558482 +0530
@@ -0,0 +1,229 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Shakti Sen <shprasad novell com>
+ *  Copyright (C) 2005 Novell, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include <glade/glade-xml.h>
+#include <gtk/gtk.h>
+#include <exchange/e-folder.h>
+#include <exchange-account.h>
+#include <exchange-hierarchy.h>
+#include "exchange-hierarchy-foreign.h"
+#include <exchange/e2k-types.h>
+#include <exchange/exchange-types.h>
+#include <e2k-propnames.h>
+#include <libedataserver/e-xml-hash-utils.h>
+#include <libedataserverui/e-name-selector.h>
+#include "exchange-config-listener.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 (GladeXML *glade_xml, ENameSelector **name_selector_ret)
+{
+	ENameSelector *name_selector;
+	ENameSelectorModel *name_selector_model;
+	ENameSelectorDialog *name_selector_dialog;
+	GtkWidget *placeholder;
+	GtkWidget *widget;
+	GtkWidget *button;
+
+	placeholder = glade_xml_get_widget (glade_xml, "user-picker-placeholder");
+	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);
+
+	button = glade_xml_get_widget (glade_xml, "button-user");
+	g_signal_connect (button, "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 (GladeXML *glade_xml)
+{
+	GtkWidget *combo;
+	GList *string_list;
+	char *strings[] = {
+		"Calendar",
+		"Inbox",
+		"Contacts",
+		"Tasks",
+		NULL
+		/* FIXME: Should these be translated?  */
+	};
+	int i;
+
+	combo = glade_xml_get_widget (glade_xml, "folder-name-combo");
+	g_assert (GTK_IS_COMBO (combo));
+
+	string_list = NULL;
+	for (i = 0; strings[i] != NULL; i ++)
+		string_list = g_list_append (string_list, strings[i]);
+	gtk_combo_set_popdown_strings (GTK_COMBO (combo), string_list);
+	g_list_free (string_list);
+
+	gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), "Calendar");
+}
+
+static void
+folder_name_entry_changed_callback (GtkEditable *editable,
+                                    void *data)
+{
+	GtkDialog *dialog = GTK_DIALOG (data);
+	const char *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
+setup_server_option_menu (GladeXML *glade_xml, gchar *mail_account)
+{
+	GtkWidget *widget;
+	GtkWidget *menu;
+	GtkWidget *menu_item;
+
+	widget = glade_xml_get_widget (glade_xml, "server-option-menu");
+	g_return_if_fail (GTK_IS_OPTION_MENU (widget));
+
+	menu = gtk_menu_new ();
+	gtk_widget_show (menu);
+
+	menu_item = gtk_menu_item_new_with_label (mail_account);
+
+	gtk_widget_show (menu_item);
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
+
+
+	gtk_option_menu_set_menu (GTK_OPTION_MENU (widget), menu);
+
+	/* FIXME: Default to the current storage in the shell view.  */
+}
+
+
+gboolean
+create_folder_subscription_dialog (gchar *mail_account, gchar **user_email_address_ret, gchar **folder_name_ret)
+{
+	ENameSelector *name_selector;
+	GladeXML *glade_xml;
+	GtkWidget *dialog;
+	GtkWidget *name_selector_widget;
+	GtkWidget *folder_name_entry;
+	char *user_email_address = NULL;
+	int response;
+	EDestinationStore *destination_store;
+	GList *destinations;
+	EDestination *destination;
+	gchar *temp;
+
+
+	glade_xml = glade_xml_new (CONNECTOR_GLADEDIR "/e-foreign-folder-dialog.glade",
+				   NULL, NULL);
+	g_return_val_if_fail (glade_xml != NULL, FALSE);
+
+	dialog = glade_xml_get_widget (glade_xml, "dialog");
+	g_return_val_if_fail (dialog != NULL, FALSE);
+
+	name_selector_widget = setup_name_selector (glade_xml, &name_selector);
+	setup_server_option_menu (glade_xml, mail_account);
+	setup_folder_name_combo (glade_xml);
+	folder_name_entry = glade_xml_get_widget (glade_xml, "folder-name-entry");
+
+	/* 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 (folder_name_entry, "changed",
+			  G_CALLBACK (folder_name_entry_changed_callback), dialog);
+
+	while (TRUE) {
+		response = gtk_dialog_run (GTK_DIALOG (dialog));
+		if (response == GTK_RESPONSE_CANCEL) {
+			gtk_widget_destroy (dialog);
+			g_object_unref (name_selector);
+			return FALSE;
+		}
+		destination_store = e_name_selector_entry_peek_destination_store (E_NAME_SELECTOR_ENTRY (GTK_ENTRY (name_selector_widget)));
+		destinations = e_destination_store_list_destinations (destination_store);
+		if (!destinations) {
+			gtk_widget_destroy (dialog);
+			g_object_unref (name_selector);
+			return FALSE;
+		}
+		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;
+
+		/* 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_notice (dialog, GTK_MESSAGE_ERROR, ("Please select a user."));
+
+
+	}
+	gtk_widget_show_all (dialog);
+
+	if (user_email_address)
+		*user_email_address_ret = user_email_address;
+	*folder_name_ret = g_strdup (gtk_entry_get_text (GTK_ENTRY (folder_name_entry)));
+
+	gtk_widget_destroy (dialog);
+	g_object_unref (name_selector);
+	return TRUE;
+
+}
+
--- /dev/null	2004-08-25 23:04:59.000000000 +0530
+++ exchange-folder.c	2005-07-07 11:18:57.066971802 +0530
@@ -0,0 +1,417 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Shakti Sen <shprasad novell com>
+ *  Copyright (C) 2005 Novell, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkdialog.h>
+#include <gconf/gconf-client.h>
+#include <exchange-hierarchy.h>
+#include <calendar/gui/e-cal-popup.h>
+#include <mail/em-popup.h>
+#include <mail/em-menu.h>
+#include "exchange-operations.h"
+#include "addressbook/gui/widgets/eab-popup.h"
+
+
+void org_gnome_folder_subscription (EPlugin *ep, EMMenuTargetSelect *target);
+void org_gnome_check_subscribed (EPlugin *ep, ECalPopupTargetSource *target);
+void org_gnome_folder_unsubscribe (EPlugin *ep, EPopupItem *p, void *data);
+void org_gnome_check_address_book_subscribed (EPlugin *ep, EABPopupTargetSource *target);
+void org_gnome_folder_ab_unsubscribe (EPlugin *ep, EPopupItem *p, void *data);
+void org_gnome_check_inbox_subscribed (EPlugin *ep, EMPopupTargetFolder *target);
+void org_gnome_folder_inbox_unsubscribe (EPlugin *ep, EPopupItem *p, void *data);
+void popup_free (EPopup *ep, GSList *items, void *data);
+void popup_inbox_free (EPopup *ep, GSList *items, void *data);
+void popup_ab_free (EPopup *ep, GSList *items, void *data);
+
+#define CONF_KEY_SELECTED_CAL_SOURCES "/apps/evolution/calendar/display/selected_calendars"
+
+
+static EPopupItem popup_inbox_items[] = {
+	{ E_POPUP_ITEM, "29.inbox_unsubscribe", N_("Unsubscribe Folder..."), org_gnome_folder_inbox_unsubscribe, NULL, "stock_new-dir", 0, EM_POPUP_FOLDER_INFERIORS }
+};
+
+void
+popup_inbox_free (EPopup *ep, GSList *items, void *data)
+{
+	g_slist_free (items);
+}
+
+void
+org_gnome_folder_inbox_unsubscribe (EPlugin *ep, EPopupItem *p, void *data)
+{
+	// To be done:
+}
+
+void
+org_gnome_check_inbox_subscribed (EPlugin *ep, EMPopupTargetFolder *target)
+{
+	GSList *menus = NULL;
+	int i = 0;
+	GSList *accounts, *acc;
+	ExchangeAccount *account = NULL;
+	gchar *path = NULL;
+	gchar *sub_folder = NULL;
+
+	accounts = exchange_config_listener_get_accounts (exchange_global_config_listener);
+	for (acc = accounts; acc;  acc = acc->next) {
+		account = acc->data;
+	}
+
+	path = g_strdup_printf (target->uri + strlen ("exchange://") + strlen (account->account_filename));
+	sub_folder = strchr (path, '@');
+
+	if (!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);
+	g_free (path);
+}
+
+static EPopupItem popup_items[] = {
+	{ E_POPUP_ITEM, "29.calendar_unsubscribe", N_("Unsubscribe Folder..."), org_gnome_folder_unsubscribe, NULL, "stock_new-dir", 0, EM_POPUP_FOLDER_INFERIORS }
+};
+
+void
+popup_free (EPopup *ep, GSList *items, void *data)
+{
+	g_slist_free (items);
+}
+
+static EPopupItem popup_ab_items[] = {
+	{ E_POPUP_ITEM, "29.address_book_unsubscribe", N_("Unsubscribe Folder..."), org_gnome_folder_ab_unsubscribe, NULL, "stock_new-dir", 0, EM_POPUP_FOLDER_INFERIORS }
+};
+
+void
+popup_ab_free (EPopup *ep, GSList *items, void *data)
+{
+	g_slist_free (items);
+}
+
+void
+org_gnome_check_address_book_subscribed (EPlugin *ep, EABPopupTargetSource *target)  
+{
+	GSList *menus = NULL;
+	int i = 0;
+	ESource *source = NULL;
+	gchar *uri = NULL;
+	gchar *path = NULL;
+	char *sub_folder = NULL;
+	GSList *accounts, *acc;
+	ExchangeAccount *account = NULL;
+
+	accounts = exchange_config_listener_get_accounts (exchange_global_config_listener);
+	for (acc = accounts; acc;  acc = acc->next) {
+		account = acc->data;
+	}
+
+	source = e_source_selector_peek_primary_selection (target->selector);
+	uri = e_source_get_uri (source);
+	path = g_strdup_printf (uri + strlen ("exchange://") + strlen (account->account_filename));
+	sub_folder = strchr (path, '@');
+
+	if (!sub_folder)
+		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_check_subscribed (EPlugin *ep, ECalPopupTargetSource *target)
+{
+	GSList *menus = NULL;
+	int i = 0;
+	ESource *source = NULL;
+	gchar *ruri = NULL;
+	gchar *path = NULL;
+	char *sub_folder = NULL;
+	GSList *accounts, *acc;
+	ExchangeAccount *account = NULL;
+
+	accounts = exchange_config_listener_get_accounts (exchange_global_config_listener);
+	for (acc = accounts; acc;  acc = acc->next) {
+		account = acc->data;
+	}
+
+	source = e_source_selector_peek_primary_selection (target->selector);
+	ruri = e_source_peek_relative_uri (source);
+	path = g_strdup_printf (ruri + strlen (account->account_filename));
+	sub_folder = strchr (path, '@');
+
+	if (!sub_folder)
+		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, int response, gpointer data)
+{
+
+	if (response == GTK_RESPONSE_OK) {
+		GSList *accounts, *acc;
+		ExchangeAccount *account = NULL;
+		gchar *path = NULL;
+		gchar *uri = NULL;
+		const char *source_uid = NULL;
+		GConfClient *client;
+		ESourceGroup *source_group = NULL;
+		ESource *source = NULL;
+		EABPopupTargetSource *target = data;
+
+		client = gconf_client_get_default ();
+
+		accounts = exchange_config_listener_get_accounts (exchange_global_config_listener);
+		for (acc = accounts; acc;  acc = acc->next) {
+			account = acc->data;
+		}
+		source = e_source_selector_peek_primary_selection (target->selector);
+		uri = e_source_get_uri (source);
+		path = g_strdup_printf (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, int response, gpointer data)
+{
+
+	if (response == GTK_RESPONSE_OK) {
+		GSList *accounts, *acc;
+		GSList *ids, *node_to_be_deleted;
+		ExchangeAccount *account = NULL;
+		gchar *path = NULL;
+		gchar *ruri = NULL;
+		const char *source_uid = NULL;
+		GConfClient *client;
+		ESourceGroup *source_group = NULL;
+		ESource *source = NULL;
+		ECalPopupTargetSource *target = data;
+
+		client = gconf_client_get_default ();
+
+		accounts = exchange_config_listener_get_accounts (exchange_global_config_listener);
+		for (acc = accounts; acc;  acc = acc->next) {
+			account = acc->data;
+		}
+		source = e_source_selector_peek_primary_selection (target->selector);
+		ruri = e_source_peek_relative_uri (source);
+		source_uid = e_source_peek_uid (source);
+
+		path = g_strdup_printf (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_folder_ab_unsubscribe (EPlugin *ep, EPopupItem *p, void *data)
+{
+	GtkWidget *dialog = NULL;
+	EABPopupTargetSource *target = data;
+	ESource *source = NULL;
+	GSList *accounts, *acc;
+	ExchangeAccount *account = NULL;
+	gchar *title = NULL;
+	gchar *displayed_folder_name = NULL;
+	gint response;
+
+	accounts = exchange_config_listener_get_accounts (exchange_global_config_listener);
+	for (acc = accounts; acc;  acc = acc->next) {
+		account = acc->data;
+	}
+
+	source = e_source_selector_peek_primary_selection (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);
+	g_free (displayed_folder_name);
+
+	gtk_widget_show (dialog);
+	unsubscribe_dialog_ab_response (dialog, response, data);
+}
+void
+org_gnome_folder_unsubscribe (EPlugin *ep, EPopupItem *p, void *data)
+{
+	GtkWidget *dialog = NULL;
+	ECalPopupTargetSource *target = data;
+	ESource *source = NULL;
+	GSList *accounts, *acc;
+	ExchangeAccount *account = NULL;
+	gchar *title = NULL;
+	gchar *displayed_folder_name = NULL;
+	gint response;
+
+	accounts = exchange_config_listener_get_accounts (exchange_global_config_listener);
+	for (acc = accounts; acc;  acc = acc->next) {
+		account = acc->data;
+	}
+
+	source = e_source_selector_peek_primary_selection (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);
+	g_free (displayed_folder_name);
+
+	gtk_widget_show (dialog);
+	unsubscribe_dialog_response (dialog, response, data);
+}
+
+
+void
+org_gnome_folder_subscription (EPlugin *ep, EMMenuTargetSelect *target)
+{
+	GSList *accounts, *acc;
+	ExchangeAccount *account = NULL;
+	EFolder *folder = NULL;
+	ExchangeHierarchy *hier;
+	ExchangeAccountFolderResult result;
+	gchar *folder_display_name = NULL;
+	gchar *folder_type = NULL;
+	gchar *physical_uri = NULL;
+	gchar *user_email_address = NULL, *storage_name, *folder_name = NULL;
+
+	accounts = exchange_config_listener_get_accounts (exchange_global_config_listener);
+	for (acc = accounts; acc;  acc = acc->next) {
+		account = acc->data;
+	}
+
+	create_folder_subscription_dialog (account->account_name, &user_email_address, &folder_name);
+
+	if (user_email_address && folder_name)
+		result = exchange_account_discover_shared_folder (account, user_email_address, folder_name, &folder);
+
+	if (!folder) {
+		return;
+	}
+
+	hier = e_folder_exchange_get_hierarchy (folder);
+	folder_display_name = g_strdup_printf ("%s's %s", hier->owner_name, folder_name);
+	folder_type = e_folder_get_type_string (folder);
+	physical_uri = e_folder_get_physical_uri (folder);
+	if (!(strcmp (folder_type, "calendar")) ||
+	    !(strcmp (folder_type, "calendar/public"))) {
+			add_folder_esource (account, EXCHANGE_CALENDAR_FOLDER, folder_display_name, physical_uri);
+	}
+	else if (!(strcmp (folder_type, "tasks")) ||
+		 !(strcmp (folder_type, "tasks/public"))) {
+			add_folder_esource (account, EXCHANGE_TASKS_FOLDER, folder_display_name, physical_uri);
+	}
+	else if (!(strcmp (folder_type, "contacts")) ||
+		 !(strcmp (folder_type, "contacts/public")) ||
+		 !(strcmp (folder_type, "contacts/ldap"))) {
+			add_folder_esource (account, EXCHANGE_CONTACTS_FOLDER, folder_display_name, physical_uri);
+}
+
+g_free (folder_display_name);
+exchange_account_open_folder (account, g_strdup_printf ("/%s", user_email_address));
+}
+
--- /dev/null	2004-08-25 23:04:59.000000000 +0530
+++ org-gnome-folder-subscription.xml	2005-07-05 17:59:30.150635192 +0530
@@ -0,0 +1,17 @@
+<Root>
+  <commands>
+    <cmd name="FolderSubscription" _label="Subscribe to Other User's Folder"
+      _tip="Subscribe to Other User's Folder"/>
+  </commands>
+
+  <menu>
+    <placeholder name="FolderPlaceholder">
+      <submenu name="Folder">
+	<placeholder name="MessagesInFolder">
+	  <separator f="" name="emaillist5"/>
+	  <menuitem name="FolderSubscription" verb=""/>
+	</placeholder>
+      </submenu>
+    </placeholder>
+  </menu>
+</Root>
? Makefile
? Makefile.am-bak
? Makefile.in
? e-shell-marshal.c
? e-shell-marshal.h
? exchange-hierarchy-foreign.c
? exchange-hierarchy-foreign.h
? libexchange-storage-1.2.pc
? libexchange-storage.pc
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution-data-server/servers/exchange/storage/Makefile.am,v
retrieving revision 1.6
diff -u -p -r1.6 Makefile.am
--- Makefile.am	22 Jun 2005 11:35:09 -0000	1.6
+++ Makefile.am	7 Jul 2005 06:08:44 -0000
@@ -38,6 +38,8 @@ libexchange_storage_1_2_la_SOURCES =				
 	exchange-folder-size.h					\
 	exchange-hierarchy-favorites.c				\
 	exchange-hierarchy-favorites.h				\
+	exchange-hierarchy-foreign.c				\
+	exchange-hierarchy-foreign.h				\
 	exchange-hierarchy-gal.c				\
 	exchange-hierarchy-gal.h				\
 	exchange-hierarchy-somedav.c				\
@@ -90,6 +92,7 @@ libexchange_storageinclude_HEADERS = 			
 	exchange-hierarchy.h					\
 	exchange-hierarchy-somedav.h				\
 	exchange-hierarchy-webdav.h				\
+	exchange-hierarchy-foreign.h				\
 	exchange-oof.h						\
 	exchange-types.h					
 
Index: exchange-account.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/servers/exchange/storage/exchange-account.c,v
retrieving revision 1.3
diff -u -p -r1.3 exchange-account.c
--- exchange-account.c	28 Jun 2005 08:27:14 -0000	1.3
+++ exchange-account.c	7 Jul 2005 06:08:45 -0000
@@ -31,6 +31,7 @@
 #include "exchange-hierarchy-webdav.h"
 #include "exchange-hierarchy-favorites.h"
 // SURF :#include "exchange-hierarchy-foreign.h"
+#include "exchange-hierarchy-foreign.h"
 #include "exchange-hierarchy-gal.h"
 //#include "exchange-constants.h"
 #include "e-folder-exchange.h"
@@ -592,14 +593,11 @@ get_hierarchy_for (ExchangeAccount *acco
 	internal_uri_prefix = exchange_account_get_foreign_uri (account, entry,
 								NULL);
 
-#if 0
-SURF : This should move to plugins.
 	hier = exchange_hierarchy_foreign_new (account, hierarchy_name,
 					       physical_uri_prefix,
 					       internal_uri_prefix,
 					       entry->display_name,
 					       entry->email, source);
-#endif
 	g_free (hierarchy_name);
 	g_free (physical_uri_prefix);
 	g_free (internal_uri_prefix);
@@ -635,8 +633,7 @@ exchange_account_discover_shared_folder 
 	hier = g_hash_table_lookup (account->priv->foreign_hierarchies, email);
 	if (hier) {
 		g_free (email);
-		// SURF : return exchange_hierarchy_foreign_add_folder (hier, folder_name, folder);
-		return EXCHANGE_ACCOUNT_FOLDER_OK;
+		return exchange_hierarchy_foreign_add_folder (hier, folder_name, folder);
 	}
 
 	dd.user = user;
@@ -669,8 +666,7 @@ exchange_account_discover_shared_folder 
 	}
 
 	hier = get_hierarchy_for (account, entry);
-	// SURF : return exchange_hierarchy_foreign_add_folder (hier, folder_name, folder);
-	return EXCHANGE_ACCOUNT_FOLDER_OK;
+	return exchange_hierarchy_foreign_add_folder (hier, folder_name, folder);
 }
 
 void
@@ -719,11 +715,8 @@ exchange_account_remove_shared_folder (E
 
 	if (!get_folder (account, path, &folder, &hier))
 		return EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST;
-#if 0
-SURF :
 	if (!EXCHANGE_IS_HIERARCHY_FOREIGN (hier))
 		return EXCHANGE_ACCOUNT_FOLDER_UNSUPPORTED_OPERATION;
-#endif
 
 	return exchange_hierarchy_remove_folder (hier, folder);
 }
@@ -1294,8 +1287,6 @@ setup_account_hierarchies (ExchangeAccou
 	g_free (phys_uri_prefix);
 
 	/* Other users' folders */
-#if 0
-SURF :
 	d = opendir (account->storage_dir);
 	if (d) {
 		while ((dent = readdir (d))) {
@@ -1312,7 +1303,6 @@ SURF :
 		}
 		closedir (d);
 	}
-#endif
 
 	/* Scan the personal and favorite folders so we can resolve references
 	 * to the Calendar, Contacts, etc even if the tree isn't
--- /dev/null	2004-08-25 23:04:59.000000000 +0530
+++ exchange-hierarchy-foreign.c	2005-07-07 11:37:19.534655012 +0530
@@ -0,0 +1,592 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Copyright (C) 2002-2004 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* ExchangeHierarchyForeign: class for a hierarchy consisting of a
+ * selected subset of folders from another user's mailbox.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "exchange-hierarchy-foreign.h"
+#include "exchange-account.h"
+#include "e-folder-exchange.h"
+#include "e2k-propnames.h"
+#include "e2k-uri.h"
+#include "e2k-utils.h"
+//#include "exchange-config-listener.h"
+#include "exchange-types.h"
+#include "e2k-types.h"
+
+#include <libedataserver/e-xml-hash-utils.h>
+#include <libedataserver/e-source-list.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct _ExchangeHierarchyForeignPrivate {
+	GMutex *hide_private_lock;
+	gboolean checked_hide_private;
+};
+
+extern const char *exchange_localfreebusy_path;
+
+#define PARENT_TYPE EXCHANGE_TYPE_HIERARCHY_SOMEDAV
+static ExchangeHierarchySomeDAVClass *parent_class = NULL;
+
+static GPtrArray *get_hrefs (ExchangeHierarchySomeDAV *hsd);
+static ExchangeAccountFolderResult create_folder (ExchangeHierarchy *hier,
+						  EFolder *parent,
+						  const char *name,
+						  const char *type);
+static ExchangeAccountFolderResult remove_folder (ExchangeHierarchy *hier,
+						  EFolder *folder);
+static ExchangeAccountFolderResult scan_subtree (ExchangeHierarchy *hier,
+						 EFolder *folder,
+						 gboolean offline);
+static void finalize (GObject *object);
+
+static void
+class_init (GObjectClass *object_class)
+{
+	ExchangeHierarchyClass *hierarchy_class =
+		EXCHANGE_HIERARCHY_CLASS (object_class);
+	ExchangeHierarchySomeDAVClass *somedav_class =
+		EXCHANGE_HIERARCHY_SOMEDAV_CLASS (object_class);
+
+	parent_class = g_type_class_ref (PARENT_TYPE);
+
+	/* virtual method override */
+	object_class->finalize = finalize;
+
+	hierarchy_class->create_folder  = create_folder;
+	hierarchy_class->remove_folder  = remove_folder;
+	hierarchy_class->scan_subtree   = scan_subtree;
+
+	somedav_class->get_hrefs        = get_hrefs;
+}
+
+static void
+init (GObject *object)
+{
+	ExchangeHierarchyForeign *hfor = EXCHANGE_HIERARCHY_FOREIGN (object);
+	ExchangeHierarchy *hier = EXCHANGE_HIERARCHY (object);
+
+	hfor->priv = g_new0 (ExchangeHierarchyForeignPrivate, 1);
+	hfor->priv->hide_private_lock = g_mutex_new ();
+	hier->hide_private_items = TRUE;
+}
+
+static void
+finalize (GObject *object)
+{
+	ExchangeHierarchyForeign *hfor = EXCHANGE_HIERARCHY_FOREIGN (object);
+
+	g_mutex_free (hfor->priv->hide_private_lock);
+	g_free (hfor->priv);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+E2K_MAKE_TYPE (exchange_hierarchy_foreign, ExchangeHierarchyForeign, class_init, init, PARENT_TYPE)
+
+static const char *privacy_props[] = {
+	PR_DELEGATES_ENTRYIDS,
+	PR_DELEGATES_SEE_PRIVATE,
+};
+static const int n_privacy_props = sizeof (privacy_props) / sizeof (privacy_props[0]);
+
+static void
+check_hide_private (ExchangeHierarchy *hier)
+{
+	ExchangeHierarchyForeign *hfor = EXCHANGE_HIERARCHY_FOREIGN (hier);
+	E2kContext *ctx;
+	E2kHTTPStatus status;
+	E2kResult *results;
+	int nresults, i;
+	GPtrArray *entryids, *privflags;
+	GByteArray *entryid;
+	const char *my_dn, *delegate_dn;
+	char *uri;
+
+	g_mutex_lock (hfor->priv->hide_private_lock);
+
+	if (hfor->priv->checked_hide_private) {
+		g_mutex_unlock (hfor->priv->hide_private_lock);
+		return;
+	}
+
+	uri = e2k_uri_concat (hier->account->home_uri,
+			      "NON_IPM_SUBTREE/Freebusy%20Data/LocalFreebusy.EML");
+	ctx = exchange_account_get_context (hier->account);
+
+	status = e2k_context_propfind (ctx, NULL, uri,
+				       privacy_props, n_privacy_props,
+				       &results, &nresults);
+	g_free (uri);
+
+	hfor->priv->checked_hide_private = TRUE;
+
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status) || nresults == 0) {
+		g_mutex_unlock (hfor->priv->hide_private_lock);
+		return;
+	}
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (results[0].status) ||
+	    !results[0].props || nresults > 1) {
+		e2k_results_free (results, nresults);
+		g_mutex_unlock (hfor->priv->hide_private_lock);
+		return;
+	}
+
+	entryids  = e2k_properties_get_prop (results[0].props,
+					     PR_DELEGATES_ENTRYIDS);
+	privflags = e2k_properties_get_prop (results[0].props,
+					     PR_DELEGATES_SEE_PRIVATE);
+	if (entryids && privflags) {
+		my_dn = hier->account->legacy_exchange_dn;
+		for (i = 0; i < entryids->len && i < privflags->len; i++) {
+			entryid = entryids->pdata[i];
+			delegate_dn = e2k_entryid_to_dn (entryid);
+
+			if (delegate_dn &&
+			    !g_ascii_strcasecmp (delegate_dn, my_dn) &&
+			    privflags->pdata[i] &&
+			    atoi (privflags->pdata[i]))
+				hier->hide_private_items = FALSE;
+			break;
+		}
+	}
+
+	e2k_results_free (results, nresults);
+	g_mutex_unlock (hfor->priv->hide_private_lock);
+}
+
+static void
+remove_all_cb (ExchangeHierarchy *hier, EFolder *folder, gpointer user_data)
+{
+	exchange_hierarchy_removed_folder (hier, folder);
+}
+
+static void
+hierarchy_foreign_cleanup (ExchangeHierarchy *hier)
+{
+	char *mf_path;
+
+	exchange_hierarchy_webdav_offline_scan_subtree (hier, remove_all_cb,
+							NULL);
+
+	mf_path = e_folder_exchange_get_storage_file (hier->toplevel, "hierarchy.xml");
+	unlink (mf_path);
+	g_free (mf_path);
+
+	exchange_hierarchy_removed_folder (hier, hier->toplevel);
+}
+
+static const char *folder_props[] = {
+	E2K_PR_EXCHANGE_FOLDER_CLASS,
+	E2K_PR_HTTPMAIL_UNREAD_COUNT,
+	E2K_PR_DAV_DISPLAY_NAME,
+	PR_ACCESS
+};
+static const int n_folder_props = sizeof (folder_props) / sizeof (folder_props[0]);
+
+static ExchangeAccountFolderResult
+find_folder (ExchangeHierarchy *hier, const char *uri, EFolder **folder_out)
+{
+	ExchangeHierarchyWebDAV *hwd = EXCHANGE_HIERARCHY_WEBDAV (hier);
+	E2kContext *ctx = exchange_account_get_context (hier->account);
+	E2kHTTPStatus status;
+	E2kResult *results;
+	int nresults;
+	EFolder *folder;
+	const char *access;
+	int offline;
+
+	status = e2k_context_propfind (ctx, NULL, uri,
+				       folder_props, n_folder_props,
+				       &results, &nresults);
+	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) 
+		return exchange_hierarchy_webdav_status_to_folder_result (status);
+	if (nresults == 0)
+		return EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST;
+
+	access = e2k_properties_get_prop (results[0].props, PR_ACCESS);
+	if (!access || !atoi (access))
+		return EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED;
+
+	folder = exchange_hierarchy_webdav_parse_folder (hwd, hier->toplevel,
+							 &results[0]);
+	e2k_results_free (results, nresults);
+
+	if (!folder)
+		return EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST;
+
+	exchange_hierarchy_new_folder (hier, folder);
+
+	if (folder_out)
+		*folder_out = folder;
+	else
+		g_object_unref (folder);
+	return EXCHANGE_ACCOUNT_FOLDER_OK;
+}
+
+static struct {
+	const char *name, *prop;
+} std_folders[] = {
+	{ N_("Calendar"),	E2K_PR_STD_FOLDER_CALENDAR },
+	{ N_("Contacts"),	E2K_PR_STD_FOLDER_CONTACTS },
+	{ N_("Deleted Items"),	E2K_PR_STD_FOLDER_DELETED_ITEMS },
+	{ N_("Drafts"),		E2K_PR_STD_FOLDER_DRAFTS },
+	{ N_("Inbox"),		E2K_PR_STD_FOLDER_INBOX },
+	{ N_("Journal"),	E2K_PR_STD_FOLDER_JOURNAL },
+	{ N_("Notes"),		E2K_PR_STD_FOLDER_NOTES },
+	{ N_("Outbox"),		E2K_PR_STD_FOLDER_OUTBOX },
+	{ N_("Sent Items"),	E2K_PR_STD_FOLDER_SENT_ITEMS },
+	{ N_("Tasks"),		E2K_PR_STD_FOLDER_TASKS }
+};
+const static int n_std_folders = sizeof (std_folders) / sizeof (std_folders[0]);
+static ExchangeAccountFolderResult
+create_internal (ExchangeHierarchy *hier, EFolder *parent,
+		 const char *name, const char *type, EFolder **folder_out)
+{
+	ExchangeAccountFolderResult result;
+	char *literal_uri = NULL, *standard_uri = NULL;
+	const char *home_uri;
+	int i;
+	int offline;
+
+	/* For now, no nesting */
+	if (parent != hier->toplevel || strchr (name + 1, '/'))
+		return EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR;
+
+	check_hide_private (hier);
+
+	home_uri = e_folder_exchange_get_internal_uri (hier->toplevel);
+	literal_uri = e2k_uri_concat (home_uri, name);
+	if (exchange_account_get_folder (hier->account, literal_uri)) {
+		g_free (literal_uri);
+		if (exchange_hierarchy_is_empty (hier))
+			hierarchy_foreign_cleanup (hier);
+		return EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS;
+	}
+
+	for (i = 0; i < n_std_folders; i++) {
+		if (g_ascii_strcasecmp (std_folders[i].name, name) != 0 &&
+		    g_utf8_collate (_(std_folders[i].name), name) != 0)
+			continue;
+
+		standard_uri = exchange_account_get_standard_uri_for (
+			hier->account, home_uri, std_folders[i].prop);
+		if (!standard_uri)
+			break;
+		if (!strcmp (literal_uri, standard_uri)) {
+			g_free (standard_uri);
+			standard_uri = NULL;
+			break;
+		}
+
+		if (exchange_account_get_folder (hier->account, standard_uri)) {
+			g_free (standard_uri);
+			g_free (literal_uri);
+			if (exchange_hierarchy_is_empty (hier))
+				hierarchy_foreign_cleanup (hier);
+			return EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS;
+		}
+
+		break;
+	}
+
+	result = find_folder (hier, literal_uri, folder_out);
+	if (result == EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST && standard_uri)
+		result = find_folder (hier, standard_uri, folder_out);
+
+	g_free (literal_uri);
+	g_free (standard_uri);
+
+	/* If the hierarchy is now empty, then we must have just been
+	 * created but then the add failed. So remove it again.
+	 */
+	if (exchange_hierarchy_is_empty (hier))
+		hierarchy_foreign_cleanup (hier);
+
+	return result;
+}
+
+
+static ExchangeAccountFolderResult
+create_folder (ExchangeHierarchy *hier, EFolder *parent,
+	       const char *name, const char *type)
+{
+	return create_internal (hier, parent, name, type, NULL);
+}
+
+static ExchangeAccountFolderResult
+remove_folder (ExchangeHierarchy *hier, EFolder *folder)
+{
+	const char *folder_type, *physical_uri;
+
+	/* Temp Fix for remove fav folders. see #59168 */
+        /* remove ESources */
+        folder_type = e_folder_get_type_string (folder);
+        physical_uri = e_folder_get_physical_uri (folder);
+
+        if (strcmp (folder_type, "calendar") == 0) {
+                remove_folder_esource (hier->account,
+				       EXCHANGE_CALENDAR_FOLDER,
+				       physical_uri);
+        }
+        else if (strcmp (folder_type, "tasks") == 0) {
+                remove_folder_esource (hier->account,
+				       EXCHANGE_TASKS_FOLDER,
+				       physical_uri);
+        }
+        else if (strcmp (folder_type, "contacts") == 0) {
+                remove_folder_esource (hier->account,
+				       EXCHANGE_CONTACTS_FOLDER,
+				       physical_uri);
+	}
+
+	if (folder != hier->toplevel)
+		exchange_hierarchy_removed_folder (hier, folder);
+
+	if (folder == hier->toplevel || exchange_hierarchy_is_empty (hier))
+		hierarchy_foreign_cleanup (hier);
+
+	return EXCHANGE_ACCOUNT_FOLDER_OK;
+}
+
+static ExchangeAccountFolderResult
+scan_subtree (ExchangeHierarchy *hier, EFolder *folder, gboolean offline)
+{
+	ExchangeAccountFolderResult folder_result;
+
+	check_hide_private (hier);
+
+	folder_result = EXCHANGE_HIERARCHY_CLASS (parent_class)->scan_subtree (hier, folder, offline);
+
+	if (exchange_hierarchy_is_empty (hier))
+		hierarchy_foreign_cleanup (hier);
+
+	return folder_result;
+}
+
+static void
+add_href (ExchangeHierarchy *hier, EFolder *folder, gpointer hrefs)
+{
+	char *uri = g_strdup (e_folder_exchange_get_internal_uri (folder));
+
+	g_ptr_array_add (hrefs, (gpointer) uri);
+}
+
+static GPtrArray *
+get_hrefs (ExchangeHierarchySomeDAV *hsd)
+{
+	GPtrArray *hrefs;
+
+	hrefs = g_ptr_array_new ();
+	exchange_hierarchy_webdav_offline_scan_subtree (EXCHANGE_HIERARCHY (hsd), add_href, hrefs);
+	return hrefs;
+}
+
+/**
+ * exchange_hierarchy_foreign_add_folder:
+ * @hier: the hierarchy
+ * @folder_name: the name of the folder to add
+ * @folder: on successful return, the created folder
+ *
+ * Adds a new folder to @hier.
+ *
+ * Return value: the folder result.
+ **/
+ExchangeAccountFolderResult
+exchange_hierarchy_foreign_add_folder (ExchangeHierarchy *hier,
+				       const char *folder_name,
+				       EFolder **folder)
+{
+	ExchangeAccountFolderResult result;
+	const char *folder_type = NULL;
+	const char *physical_uri = NULL;
+	char *new_folder_name;
+
+	result =  create_internal (hier, hier->toplevel, folder_name, NULL, folder);
+#if 0
+	if (result == EXCHANGE_ACCOUNT_FOLDER_OK) {
+		// Add the esources
+		folder_type = e_folder_get_type_string (*folder);
+		physical_uri = e_folder_get_physical_uri (*folder);
+		new_folder_name = g_strdup_printf("%s's %s", 
+					hier->owner_name, folder_name);
+
+		if (!(strcmp (folder_type, "calendar")) ||
+		!(strcmp (folder_type, "calendar/public"))) {
+			add_folder_esource (hier->account,
+				     	    EXCHANGE_CALENDAR_FOLDER,
+				     	    new_folder_name,
+				    	    physical_uri);
+		}
+		else if (!(strcmp (folder_type, "tasks")) ||
+			 !(strcmp (folder_type, "tasks/public"))) {
+				add_folder_esource (hier->account,
+				     		    EXCHANGE_TASKS_FOLDER,
+				     		    new_folder_name,
+				     		    physical_uri);
+		}
+		else if (!(strcmp (folder_type, "contacts")) ||
+			 !(strcmp (folder_type, "contacts/public")) ||
+			 !(strcmp (folder_type, "contacts/ldap"))) {
+				add_folder_esource (hier->account,
+				     		    EXCHANGE_CONTACTS_FOLDER,
+				     		    new_folder_name,
+				     		    physical_uri);
+		}
+		g_free (new_folder_name);
+	}
+#endif
+	return result;
+}
+
+static ExchangeHierarchy *
+hierarchy_foreign_new (ExchangeAccount *account,
+		       const char *hierarchy_name,
+		       const char *physical_uri_prefix,
+		       const char *internal_uri_prefix,
+		       const char *owner_name,
+		       const char *owner_email,
+		       const char *source_uri)
+{
+	ExchangeHierarchyForeign *hfor;
+
+	g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL);
+
+	hfor = g_object_new (EXCHANGE_TYPE_HIERARCHY_FOREIGN, NULL);
+
+	exchange_hierarchy_webdav_construct (EXCHANGE_HIERARCHY_WEBDAV (hfor),
+					     account,
+					     EXCHANGE_HIERARCHY_FOREIGN,
+					     hierarchy_name,
+					     physical_uri_prefix,
+					     internal_uri_prefix,
+					     owner_name, owner_email,
+					     source_uri,
+					     FALSE);
+
+	return EXCHANGE_HIERARCHY (hfor);
+}
+
+/**
+ * exchange_hierarchy_foreign_new:
+ * @account: an #ExchangeAccount
+ * @hierarchy_name: the name of the hierarchy
+ * @physical_uri_prefix: the prefix of physical URIs in this hierarchy
+ * @internal_uri_prefix: the prefix of internal (http) URIs in this hierarchy
+ * @owner_name: display name of the owner of the hierarchy
+ * @owner_email: email address of the owner of the hierarchy
+ * @source_uri: evolution-mail source uri for the hierarchy
+ *
+ * Creates a new (initially empty) hierarchy for another user's
+ * folders.
+ *
+ * Return value: the new hierarchy.
+ **/
+ExchangeHierarchy *
+exchange_hierarchy_foreign_new (ExchangeAccount *account,
+				const char *hierarchy_name,
+				const char *physical_uri_prefix,
+				const char *internal_uri_prefix,
+				const char *owner_name,
+				const char *owner_email,
+				const char *source_uri)
+{
+	ExchangeHierarchy *hier;
+	char *mf_path;
+	GHashTable *props;
+	xmlDoc *doc;
+
+	g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL);
+	
+	hier = hierarchy_foreign_new (account, hierarchy_name,
+				      physical_uri_prefix,
+				      internal_uri_prefix,
+				      owner_name, owner_email,
+				      source_uri);
+
+	props = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (props, "name", (char *)hierarchy_name);
+	g_hash_table_insert (props, "physical_uri_prefix",
+			     (char *)physical_uri_prefix);
+	g_hash_table_insert (props, "internal_uri_prefix",
+			     (char *)internal_uri_prefix);
+	g_hash_table_insert (props, "owner_name", (char *)owner_name);
+	g_hash_table_insert (props, "owner_email", (char *)owner_email);
+	g_hash_table_insert (props, "source_uri", (char *)source_uri);
+
+	mf_path = e_folder_exchange_get_storage_file (hier->toplevel, "hierarchy.xml");
+	doc = e_xml_from_hash (props, E_XML_HASH_TYPE_PROPERTY,
+			       "foreign-hierarchy");
+	xmlSaveFile (mf_path, doc);
+	g_hash_table_destroy (props);
+	g_free (mf_path);
+	xmlFreeDoc (doc);
+
+	return hier;
+}
+
+/**
+ * exchange_hierarchy_foreign_new_from_dir:
+ * @account: an #ExchangeAccount
+ * @folder_path: pathname to a directory containing a hierarchy.xml file
+ *
+ * Recreates a new hierarchy from saved values.
+ *
+ * Return value: the new hierarchy.
+ **/
+ExchangeHierarchy *
+exchange_hierarchy_foreign_new_from_dir (ExchangeAccount *account,
+					 const char *folder_path)
+{
+	ExchangeHierarchy *hier;
+	char *mf_path;
+	GHashTable *props;
+	xmlDoc *doc;
+
+	g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL);
+	g_return_val_if_fail (folder_path != NULL, NULL);
+
+	mf_path = g_build_filename (folder_path, "hierarchy.xml", NULL);
+	doc = xmlParseFile (mf_path);
+	g_free (mf_path);
+	if (!doc)
+		return NULL;
+
+	props = e_xml_to_hash (doc, E_XML_HASH_TYPE_PROPERTY);
+	xmlFreeDoc (doc);
+
+	hier = hierarchy_foreign_new (account,
+				      g_hash_table_lookup (props, "name"),
+				      g_hash_table_lookup (props, "physical_uri_prefix"),
+				      g_hash_table_lookup (props, "internal_uri_prefix"),
+				      g_hash_table_lookup (props, "owner_name"),
+				      g_hash_table_lookup (props, "owner_email"),
+				      g_hash_table_lookup (props, "source_uri"));
+
+	e_xml_destroy_hash (props);
+	return hier;
+}
--- /dev/null	2004-08-25 23:04:59.000000000 +0530
+++ exchange-hierarchy-foreign.h	2005-07-05 18:11:41.081780546 +0530
@@ -0,0 +1,56 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* Copyright (C) 2001-2004 Novell, Inc. */
+
+#ifndef __EXCHANGE_HIERARCHY_FOREIGN_H__
+#define __EXCHANGE_HIERARCHY_FOREIGN_H__
+
+#include "exchange-hierarchy-somedav.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define EXCHANGE_TYPE_HIERARCHY_FOREIGN            (exchange_hierarchy_foreign_get_type ())
+#define EXCHANGE_HIERARCHY_FOREIGN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_TYPE_HIERARCHY_FOREIGN, ExchangeHierarchyForeign))
+#define EXCHANGE_HIERARCHY_FOREIGN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_TYPE_HIERARCHY_FOREIGN, ExchangeHierarchyForeignClass))
+#define EXCHANGE_IS_HIERARCHY_FOREIGN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_TYPE_HIERARCHY_FOREIGN))
+#define EXCHANGE_IS_HIERARCHY_FOREIGN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EXCHANGE_TYPE_HIERARCHY_FOREIGN))
+
+typedef struct _ExchangeHierarchyForeignPrivate  ExchangeHierarchyForeignPrivate;
+
+struct _ExchangeHierarchyForeign {
+	ExchangeHierarchySomeDAV parent;
+
+	ExchangeHierarchyForeignPrivate *priv;
+};
+
+struct _ExchangeHierarchyForeignClass {
+	ExchangeHierarchySomeDAVClass parent_class;
+
+};
+
+typedef struct _ExchangeHierarchyForeignClass ExchangeHierarchyForeignClass;
+typedef struct _ExchangeHierarchyForeign ExchangeHierarchyForeign;
+
+GType              exchange_hierarchy_foreign_get_type (void);
+
+ExchangeHierarchy *exchange_hierarchy_foreign_new          (ExchangeAccount *account,
+							    const char *hierarchy_name,
+							    const char *physical_uri_prefix,
+							    const char *internal_uri_prefix,
+							    const char *owner_name,
+							    const char *owner_email,
+							    const char *source_uri);
+ExchangeHierarchy *exchange_hierarchy_foreign_new_from_dir (ExchangeAccount *account,
+							    const char *folder_path);
+
+ExchangeAccountFolderResult  exchange_hierarchy_foreign_add_folder (ExchangeHierarchy *hier,
+								    const char *folder_name,
+								    EFolder **folder);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __EXCHANGE_HIERARCHY_FOREIGN_H__ */


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