Re: [evolution-patches] Free/Busy Bounty rev 2



On Mon, 2004-01-12 at 16:29 +0100, Rodrigo Moya wrote:
> On Sun, 2004-01-11 at 21:38 -0700, Gary Ekker wrote:
> > I have attached a new revision of the patch to the bug: 
> > 
> > http://bugzilla.gnome.org/show_bug.cgi?id=127539
> > 
> > My ISP's ftp server is down, so I didn't post any screenshots. Hopefully
> > this is the final revision. It will now check to see if it needs to
> > publish, and do so if it has been more than a day or week depending on
> > what the user has set. It will also publish after the the settings have
> > been changed. Additionaly you can arbitrarily publish with the Actions
> > menu or the pop-up menu.
> > 
> > Automatic publishing is set up in calendar-component.c: createControls.
> > It occured to me that it may be good to only check to publish on the
> > initial creation of the component and then remove the callback with
> > g_idle_remove rather than have it continue to try, the code to do this
> > is there, but commented out. This would especially be good if the server
> > to which the user is publishing is down. Thoughts?
> > 
> but if you remove the g_idle handler, how would you publish again, in
> the next hour or day?

After further thought on this, i agree, it should  not be removed.
Fixed.

> more comments below
> 
> > +static gboolean
> > +init_calendar_publishing_cb (gpointer data)
> > +{
> > +#if 0
> > +       guint *idle_id = (guint *) data;
> > +
> > +       /* remove the idle function--We could do this so that it runs
> once 
> > +       on each startup */
> > +       g_source_remove (*idle_id);
> > +       g_free (idle_id);
> > +#endif
> >
> returning FALSE on the callback will disable calling it again, so there
> is no need to g_source_remove it.
> 
> > +       idle_id = g_new0 (guint, 1);
> > +       *idle_id = g_idle_add ((GSourceFunc)
> init_calendar_publishing_cb, idle_id);
> >
> instead of allocating memory, you can pass the integer as 'user_data' by
> using GINT_TO_POINTER. Then, you can retrieve it with GPOINTER_TO_INT,
> in the callback.
> 
> > +                       icomp = e_cal_component_get_icalcomponent
> (pub_comp);
> > +                       icomp_clone =
> e_cal_component_get_icalcomponent (*clone);
> > +                       for (prop = icalcomponent_get_first_property
> (icomp,
> > +
> ICAL_FREEBUSY_PROPERTY);
> > +                               prop != NULL;
> > +                               prop = icalcomponent_get_next_property
> (icomp, 
> > +
> ICAL_FREEBUSY_PROPERTY))
> > +                       {
> > +                               icalproperty *p;
> > +               
> > +                               p = icalproperty_new_clone (prop);
> > +                               icalcomponent_add_property
> (icomp_clone, p);
> > +                       }
> >
> what is this 'for' loop for? You are adding the properties from the
> component you already cloned.
> 

There are two components here. What this function does it aggregate the
data. So if we are getting Free/Busy from multiple calendars, this is
called once for each ESource and the FB properties are all added to one
component. If there still seems to be a problem here given that
information, let me know. I can't think of another way to accomplish
this right now.

> > +       /* Publish the component */
> > +       session = soup_session_async_new ();
> >
> you should probably free the session before returning from
> itip_publish_comp. There are a few places where the function returns
> that needs memory to be freed.
> 
Done. Thanks for the suggestions. Attached is the latest revision.

> cheers
? free-busy.diff
? free-busy2.diff
? free-busy3.diff
? name
? common/Makefile
? common/Makefile.in
? gui/apps_evolution_calendar-1.5.schemas
? gui/e-pub-utils.c
? gui/e-pub-utils.h
? gui/fb-utils.c
? gui/fb-utils.h
? gui/dialogs/cal-prefs-dialog.gladep
? gui/dialogs/fb-editor.glade
? gui/dialogs/fb-editor.gladep
? gui/dialogs/url-editor-dialog.c
? gui/dialogs/url-editor-dialog.glade
? gui/dialogs/url-editor-dialog.gladep
? gui/dialogs/url-editor-dialog.h
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/calendar/ChangeLog,v
retrieving revision 1.2058
diff -u -r1.2058 ChangeLog
--- ChangeLog	9 Jan 2004 20:49:37 -0000	1.2058
+++ ChangeLog	12 Jan 2004 18:27:08 -0000
@@ -1,3 +1,66 @@
+2004-01-11 Gary Ekker <gekker novell com>
+
+	* gui/Makefile.am: add SOUP_CFLAGS, SOUP_LIBS, and fb-utils.[ch]
+	for Free/Busy publishing
+	
+	* gui/apps_evolution_calendar.schemas.in.in: add schema for
+	/apps/evo/calendar/free_busy key
+	
+	* gui/calendar-commands.c (publish_freebusy_cmd): change to
+	publish component rather than attach as email
+	
+	* gui/calendar-config-keys.h: add free_busy/urls key definition
+	
+	* gui/calendar-config.[ch] (calendar_config_get_free_busy): new
+  	method for retrieving FB gconf key
+	(calendar_config_set_free_busy): new method for saving FB
+	gconf key
+	
+	* gui/e-cal-view.c (on_publish): change to publish component
+	rather than attach as email
+	
+	* gui/itip-utils.[ch] (itip_publish_begin): new method to process 
+	e_cal_components and aggregate the data if we are publishing
+	for multiple calendars
+	(itip_publish_comp): new method to publish the ical data to an
+	http server via libsoup
+	(comp_fb_normalize): new static method to ensure rfc 2446 compliant 
+	data before publishing icalcomponent_get_uid
+	(fb_sort): new static method to sort FB properties in ascending order
+	
+	* gui/dialogs/Makefile.am: add url-editor-dialog.[ch] and 
+	url-editor-dialog.glade for configure FB publishing
+	
+	* gui/dialogs/cal-prefs-dialog.[ch] (cal_prefs_dialog_url_add_clicked):
+	(cal_prefs_dialog_url_edit_clicked):new method for events in FB tab 
+	of cal-prefs-dialog
+	(cal_prefs_dialog_url_remove_clicked): ditto
+	(cal_prefs_dialog_url_enable_clicked): ditto
+	(cal_prefs_dialog_url_url_list_change): ditto
+	(cal_prefs_dialog_url_url_list_enable_toggled): ditto
+	(cal_prefs_dialog_url_url_list_double_click): ditto
+	(show_fb_config): new method for updating dialog with FB specific
+	data in gconf
+	(update_fb_config): new method for updating gconf with FB specific
+	data from dialogs
+	(setup_changes): detect changes in url_list gtk_tree_view
+	(get_widgets): include new dialog widgets for FB config
+	(init_widgets): connect signals for new FB config widgets
+	
+	* gui/dialogs/cal-prefs-dialog.glade: add new widgets for FB config
+	
+	* gui/dialogs/url-editor-dialog.[ch]: add files for FB url-editor dialog
+	
+	* gui/dialogs/url-editor-dialog.glade: ditto
+	
+	* gui/e-pub-utils.[ch]: add files with FB publishing utilities
+
+	* gui/calendar-component.c (init_calendar_publishing): sets up
+	listeners to publish calendar, g_idle_add, and on gconf change
+	(init_calendar_publishing_cb): ditto
+	(conf_changed_callback): ditto
+	(impl_createControls): ditto
+	
 2004-01-09  Hans Petter Jansson  <hpj ximian com>
 
 	* gui/calendar-component.c (new_calendar_cb): calendar_config ->
Index: gui/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/Makefile.am,v
retrieving revision 1.290
diff -u -r1.290 Makefile.am
--- gui/Makefile.am	22 Dec 2003 15:57:20 -0000	1.290
+++ gui/Makefile.am	12 Jan 2004 18:27:08 -0000
@@ -166,6 +166,8 @@
 	e-meeting-utils.h			\
 	e-mini-calendar-config.c		\
 	e-mini-calendar-config.h		\
+	e-pub-utils.c				\
+	e-pub-utils.h				\
 	e-select-names-editable.c		\
 	e-select-names-editable.h		\
 	e-select-names-renderer.c		\
Index: gui/apps_evolution_calendar.schemas.in.in
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/apps_evolution_calendar.schemas.in.in,v
retrieving revision 1.1
diff -u -r1.1 apps_evolution_calendar.schemas.in.in
--- gui/apps_evolution_calendar.schemas.in.in	2 Dec 2003 15:55:45 -0000	1.1
+++ gui/apps_evolution_calendar.schemas.in.in	12 Jan 2004 18:27:08 -0000
@@ -355,5 +355,17 @@
         <short>Programs that can run as part of alarms</short>
       </locale>
     </schema>
+    
+    <schema>
+      <key>/schemas/apps/evolution/calendar/publish/uris</key>
+      <applyto>/apps/evolution/calendar/publish/uris</applyto>
+      <owner>evolution-calendar</owner>
+      <type>list</type>
+      <list_type>string</list_type>
+      <default>[]</default>
+      <locale name="C">
+        <short>List of urls for free/busy publishing</short>
+      </locale>
+    </schema>    
   </schemalist>
 </gconfschemafile>
Index: gui/calendar-commands.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-commands.c,v
retrieving revision 1.141
diff -u -r1.141 calendar-commands.c
--- gui/calendar-commands.c	9 Jan 2004 19:50:08 -0000	1.141
+++ gui/calendar-commands.c	12 Jan 2004 18:27:08 -0000
@@ -60,6 +60,7 @@
 #include "print.h"
 #include "dialogs/cal-prefs-dialog.h"
 #include "itip-utils.h"
+#include "e-pub-utils.h"
 #include "evolution-shell-component-utils.h"
 
 /* Focusing information for the calendar view.  We have to keep track of this
@@ -319,36 +320,7 @@
 static void
 publish_freebusy_cmd (BonoboUIComponent *uic, gpointer data, const gchar *path)
 {
-	GnomeCalendar *gcal;
-	GList *client_list, *cl;
-	GList *comp_list = NULL;
-	icaltimezone *utc;
-	time_t start = time (NULL), end;
-
-	gcal = GNOME_CALENDAR (data);
-
-	utc = icaltimezone_get_utc_timezone ();
-	start = time_day_begin_with_zone (start, utc);
-	end = time_add_week_with_zone (start, 6, utc);
-
-	/* FIXME Should we aggregate the data? */
-	client_list = e_cal_model_get_client_list (gnome_calendar_get_calendar_model (gcal));
-	for (cl = client_list; cl != NULL; cl = cl->next) {
-		if (e_cal_get_free_busy ((ECal *) cl->data, NULL, start, end, &comp_list, NULL)) {
-			GList *l;
-
-			for (l = comp_list; l; l = l->next) {
-				ECalComponent *comp = E_CAL_COMPONENT (l->data);
-				itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, (ECal *) cl->data, NULL);
-
-				g_object_unref (comp);
-			}
-
-			g_list_free (comp_list);
-		}
-	}
-
-	g_list_free (client_list);
+	e_pub_publish (TRUE);
 }
 
 static void
Index: gui/calendar-component.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-component.c,v
retrieving revision 1.130
diff -u -r1.130 calendar-component.c
--- gui/calendar-component.c	9 Jan 2004 20:49:38 -0000	1.130
+++ gui/calendar-component.c	12 Jan 2004 18:27:09 -0000
@@ -30,6 +30,8 @@
 #include <bonobo/bonobo-control.h>
 #include <bonobo/bonobo-i18n.h>
 #include <bonobo/bonobo-exception.h>
+#include "e-pub-utils.h"
+#include "calendar-config-keys.h"
 #include "calendar-config.h"
 #include "calendar-component.h"
 #include "calendar-commands.h"
@@ -59,6 +61,7 @@
 	char *config_directory;
 
 	GConfClient *gconf_client;
+	int gconf_notify_id;
 	ESourceList *source_list;
 	GSList *source_selection;
 	
@@ -436,6 +439,25 @@
 	update_primary_selection (data);
 }
 
+static gboolean
+init_calendar_publishing_cb (gpointer data)
+{	
+	/* Publish if it is time to publish again */
+	e_pub_publish (FALSE);
+
+	return TRUE;
+}
+
+static void
+conf_changed_callback (GConfClient *client,
+		       unsigned int connection_id,
+		       GConfEntry *entry,
+		       void *user_data)
+{
+	/* publish config changed, so publish */
+	e_pub_publish (TRUE);
+}
+
 /* GObject methods.  */
 
 static void
@@ -589,6 +611,25 @@
 }
 
 static void
+init_calendar_publishing (CalendarComponent *calendar_component)
+{
+	guint *idle_id;
+	CalendarComponentPrivate *priv;
+	
+	priv = calendar_component->priv;
+	
+	gconf_client_add_dir (priv->gconf_client, CALENDAR_CONFIG_PUBLISH, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+	priv->gconf_notify_id
+		= gconf_client_notify_add (priv->gconf_client, CALENDAR_CONFIG_PUBLISH,
+					   (GConfClientNotifyFunc) conf_changed_callback, NULL,
+					   NULL, NULL);
+	
+	idle_id = g_new0 (guint, 1);
+	*idle_id = g_idle_add ((GSourceFunc) init_calendar_publishing_cb, GINT_TO_POINTER (idle_id));
+}
+
+static void
 impl_createControls (PortableServer_Servant servant,
 		     Bonobo_Control *corba_sidebar_control,
 		     Bonobo_Control *corba_view_control,
@@ -636,6 +677,9 @@
 	e_activity_handler_attach_task_bar (priv->activity_handler, E_TASK_BAR (statusbar_widget));
 	statusbar_control = bonobo_control_new (statusbar_widget);
 
+	/* Initialize Calendar Publishing */
+	init_calendar_publishing(calendar_component);
+	
 	/* connect after setting the initial selections, or we'll get unwanted calls
 	   to calendar_control_sensitize_calendar_commands */
 	g_signal_connect_object (priv->source_selector, "selection_changed",
Index: gui/calendar-config-keys.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-config-keys.h,v
retrieving revision 1.4
diff -u -r1.4 calendar-config-keys.h
--- gui/calendar-config-keys.h	3 Dec 2003 16:37:22 -0000	1.4
+++ gui/calendar-config-keys.h	12 Jan 2004 18:27:09 -0000
@@ -70,6 +70,9 @@
 #define CALENDAR_CONFIG_DEFAULT_REMINDER_INTERVAL CALENDAR_CONFIG_PREFIX "/other/default_reminder_interval"
 #define CALENDAR_CONFIG_DEFAULT_REMINDER_UNITS CALENDAR_CONFIG_PREFIX "/other/default_reminder_units"
 
+/* Free/Busy settings */
+#define CALENDAR_CONFIG_PUBLISH CALENDAR_CONFIG_PREFIX"/publish/uris"
+
 G_END_DECLS
 
 #endif
Index: gui/calendar-config.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-config.c,v
retrieving revision 1.65
diff -u -r1.65 calendar-config.c
--- gui/calendar-config.c	14 Dec 2003 23:57:08 -0000	1.65
+++ gui/calendar-config.c	12 Jan 2004 18:27:09 -0000
@@ -1025,3 +1025,16 @@
 	return sexp;
 }
 
+GSList *
+calendar_config_get_free_busy(void)
+{	
+	return gconf_client_get_list (config, CALENDAR_CONFIG_PUBLISH, 
+				      GCONF_VALUE_STRING, NULL);
+}
+
+void
+calendar_config_set_free_busy (GSList *url_list)
+{
+	gconf_client_set_list (config, CALENDAR_CONFIG_PUBLISH, 
+			       GCONF_VALUE_STRING, url_list, NULL);
+}
Index: gui/calendar-config.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-config.h,v
retrieving revision 1.30
diff -u -r1.30 calendar-config.h
--- gui/calendar-config.h	19 Nov 2003 03:55:31 -0000	1.30
+++ gui/calendar-config.h	12 Jan 2004 18:27:09 -0000
@@ -202,6 +202,9 @@
 CalUnits calendar_config_get_default_reminder_units (void);
 void     calendar_config_set_default_reminder_units (CalUnits units);
 
+/* Free/Busy Settings */
+GSList * calendar_config_get_free_busy(void);
+void calendar_config_set_free_busy(GSList * url_list);
 
 /* Convenience functions to configure common properties of ECalendar,
    EDateEdit & ECalendarTable widgets, and the ECellDateEdit ETable cell. */
Index: gui/e-cal-view.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/e-cal-view.c,v
retrieving revision 1.29
diff -u -r1.29 e-cal-view.c
--- gui/e-cal-view.c	9 Jan 2004 07:48:29 -0000	1.29
+++ gui/e-cal-view.c	12 Jan 2004 18:27:11 -0000
@@ -41,6 +41,7 @@
 #include "e-cal-view.h"
 #include "e-comp-editor-registry.h"
 #include "itip-utils.h"
+#include "e-pub-utils.h"
 #include "dialogs/delete-comp.h"
 #include "dialogs/delete-error.h"
 #include "dialogs/event-editor.h"
@@ -1127,34 +1128,7 @@
 static void
 on_publish (GtkWidget *widget, gpointer user_data)
 {
-	ECalendarView *cal_view;
-	icaltimezone *utc;
-	time_t start = time (NULL), end;
-	GList *comp_list = NULL, *client_list, *cl;
-
-	cal_view = E_CALENDAR_VIEW (user_data);
-
-	utc = icaltimezone_get_utc_timezone ();
-	start = time_day_begin_with_zone (start, utc);
-	end = time_add_week_with_zone (start, 6, utc);
-
-	client_list = e_cal_model_get_client_list (cal_view->priv->model);
-	for (cl = client_list; cl != NULL; cl = cl->next) {
-		if (e_cal_get_free_busy ((ECal *) cl->data, NULL, start, end, &comp_list, NULL)) {
-			GList *l;
-
-			for (l = comp_list; l; l = l->next) {
-				ECalComponent *comp = E_CAL_COMPONENT (l->data);
-				itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, (ECal *) cl->data, NULL);
-
-				g_object_unref (comp);
-			}
-
-			g_list_free (comp_list);
-		}
-	}
-
-	g_list_free (client_list);
+	e_pub_publish (TRUE);
 }
 
 static void
Index: gui/itip-utils.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/itip-utils.c,v
retrieving revision 1.84
diff -u -r1.84 itip-utils.c
--- gui/itip-utils.c	1 Dec 2003 22:14:20 -0000	1.84
+++ gui/itip-utils.c	12 Jan 2004 18:27:12 -0000
@@ -37,6 +37,10 @@
 #include <e-util/e-time-utils.h>
 #include <libecal/e-cal-time-util.h>
 #include <libecal/e-cal-util.h>
+#include <libsoup/soup-session-async.h>
+#include <libsoup/soup-message.h>
+#include <libsoup/soup-uri.h>
+#include "e-util/e-passwords.h"
 #include "calendar-config.h"
 #include "itip-utils.h"
 
@@ -977,3 +981,217 @@
 	return retval;
 }
 
+gboolean
+itip_publish_begin (ECalComponent *pub_comp, ECal *client, 
+		    gboolean cloned, ECalComponent **clone)
+{
+	icalcomponent *icomp =NULL, *icomp_clone = NULL;
+	icalproperty *prop;
+		
+	if (e_cal_component_get_vtype (pub_comp) == E_CAL_COMPONENT_FREEBUSY) {
+				
+		if (!cloned) {
+			*clone = e_cal_component_clone(pub_comp);
+			cloned = TRUE;
+		} else {
+			
+			icomp = e_cal_component_get_icalcomponent (pub_comp);
+			icomp_clone = e_cal_component_get_icalcomponent (*clone);
+			for (prop = icalcomponent_get_first_property (icomp,
+						      ICAL_FREEBUSY_PROPERTY);
+	     			prop != NULL;
+	     			prop = icalcomponent_get_next_property (icomp, 
+						       ICAL_FREEBUSY_PROPERTY))
+			{
+				icalproperty *p;
+		
+				p = icalproperty_new_clone (prop);
+				icalcomponent_add_property (icomp_clone, p);
+			}
+		}		
+	}
+
+	return TRUE;
+}
+
+static void
+fb_sort (struct icalperiodtype *ipt, int fb_count)
+{
+	int i,j;
+	
+	if (ipt == NULL || fb_count == 0)
+		return;
+	
+	for (i = 0; i < fb_count-1; i++) {
+		for (j = i+1; j < fb_count; j++) {
+			struct icalperiodtype temp;
+				
+			if (icaltime_compare(ipt[i].start, ipt[j].start) < 0)
+				continue;
+			
+			if (icaltime_compare(ipt[i].start, ipt[j].start) == 0){
+				if (icaltime_compare(ipt[i].end, 
+						     ipt[j].start) < 0)
+					continue;
+			}
+			temp = ipt[i];
+			ipt[i] = ipt[j];
+			ipt[j] = temp;
+		}
+	}
+}
+
+static icalcomponent *
+comp_fb_normalize (icalcomponent *icomp)
+{
+	icalcomponent *iclone;
+	icalproperty *prop, *p;
+	const char *uid,  *comment;
+	struct icaltimetype itt;
+	int fb_count, i = 0, j;
+	struct icalperiodtype *ipt;
+	
+	iclone = icalcomponent_new (ICAL_VFREEBUSY_COMPONENT);
+	
+	prop = icalcomponent_get_first_property (icomp, 
+						 ICAL_ORGANIZER_PROPERTY);
+	p = icalproperty_new_clone (prop);
+	icalcomponent_add_property (iclone, p);
+	
+	itt = icalcomponent_get_dtstart (icomp);
+	icalcomponent_set_dtstart(iclone, itt);
+	
+	itt = icalcomponent_get_dtend (icomp);
+	icalcomponent_set_dtend (iclone, itt);
+	
+	fb_count =  icalcomponent_count_properties (icomp, 
+						    ICAL_FREEBUSY_PROPERTY);
+	ipt = g_new0(struct icalperiodtype, fb_count+1);
+	
+	for (prop = icalcomponent_get_first_property (icomp, 
+						      ICAL_FREEBUSY_PROPERTY);
+		prop != NULL;
+		prop = icalcomponent_get_next_property (icomp, 
+							ICAL_FREEBUSY_PROPERTY))
+	{
+		ipt[i] = icalproperty_get_freebusy(prop);
+		i++;
+	}
+	
+	fb_sort (ipt, fb_count);
+	
+	for (j = 0; j <= fb_count-1; j++) {
+		icalparameter *param;
+		
+		prop = icalproperty_new_freebusy (ipt[j]);
+		param = icalparameter_new_fbtype (ICAL_FBTYPE_BUSY);
+		icalproperty_add_parameter (prop, param);
+		icalcomponent_add_property (iclone, prop);
+	}
+	g_free (ipt);
+	
+	/* Should I strip this RFC 2446 says there must not be a UID
+		if the METHOD is PUBLISH?? */
+	uid = icalcomponent_get_uid(icomp);
+	if (uid)
+		icalcomponent_set_uid (iclone, uid);
+
+	itt = icaltime_from_timet_with_zone (time (NULL), FALSE,
+					     icaltimezone_get_utc_timezone ());
+	icalcomponent_set_dtstamp (iclone, itt);	
+	
+	prop = icalcomponent_get_first_property (icomp, ICAL_URL_PROPERTY);
+	p = icalproperty_new_clone (prop);
+	icalcomponent_add_property (iclone, p);
+	
+	comment =  icalcomponent_get_comment(icomp);
+	if (comment)
+		icalcomponent_set_comment(iclone, comment);
+
+	for (prop = icalcomponent_get_first_property (icomp, ICAL_X_PROPERTY);
+	     prop != NULL;
+	     prop = icalcomponent_get_next_property (icomp, ICAL_X_PROPERTY))
+	{		
+		p = icalproperty_new_clone (prop);
+		icalcomponent_add_property (iclone, p);
+	}
+	
+	return iclone;
+
+	g_object_unref (iclone);
+	return NULL;
+}
+
+gboolean
+itip_publish_comp (ECal *client, gchar *uri, gchar *username, 
+		   gchar *password, ECalComponent **pub_comp)
+{
+	icalcomponent *toplevel = NULL, *icalcomp = NULL;
+	icalcomponent *icomp = NULL;
+	SoupSession *session;
+	SoupMessage *msg;
+	SoupUri *real_uri;
+	char *ical_string;
+	char *prompt;
+	gboolean remember = FALSE;
+	
+	toplevel = e_cal_util_new_top_level ();
+	icalcomponent_set_method(toplevel, ICAL_METHOD_PUBLISH);
+	
+	e_cal_component_set_url (*pub_comp, uri);
+	
+	icalcomp = e_cal_component_get_icalcomponent (*pub_comp);
+	
+	icomp = comp_fb_normalize (icalcomp);	
+
+	icalcomponent_add_component (toplevel, icomp);
+	ical_string = icalcomponent_as_ical_string (toplevel);
+
+	/* Publish the component */
+	session = soup_session_async_new ();
+
+	/* add username and password to the uri */	
+	if (strlen(password) == 0) {
+		prompt = g_strdup_printf (_("Enter the password for %s"), uri);
+		password = e_passwords_ask_password (_("Enter password"), 
+						     "Calendar", NULL, 
+						     prompt, TRUE, 
+						   E_PASSWORDS_DO_NOT_REMEMBER,
+						     &remember, NULL);
+
+		g_free (prompt);
+	}
+
+	real_uri = soup_uri_new(uri);
+	if (!real_uri) {
+		g_warning (G_STRLOC ": Invalid URL: %s", uri);
+		return FALSE;
+	}
+	
+	real_uri->user = g_strdup(username);
+	real_uri->passwd = g_strdup(password);
+		
+	/* build the SOAP message */
+	msg = soup_message_new_from_uri (SOUP_METHOD_PUT, real_uri);
+	if (!msg) {
+		g_warning (G_STRLOC ": Could not build SOAP message");
+		return FALSE;
+	}
+	soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);	
+	soup_message_set_request (msg, "text/calendar", SOUP_BUFFER_USER_OWNED,
+				  ical_string, strlen (ical_string));
+	
+	/* send message to server */
+	soup_session_send_message (session, msg);
+	if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+		g_warning(G_STRLOC ": Could not publish Free/Busy: %d: %s", 
+			  msg->status_code, 
+			  soup_status_get_phrase(msg->status_code));
+		return FALSE;
+	}
+	
+	soup_uri_free (real_uri);
+	g_object_unref (session);
+	
+	return TRUE;
+}
Index: gui/itip-utils.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/itip-utils.h,v
retrieving revision 1.15
diff -u -r1.15 itip-utils.h
--- gui/itip-utils.h	7 Nov 2003 05:52:00 -0000	1.15
+++ gui/itip-utils.h	12 Jan 2004 18:27:12 -0000
@@ -31,5 +31,10 @@
 gboolean itip_send_comp (ECalComponentItipMethod method, ECalComponent *comp,
 			 ECal *client, icalcomponent *zones);
 
+gboolean itip_publish_comp (ECal *client, gchar* uri, gchar* username, 
+			    gchar* password, ECalComponent **pub_comp);
+
+gboolean itip_publish_begin (ECalComponent *pub_comp, ECal *client, 
+			     gboolean cloned, ECalComponent **clone);
 
 #endif
Index: gui/dialogs/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/Makefile.am,v
retrieving revision 1.58
diff -u -r1.58 Makefile.am
--- gui/dialogs/Makefile.am	9 Jan 2004 20:49:39 -0000	1.58
+++ gui/dialogs/Makefile.am	12 Jan 2004 18:27:12 -0000
@@ -78,7 +78,9 @@
 	task-details-page.c	\
 	task-details-page.h	\
 	task-page.c		\
-	task-page.h
+	task-page.h		\
+	url-editor-dialog.c	\
+	url-editor-dialog.h	
 
 glade_DATA =				\
 	alarm-options.glade		\
@@ -91,8 +93,8 @@
 	recurrence-page.glade		\
 	schedule-page.glade		\
 	task-details-page.glade		\
-	task-page.glade
-
+	task-page.glade			\
+	url-editor-dialog.glade
 
 CLEANFILES = $(BUILT_SOURCES)
 
Index: gui/dialogs/cal-prefs-dialog.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/cal-prefs-dialog.c,v
retrieving revision 1.31
diff -u -r1.31 cal-prefs-dialog.c
--- gui/dialogs/cal-prefs-dialog.c	18 Nov 2003 04:24:25 -0000	1.31
+++ gui/dialogs/cal-prefs-dialog.c	12 Jan 2004 18:27:13 -0000
@@ -34,10 +34,16 @@
 #include "../e-timezone-entry.h"
 #include "cal-prefs-dialog.h"
 #include "../calendar-config.h"
+#include "url-editor-dialog.h"
 
+#include <gtk/gtk.h>
+#include <gtk/gtkmain.h>
 #include <gtk/gtksignal.h>
 #include <gtk/gtkoptionmenu.h>
 #include <gtk/gtktogglebutton.h>
+#include <libxml/tree.h>
+#include <string.h>
+#include <libgnome/gnome-i18n.h>
 #include <libgnomeui/gnome-color-picker.h>
 #include <glade/glade.h>
 #include <gal/util/e-util.h>
@@ -45,40 +51,6 @@
 #include <widgets/misc/e-dateedit.h>
 
 
-struct _DialogData {
-	/* Glade XML data */
-	GladeXML *xml;
-
-	GtkWidget *page;
-
-	GtkWidget *timezone;
-	GtkWidget *working_days[7];
-	GtkWidget *week_start_day;
-	GtkWidget *start_of_day;
-	GtkWidget *end_of_day;
-	GtkWidget *use_12_hour;
-	GtkWidget *use_24_hour;
-	GtkWidget *time_divisions;
-	GtkWidget *show_end_times;
-	GtkWidget *compress_weekend;
-	GtkWidget *dnav_show_week_no;
-
-	/* Widgets for the task list options */
-	GtkWidget *tasks_due_today_color;
-	GtkWidget *tasks_overdue_color;
-
-	GtkWidget *tasks_hide_completed_checkbutton;
-	GtkWidget *tasks_hide_completed_spinbutton;
-	GtkWidget *tasks_hide_completed_optionmenu;
-
-	/* Other page options */
-	GtkWidget *confirm_delete;
-	GtkWidget *default_reminder;
-	GtkWidget *default_reminder_interval;
-	GtkWidget *default_reminder_units;
-};
-typedef struct _DialogData DialogData;
-
 static const int week_start_day_map[] = {
 	1, 2, 3, 4, 5, 6, 0, -1
 };
@@ -96,7 +68,6 @@
 	CAL_MINUTES, CAL_HOURS, CAL_DAYS, -1
 };
 
-
 static gboolean get_widgets (DialogData *data);
 
 static void widget_changed_callback (GtkWidget *, void *data);
@@ -115,8 +86,23 @@
 static void cal_prefs_dialog_start_of_day_changed (GtkWidget *button, void *data);
 static void cal_prefs_dialog_hide_completed_tasks_toggled (GtkWidget *button, void *data);
 
+static void cal_prefs_dialog_url_add_clicked(GtkWidget *button, void *data);
+static void cal_prefs_dialog_url_edit_clicked(GtkWidget *button, void *data);
+static void cal_prefs_dialog_url_remove_clicked(GtkWidget *button, void *data);
+static void cal_prefs_dialog_url_enable_clicked(GtkWidget *button, void *data);
+static void cal_prefs_dialog_url_list_change (GtkTreeSelection *selection, 
+					      DialogData *dialog_data);
+static void cal_prefs_dialog_url_list_enable_toggled (GtkCellRendererToggle *renderer, const char *path_string, void *data);
+static void cal_prefs_dialog_url_list_double_click(GtkTreeView *treeview, 
+						   GtkTreePath *path, 
+						   GtkTreeViewColumn *column, 
+						   DialogData *dialog_data);
+static void show_fb_config (DialogData *dialog_data);
+static void update_fb_config (DialogData *dialog_data);
+
 GtkWidget *cal_prefs_dialog_create_time_edit (void);
 
+#define PREFS_WINDOW(dialog_data) GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (dialog_data), GTK_TYPE_WINDOW))
 
 /**
  * cal_prefs_dialog_new:
@@ -233,6 +219,8 @@
 	connect_changed (dialog_data->default_reminder_interval, "changed", config_control);
 	connect_changed (GTK_OPTION_MENU (dialog_data->default_reminder_units)->menu, "selection_done", config_control);
 
+	connect_changed ((GtkWidget *) gtk_tree_view_get_selection (dialog_data->url_list), "changed", config_control);
+	
 	/* These use GnomeColorPicker so we have to use a different signal.  */
 	g_signal_connect((dialog_data->tasks_due_today_color), "color_set",
 			    G_CALLBACK (color_set_callback), config_control);
@@ -282,6 +270,12 @@
 	data->default_reminder = GW ("default-reminder");
 	data->default_reminder_interval = GW ("default-reminder-interval");
 	data->default_reminder_units = GW ("default-reminder-units");
+	
+	data->url_add = GW ("url_add");
+	data->url_edit = GW ("url_edit");
+	data->url_remove = GW ("url_remove");
+	data->url_enable = GW ("url_enable");
+	data->url_list = GTK_TREE_VIEW (GW ("url_list"));
 
 #undef GW
 
@@ -311,7 +305,12 @@
 		&& data->confirm_delete
 		&& data->default_reminder
 		&& data->default_reminder_interval
-		&& data->default_reminder_units);
+		&& data->default_reminder_units
+		&& data->url_add
+		&& data->url_edit
+		&& data->url_remove
+		&& data->url_enable
+		&& data->url_list);
 }
 
 
@@ -361,6 +360,13 @@
 static void
 init_widgets (DialogData *dialog_data)
 {
+	GtkCellRenderer *renderer = NULL;
+	GtkTreeSelection *selection;
+	GtkListStore *model;
+	
+	dialog_data->url_editor = FALSE;
+	dialog_data->url_editor_dlg =NULL;
+	
 	g_signal_connect((dialog_data->use_24_hour), "toggled",
 			    G_CALLBACK (cal_prefs_dialog_use_24_hour_toggled),
 			    dialog_data);
@@ -377,8 +383,65 @@
 			    "toggled",
 			    G_CALLBACK (cal_prefs_dialog_hide_completed_tasks_toggled),
 			    dialog_data);
-}
+	
+	/* Free/Busy ... */
+	g_signal_connect((dialog_data->url_add), "clicked",
+			    G_CALLBACK (cal_prefs_dialog_url_add_clicked),
+			    dialog_data);
+
+	g_signal_connect((dialog_data->url_edit), "clicked",
+			    G_CALLBACK (cal_prefs_dialog_url_edit_clicked),
+			    dialog_data);
 
+	g_signal_connect((dialog_data->url_remove), "clicked",
+			    G_CALLBACK (cal_prefs_dialog_url_remove_clicked),
+			    dialog_data);
+
+	g_signal_connect((dialog_data->url_enable), "clicked",
+			    G_CALLBACK (cal_prefs_dialog_url_enable_clicked),
+			    dialog_data);
+
+	/* Free/Busy Listview */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_object_set ((GObject *) renderer, "activatable", TRUE, NULL);
+	
+	model = gtk_list_store_new (URL_LIST_N_COLUMNS, G_TYPE_BOOLEAN,
+				    G_TYPE_STRING, G_TYPE_POINTER);
+	
+	gtk_tree_view_set_model (dialog_data->url_list, 
+				 (GtkTreeModel *) model);
+
+	gtk_tree_view_insert_column_with_attributes (dialog_data->url_list, -1,
+						    _("Enabled"), renderer,
+						    "active", 
+						     URL_LIST_ENABLED_COLUMN, 
+						    NULL);
+
+	g_signal_connect(renderer, "toggled", 
+			 G_CALLBACK (cal_prefs_dialog_url_list_enable_toggled),
+			 dialog_data);
+	
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(dialog_data->url_list, -1, 
+						    _("Location"), renderer,
+						    "text", 
+						    URL_LIST_LOCATION_COLUMN, 
+						    NULL);
+	
+	selection = gtk_tree_view_get_selection ((GtkTreeView *) dialog_data->url_list);
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+	gtk_tree_view_set_headers_visible ((GtkTreeView *) dialog_data->url_list, TRUE);
+	
+	
+	g_signal_connect (gtk_tree_view_get_selection (dialog_data->url_list),
+			  "changed", 
+			  G_CALLBACK (cal_prefs_dialog_url_list_change), 
+			  dialog_data);
+	
+	g_signal_connect(dialog_data->url_list, "row-activated",
+			 G_CALLBACK (cal_prefs_dialog_url_list_double_click),
+			 dialog_data);
+}
 
 static void
 cal_prefs_dialog_use_24_hour_toggled (GtkWidget	*button,
@@ -479,6 +542,300 @@
 				    65535);
 }
 
+static void
+cal_prefs_dialog_url_add_clicked  (GtkWidget *button, void *data)
+{
+	DialogData *dialog_data = (DialogData *) data;
+	EPublishUri *url = NULL;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+	
+	model = gtk_tree_view_get_model (dialog_data->url_list);
+	url = g_new0 (EPublishUri, 1);
+	url->enabled = TRUE;
+	url->location = "";
+	
+	if (!dialog_data->url_editor) {
+			
+		dialog_data->url_editor = url_editor_dialog_new (dialog_data, 
+								 url);
+	
+		if (url->location != "") {
+			gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+			gtk_list_store_set(GTK_LIST_STORE(model), &iter, 
+					   URL_LIST_ENABLED_COLUMN, 
+					   url->enabled,
+					   URL_LIST_LOCATION_COLUMN, 
+					   g_strdup (url->location),
+					   URL_LIST_FREE_BUSY_URL_COLUMN, url,
+					   -1);
+		
+			if (!GTK_WIDGET_SENSITIVE((GtkWidget *) dialog_data->url_remove)) {
+				selection = gtk_tree_view_get_selection ((GtkTreeView *) dialog_data->url_list);
+				gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter);
+				gtk_widget_set_sensitive ((GtkWidget*) dialog_data->url_remove, TRUE);
+				gtk_tree_selection_select_iter (selection, &iter);
+			}	
+		}
+		dialog_data->url_editor = FALSE;
+		dialog_data->url_editor_dlg = NULL;
+	} else {
+		gdk_window_raise (dialog_data->url_editor_dlg->window);
+	}	
+}
+
+static void
+cal_prefs_dialog_url_edit_clicked  (GtkWidget *button, void *data)
+{
+	DialogData *dialog_data = (DialogData *) data;
+	
+	if (!dialog_data->url_editor) {
+		GtkTreeSelection *selection;
+		EPublishUri *url = NULL;
+		GtkTreeModel *model;
+		GtkTreeIter iter;
+		
+		selection = gtk_tree_view_get_selection ((GtkTreeView *) dialog_data->url_list);
+		if (gtk_tree_selection_get_selected (selection, &model, &iter)){
+			gtk_tree_model_get (model, &iter, 
+					    URL_LIST_FREE_BUSY_URL_COLUMN, 
+					    &url, 
+					    -1);
+
+		}
+
+		if (url) {
+			
+			dialog_data->url_editor = url_editor_dialog_new (dialog_data, url);
+	
+			gtk_list_store_set((GtkListStore *) model, &iter, 
+					   URL_LIST_LOCATION_COLUMN, 
+					   g_strdup (url->location), 
+					   URL_LIST_ENABLED_COLUMN, 
+					   url->enabled, 
+					   URL_LIST_FREE_BUSY_URL_COLUMN, url,
+					   -1);
+
+			if (!GTK_WIDGET_SENSITIVE((GtkWidget *) dialog_data->url_remove)) {
+				selection = gtk_tree_view_get_selection ((GtkTreeView *) dialog_data->url_list);
+				gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter);
+				gtk_widget_set_sensitive ((GtkWidget*) dialog_data->url_remove, TRUE);
+				gtk_tree_selection_select_iter (selection, &iter);
+			}
+			dialog_data->url_editor = FALSE;
+			dialog_data->url_editor_dlg = NULL;
+		}
+	} else {
+		gdk_window_raise (dialog_data->url_editor_dlg->window);
+	}	
+}
+
+static void
+cal_prefs_dialog_url_remove_clicked  (GtkWidget *button, void *data)
+{
+	DialogData *dialog_data = (DialogData *) data;
+	EPublishUri *url = NULL;
+	GtkTreeSelection * selection;
+	GtkTreeModel *model;
+	GtkWidget *confirm;
+	GtkTreeIter iter;
+	int ans;
+	
+	selection = gtk_tree_view_get_selection (dialog_data->url_list);
+	if (gtk_tree_selection_get_selected (selection, &model, &iter))
+		gtk_tree_model_get (model, &iter, 
+				    URL_LIST_FREE_BUSY_URL_COLUMN, &url, 
+				    -1);
+	
+	/* make sure we have a valid account selected and that 
+	   we aren't editing anything... */
+	if (url == NULL || dialog_data->url_editor)
+		return;
+	
+	confirm = gtk_message_dialog_new (PREFS_WINDOW (dialog_data),
+					  GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
+					  GTK_MESSAGE_QUESTION, 
+					  GTK_BUTTONS_NONE,
+					  _("Are you sure you want to remove this URL?"));
+	
+	(GtkButton *) button = gtk_button_new_from_stock (GTK_STOCK_YES);
+	gtk_button_set_label ((GtkButton *) button, _("Remove"));
+	gtk_dialog_add_action_widget ((GtkDialog *) confirm, (GtkWidget *) button, GTK_RESPONSE_YES);
+	gtk_widget_show ((GtkWidget *) button);
+	
+	(GtkButton *) button = gtk_button_new_from_stock (GTK_STOCK_NO);
+	gtk_button_set_label ((GtkButton *) button, _("Don't Remove"));
+	gtk_dialog_add_action_widget ((GtkDialog *) confirm, 
+				      (GtkWidget *) button, GTK_RESPONSE_NO);
+
+	gtk_widget_show ((GtkWidget *) button);
+	
+	ans = gtk_dialog_run ((GtkDialog *) confirm);
+	gtk_widget_destroy (confirm);
+	
+	if (ans == GTK_RESPONSE_YES) {
+		int len;
+		
+		gtk_list_store_remove ((GtkListStore *) model, &iter);
+		
+		len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL);
+		if (len > 0) {
+			gtk_tree_selection_select_iter (selection, &iter);
+		} else {
+			gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_edit), FALSE);
+			gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_remove), FALSE);
+			gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_enable), FALSE);
+		}
+		g_free(url);
+	}
+}
+
+static void
+cal_prefs_dialog_url_enable_clicked  (GtkWidget *button, void *data)
+{
+	DialogData *dialog_data = (DialogData *) data;
+	EPublishUri *url = NULL;
+	GtkTreeSelection * selection;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	
+	selection = gtk_tree_view_get_selection (dialog_data->url_list);
+	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		gtk_tree_model_get (model, &iter, 
+				    URL_LIST_FREE_BUSY_URL_COLUMN, &url, 
+				    -1);
+		url->enabled = !url->enabled;
+		gtk_list_store_set ((GtkListStore *) model, &iter, 
+				    URL_LIST_ENABLED_COLUMN, url->enabled, 
+				    -1);
+		
+		gtk_button_set_label ((GtkButton *) dialog_data->url_enable, 
+				      url->enabled ? _("Disable") : _("Enable"));
+	}
+}
+ 
+static void
+cal_prefs_dialog_url_list_enable_toggled (GtkCellRendererToggle *renderer, 
+					   const char *path_string, 
+					   void *data)
+{
+	DialogData *dialog_data = (DialogData *) data;
+	GtkTreeSelection * selection;
+	EPublishUri *url = NULL;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	
+	path = gtk_tree_path_new_from_string (path_string);
+	model = gtk_tree_view_get_model (dialog_data->url_list);
+	selection = gtk_tree_view_get_selection (dialog_data->url_list);
+
+	if (gtk_tree_model_get_iter (model, &iter, path)) {
+		gtk_tree_model_get (model, &iter, 
+				    URL_LIST_FREE_BUSY_URL_COLUMN, &url, 
+				    -1);
+
+		url->enabled = !url->enabled;
+		gtk_list_store_set((GtkListStore *) model, &iter, 
+				   URL_LIST_ENABLED_COLUMN,
+				   url->enabled, -1);
+
+		if (gtk_tree_selection_iter_is_selected (selection, &iter))
+			gtk_button_set_label ((GtkButton *) dialog_data->url_enable, 
+					      url->enabled ? _("Disable") : _("Enable"));
+	}
+
+	gtk_tree_path_free(path);
+}
+
+static void
+cal_prefs_dialog_url_list_double_click (GtkTreeView *treeview, 
+					GtkTreePath *path, 
+					GtkTreeViewColumn *column, 
+					DialogData *dialog_data)
+{
+	cal_prefs_dialog_url_edit_clicked  (NULL, dialog_data);
+}				
+
+static void
+cal_prefs_dialog_url_list_change (GtkTreeSelection *selection, 
+				  DialogData *dialog_data)
+{
+	EPublishUri *url = NULL;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	int state;
+	
+	state = gtk_tree_selection_get_selected (selection, &model, &iter);
+	if (state) {
+		gtk_tree_model_get (model, &iter, 
+				    URL_LIST_FREE_BUSY_URL_COLUMN, &url, 
+				    -1);
+
+		if (url->location && url->enabled)
+			gtk_button_set_label ((GtkButton *) dialog_data->url_enable, _("Disable"));
+		else
+			gtk_button_set_label ((GtkButton *) dialog_data->url_enable, _("Enable"));
+	} else {
+		gtk_widget_grab_focus (GTK_WIDGET (dialog_data->url_add));
+	}
+	
+	gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_edit), state);
+	gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_remove), state);
+	gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_enable), state);
+}
+
+/* Shows the current Free/Busy settings in the dialog */
+static void
+show_fb_config (DialogData *dialog_data)
+{
+	GSList *url_config_list;
+	GtkListStore *model;
+	GtkTreeIter iter;
+	
+	model = (GtkListStore *) gtk_tree_view_get_model (dialog_data->url_list);
+	gtk_list_store_clear (model);
+	
+	/* restore urls from gconf */
+	url_config_list = calendar_config_get_free_busy();
+	
+	while (url_config_list) {
+		gchar *xml = (gchar *)url_config_list->data;
+		EPublishUri *url;
+		url = g_new0 (EPublishUri, 1);
+		
+		e_pub_uri_from_xml (url, xml);
+		if (url->location) {
+			gtk_list_store_append(model, &iter);
+			gtk_list_store_set(model, &iter, 
+					   URL_LIST_ENABLED_COLUMN, 
+					   url->enabled,
+					   URL_LIST_LOCATION_COLUMN, 
+					   url->location,
+					   URL_LIST_FREE_BUSY_URL_COLUMN, url,
+					   -1);
+		}
+
+		url_config_list = g_slist_next(url_config_list);
+		g_free (xml);
+	}
+
+	g_slist_foreach (url_config_list, (GFunc) g_free, NULL);
+	g_slist_free(url_config_list);
+	if (!gtk_tree_model_get_iter_first((GtkTreeModel *) model, &iter)) {
+		/* list is empty-disable edit, remove, and enable buttons */
+		gtk_widget_set_sensitive(GTK_WIDGET(dialog_data->url_edit), 
+					 FALSE);
+
+		gtk_widget_set_sensitive(GTK_WIDGET(dialog_data->url_remove), 
+					 FALSE);
+
+		gtk_widget_set_sensitive(GTK_WIDGET(dialog_data->url_enable), 
+					 FALSE);
+	}
+}
+
 /* Shows the current task list settings in the dialog */
 static void
 show_task_list_config (DialogData *dialog_data)
@@ -576,6 +933,9 @@
 	/* Task list */
 
 	show_task_list_config (dialog_data);
+	
+	/* Free/Busy */
+	show_fb_config (dialog_data);
 
 	/* Other page */
 
@@ -605,6 +965,41 @@
 	return spec;
 }
 
+/* Updates the Free/Busy config values from the settings in the dialog*/
+static void
+update_fb_config (DialogData *dialog_data)
+{
+	GtkTreeIter iter;
+	GtkListStore *model = NULL;
+	gboolean valid;
+	GSList *url_list;
+ 	
+	url_list = NULL;
+	
+	model = (GtkListStore *) gtk_tree_view_get_model (dialog_data->url_list);
+	
+	valid = gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter);
+	while (valid) {
+		EPublishUri *url;
+		gchar *xml;
+		
+		gtk_tree_model_get ((GtkTreeModel *) model, &iter, 
+					URL_LIST_FREE_BUSY_URL_COLUMN, &url, 
+					-1);
+
+		xml = e_pub_uri_to_xml (url);
+		if (xml != NULL) {
+			url_list = g_slist_append(url_list, xml);
+		}
+		g_free (url);
+		
+		valid = gtk_tree_model_iter_next((GtkTreeModel *) model, &iter);
+	}
+	calendar_config_set_free_busy(url_list);
+
+	g_slist_free (url_list);
+}
+
 /* Updates the task list config values from the settings in the dialog */
 static void
 update_task_list_config (DialogData *dialog_data)
@@ -671,6 +1066,9 @@
 
 	/* Task list */
 	update_task_list_config (dialog_data);
+	
+	/* Free/Busy */
+	update_fb_config (dialog_data);
 
 	/* Other page */
 
Index: gui/dialogs/cal-prefs-dialog.glade
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/cal-prefs-dialog.glade,v
retrieving revision 1.24
diff -u -r1.24 cal-prefs-dialog.glade
--- gui/dialogs/cal-prefs-dialog.glade	19 Dec 2003 17:49:01 -0000	1.24
+++ gui/dialogs/cal-prefs-dialog.glade	12 Jan 2004 18:27:14 -0000
@@ -1005,7 +1005,6 @@
 
 	  <child>
 	    <widget class="GtkVBox" id="vbox8">
-	      <property name="border_width">6</property>
 	      <property name="visible">True</property>
 	      <property name="homogeneous">False</property>
 	      <property name="spacing">6</property>
@@ -1444,6 +1443,369 @@
 	    <widget class="GtkLabel" id="label7">
 	      <property name="visible">True</property>
 	      <property name="label" translatable="yes">_Display</property>
+	      <property name="use_underline">True</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_CENTER</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	    </widget>
+	    <packing>
+	      <property name="type">tab</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkVBox" id="vbox14">
+	      <property name="border_width">12</property>
+	      <property name="visible">True</property>
+	      <property name="homogeneous">False</property>
+	      <property name="spacing">0</property>
+
+	      <child>
+		<widget class="GtkVBox" id="vbox18">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">6</property>
+
+		  <child>
+		    <widget class="GtkLabel" id="label49">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">&lt;span weight=&quot;bold&quot;&gt;Free/Busy URLs&lt;/span&gt;</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">True</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkHBox" id="hbox24">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">0</property>
+
+		      <child>
+			<widget class="GtkLabel" id="label50">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">    </property>
+			  <property name="use_underline">False</property>
+			  <property name="use_markup">False</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkVBox" id="vbox19">
+			  <property name="visible">True</property>
+			  <property name="homogeneous">False</property>
+			  <property name="spacing">0</property>
+
+			  <child>
+			    <widget class="GtkHBox" id="hbox20">
+			      <property name="visible">True</property>
+			      <property name="homogeneous">False</property>
+			      <property name="spacing">6</property>
+
+			      <child>
+				<widget class="GtkScrolledWindow" id="scrolledwindow1">
+				  <property name="visible">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+				  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+				  <property name="shadow_type">GTK_SHADOW_IN</property>
+				  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+				  <child>
+				    <widget class="GtkTreeView" id="url_list">
+				      <property name="visible">True</property>
+				      <property name="can_focus">True</property>
+				      <property name="headers_visible">True</property>
+				      <property name="rules_hint">False</property>
+				      <property name="reorderable">False</property>
+				      <property name="enable_search">True</property>
+				    </widget>
+				  </child>
+				</widget>
+				<packing>
+				  <property name="padding">0</property>
+				  <property name="expand">True</property>
+				  <property name="fill">True</property>
+				</packing>
+			      </child>
+
+			      <child>
+				<widget class="GtkVBox" id="vbox15">
+				  <property name="visible">True</property>
+				  <property name="homogeneous">False</property>
+				  <property name="spacing">0</property>
+
+				  <child>
+				    <widget class="GtkLabel" id="label44">
+				      <property name="height_request">34</property>
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes"></property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_CENTER</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">0.5</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				    </widget>
+				    <packing>
+				      <property name="padding">0</property>
+				      <property name="expand">False</property>
+				      <property name="fill">False</property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkVButtonBox" id="vbuttonbox3">
+				      <property name="visible">True</property>
+				      <property name="layout_style">GTK_BUTTONBOX_START</property>
+				      <property name="spacing">3</property>
+
+				      <child>
+					<widget class="GtkButton" id="url_add">
+					  <property name="visible">True</property>
+					  <property name="can_default">True</property>
+					  <property name="can_focus">True</property>
+					  <property name="relief">GTK_RELIEF_NORMAL</property>
+
+					  <child>
+					    <widget class="GtkAlignment" id="alignment5">
+					      <property name="visible">True</property>
+					      <property name="can_default">True</property>
+					      <property name="can_focus">True</property>
+					      <property name="xalign">0.5</property>
+					      <property name="yalign">0.5</property>
+					      <property name="xscale">0</property>
+					      <property name="yscale">0</property>
+
+					      <child>
+						<widget class="GtkHBox" id="hbox22">
+						  <property name="visible">True</property>
+						  <property name="homogeneous">False</property>
+						  <property name="spacing">2</property>
+
+						  <child>
+						    <widget class="GtkImage" id="image1">
+						      <property name="visible">True</property>
+						      <property name="stock">gtk-add</property>
+						      <property name="icon_size">4</property>
+						      <property name="xalign">0.5</property>
+						      <property name="yalign">0.5</property>
+						      <property name="xpad">0</property>
+						      <property name="ypad">0</property>
+						    </widget>
+						    <packing>
+						      <property name="padding">0</property>
+						      <property name="expand">False</property>
+						      <property name="fill">False</property>
+						    </packing>
+						  </child>
+
+						  <child>
+						    <widget class="GtkLabel" id="labeladd">
+						      <property name="visible">True</property>
+						      <property name="can_default">True</property>
+						      <property name="can_focus">True</property>
+						      <property name="label" translatable="yes">_Add URL</property>
+						      <property name="use_underline">True</property>
+						      <property name="use_markup">False</property>
+						      <property name="justify">GTK_JUSTIFY_LEFT</property>
+						      <property name="wrap">False</property>
+						      <property name="selectable">False</property>
+						      <property name="xalign">0.5</property>
+						      <property name="yalign">0.5</property>
+						      <property name="xpad">0</property>
+						      <property name="ypad">0</property>
+						    </widget>
+						    <packing>
+						      <property name="padding">0</property>
+						      <property name="expand">False</property>
+						      <property name="fill">False</property>
+						    </packing>
+						  </child>
+						</widget>
+					      </child>
+					    </widget>
+					  </child>
+					</widget>
+				      </child>
+
+				      <child>
+					<widget class="GtkButton" id="url_edit">
+					  <property name="visible">True</property>
+					  <property name="sensitive">False</property>
+					  <property name="can_default">True</property>
+					  <property name="can_focus">True</property>
+					  <property name="label" translatable="yes">_Edit</property>
+					  <property name="use_underline">True</property>
+					  <property name="relief">GTK_RELIEF_NORMAL</property>
+					</widget>
+				      </child>
+
+				      <child>
+					<widget class="GtkButton" id="url_remove">
+					  <property name="visible">True</property>
+					  <property name="sensitive">False</property>
+					  <property name="can_default">True</property>
+					  <property name="can_focus">True</property>
+					  <property name="label">gtk-remove</property>
+					  <property name="use_stock">True</property>
+					  <property name="relief">GTK_RELIEF_NORMAL</property>
+					</widget>
+				      </child>
+				    </widget>
+				    <packing>
+				      <property name="padding">0</property>
+				      <property name="expand">False</property>
+				      <property name="fill">False</property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkLabel" id="label45">
+				      <property name="height_request">34</property>
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes"></property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">0.5</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				    </widget>
+				    <packing>
+				      <property name="padding">0</property>
+				      <property name="expand">False</property>
+				      <property name="fill">False</property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkVButtonBox" id="vbuttonbox4">
+				      <property name="visible">True</property>
+				      <property name="layout_style">GTK_BUTTONBOX_START</property>
+				      <property name="spacing">3</property>
+
+				      <child>
+					<widget class="GtkButton" id="url_enable">
+					  <property name="width_request">91</property>
+					  <property name="visible">True</property>
+					  <property name="sensitive">False</property>
+					  <property name="can_default">True</property>
+					  <property name="can_focus">True</property>
+					  <property name="label" translatable="yes">E_nable</property>
+					  <property name="use_underline">True</property>
+					  <property name="relief">GTK_RELIEF_NORMAL</property>
+					</widget>
+				      </child>
+				    </widget>
+				    <packing>
+				      <property name="padding">0</property>
+				      <property name="expand">False</property>
+				      <property name="fill">False</property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkLabel" id="label46">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes"></property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">0.5</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				    </widget>
+				    <packing>
+				      <property name="padding">0</property>
+				      <property name="expand">False</property>
+				      <property name="fill">False</property>
+				    </packing>
+				  </child>
+				</widget>
+				<packing>
+				  <property name="padding">0</property>
+				  <property name="expand">False</property>
+				  <property name="fill">False</property>
+				</packing>
+			      </child>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">True</property>
+			      <property name="fill">True</property>
+			    </packing>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">True</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">True</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="tab_expand">False</property>
+	      <property name="tab_fill">True</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkLabel" id="label42">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_Free/Busy</property>
 	      <property name="use_underline">True</property>
 	      <property name="use_markup">False</property>
 	      <property name="justify">GTK_JUSTIFY_CENTER</property>
Index: gui/dialogs/cal-prefs-dialog.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/cal-prefs-dialog.h,v
retrieving revision 1.9
diff -u -r1.9 cal-prefs-dialog.h
--- gui/dialogs/cal-prefs-dialog.h	7 Nov 2002 02:00:56 -0000	1.9
+++ gui/dialogs/cal-prefs-dialog.h	12 Jan 2004 18:27:14 -0000
@@ -30,9 +30,68 @@
 #ifndef _CAL_PREFS_DIALOG_H_
 #define _CAL_PREFS_DIALOG_H_
 
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+#include "../e-pub-utils.h"
 #include "evolution-config-control.h"
 
 G_BEGIN_DECLS
+
+enum {
+	URL_LIST_ENABLED_COLUMN,
+	URL_LIST_LOCATION_COLUMN,
+	URL_LIST_FREE_BUSY_URL_COLUMN,
+	URL_LIST_N_COLUMNS
+};
+
+struct _DialogData {
+	/* Glade XML data */
+	GladeXML *xml;
+	
+	GConfClient *gconf;
+
+	GtkWidget *page;
+
+	GtkWidget *timezone;
+	GtkWidget *working_days[7];
+	GtkWidget *week_start_day;
+	GtkWidget *start_of_day;
+	GtkWidget *end_of_day;
+	GtkWidget *use_12_hour;
+	GtkWidget *use_24_hour;
+	GtkWidget *time_divisions;
+	GtkWidget *show_end_times;
+	GtkWidget *compress_weekend;
+	GtkWidget *dnav_show_week_no;
+
+	/* Widgets for the task list options */
+	GtkWidget *tasks_due_today_color;
+	GtkWidget *tasks_overdue_color;
+
+	GtkWidget *tasks_hide_completed_checkbutton;
+	GtkWidget *tasks_hide_completed_spinbutton;
+	GtkWidget *tasks_hide_completed_optionmenu;
+	
+	/* Widgets for the Free/Busy options */
+	GtkWidget *url_add;
+	GtkWidget *url_edit;
+	GtkWidget *url_remove;
+	GtkWidget *url_enable;
+	GtkTreeView *url_list;
+	gboolean url_editor;
+	GtkWidget* url_editor_dlg;
+	guint destroyed : 1;
+	
+		
+	/* Other page options */
+	GtkWidget *confirm_delete;
+	GtkWidget *default_reminder;
+	GtkWidget *default_reminder_interval;
+	GtkWidget *default_reminder_units;
+};
+typedef struct _DialogData DialogData;
 
 EvolutionConfigControl *cal_prefs_dialog_new (void);
 


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