[evolution-patches] GroupWise Calendars: Moving away from getQM & Proxy Support



Hi,

The attached patches contains the code changes made to eds to move away from getQuickMessages. This movement is needed since getQM is incompatible with proxy account. 

The serv-gw.patch contains the changes made to the e-gw-connection files, which defines all the APIs for server Interaction. A few functions are added to this file as a part of implementing the Proxy feature.

Please review them.

Thanks,
Sankar P
? backends/groupwise/temp
? tests/ecal/test-recur
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/ChangeLog,v
retrieving revision 1.473
diff -u -p -r1.473 ChangeLog
--- ChangeLog	2 Jul 2005 10:04:58 -0000	1.473
+++ ChangeLog	5 Jul 2005 17:23:32 -0000
@@ -1,3 +1,18 @@
+2005-07-05  Sankar P  <psankar novell com>
+	
+	* libecal/e-cal.c: (open_calendar)
+	Changed the password prompt string if the account is of type Proxy. 
+
+2005-07-05  Sankar P  <psankar novell com>
+	
+	* backends/groupwise/e-cal-backend-groupwise.c: (get_deltas)
+	Moved from getQuickMessages to combination of getItems and readCursor, 
+	due to the problems in getQuickMessages. 
+	* libedata-cal/e-cal-backend-cache.[ch]: 
+	(e_cal_backend_cache_get_key_value) 
+	(e_cal_backend_cache_put_key_value):
+	Added functions so as to put/get strings onto cache
+
 2005-07-02  Chenthill Palanisamy  <pchenthill novell com>
 
 	* backends/groupwise/e-cal-backend-groupwise-utils.c
Index: backends/groupwise/e-cal-backend-groupwise.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/backends/groupwise/e-cal-backend-groupwise.c,v
retrieving revision 1.148
diff -u -p -r1.148 e-cal-backend-groupwise.c
--- backends/groupwise/e-cal-backend-groupwise.c	2 Jul 2005 10:04:58 -0000	1.148
+++ backends/groupwise/e-cal-backend-groupwise.c	5 Jul 2005 17:23:34 -0000
@@ -29,12 +29,14 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <time.h>
 #include <unistd.h>
 #include <glib/gi18n-lib.h>
 #include <libgnomevfs/gnome-vfs-uri.h>
 #include <libgnomevfs/gnome-vfs.h>
 #include <libedataserver/e-xml-hash-utils.h>
 #include <libedataserver/e-url.h>
+#include <libedataserver/e-time-utils.h>
 #include <libedata-cal/e-cal-backend-cache.h>
 #include <libedata-cal/e-cal-backend-util.h>
 #include <libecal/e-cal-component.h>
@@ -42,6 +44,7 @@
 #include "e-cal-backend-groupwise.h"
 #include "e-cal-backend-groupwise-utils.h"
 #include "e-gw-connection.h"
+//#include <libedataserverui/e-passwords.h>
 
 /* Private part of the CalBackendGroupwise structure */
 struct _ECalBackendGroupwisePrivate {
@@ -207,29 +210,45 @@ populate_cache (ECalBackendGroupwise *cb
 static gboolean
 get_deltas (gpointer handle)
 {
- 	ECalBackendGroupwise *cbgw;
+	ECalBackendGroupwise *cbgw;
 	ECalBackendGroupwisePrivate *priv;
 	EGwConnection *cnc; 
- 	ECalBackendCache *cache; 
-        EGwConnectionStatus status; 
-	icalcomponent_kind kind;
-	GSList *item_list, *cache_keys, *l;
-	char *comp_str;
+	ECalBackendCache *cache; 
+	EGwConnectionStatus status; 
+
+	GSList  *cache_keys, *l;
+	GList *item_list, *l1;
+
+	char *comp_str = NULL;
 	char *time_string = NULL;
 	char t_str [100]; 
-	const char *serv_time;
-	struct stat buf;
+
 	static GStaticMutex connecting = G_STATIC_MUTEX_INIT;
-        
+
+	const char *position ; 
+	const char *serv_time;
+	const char *time_interval_string;
+	const char *key = "attempts";
+	const char *attempts;
+
+	EGwFilter *filter;
+	gboolean done = FALSE;
+	int time_interval;
+	int cursor = 0;
+	icaltimetype temp;
+	icalcomponent_kind kind;
+	struct tm *tm;
+	time_t current_time;
+
 	if (!handle)
 		return FALSE;
 	cbgw = (ECalBackendGroupwise *) handle;
 	priv= cbgw->priv;
 	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbgw));
- 	cnc = priv->cnc; 
- 	cache = priv->cache; 
+	cnc = priv->cnc; 
+	cache = priv->cache; 
 	item_list = NULL;
-	
+
 	if (priv->mode == CAL_MODE_LOCAL)
 		return FALSE;
 
@@ -237,46 +256,57 @@ get_deltas (gpointer handle)
 
 	serv_time = e_cal_backend_cache_get_server_utc_time (cache);
 	if (serv_time) {
+		t_str[0]='\0';
 		g_strlcpy (t_str, e_cal_backend_cache_get_server_utc_time (cache), 100);
 		if (!*t_str || !strcmp (t_str, "")) {
-			icaltimetype temp;
-			time_t current_time;
-			const struct tm *tm;
-
-			g_warning (" Could not get the correct time stamp for using in getQuick Messages\n");
-			temp = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
-			current_time = icaltime_as_timet_with_zone (temp, icaltimezone_get_utc_timezone ());
-			tm = gmtime (&current_time);
-			strftime (t_str, 100, "%Y-%m-%dT%H:%M:%SZ", tm);
+			g_warning ("\n\a Could not create the correct time stamp. Unsetting the marker to repopulate cache\n\a");
+			e_cal_backend_cache_unset_marker (cache);
+			return TRUE;
 		}
 		time_string = g_strdup (t_str);
+	} else {
+		g_warning ("\n\a Could not get the correct time stamp. Using the loginResponse time instead\n\a");
+
+		return TRUE;
 	}
 
-	status = e_gw_connection_get_quick_messages (cnc, cbgw->priv->container_id, "attachments recipients message recipientStatus default peek", &time_string, "New", "CalendarItem", NULL,  -1,  &item_list);
-	
+	filter = e_gw_filter_new ();
+
+	//NewItems created after the time-stamp
+	e_gw_filter_add_filter_component (filter, E_GW_FILTER_OP_GREATERTHAN, "created", time_string);
+
+	status = e_gw_connection_get_items (cnc, cbgw->priv->container_id, "attachments recipients message recipientStatus default peek", filter, &item_list);
 	if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
-		status = e_gw_connection_get_quick_messages (cnc, cbgw->priv->container_id, "attachments recipients message recipientStatus default peek", &time_string, "New", "CalendarItem", NULL,  -1,  &item_list);
-	
+		status = e_gw_connection_get_items (cnc, cbgw->priv->container_id, "attachments recipients message recipientStatus default peek", filter, &item_list);
+
+	g_object_unref (filter);	
+
 	if (status != E_GW_CONNECTION_STATUS_OK) {
-				
+		attempts = e_cal_backend_cache_get_key_value (cache, key);
+		if (attempts) {
+			e_cal_backend_cache_put_key_value (cache, key, "2");
+		} else {
+			int failures;
+			failures = g_ascii_strtod(attempts, NULL) + 1;
+			e_cal_backend_cache_put_key_value (cache, key, GINT_TO_POINTER (failures));
+		}
+
 		if (status == E_GW_CONNECTION_STATUS_NO_RESPONSE) {
 			g_static_mutex_unlock (&connecting);
 			return TRUE;
 		}
-
 		e_cal_backend_groupwise_notify_error_code (cbgw, status);
 		g_static_mutex_unlock (&connecting);
 		return TRUE;
 	}
-	/* store the timestamp in the cache */	
-	e_cal_backend_cache_put_server_utc_time (cache, time_string);
-	g_free (time_string), time_string = NULL;
-
 	e_file_cache_freeze_changes (E_FILE_CACHE (cache));
-	for (; item_list != NULL; item_list = g_slist_next(item_list)) {
-		EGwItem *item = E_GW_ITEM(item_list->data);
-		ECalComponent *comp = e_gw_item_to_cal_component (item, cbgw);
-		
+	for (; item_list != NULL; item_list = g_list_next(item_list)) {
+		EGwItem *item = NULL;
+		ECalComponent *comp = NULL;
+
+		item = E_GW_ITEM(item_list->data);
+		comp = e_gw_item_to_cal_component (item, cbgw);
+
 		e_cal_component_commit_sequence (comp);
 
 		if (comp) {
@@ -285,34 +315,50 @@ get_deltas (gpointer handle)
 			else  {
 				if (kind == icalcomponent_isa (e_cal_component_get_icalcomponent (comp))) {
 					comp_str = e_cal_component_get_as_string (comp);	
-					e_cal_backend_notify_object_created (E_CAL_BACKEND (cbgw), comp_str);
-					g_free (comp_str);
+					if (comp_str) {
+						e_cal_backend_notify_object_created (E_CAL_BACKEND (cbgw), comp_str);
+						g_free (comp_str);
+						comp_str = NULL;
+					}
 				}
 			}
 		}
 		else 
 			g_message ("Invalid component returned");
 
-		g_object_unref (comp);
-		g_object_unref (item);
+		if (comp)
+			g_object_unref (comp);
+		if (item)
+			g_object_unref (item);
 	}
 	if (item_list) {
-		g_slist_free (item_list);
+		g_list_free (item_list);
 		item_list = NULL;
 	}
 	e_file_cache_thaw_changes (E_FILE_CACHE (cache));
-	
-	/* We must use the same timestamp used for getQm call with message list New */ 
-	time_string = g_strdup (t_str);
 
-	status = e_gw_connection_get_quick_messages (cnc, cbgw->priv->container_id,"attachments recipients message recipientStatus  default", &time_string, "Modified", "CalendarItem", NULL,  -1,  &item_list);
-	
+	filter = e_gw_filter_new ();
+	//Items modified after the time-stamp
+	e_gw_filter_add_filter_component (filter, E_GW_FILTER_OP_GREATERTHAN, "modified", time_string);
+
+	status = e_gw_connection_get_items (cnc, cbgw->priv->container_id, "attachments recipients message recipientStatus default peek", filter, &item_list);
 	if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
-		status = e_gw_connection_get_quick_messages (cnc, cbgw->priv->container_id,"recipients message recipientStatus  default", &time_string, "Modified", "CalendarItem", NULL,  -1,  &item_list);
+		status = e_gw_connection_get_items (cnc, cbgw->priv->container_id, "attachments recipients message recipientStatus default peek", filter, &item_list);
+
+
+	g_object_unref (filter);
 
-		
-	g_free (time_string);
 	if (status != E_GW_CONNECTION_STATUS_OK) {
+
+		attempts = e_cal_backend_cache_get_key_value (cache, key);
+		if (attempts) {
+			e_cal_backend_cache_put_key_value (cache, key, "2");
+		} else {
+			int failures;
+			failures = g_ascii_strtod(attempts, NULL) + 1;
+			e_cal_backend_cache_put_key_value (cache, key, GINT_TO_POINTER (failures));
+		}
+
 		if (status == E_GW_CONNECTION_STATUS_NO_RESPONSE) { 
 			g_static_mutex_unlock (&connecting);
 			return TRUE;
@@ -323,14 +369,14 @@ get_deltas (gpointer handle)
 		return TRUE;
 	}
 
-
 	e_file_cache_freeze_changes (E_FILE_CACHE (cache));
-	
-	for (; item_list != NULL; item_list = g_slist_next(item_list)) {
-		EGwItem *item = E_GW_ITEM(item_list->data);
-		ECalComponent *modified_comp, *cache_comp;
-		char *cache_comp_str;
-		
+
+	for (; item_list != NULL; item_list = g_list_next(item_list)) {
+		EGwItem *item = NULL;
+		item = E_GW_ITEM(item_list->data);
+		ECalComponent *modified_comp = NULL, *cache_comp = NULL;
+		char *cache_comp_str = NULL;
+
 		modified_comp = e_gw_item_to_cal_component (item, cbgw);
 		if (!modified_comp) {
 			g_message ("Invalid component returned in update");
@@ -342,55 +388,75 @@ get_deltas (gpointer handle)
 
 		if (kind == icalcomponent_isa (e_cal_component_get_icalcomponent (modified_comp))) {
 			cache_comp_str = e_cal_component_get_as_string (cache_comp);
-			e_cal_backend_notify_object_modified (E_CAL_BACKEND (cbgw), cache_comp_str, e_cal_component_get_as_string (modified_comp));
-			g_free (cache_comp_str);
+			if (cache_comp_str) {
+				e_cal_backend_notify_object_modified (E_CAL_BACKEND (cbgw), cache_comp_str, e_cal_component_get_as_string (modified_comp));
+				g_free (cache_comp_str);
+				cache_comp_str = NULL;
+			}
 		}
 		e_cal_backend_cache_put_component (cache, modified_comp);
-		g_object_unref (item);
+		if (item)
+			g_object_unref (item);
 		g_object_unref (modified_comp);
 	}
 	e_file_cache_thaw_changes (E_FILE_CACHE (cache));
 
 	if (item_list) {
-		g_slist_free (item_list);
+		g_list_free (item_list);
 		item_list = NULL;
 	}
-	
-	status = e_gw_connection_get_quick_messages (cnc, cbgw->priv->container_id, "iCalId", NULL, "All", "CalendarItem", NULL,  -1,  &item_list);
 
-	if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
-		status = e_gw_connection_get_quick_messages (cnc, cbgw->priv->container_id, "iCalId", NULL, "All", "CalendarItem", NULL,  -1,  &item_list);
+	position = E_GW_CURSOR_POSITION_END;
+	cursor = 0;
+	status = e_gw_connection_create_cursor (cnc, cbgw->priv->container_id, "iCalId", NULL, &cursor);
 
 	if (status != E_GW_CONNECTION_STATUS_OK) {
-		if (status == E_GW_CONNECTION_STATUS_NO_RESPONSE) {
-			g_static_mutex_unlock (&connecting);
-			return TRUE;
-		}
-
 		e_cal_backend_groupwise_notify_error_code (cbgw, status);
 		g_static_mutex_unlock (&connecting);
-		return TRUE;
+		return status;
 	}
 
-	/* handle deleted items here by going over the entire cache and
-	 * checking for deleted items.*/
-	
 	cache_keys = e_cal_backend_cache_get_keys (cache);
-	for (l = item_list; l; l = g_slist_next (l)) {
-		/* this works assuming rid is null*/
-		cache_keys = g_slist_delete_link (cache_keys, 
-				g_slist_find_custom (cache_keys, l->data, (GCompareFunc) strcmp));
-		g_free (l->data);
+	done = FALSE;
+	while (!done) {
+		status = e_gw_connection_read_ical_ids (cnc, cbgw->priv->container_id, cursor, FALSE, CURSOR_ITEM_LIMIT, position, &item_list);
+		if (status != E_GW_CONNECTION_STATUS_OK) {
+			if (status == E_GW_CONNECTION_STATUS_NO_RESPONSE) {
+				g_static_mutex_unlock (&connecting);
+				return TRUE;
+			}
+			e_cal_backend_groupwise_notify_error_code (cbgw, status);
+			g_static_mutex_unlock (&connecting);
+			return TRUE;
+		}
+		/* handle deleted items here by going over the entire cache and
+		 * checking for deleted items.*/
+		for (l1 = item_list; l1; l1 = g_list_next (l1)) {
+			char *icalid;
+			icalid = (char *)(l1->data);
+			cache_keys = g_slist_delete_link (cache_keys, 
+					g_slist_find_custom (cache_keys, icalid, (GCompareFunc) strcmp));
+			if (l1->data)
+				g_free (l1->data);
+		}	
+		if (!item_list  || g_list_length (item_list) == 0)
+			done = TRUE;
+		if (item_list) {
+			g_list_free (item_list);
+			item_list = NULL;
+		}
+		position = E_GW_CURSOR_POSITION_CURRENT;
 	}
-
+	e_gw_connection_destroy_cursor (cnc, cbgw->priv->container_id, cursor);
 	e_file_cache_freeze_changes (E_FILE_CACHE (cache));
+
 	for (l = cache_keys; l ; l = g_slist_next (l)) {
-		/* assumes rid is null - which works for now */
+
 		ECalComponent *comp = NULL;
 		ECalComponentVType vtype;
 
 		comp = e_cal_backend_cache_get_component (cache, (const char *) l->data, NULL);	
-		
+
 		if (!comp)
 			continue;
 
@@ -398,27 +464,55 @@ get_deltas (gpointer handle)
 		if ((vtype == E_CAL_COMPONENT_EVENT) ||
 				(vtype == E_CAL_COMPONENT_TODO)) {
 			comp_str = e_cal_component_get_as_string (comp);
-			e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbgw), 
-							     (char *) l->data, comp_str, NULL);
-			e_cal_backend_cache_remove_component (cache, (const char *) l->data, NULL);
-			g_free (comp_str);
+			if (comp_str) {
+				e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbgw), 
+						(char *) l->data, comp_str, NULL);
+				e_cal_backend_cache_remove_component (cache, (const char *) l->data, NULL);
+				g_free (comp_str);
+				comp_str = NULL;
+			}
 		}
 		g_object_unref (comp);
 	}
 	e_file_cache_thaw_changes (E_FILE_CACHE (cache));
 
 	if (item_list) {
-		g_slist_free (item_list);
+		g_list_free (item_list);
 		item_list = NULL;
 	}
 	if (cache_keys) {
 		g_slist_free (cache_keys);
 		item_list = NULL;
 	}
-	
+
 	g_static_mutex_unlock (&connecting);
-		
-        return TRUE;        
+
+	attempts = e_cal_backend_cache_get_key_value (cache, key);
+
+	temp = icaltime_from_string (time_string);
+	current_time = icaltime_as_timet_with_zone (temp, icaltimezone_get_utc_timezone ());
+	tm = gmtime (&current_time);
+
+	time_interval = (CACHE_REFRESH_INTERVAL / 60000);
+	time_interval_string = g_getenv ("GETQM_TIME_INTERVAL");
+	if (time_interval_string) {
+		time_interval = g_ascii_strtod (time_interval_string, NULL);
+	} 
+	if (attempts) {
+		tm->tm_min += (time_interval * g_ascii_strtod (attempts, NULL));
+		e_cal_backend_cache_put_key_value (cache, key, NULL);
+	} else {
+		tm->tm_min += time_interval;
+	}
+	strftime (t_str, 100, "%Y-%m-%dT%H:%M:%SZ", tm);
+	time_string = g_strdup (t_str);
+
+	e_cal_backend_cache_put_server_utc_time (cache, time_string);
+
+	g_free (time_string);
+	time_string = NULL;
+
+	return TRUE;        
 }
 
 static gboolean
@@ -512,14 +606,13 @@ cache_init (ECalBackendGroupwise *cbgw)
 	if (!e_cal_backend_cache_get_marker (priv->cache)) {
 		/* Populate the cache for the first time.*/
 		/* start a timed polling thread set to 1 minute*/
-		cnc_status = populate_cache (cbgw);
+			cnc_status = populate_cache (cbgw);
 		if (cnc_status != E_GW_CONNECTION_STATUS_OK) {
 			g_warning (G_STRLOC ": Could not populate the cache");
 			/*FIXME  why dont we do a notify here */
 			return GNOME_Evolution_Calendar_PermissionDenied;
 		} else {
 			char *utc_str;
-			
 			utc_str = (char *) e_gw_connection_get_server_time (priv->cnc);
 			e_cal_backend_cache_set_marker (priv->cache);
 			e_cal_backend_cache_put_server_utc_time (priv->cache, utc_str);
@@ -552,9 +645,14 @@ cache_init (ECalBackendGroupwise *cbgw)
 		
 		/* get the deltas from the cache */
 		if (get_deltas (cbgw)) {
+			char *utc_str;
 			if (kind == ICAL_VEVENT_COMPONENT)
 				priv->timeout_id = g_timeout_add (time_interval, (GSourceFunc) get_deltas_timeout, (gpointer) cbgw);
-			priv->mode = CAL_MODE_REMOTE;
+			priv->mode = CAL_MODE_REMOTE; 
+			
+			utc_str = (char *) e_gw_connection_get_server_time (priv->cnc);
+			e_cal_backend_cache_put_server_utc_time (priv->cache, utc_str);
+
 			return GNOME_Evolution_Calendar_Success;
 		} else {
 			g_warning (G_STRLOC ": Could not populate the cache");
@@ -622,36 +720,66 @@ connect_to_server (ECalBackendGroupwise 
 	ESource *source;
 	const char *use_ssl;
 	char *http_uri;
+	int permissions, flag;
 	GThread *thread;
 	GError *error = NULL;
+	char *user = NULL;
+	icalcomponent_kind kind;
+	
 	priv = cbgw->priv;
-
+	
 	source = e_cal_backend_get_source (E_CAL_BACKEND (cbgw));
 	real_uri = NULL;
 	if (source)
 		real_uri = form_uri (source);
 	use_ssl = e_source_get_property (source, "use_ssl");
- 
+
 	if (!real_uri) {
 		e_cal_backend_notify_error (E_CAL_BACKEND (cbgw), _("Invalid server URI"));
 		return GNOME_Evolution_Calendar_NoSuchCal;
 	} else {
+		user = (char *) e_source_get_property (source, "parent_id_name");
 		/* create connection to server */
-		priv->cnc = e_gw_connection_new (
-			real_uri,
-			priv->username,
-			priv->password);
-
-		if (!E_IS_GW_CONNECTION(priv->cnc) && use_ssl && g_str_equal (use_ssl, "when-possible")) {
-			http_uri = g_strconcat ("http://";, real_uri + 8, NULL);
-			priv->cnc = e_gw_connection_new (http_uri, priv->username, priv->password);
-			g_free (http_uri);
+		if (user) {
+			EGwConnection *cnc;
+			/* create connection to server */
+			cnc = e_gw_connection_new (real_uri, user, priv->password);
+			if (!cnc) {
+				e_cal_backend_notify_error (E_CAL_BACKEND (cbgw), _("Authentication failed"));
+				return GNOME_Evolution_Calendar_AuthenticationFailed;
+			}
+				
+			priv->cnc = e_gw_proxy_connection_new (cnc, user, priv->password, priv->username, &permissions);
+
+			g_object_unref(cnc);
+
+			kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbgw));
+
+			if (kind == ICAL_VEVENT_COMPONENT)
+				flag = PROXY_APPOINTMENT_WRITE;
+			else
+				flag = PROXY_TASK_WRITE;
+
+			if (permissions & flag) { 
+				cbgw->priv->read_only = FALSE;
+			} else { 
+				cbgw->priv->read_only = TRUE;
+			}
+		} else {
+
+			priv->cnc = e_gw_connection_new (
+					real_uri,
+					priv->username,
+					priv->password);
+
+			if (!E_IS_GW_CONNECTION(priv->cnc) && use_ssl && g_str_equal (use_ssl, "when-possible")) {
+				http_uri = g_strconcat ("http://";, real_uri + 8, NULL);
+				priv->cnc = e_gw_connection_new (http_uri, priv->username, priv->password);
+				g_free (http_uri);
+			}
+			cbgw->priv->read_only = FALSE;
 		}
 		g_free (real_uri);
-			
-		/* As of now we are assuming that logged in user has write rights to calender */
-		/* we need to read actual rights from server when we implement proxy user access */
-		cbgw->priv->read_only = FALSE;
 
 		if (priv->cnc && priv->cache && priv->container_id) {
 			priv->mode = CAL_MODE_REMOTE;
@@ -670,7 +798,7 @@ connect_to_server (ECalBackendGroupwise 
 				priv->timeout_id = g_timeout_add (CACHE_REFRESH_INTERVAL, (GSourceFunc) get_deltas_timeout, (gpointer)cbgw);
 
 			}
-	
+
 			return GNOME_Evolution_Calendar_Success;
 		}
 		priv->mode_changed = FALSE;
@@ -680,6 +808,18 @@ connect_to_server (ECalBackendGroupwise 
 			/* get the ID for the container */
 			if (priv->container_id)
 				g_free (priv->container_id);
+
+			kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbgw));
+
+			if (kind == ICAL_VEVENT_COMPONENT) {
+				priv->container_id = g_strdup (e_gw_connection_get_container_id (priv->cnc, "Calendar"));
+				e_source_set_name (e_cal_backend_get_source (E_CAL_BACKEND (cbgw)), _("Calendar"));
+			} else if (kind == ICAL_VTODO_COMPONENT) {
+				priv->container_id = g_strdup (e_gw_connection_get_container_id (priv->cnc, "Calendar"));
+				e_source_set_name (e_cal_backend_get_source (E_CAL_BACKEND (cbgw)), _("Calendar"));
+			} else
+				priv->container_id = NULL;
+
 			
 			if ((status = set_container_id_with_count (cbgw)) != GNOME_Evolution_Calendar_Success) {
 				return status;
@@ -696,17 +836,15 @@ connect_to_server (ECalBackendGroupwise 
 			thread = g_thread_create ((GThreadFunc) cache_init, cbgw, FALSE, &error);
 			if (!thread) {
 				g_warning (G_STRLOC ": %s", error->message);
-				g_error_free (error);
 
 				e_cal_backend_notify_error (E_CAL_BACKEND (cbgw), _("Could not create thread for populating cache"));
 				return GNOME_Evolution_Calendar_OtherError;
 			}
-
-
 		} else {
 			e_cal_backend_notify_error (E_CAL_BACKEND (cbgw), _("Authentication failed"));
 			return GNOME_Evolution_Calendar_AuthenticationFailed;
 		}
+
 	}
 
 	if (!e_gw_connection_get_version (priv->cnc)) 
@@ -865,7 +1003,6 @@ e_cal_backend_groupwise_get_static_capab
 				  CAL_STATIC_CAPABILITY_REQ_SEND_OPTIONS "," \
 				  CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT "," \
 				  CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED "," \
-				  CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY "," \
 				  CAL_STATIC_CAPABILITY_NO_ORGANIZER "," \
 				  CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
 
Index: libecal/e-cal.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libecal/e-cal.c,v
retrieving revision 1.103
diff -u -p -r1.103 e-cal.c
--- libecal/e-cal.c	2 Jul 2005 07:08:11 -0000	1.103
+++ libecal/e-cal.c	5 Jul 2005 17:23:38 -0000
@@ -1563,7 +1563,7 @@ open_calendar (ECal *ecal, gboolean only
 
 	/* see if the backend needs authentication */
 	if ( (priv->mode !=  CAL_MODE_LOCAL) && e_source_get_property (priv->source, "auth")) {
-		char *prompt, *key;
+		char *prompt, *key, *parent_source_url, *user;
 
 		priv->load_state = E_CAL_LOAD_AUTHENTICATING;
 
@@ -1587,8 +1587,14 @@ open_calendar (ECal *ecal, gboolean only
 		}
 
 		/* actually ask the client for authentication */
-		prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
-					  e_source_peek_name (priv->source), username);
+		user = e_source_get_property (priv->source, "parent_id_name");
+		if (user) {			
+			prompt = g_strdup_printf (_("Enter password for %s to enable proxy for user %s"), e_source_peek_name (priv->source), user);
+
+		} else {
+			prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
+					e_source_peek_name (priv->source), username);
+		}
 		key = e_source_get_uri (priv->source);
 		if (!key) {
 			e_calendar_remove_op (ecal, our_op);
@@ -4023,10 +4029,6 @@ e_cal_create_object (ECal *ecal, icalcom
 	status = our_op->status;
 	if (uid)
 		*uid = our_op->uid;
-	else {
-		g_free (our_op->uid);
-		our_op->uid = NULL;
-	}
 	
 	e_calendar_remove_op (ecal, our_op);
 	g_mutex_unlock (our_op->mutex);
Index: libedata-cal/e-cal-backend-cache.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libedata-cal/e-cal-backend-cache.c,v
retrieving revision 1.22
diff -u -p -r1.22 e-cal-backend-cache.c
--- libedata-cal/e-cal-backend-cache.c	9 May 2005 12:24:35 -0000	1.22
+++ libedata-cal/e-cal-backend-cache.c	5 Jul 2005 17:23:38 -0000
@@ -697,6 +697,20 @@ e_cal_backend_cache_set_marker (ECalBack
 }
 
 /**
+ * e_cal_backend_cache_unset_marker:
+ * @cache: An #ECalBackendCache object.
+ *
+ * Unsets the marker so that the cache will be repopulated 
+ */
+void
+e_cal_backend_cache_unset_marker (ECalBackendCache *cache)
+{
+	g_return_if_fail (E_IS_CAL_BACKEND_CACHE (cache));
+	e_file_cache_remove_object (E_FILE_CACHE (cache), "populated");
+}
+
+
+/**
  * e_cal_backend_cache_get_marker:
  * @cache: An #ECalBackendCache object.
  *
@@ -752,4 +766,51 @@ e_cal_backend_cache_get_server_utc_time 
 	g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
 	
        	return	e_file_cache_get_object (E_FILE_CACHE (cache), "server_utc_time");
+}
+
+/**
+ * e_cal_backend_cache_put_key_value:
+ * @cache: An #ECalBackendCache object.
+ * @keyp: The Key parameter to identify uniquely.
+ * @valuep: The value for the keyp parameter.
+ *
+ * Return value: TRUE if the operation was successful, FALSE otherwise.
+ */
+gboolean
+e_cal_backend_cache_put_key_value (ECalBackendCache *cache, const char *keyp, const char *valuep)
+{
+	char *value, *key;
+	gboolean ret_val = FALSE;
+	
+	g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), FALSE);
+
+	key = g_strdup (keyp);
+	if (valuep) {
+		e_file_cache_remove_object (E_FILE_CACHE (cache), key);
+		return TRUE;
+	}
+	
+	value = g_strdup (valuep);
+
+	if (!(ret_val = e_file_cache_add_object (E_FILE_CACHE (cache), key, value)))
+		ret_val = e_file_cache_replace_object (E_FILE_CACHE (cache), key, value);
+
+	g_free (value);
+
+	return ret_val;
+}
+
+/**
+ * e_cal_backend_cache_get_key_value:
+ * @cache: An #ECalBackendCache object.
+ *
+ * Return value: The value.
+ */
+const char *
+e_cal_backend_cache_get_key_value (ECalBackendCache *cache, const char *key)
+{
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
+	
+       	return	e_file_cache_get_object (E_FILE_CACHE (cache), key);
 }
Index: libedata-cal/e-cal-backend-cache.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libedata-cal/e-cal-backend-cache.h,v
retrieving revision 1.13
diff -u -p -r1.13 e-cal-backend-cache.h
--- libedata-cal/e-cal-backend-cache.h	25 Feb 2005 06:36:51 -0000	1.13
+++ libedata-cal/e-cal-backend-cache.h	5 Jul 2005 17:23:38 -0000
@@ -72,6 +72,9 @@ void                e_cal_backend_cache_
 gboolean e_cal_backend_cache_put_server_utc_time (ECalBackendCache *cache, char *utc_str);
 const char * e_cal_backend_cache_get_server_utc_time (ECalBackendCache *cache);
 
+gboolean e_cal_backend_cache_put_key_value (ECalBackendCache *cache, const char *keyp, const char *valuep);
+const char * e_cal_backend_cache_get_key_value (ECalBackendCache *cache, const char *key);
+
 G_END_DECLS
 
 #endif
Index: servers/groupwise/e-gw-connection.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/servers/groupwise/e-gw-connection.c,v
retrieving revision 1.121
diff -u -p -r1.121 e-gw-connection.c
--- servers/groupwise/e-gw-connection.c	5 Jul 2005 04:24:02 -0000	1.121
+++ servers/groupwise/e-gw-connection.c	5 Jul 2005 17:27:17 -0000
@@ -36,7 +36,7 @@
 
 
 static GObjectClass *parent_class = NULL;
-static GHashTable *loaded_connections = NULL;
+static GHashTable *loaded_connections_permissions = NULL;
 
 struct _EGwConnectionPrivate {
 	SoupSession *soup_session;
@@ -221,16 +221,16 @@ e_gw_connection_dispose (GObject *object
 	printf ("gw connection dispose \n");
 	
 	/* removed the connection from the hash table */
-	if (loaded_connections != NULL) {
+	if (loaded_connections_permissions != NULL) {
 		hash_key = g_strdup_printf ("%s:%s %s",
 					    priv->username ? priv->username : "",
 					    priv->password ? priv->password : "",
 					    priv->uri);
-		if (g_hash_table_lookup_extended (loaded_connections, hash_key, &orig_key, &orig_value)) {
-			g_hash_table_remove (loaded_connections, hash_key);
-			if (g_hash_table_size (loaded_connections) == 0) {
-				g_hash_table_destroy (loaded_connections);
-				loaded_connections = NULL;
+		if (g_hash_table_lookup_extended (loaded_connections_permissions, hash_key, &orig_key, &orig_value)) {
+			g_hash_table_remove (loaded_connections_permissions, hash_key);
+			if (g_hash_table_size (loaded_connections_permissions) == 0) {
+				g_hash_table_destroy (loaded_connections_permissions);
+				loaded_connections_permissions = NULL;
 			}
 
 			g_free (orig_key);
@@ -418,12 +418,12 @@ e_gw_connection_new (const char *uri, co
 	g_static_mutex_lock (&connecting);
 
 	/* search the connection in our hash table */
-	if (loaded_connections != NULL) {
+	if (loaded_connections_permissions != NULL) {
 		hash_key = g_strdup_printf ("%s:%s %s",
 					    username ? username : "",
 					    password ? password : "",
 					    uri);
-		cnc = g_hash_table_lookup (loaded_connections, hash_key);
+		cnc = g_hash_table_lookup (loaded_connections_permissions, hash_key);
 		g_free (hash_key);
 
 		if (E_IS_GW_CONNECTION (cnc)) {
@@ -527,14 +527,14 @@ e_gw_connection_new (const char *uri, co
 	if (param) 
 		cnc->priv->server_time = soup_soap_parameter_get_string_value (param);
 
-	/* add the connection to the loaded_connections hash table */
+	/* add the connection to the loaded_connections_permissions hash table */
 	hash_key = g_strdup_printf ("%s:%s %s",
 				    cnc->priv->username ? cnc->priv->username : "",
 				    cnc->priv->password ? cnc->priv->password : "",
 				    cnc->priv->uri);
-	if (loaded_connections == NULL)
-		loaded_connections = g_hash_table_new (g_str_hash, g_str_equal);
-	g_hash_table_insert (loaded_connections, hash_key, cnc);
+	if (loaded_connections_permissions == NULL)
+		loaded_connections_permissions = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (loaded_connections_permissions, hash_key, cnc);
 
 	/* free memory */
 	g_object_unref (response);
@@ -3280,3 +3280,848 @@ e_gw_connection_remove_junk_entry (EGwCo
 	return status;
 
 }
+
+EGwConnectionStatus
+e_gw_connection_get_proxy_access_list (EGwConnection *cnc, GList **proxy_list)
+{
+	SoupSoapMessage *msg = NULL;
+	SoupSoapResponse *response = NULL;
+	EGwConnectionStatus status;
+	SoupSoapParameter *param;
+	SoupSoapParameter *type_param;
+	SoupSoapParameter *individualRights;
+	char *value;
+
+	g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_INVALID_CONNECTION);
+
+	/* build the SOAP message */
+	msg = e_gw_message_new_with_header (cnc->priv->uri, cnc->priv->session_id, "getProxyAccessListRequest");
+
+	e_gw_message_write_footer (msg);
+
+	/* send message to server */
+	response = e_gw_connection_send_message (cnc, msg);
+	if (!response) {
+		g_object_unref (msg);
+		return E_GW_CONNECTION_STATUS_NO_RESPONSE;
+	}
+
+	status = e_gw_connection_parse_response_status (response);
+	if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
+		reauthenticate (cnc);
+
+	/* parse the response and create the individual proxy accounts */
+	*proxy_list = NULL;
+	param = soup_soap_response_get_first_parameter_by_name (response, "accessRights");	
+	if (!param) {
+		g_object_unref (response);
+		return status;
+	} else 	{
+		SoupSoapParameter *subparam;
+		for (subparam = soup_soap_parameter_get_first_child_by_name (param, "entry");
+				subparam != NULL;
+				subparam = soup_soap_parameter_get_next_child_by_name (subparam, "entry")) {
+		
+			proxyHandler *aclInstance;
+			aclInstance = (proxyHandler *) malloc(sizeof(proxyHandler));
+			aclInstance->permissions = 0;
+			aclInstance->flags = 0;
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "email");
+			value = NULL;
+			if (type_param)	{
+				value = soup_soap_parameter_get_string_value (type_param);
+				aclInstance->proxy_email = g_strdup_printf("%s", value);
+			}
+
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "displayName");
+			value = NULL;
+			if (type_param)	{
+				value = soup_soap_parameter_get_string_value (type_param);
+				aclInstance->proxy_name = g_strdup_printf ("%s", value);
+			}
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "id");
+			value = NULL;
+			if (type_param)	{
+				value = soup_soap_parameter_get_string_value (type_param);
+				aclInstance->uniqueid = g_strdup_printf ("%s", value);
+			} else 
+				aclInstance->uniqueid = NULL;
+
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "mail");
+			value = NULL;
+			if (type_param)	{
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"read");				 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_MAIL_READ;
+				}
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"write");				 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_MAIL_WRITE;
+				}
+			}
+			
+			if (value)
+				g_free (value);
+
+			value = NULL;
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "appointment");
+			if (type_param) {
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"read");				 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_APPOINTMENT_READ;
+				}
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"write");				 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_APPOINTMENT_WRITE;
+				}
+			}
+			if (value)
+				g_free (value);
+
+			value = NULL;
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "task");
+			if (type_param)	{
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"read");				 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_TASK_READ;
+				}
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"write");				 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_TASK_WRITE;
+				}
+			}
+			if (value)
+				g_free (value);
+
+			value = NULL;
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "note");
+			if (type_param)	{
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"read");				 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_NOTES_READ;
+				}
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"write");				 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_NOTES_WRITE;
+				}
+			}
+			if (value)
+				g_free (value);
+
+
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "misc");
+			value = NULL;
+			if (type_param)	{
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"alarms");
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_GET_ALARMS;
+				}
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"notify");
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_GET_NOTIFICATIONS;
+				}
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"setup"); 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_MODIFY_FOLDERS;
+				}
+				individualRights= soup_soap_parameter_get_first_child_by_name (type_param,"readHidden"); 
+				if (individualRights) {
+					value = soup_soap_parameter_get_string_value (individualRights);
+					aclInstance->permissions |= PROXY_READ_PRIVATE;
+				}
+			}
+			if (value)
+				g_free(value);
+
+			*proxy_list = g_list_append(*proxy_list, aclInstance);
+		}
+	}
+	/* free memory */
+	if (response)
+		g_object_unref (response);
+	if (msg)
+		g_object_unref (msg);
+	return status;
+}
+
+EGwConnectionStatus 
+e_gw_proxy_add (EGwConnection *cnc, proxyHandler *new_proxy)
+{
+	SoupSoapMessage *msg = NULL;
+	SoupSoapResponse *response = NULL;
+	EGwConnectionStatus status;
+	gboolean added = FALSE;
+	
+	g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_UNKNOWN);
+	msg = e_gw_message_new_with_header (e_gw_connection_get_uri (cnc), e_gw_connection_get_session_id (cnc), "createProxyAccessRequest");
+	soup_soap_message_start_element (msg, "entry", NULL, NULL);
+	e_gw_message_write_string_parameter (msg, "email", NULL, new_proxy->proxy_email);
+	e_gw_message_write_string_parameter (msg, "displayName", NULL, new_proxy->proxy_name);	
+
+	if (new_proxy->permissions & PROXY_MAIL_READ){
+		added = TRUE;
+		soup_soap_message_start_element (msg, "mail", NULL, NULL);
+		e_gw_message_write_int_parameter (msg, "read", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_MAIL_WRITE){
+		if (added == FALSE){
+			added=TRUE;
+			soup_soap_message_start_element (msg, "mail", NULL, NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "write", NULL, 1);
+	}
+	if (added == TRUE)
+		soup_soap_message_end_element(msg);
+
+	added = FALSE;
+	if (new_proxy->permissions & PROXY_APPOINTMENT_READ){
+		added=TRUE;
+		soup_soap_message_start_element (msg, "appointment", NULL, NULL);
+		e_gw_message_write_int_parameter (msg, "read", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_APPOINTMENT_WRITE){
+		if(added == FALSE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element (msg, "appointment", NULL, NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "write", NULL, 1);
+	}
+	if (added == TRUE)
+		soup_soap_message_end_element  (msg);
+
+	added = FALSE;
+	if (new_proxy->permissions & PROXY_TASK_READ){
+		added=TRUE;
+		soup_soap_message_start_element (msg, "task", NULL, NULL);
+		e_gw_message_write_int_parameter (msg, "read", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_TASK_WRITE){
+		if (added == FALSE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element (msg, "task", NULL, NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "write", NULL, 1);
+	}
+	if (added == TRUE)
+		soup_soap_message_end_element(msg);
+
+	added = FALSE;
+	if (new_proxy->permissions & PROXY_NOTES_READ){
+		added=TRUE;
+		soup_soap_message_start_element (msg, "note", NULL, NULL);
+		e_gw_message_write_int_parameter (msg, "read", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_NOTES_WRITE){
+			if(added==FALSE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element (msg, "note", NULL, NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "write", NULL, 1);
+	}
+	if (added == TRUE)
+		soup_soap_message_end_element(msg);
+	
+	added = FALSE;
+	if (new_proxy->permissions & PROXY_GET_ALARMS){
+		added=TRUE;
+		soup_soap_message_start_element(msg,"misc",NULL,NULL);
+		e_gw_message_write_int_parameter (msg, "alarms", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_GET_NOTIFICATIONS){
+		if (added!=TRUE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element(msg,"misc",NULL,NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "notify", NULL, 1);
+	}
+	
+	if (new_proxy->permissions & PROXY_MODIFY_FOLDERS){
+		if (added!=TRUE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element(msg,"misc",NULL,NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "setup", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_READ_PRIVATE){
+		if (added!=TRUE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element(msg,"misc",NULL,NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "readHidden", NULL, 1);
+	}
+	if (added==TRUE)
+		soup_soap_message_end_element(msg);			
+	e_gw_message_write_footer (msg);
+	response = e_gw_connection_send_message (cnc, msg);
+	if (!response) {
+		g_object_unref (msg);
+		return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
+	}
+	status = e_gw_connection_parse_response_status (response);
+
+	if (response)
+	g_object_unref (response);
+
+	if (msg)
+	g_object_unref (msg);
+	return status;
+}
+
+EGwConnectionStatus
+e_gw_proxy_remove (EGwConnection *cnc, proxyHandler *newProxy)
+{
+	SoupSoapMessage *msg;
+	SoupSoapResponse *response;
+	EGwConnectionStatus status;
+
+	g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_UNKNOWN);
+
+	msg = e_gw_message_new_with_header (e_gw_connection_get_uri(cnc), e_gw_connection_get_session_id(cnc), "removeProxyAccessRequest");
+
+	e_gw_message_write_string_parameter (msg, "id", NULL, newProxy->uniqueid);
+
+	e_gw_message_write_footer (msg);
+
+	response = e_gw_connection_send_message (cnc, msg);
+	if (!response) {
+		g_object_unref (msg);
+		return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
+	}
+	status = e_gw_connection_parse_response_status (response);
+	g_object_unref (response);
+	g_object_unref (msg);
+	return E_GW_CONNECTION_STATUS_OK;
+
+}
+
+EGwConnectionStatus 
+e_gw_proxy_changed (EGwConnection *cnc, proxyHandler *new_proxy)
+{
+	SoupSoapMessage *msg = NULL;
+	SoupSoapResponse *response = NULL;
+	EGwConnectionStatus status;
+	gboolean added = FALSE;
+	
+	g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_UNKNOWN);
+	msg = e_gw_message_new_with_header (e_gw_connection_get_uri (cnc), e_gw_connection_get_session_id (cnc), "modifyProxyAccessRequest");
+	e_gw_message_write_string_parameter (msg, "id", NULL, new_proxy->uniqueid);
+	soup_soap_message_start_element (msg, "updates", NULL, NULL);
+	e_gw_message_write_string_parameter (msg, "email", NULL, new_proxy->proxy_email);
+	e_gw_message_write_string_parameter (msg, "displayName", NULL, new_proxy->proxy_name);	
+	
+	if (new_proxy->permissions & PROXY_MAIL_READ){
+		added = TRUE;
+		soup_soap_message_start_element (msg, "mail", NULL, NULL);
+		e_gw_message_write_int_parameter (msg, "read", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_MAIL_WRITE){
+		if (added == FALSE){
+			added=TRUE;
+			soup_soap_message_start_element (msg, "mail", NULL, NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "write", NULL, 1);
+	}
+	if (added == TRUE)
+		soup_soap_message_end_element(msg);
+
+	added = FALSE;
+	if (new_proxy->permissions & PROXY_APPOINTMENT_READ){
+		added=TRUE;
+		soup_soap_message_start_element (msg, "appointment", NULL, NULL);
+		e_gw_message_write_int_parameter (msg, "read", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_APPOINTMENT_WRITE){
+		if(added == FALSE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element (msg, "appointment", NULL, NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "write", NULL, 1);
+	}
+	if (added == TRUE)
+		soup_soap_message_end_element(msg);
+
+	added = FALSE;
+	if (new_proxy->permissions & PROXY_TASK_READ){
+		added=TRUE;
+		soup_soap_message_start_element (msg, "task", NULL, NULL);
+		e_gw_message_write_int_parameter (msg, "read", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_TASK_WRITE){
+		if (added == FALSE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element (msg, "task", NULL, NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "write", NULL, 1);
+	}
+	if (added == TRUE)
+		soup_soap_message_end_element(msg);
+
+	added = FALSE;
+	if (new_proxy->permissions & PROXY_NOTES_READ){
+		added=TRUE;
+		soup_soap_message_start_element (msg, "note", NULL, NULL);
+		e_gw_message_write_int_parameter (msg, "read", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_NOTES_WRITE){
+			if(added==FALSE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element (msg, "note", NULL, NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "write", NULL, 1);
+	}
+	if (added == TRUE)
+		soup_soap_message_end_element(msg);
+	
+	added = FALSE;
+	if (new_proxy->permissions & PROXY_GET_ALARMS){
+		added=TRUE;
+		soup_soap_message_start_element(msg,"misc",NULL,NULL);
+		e_gw_message_write_int_parameter (msg, "alarms", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_GET_NOTIFICATIONS){
+		if (added!=TRUE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element(msg,"misc",NULL,NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "notify", NULL, 1);
+	}
+	
+	if (new_proxy->permissions & PROXY_MODIFY_FOLDERS){
+		if (added!=TRUE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element(msg,"misc",NULL,NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "setup", NULL, 1);
+	}
+	if (new_proxy->permissions & PROXY_READ_PRIVATE){
+		if (added!=TRUE)
+		{
+			added=TRUE;
+			soup_soap_message_start_element(msg,"misc",NULL,NULL);
+		}
+		e_gw_message_write_int_parameter (msg, "readHidden", NULL, 1);
+	}
+	if (added==TRUE)
+		soup_soap_message_end_element(msg);			
+	e_gw_message_write_footer (msg);
+	response = e_gw_connection_send_message (cnc, msg);
+	
+	if (!response) {
+		g_object_unref (msg);
+		return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
+	}
+	status = e_gw_connection_parse_response_status (response);
+
+	if (response)
+	g_object_unref (response);
+
+	if (msg)
+	g_object_unref (msg);
+	return status;
+}
+
+EGwConnectionStatus
+e_gw_connection_get_proxy_list (EGwConnection *cnc, GList **proxy_info)
+{
+	SoupSoapMessage *msg;
+        SoupSoapResponse *response;
+        EGwConnectionStatus status;
+        SoupSoapParameter *param;
+	SoupSoapParameter *type_param;
+	char *value;
+	g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_INVALID_OBJECT);
+	/* build the SOAP message */
+        msg = e_gw_message_new_with_header (cnc->priv->uri, cnc->priv->session_id, "getProxyListRequest");
+        if (!msg) {
+                g_warning (G_STRLOC ": Could not build SOAP message");
+                return E_GW_CONNECTION_STATUS_UNKNOWN;
+        }
+	
+	e_gw_message_write_footer (msg);
+        
+	/* send message to server */
+        response = e_gw_connection_send_message (cnc, msg);
+        if (!response) {
+                g_object_unref (msg);
+                return E_GW_CONNECTION_STATUS_NO_RESPONSE;
+        }
+	status = e_gw_connection_parse_response_status (response);
+        if (status != E_GW_CONNECTION_STATUS_OK) {
+		if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
+			reauthenticate (cnc);
+		g_object_unref (response);
+                g_object_unref (msg);
+		return status;
+	}
+	/* if status is OK - parse result. return the list */	
+	param = soup_soap_response_get_first_parameter_by_name (response, "proxies");
+			SoupSoapParameter *subparam;
+		for (subparam = soup_soap_parameter_get_first_child_by_name (param, "proxy");
+				subparam != NULL;
+				subparam = soup_soap_parameter_get_next_child_by_name (subparam, "proxy")) 
+		{
+
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "displayName");
+			value = NULL;
+			if (type_param)	{
+				value = soup_soap_parameter_get_string_value (type_param);
+				*proxy_info = g_list_append(*proxy_info, value);
+			}
+			type_param = soup_soap_parameter_get_first_child_by_name (subparam, "email");
+			value = NULL;
+			if (type_param)	{
+				value = soup_soap_parameter_get_string_value (type_param);
+				*proxy_info = g_list_append(*proxy_info, value);
+			}
+		}	
+        if (!param) {
+                g_object_unref (response);
+                g_object_unref (msg);
+                return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
+        }
+       	
+        g_object_unref (response);
+	g_object_unref (msg);
+
+        return E_GW_CONNECTION_STATUS_OK;
+}
+
+static SoupSoapMessage*
+form_proxy_login_request (EGwConnection *cnc, const char* username, const char* password, const char *proxy)
+{
+	SoupSoapMessage *msg;
+	/* build the SOAP message */
+	msg = e_gw_message_new_with_header (cnc->priv->uri, cnc->priv->session_id, "loginRequest");
+	soup_soap_message_start_element (msg, "auth", "types", NULL);
+	soup_soap_message_add_attribute (msg, "type", "types:Proxy", "xsi",
+					 "http://www.w3.org/2001/XMLSchema-instance";);
+	e_gw_message_write_string_parameter (msg, "username", "types", username);
+	e_gw_message_write_string_parameter (msg, "password", "types", password);
+	e_gw_message_write_string_parameter (msg, "proxy", "types", proxy);
+	soup_soap_message_end_element (msg);
+	e_gw_message_write_footer (msg);
+	return msg;
+}
+
+EGwConnection *
+e_gw_proxy_connection_new (EGwConnection *parent_cnc, char *username, const char *password, const char *proxy, int  *permissions)
+{
+	EGwConnection *cnc;
+	SoupSoapMessage *msg;
+	SoupSoapResponse *response;
+	EGwConnectionStatus status;
+	SoupSoapParameter *param;
+	SoupSoapParameter *subparam;
+	SoupSoapParameter *individualRights;
+	char *value;
+	char *hash_key;
+	char *name = NULL;
+	int i;
+	char *permissions_key = NULL;
+	
+	static GStaticMutex connecting = G_STATIC_MUTEX_INIT;	
+
+	g_static_mutex_lock (&connecting);
+
+	for (i=0; proxy[i]!='\0' && proxy[i]!='@'; i++);
+	if (proxy[i]=='@')
+		name = g_strndup(proxy, i);
+	else 
+		name = g_strdup (proxy);
+	/* search the connection in our hash table */
+	if (loaded_connections_permissions != NULL) {
+		hash_key = g_strdup_printf ( "%s:%s %s",
+				name,
+				"",
+				parent_cnc->priv->uri);
+		cnc = g_hash_table_lookup (loaded_connections_permissions, hash_key);
+		permissions_key = g_strdup_printf ("%s:permissions", hash_key);
+		g_free (hash_key);
+
+		if (E_IS_GW_CONNECTION (cnc)) {
+			*permissions = g_hash_table_lookup (loaded_connections_permissions, permissions_key);
+			g_free (permissions_key);
+			g_object_ref (cnc);
+			g_static_mutex_unlock (&connecting);
+			return cnc;
+		}
+		g_free (permissions_key);
+	}
+	
+	/* not found, so create a new connection */
+	cnc = g_object_new (E_TYPE_GW_CONNECTION, NULL);
+	
+	msg = form_proxy_login_request (parent_cnc, username, password, proxy);
+
+	/* send message to server */
+	response = e_gw_connection_send_message (parent_cnc, msg);
+
+	if (!response) {
+		g_object_unref (cnc);
+		g_static_mutex_unlock (&connecting);
+		g_object_unref (msg);
+		return NULL;
+	}
+
+	status = e_gw_connection_parse_response_status (response);
+
+	param = soup_soap_response_get_first_parameter_by_name (response, "session");
+	if (!param) {
+		g_object_unref (response);
+		g_object_unref (msg);
+		g_object_unref (cnc);
+		g_static_mutex_unlock (&connecting);
+		return NULL;
+	}
+
+	cnc->priv->uri = g_strdup (parent_cnc->priv->uri);
+	cnc->priv->username = g_strdup (proxy);
+	cnc->priv->password = NULL;
+	cnc->priv->session_id = soup_soap_parameter_get_string_value (param);
+
+	/* retrieve user information */
+	param = soup_soap_response_get_first_parameter_by_name (response, "entry");
+
+	if (param) {
+		char *param_value;
+
+		subparam = soup_soap_parameter_get_first_child_by_name (param, "email");
+		if (subparam) {
+			param_value = soup_soap_parameter_get_string_value (subparam);
+			cnc->priv->user_email  = param_value;
+		}
+
+		subparam = soup_soap_parameter_get_first_child_by_name (param, "name");
+		if (subparam) {
+			param_value = soup_soap_parameter_get_string_value (subparam);
+			cnc->priv->user_name = param_value;
+		}
+
+		subparam = soup_soap_parameter_get_first_child_by_name (param, "uuid");
+		if (subparam) {
+			param_value = soup_soap_parameter_get_string_value (subparam);
+			cnc->priv->user_uuid = param_value;
+		}
+		*permissions = 0;
+		subparam = soup_soap_parameter_get_first_child_by_name (param, "mail");
+		value = NULL;
+		if (subparam)	{
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"read");				 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_MAIL_READ;
+			}
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"write");				 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_MAIL_WRITE;
+			}
+		}
+
+		if (value)
+			g_free (value);
+
+		value = NULL;
+		subparam = soup_soap_parameter_get_first_child_by_name (param, "appointment");
+		if (subparam) {
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"read");				 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_APPOINTMENT_READ;
+			}
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"write");				 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_APPOINTMENT_WRITE;
+			}
+		}
+		if (value)
+			g_free (value);
+
+		value = NULL;
+		subparam = soup_soap_parameter_get_first_child_by_name (param, "task");
+		if (subparam)	{
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"read");				 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_TASK_READ;
+			}
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"write");				 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_TASK_WRITE;
+			}
+		}
+		if (value)
+			g_free (value);
+
+		value = NULL;
+		subparam = soup_soap_parameter_get_first_child_by_name (param, "note");
+		if (subparam)	{
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"read");				 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_NOTES_READ;
+			}
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"write");				 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_NOTES_WRITE;
+			}
+		}
+		if (value)
+			g_free (value);
+
+
+		subparam = soup_soap_parameter_get_first_child_by_name (param, "misc");
+		value = NULL;
+		if (subparam)	{
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"alarms");
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_GET_ALARMS;
+			}
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"notify");
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_GET_NOTIFICATIONS;
+			}
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"setup"); 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_MODIFY_FOLDERS;
+			}
+			individualRights= soup_soap_parameter_get_first_child_by_name (subparam,"readHidden"); 
+			if (individualRights) {
+				value = soup_soap_parameter_get_string_value (individualRights);
+				*permissions |= PROXY_READ_PRIVATE;
+			}
+		}
+		if (value)
+			g_free(value);
+	}
+
+	param = soup_soap_response_get_first_parameter_by_name (response, "gwVersion");
+	if (param) {
+		char *param_value;
+		param_value = soup_soap_parameter_get_string_value (param);
+		cnc->priv->version = param_value;
+	} else
+		cnc->priv->version = NULL;	
+
+	param = soup_soap_response_get_first_parameter_by_name (response, "serverUTCTime");
+	if (param) 
+		cnc->priv->server_time = soup_soap_parameter_get_string_value (param);
+
+	/* add the connection to the loaded_connections_permissions hash table */
+	hash_key = g_strdup_printf ("%s:%s %s",
+			name,
+			"",
+			cnc->priv->uri);
+
+	g_hash_table_insert (loaded_connections_permissions, hash_key, cnc);
+	
+	permissions_key = g_strdup_printf ("%s:permissions", hash_key);
+	g_hash_table_insert (loaded_connections_permissions, permissions_key, GINT_TO_POINTER(*permissions));
+	
+	/* free memory */
+	g_object_unref (response);
+	g_object_unref (msg);
+	g_static_mutex_unlock (&connecting);
+	return cnc;
+}
+
+EGwConnectionStatus
+e_gw_connection_read_ical_ids (EGwConnection *cnc, const char *container, int cursor, gboolean forward, int count, const char *cursor_seek, GList **list)
+{
+	SoupSoapMessage *msg;
+	SoupSoapResponse *response;
+	EGwConnectionStatus status;
+	SoupSoapParameter *param, *subparam, *child;
+	const char *name, *value;
+	g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_UNKNOWN);
+	g_return_val_if_fail ((container != NULL), E_GW_CONNECTION_STATUS_UNKNOWN);
+
+	msg = e_gw_message_new_with_header (cnc->priv->uri, cnc->priv->session_id, "readCursorRequest");
+	e_gw_message_write_int_parameter (msg, "cursor", NULL, cursor);
+	/* there is problem in read curosr if you set this, uncomment after the problem 
+	   is fixed in server */
+	e_gw_message_write_string_parameter (msg, "position", NULL, cursor_seek);
+	e_gw_message_write_string_parameter (msg, "forward", NULL, forward ? "true": "false");
+	e_gw_message_write_string_parameter (msg, "container", NULL, container);
+	e_gw_message_write_int_parameter (msg, "count", NULL, count);
+
+	e_gw_message_write_footer (msg);
+
+	/* send message to server */
+	response = e_gw_connection_send_message (cnc, msg);
+	if (!response) {
+		g_object_unref (msg);
+		return E_GW_CONNECTION_STATUS_NO_RESPONSE;
+	}
+
+	status = e_gw_connection_parse_response_status (response);
+	if (status != E_GW_CONNECTION_STATUS_OK) {
+		if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
+			reauthenticate (cnc);
+		g_object_unref (response);
+		g_object_unref (msg);
+		return status;
+	}
+
+	/* if status is OK - parse result. return the list */	
+	param = soup_soap_response_get_first_parameter_by_name (response, "items");
+	if (!param) {
+		g_object_unref (response);
+		g_object_unref (msg);
+		return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
+	}
+
+	/* parse these parameters into ecalcomponents*/
+	for (subparam = soup_soap_parameter_get_first_child_by_name (param, "item");
+			subparam != NULL;
+			subparam = soup_soap_parameter_get_next_child_by_name (subparam, "item")) {
+
+		for (child = soup_soap_parameter_get_first_child (subparam);
+				child != NULL;
+				child = soup_soap_parameter_get_next_child (child)) {
+
+			name = soup_soap_parameter_get_name (child);
+
+			if (!g_ascii_strcasecmp (name, "iCalId")) {
+				value = NULL;
+				value = soup_soap_parameter_get_string_value (child);
+				if (value)
+					*list = g_list_append (*list, g_strdup(value));
+			}
+		}
+	}
+	/* free memory */
+	g_object_unref (response);
+	g_object_unref (msg);
+	return E_GW_CONNECTION_STATUS_OK;
+}
+
+
Index: servers/groupwise/e-gw-connection.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/servers/groupwise/e-gw-connection.h,v
retrieving revision 1.60
diff -u -p -r1.60 e-gw-connection.h
--- servers/groupwise/e-gw-connection.h	5 Jul 2005 04:24:02 -0000	1.60
+++ servers/groupwise/e-gw-connection.h	5 Jul 2005 17:27:17 -0000
@@ -26,6 +26,7 @@
 
 #include <glib-object.h>
 #include <libsoup/soup-soap-message.h>
+#include <libedataserver/e-proxy.h>
 #include "e-gw-container.h"
 #include "e-gw-item.h"
 #include "e-gw-filter.h"
@@ -162,6 +163,13 @@ EGwConnectionStatus e_gw_connection_get_
 EGwConnectionStatus e_gw_connection_modify_junk_settings (EGwConnection *cnc, int use_junk, int use_block, int use_pab , int persistence);
 EGwConnectionStatus e_gw_connection_get_junk_entries (EGwConnection *cnc, GList **entries);
 EGwConnectionStatus  e_gw_connection_remove_junk_entry (EGwConnection *cnc, const char *id);
+EGwConnectionStatus e_gw_connection_get_proxy_access_list (EGwConnection *cnc, GList **proxy_list);
+EGwConnectionStatus e_gw_proxy_add (EGwConnection *cnc, proxyHandler *new_proxy);
+EGwConnectionStatus e_gw_proxy_remove (EGwConnection *cnc, proxyHandler *newProxy);
+EGwConnectionStatus e_gw_proxy_changed (EGwConnection *cnc, proxyHandler *newProxy);
+EGwConnectionStatus e_gw_connection_get_proxy_list (EGwConnection *cnc, GList **proxy_info);
+EGwConnection *e_gw_proxy_connection_new (EGwConnection *cnc1, char *username, const char *password, const char *proxy, int* permissions);
+EGwConnectionStatus e_gw_connection_read_ical_ids (EGwConnection *cnc, const char *container, int cursor, gboolean forward, int count, const char *cursor_seek, GList **list);
 G_END_DECLS
 
 #endif
Index: servers/groupwise/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/servers/groupwise/ChangeLog,v
retrieving revision 1.146
diff -u -p -r1.146 ChangeLog
--- servers/groupwise/ChangeLog	5 Jul 2005 11:45:13 -0000	1.146
+++ servers/groupwise/ChangeLog	5 Jul 2005 17:27:18 -0000
@@ -1,3 +1,31 @@
+2005-07-05  Sankar P  <psankar novell com>
+
+	* e-gw-connection.[ch] :
+	(e_gw_connection_read_ical_ids): Added function which is necessary for 
+	identifying deleted appointments, meetings and tasks. This is created as part of 
+	the movement to getItems from getQuickMessages.
+	
+2005-07-05  Sankar P  <psankar novell com>
+
+	* e-gw-connection.c : 
+	loaded_connections hashtable is renamed as loaded_connections_permissions, 
+	so as to enable storing proxy permissions on the hashtable. 
+	The permissions needs to be stored,
+	because they can be obtained only in the loginResponse.
+	* e-gw-connection.[ch] :
+	(e_gw_connection_get_proxy_access_list)
+	(e_gw_connection_get_proxy_list)
+	(e_gw_proxy_connection_new):
+	Added functions for the Proxy feature.
+
+2005-07-05  Shreyas Srinivasan  <sshreyas novell com>
+
+	* e-gw-connection.[ch] :
+	(e_gw_proxy_add)
+	(e_gw_proxy_remove)
+	(e_gw_proxy_changed) :
+	Added functions for the Proxy feature.	
+	
 2005-07-05  Harish Krishnaswamy  <kharish novell com>
 
 	* e-gw-item.c: (e_gw_item_new_from_soap_parameter),


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