Index: plugins/google-account-setup/ChangeLog
===================================================================
--- plugins/google-account-setup/ChangeLog	(revision 35830)
+++ plugins/google-account-setup/ChangeLog	(working copy)
@@ -1,3 +1,14 @@
+2008-07-24  Milan Crha  <mcrha@redhat.com>
+
+	** Fix for bug #535745
+
+	* google-source.c: (sanitize_user_mail), (construct_default_uri),
+	(is_default_uri), (init_combo_values), (user_changed),
+	(cal_combo_changed), (claim_error), (retrieve_list_clicked),
+	(plugin_google): New widgets and functionality to retrieve list
+	of subscribed calendars from the Google account and let user choose
+	which one would be shown.
+
 2008-05-24  Jörgen Scheibengruber  <mfcn@gmx.de>
 
 	* Makefile.am:
Index: plugins/google-account-setup/google-source.c
===================================================================
--- plugins/google-account-setup/google-source.c	(revision 35830)
+++ plugins/google-account-setup/google-source.c	(working copy)
@@ -40,10 +40,18 @@
 #include <libedataserver/e-url.h>
 #include <libedataserver/e-account-list.h>
 #include <libecal/e-cal.h>
+#include <libedataserverui/e-cell-renderer-color.h>
+#include <libedataserverui/e-passwords.h>
+
+#include <google/libgdata/gdata-service-iface.h>
+#include <google/libgdata/gdata-feed.h>
+#include <google/libgdata-google/gdata-google-service.h>
 
 #include "google-contacts-source.h"
 
 #define CALENDAR_LOCATION "http://www.google.com/calendar/feeds/"
+#define CALENDAR_DEFAULT_PATH "/private/full"
+#define URL_GET_SUBSCRIBED_CALENDARS "http://www.google.com/calendar/feeds/default/allcalendars/full"
 
 #define d(x)
 
@@ -58,6 +66,8 @@ GtkWidget *      plugin_google          
 /*****************************************************************************/
 /* plugin intialization */
 
+
+
 static void
 ensure_google_source_group ()
 {
@@ -174,6 +184,83 @@ is_email (const char *address)
 	return TRUE;
 }
 
+static char *
+sanitize_user_mail (const char *user)
+{
+	if (!user)
+		return NULL;
+
+	if (!is_email (user)) {
+		return g_strconcat (user, "%40gmail.com", NULL);
+	} else {
+		char *tmp = g_malloc0 (sizeof (char) * (1 + strlen (user) + 2));
+		char *at = strchr (user, '@');
+
+		strncpy (tmp, user, at - user);
+		strcat (tmp, "%40");
+		strcat (tmp, at + 1);
+
+		return tmp;
+	}
+}
+
+static char *
+construct_default_uri (const char *username)
+{
+	char *user, *uri;
+
+	user = sanitize_user_mail (username);
+	uri = g_strconcat (CALENDAR_LOCATION, user, CALENDAR_DEFAULT_PATH, NULL);
+	g_free (user);
+
+	return uri;
+}
+
+/* checks whether the given_uri is pointing to the default user's calendar or not */
+static gboolean
+is_default_uri (const char *given_uri, const char *username)
+{
+	char *uri, *at;
+	int ats;
+	gboolean res;
+
+	if (!given_uri)
+		return TRUE;
+
+	uri = construct_default_uri (username);
+
+	/* count number of '@' in given_uri to know how much memory will be required */
+	ats = 0;
+	for (at = strchr (given_uri, '@'); at; at = strchr (at + 1, '@')) {
+		ats++;
+	}
+
+	if (!ats)
+		res = g_ascii_strcasecmp (given_uri, uri) == 0;
+	else {
+		const char *last;
+		char *tmp = g_malloc0 (sizeof (char) * (1 + strlen (given_uri) + (2 * ats)));
+
+		last = given_uri;
+		for (at = strchr (last, '@'); at; at = strchr (at + 1, '@')) {
+			strncat (tmp, last, at - last);
+			strcat (tmp, "%40");
+			last = at + 1;
+		}
+		strcat (tmp, last);
+
+		res = g_ascii_strcasecmp (tmp, uri) == 0;
+
+		g_free (tmp);
+	}
+
+	g_free (uri);
+
+	return res;
+}
+
+static void init_combo_values (GtkComboBox *combo, const char *deftitle, const char *defuri);
+
 static void
 user_changed (GtkEntry *editable, ESource *source)
 {
@@ -181,10 +268,8 @@ user_changed (GtkEntry *editable, ESourc
 	char       *uri;
 	char       *ruri;
 	const char *user;
-	char *projection;
 
 	uri = e_source_get_uri (source);
-	user = gtk_entry_get_text (GTK_ENTRY (editable));
 
 	if (uri == NULL) {
 		g_free (uri);
@@ -193,24 +278,27 @@ user_changed (GtkEntry *editable, ESourc
 
 	euri = e_uri_new (uri);
 	g_free (euri->user);
+	euri->user = NULL;
 
-	if (user != NULL) {
-		euri->user = g_strdup (user);
-		e_source_set_property (source, "auth", "1");
-	} else {
-		e_source_set_property (source, "auth", NULL);
-	}
-
-	projection = g_strdup ("/private/full");
+	/* two reasons why set readonly to FALSE:
+	   a) the e_source_set_relative_uri does nothing for readonly sources
+	   b) we are going to set default uri, which should be always writeable */
+	e_source_set_readonly (source, FALSE);
 
-	if (!is_email (user)) {
-		user = g_strconcat (user, "@gmail.com", NULL);
-	}
+	user = gtk_entry_get_text (GTK_ENTRY (editable));
+	uri = construct_default_uri (user);
+	e_source_set_relative_uri (source, uri);
+	g_free (uri);
 
-	e_source_set_relative_uri (source, g_strconcat (CALENDAR_LOCATION, g_strdup(user), g_strdup (projection), NULL));
-	e_source_set_property (source, "username", euri->user);
+	e_source_set_property (source, "username", gtk_entry_get_text (GTK_ENTRY (editable)));
 	e_source_set_property (source, "protocol", "google");
 	e_source_set_property (source, "auth-domain", "google");
+	e_source_set_property (source, "auth", (user && *user) ? "1" : NULL);
+	e_source_set_property (source, "googlename", NULL);
+
+	/* we changed user, thus reset the chosen calendar combo too, because
+	   other user means other calendars subscribed */
+	init_combo_values (GTK_COMBO_BOX (g_object_get_data (G_OBJECT (editable), "CalendarCombo")), _("Default"), NULL);
 
 	ruri = print_uri_noproto (euri);
 	g_free (ruri);
@@ -296,6 +384,229 @@ set_refresh_time (ESource *source, GtkWi
 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), time);
 }
 
+enum {
+	COL_COLOR = 0, /* GDK_TYPE_COLOR */
+	COL_TITLE,     /* G_TYPE_STRING */
+	COL_URL_PATH,  /* G_TYPE_STRING */
+	COL_READ_ONLY, /* G_TYPE_BOOLEAN */
+	NUM_COLUMNS
+};
+
+static void
+init_combo_values (GtkComboBox *combo, const char *deftitle, const char *defuri)
+{
+	GtkTreeIter iter;
+	GtkListStore *store;
+
+	if (!combo)
+		return;
+
+	store = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+
+	gtk_list_store_clear (store);
+
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter,
+		COL_COLOR, NULL,
+		COL_TITLE, deftitle,
+		COL_URL_PATH, defuri,
+		COL_READ_ONLY, FALSE,
+		-1);
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+}
+
+static void
+cal_combo_changed (GtkComboBox *combo, ESource *source)
+{
+	GtkListStore *store;
+	GtkTreeIter iter;
+
+	g_return_if_fail (combo != NULL);
+	g_return_if_fail (source != NULL);
+
+	store = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+
+	if (gtk_combo_box_get_active_iter (combo, &iter)) {
+		char *uri = NULL, *title = NULL;
+		gboolean readonly = FALSE;
+
+		gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COL_TITLE, &title, COL_URL_PATH, &uri, COL_READ_ONLY, &readonly, -1);
+
+		if (!uri)
+			uri = construct_default_uri (e_source_get_property (source, "username"));
+
+		if (is_default_uri (uri, e_source_get_property (source, "username"))) {
+			/* do not store title when we use default uri */
+			g_free (title);
+			title = NULL;
+		}
+
+		/* first set readonly to FALSE, otherwise if TRUE, then e_source_set_readonly does nothing */
+		e_source_set_readonly (source, FALSE);
+		e_source_set_relative_uri (source, uri);
+		e_source_set_readonly (source, readonly);
+		e_source_set_property (source, "googlename", title);
+		e_source_set_property (source, "protocol", "google");
+		e_source_set_property (source, "auth-domain", "google");
+
+		g_free (title);
+		g_free (uri);
+	}
+}
+
+static void
+claim_error (GtkWindow *parent, const char *error)
+{
+	GtkWidget *dialog;
+
+	dialog = gtk_message_dialog_new (parent,
+			GTK_DIALOG_DESTROY_WITH_PARENT,
+			GTK_MESSAGE_ERROR,
+			GTK_BUTTONS_CLOSE,
+			error);
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+}
+
+static void
+retrieve_list_clicked (GtkButton *button, GtkComboBox *combo)
+{
+	ESource *source;
+	GDataGoogleService *service;
+	GDataFeed *feed;
+	char *password, *tmp;
+	const char *username;
+	GError *error = NULL;
+	GtkWindow *parent;
+
+	g_return_if_fail (button != NULL);
+	g_return_if_fail (combo != NULL);
+
+	parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button)));
+
+	source = g_object_get_data (G_OBJECT (button), "ESource");
+	g_return_if_fail (source != NULL);
+
+	username = e_source_get_property (source, "username");
+	if (!username || !*username) {
+		claim_error (parent, _("Please enter user name first."));
+		return;
+	}
+
+	tmp = g_strdup_printf (_("Enter password for user %s to access list of subscribed calendars."), username);
+	password = e_passwords_ask_password (_("Enter password"), "Calendar", "", tmp, 
+			E_PASSWORDS_REMEMBER_NEVER | E_PASSWORDS_REPROMPT | E_PASSWORDS_SECRET | E_PASSWORDS_DISABLE_REMEMBER,
+			NULL, parent);
+	g_free (tmp);
+
+	if (!password)
+		return;
+
+	service = gdata_google_service_new ("cl", "evolution-client-0.0.1");
+	gdata_service_set_credentials (GDATA_SERVICE (service), username, password);
+	/* privacy... maybe... */
+	memset (password, 0, strlen (password));
+	g_free (password);
+
+	feed = gdata_service_get_feed (GDATA_SERVICE (service), URL_GET_SUBSCRIBED_CALENDARS, &error);
+
+	if (feed) {
+		GSList *l;
+		char *old_selected = NULL;
+		int idx, active = -1, default_idx = -1;
+		GtkListStore *store = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+		GtkTreeIter iter;
+
+		if (gtk_combo_box_get_active_iter (combo, &iter))
+			gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COL_URL_PATH, &old_selected, -1);
+
+		gtk_list_store_clear (store);
+
+		for (l = gdata_feed_get_entries (feed), idx = 1; l != NULL; l = l->next) {
+			const char *uri, *title, *color, *access;
+			GSList *links;
+			GDataEntry *entry = (GDataEntry *) l->data;
+
+			if (!entry || !GDATA_IS_ENTRY (entry))
+				continue;
+
+			/* skip hidden entries */
+			if (gdata_entry_get_custom (entry, "hidden") && g_ascii_strcasecmp (gdata_entry_get_custom (entry, "hidden"), "true") == 0)
+				continue;
+
+			uri = NULL;
+			for (links = gdata_entry_get_links (entry); links && !uri; links = links->next) {
+				GDataEntryLink *link = (GDataEntryLink *)links->data;
+
+				if (!link || !link->href || !link->rel)
+					continue;
+
+				if (g_ascii_strcasecmp (link->rel, "alternate") == 0)
+					uri = link->href;
+			}
+
+			title = gdata_entry_get_title (entry);
+			color = gdata_entry_get_custom (entry, "color");
+			access = gdata_entry_get_custom (entry, "accesslevel");
+
+			if (uri && title) {
+				GdkColor gdkcolor;
+
+				if (old_selected && g_str_equal (old_selected, uri))
+					active = idx;
+
+				if (color)
+					gdk_color_parse (color, &gdkcolor);
+
+				if (default_idx == -1 && is_default_uri (uri, username)) {
+					/* have the default uri always NULL and first in the combo */
+					uri = NULL;
+					gtk_list_store_insert (store, &iter, 0);
+					default_idx = idx;
+				} else {
+					gtk_list_store_append (store, &iter);
+				}
+
+				gtk_list_store_set (store, &iter,
+					COL_COLOR, color ? &gdkcolor : NULL,
+					COL_TITLE, title,
+					COL_URL_PATH, uri,
+					COL_READ_ONLY, access && !g_str_equal (access, "owner") && !g_str_equal (access, "contributor"),
+					-1);
+				idx++;
+			}
+		}
+
+		if (default_idx == -1) {
+			/* Hey, why we didn't find the default uri? Did something go so wrong or what? */
+			gtk_list_store_insert (store, &iter, 0);
+			gtk_list_store_set (store, &iter,
+				COL_COLOR, NULL,
+				COL_TITLE, _("Default"),
+				COL_URL_PATH, NULL,
+				COL_READ_ONLY, FALSE,
+				-1);
+		}
+
+		gtk_combo_box_set_active (combo, active == -1 ? 0 : active);
+
+		g_free (old_selected);
+		g_object_unref (feed);
+	} else {
+		tmp = g_strdup_printf (_("Cannot read data from Google server.\n%s"), (error && error->message) ? error->message : _("Unknown error."));
+		claim_error (parent, tmp);
+		g_free (tmp);
+
+		if (error) {
+			g_error_free (error);
+			error = NULL;
+		}
+	}
+
+	g_object_unref (service);
+}
+
 GtkWidget *
 plugin_google  (EPlugin                    *epl,
 	     EConfigHookItemFactoryData *data)
@@ -310,11 +621,14 @@ plugin_google  (EPlugin                 
 	GtkWidget    *luser;
 	GtkWidget    *user;
 	GtkWidget    *label;
+	GtkWidget    *combo;
 	char         *uri;
 	char         *username;
 	const char   *ssl_prop;
 	gboolean      ssl_enabled;
 	int           row;
+	GtkCellRenderer *renderer;
+	GtkListStore *store;
 
 	GtkWidget *option, *spin, *menu, *hbox;
 	GtkWidget *times [4];
@@ -430,7 +744,48 @@ plugin_google  (EPlugin                 
         g_free (uri);
 	g_free (username);
 
-	return widget;
-}
+	label = gtk_label_new_with_mnemonic (_("Cal_endar:"));
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_widget_show (label);
+	gtk_table_attach (GTK_TABLE (parent), label, 0, 1, row + 4, row + 5, GTK_FILL | GTK_EXPAND, 0, 0, 0);
 
+	store = gtk_list_store_new (
+		NUM_COLUMNS,
+		GDK_TYPE_COLOR,		/* COL_COLOR */
+		G_TYPE_STRING,		/* COL_TITLE */
+		G_TYPE_STRING,		/* COL_URL_PATH */
+		G_TYPE_BOOLEAN);	/* COL_READ_ONLY */
 
+	combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
+
+	renderer = e_cell_renderer_color_new ();
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
+	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, "color", COL_COLOR, NULL);
+
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, "text", COL_TITLE, NULL);
+
+	init_combo_values (GTK_COMBO_BOX (combo),
+		e_source_get_property (source, "googlename") ? e_source_get_property (source, "googlename") : _("Default"),
+		e_source_get_property (source, "googlename") ? e_source_peek_relative_uri (source) : NULL);
+
+	g_signal_connect (combo, "changed", G_CALLBACK (cal_combo_changed), source);
+
+	g_object_set_data (G_OBJECT (user), "CalendarCombo", combo);
+
+	hbox = gtk_hbox_new (FALSE, 6);
+
+	gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
+	label = gtk_button_new_with_mnemonic (_("Retrieve _list"));
+	g_signal_connect (label, "clicked", G_CALLBACK (retrieve_list_clicked), combo);
+	g_object_set_data (G_OBJECT (label), "ESource", source);
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+	gtk_widget_show_all (hbox);
+	gtk_table_attach (GTK_TABLE (parent), hbox, 1, 2, row + 4, row + 5, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+
+	return widget;
+}
Index: configure.in
===================================================================
--- configure.in	(revision 35830)
+++ configure.in	(working copy)
@@ -184,7 +184,9 @@ PKG_CHECK_MODULES(EVOLUTION_DATA_SERVER,
          libedataserver-$EDS_PACKAGE >= eds_minimum_version
          libedataserverui-$EDS_PACKAGE >= eds_minimum_version
          libegroupwise-$EDS_PACKAGE >= eds_minimum_version
-         libebackend-$EDS_PACKAGE >= eds_minimum_version])
+         libebackend-$EDS_PACKAGE >= eds_minimum_version
+	 libgdata-$EDS_PACKAGE >= eds_minimum_version
+	 libgdata-google-$EDS_PACKAGE >= eds_minimum_version])
 
 
 dnl ******************
@@ -1570,7 +1572,7 @@ EVO_SET_COMPILE_FLAGS(LIBSOUP, libsoup-2
 AC_SUBST(LIBSOUP_CFLAGS)
 AC_SUBST(LIBSOUP_LIBS)
 
-EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, libgnomeui-2.0 libbonoboui-2.0 libglade-2.0 gio-2.0 gconf-2.0 gobject-2.0 libgtkhtml-$GTKHTML_PACKAGE libebook-$EDS_PACKAGE libecal-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE libebackend-$EDS_PACKAGE $HAL_REQUIREMENT $libnotify gtkhtml-editor)
+EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, libgnomeui-2.0 libbonoboui-2.0 libglade-2.0 gio-2.0 gconf-2.0 gobject-2.0 libgtkhtml-$GTKHTML_PACKAGE libebook-$EDS_PACKAGE libecal-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE libebackend-$EDS_PACKAGE $HAL_REQUIREMENT $libnotify gtkhtml-editor libgdata-$EDS_PACKAGE libgdata-google-$EDS_PACKAGE)
 AC_SUBST(EVOLUTION_CALENDAR_CFLAGS)
 AC_SUBST(EVOLUTION_CALENDAR_LIBS)
 
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 35830)
+++ ChangeLog	(working copy)
@@ -1,3 +1,10 @@
+2008-07-24  Milan Crha  <mcrha@redhat.com>
+
+	** Part of fix for bug #535745
+
+	* configure.in: Require and link calendar libs with libgdata
+	and libgdata-google.
+
 2008-07-23  Johnny Jacob  <jjohnny@novell.com>
 
 	* configure.in: Version bumped to 2.23.6.
