aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/gui
diff options
context:
space:
mode:
authorGary Ekker <gekker@novell.com>2004-01-13 09:59:28 +0800
committerJP Rosevear <jpr@src.gnome.org>2004-01-13 09:59:28 +0800
commit449f48576b556874742934cacfbc80c041ff12fd (patch)
tree373f3fbea0dcc0c4aa8756ce56d7b085a079b6c9 /calendar/gui
parent99f392e5f1db3f927ae93eef5ca657f5a3db7f72 (diff)
downloadgsoc2013-evolution-449f48576b556874742934cacfbc80c041ff12fd.tar.gz
gsoc2013-evolution-449f48576b556874742934cacfbc80c041ff12fd.tar.zst
gsoc2013-evolution-449f48576b556874742934cacfbc80c041ff12fd.zip
add e-pub-utils.[ch] for Free/Busy publishing
2004-01-12 Gary Ekker <gekker@novell.com> * gui/Makefile.am: add e-pub-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 svn path=/trunk/; revision=24190
Diffstat (limited to 'calendar/gui')
-rw-r--r--calendar/gui/Makefile.am2
-rw-r--r--calendar/gui/apps_evolution_calendar.schemas.in.in12
-rw-r--r--calendar/gui/calendar-commands.c32
-rw-r--r--calendar/gui/calendar-component.c43
-rw-r--r--calendar/gui/calendar-config-keys.h3
-rw-r--r--calendar/gui/calendar-config.c13
-rw-r--r--calendar/gui/calendar-config.h3
-rw-r--r--calendar/gui/dialogs/Makefile.am8
-rw-r--r--calendar/gui/dialogs/cal-prefs-dialog.c472
-rw-r--r--calendar/gui/dialogs/cal-prefs-dialog.glade269
-rw-r--r--calendar/gui/dialogs/cal-prefs-dialog.h59
-rw-r--r--calendar/gui/dialogs/url-editor-dialog.c360
-rw-r--r--calendar/gui/dialogs/url-editor-dialog.glade501
-rw-r--r--calendar/gui/dialogs/url-editor-dialog.h68
-rw-r--r--calendar/gui/e-cal-view.c30
-rw-r--r--calendar/gui/e-calendar-view.c30
-rw-r--r--calendar/gui/e-pub-utils.c310
-rw-r--r--calendar/gui/e-pub-utils.h62
-rw-r--r--calendar/gui/itip-utils.c221
-rw-r--r--calendar/gui/itip-utils.h5
20 files changed, 2376 insertions, 127 deletions
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index a6e4ab0f66..fe5916c50b 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -166,6 +166,8 @@ libevolution_calendar_la_SOURCES = \
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 \
diff --git a/calendar/gui/apps_evolution_calendar.schemas.in.in b/calendar/gui/apps_evolution_calendar.schemas.in.in
index 27e9aa44e2..b42d3f8498 100644
--- a/calendar/gui/apps_evolution_calendar.schemas.in.in
+++ b/calendar/gui/apps_evolution_calendar.schemas.in.in
@@ -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>
diff --git a/calendar/gui/calendar-commands.c b/calendar/gui/calendar-commands.c
index 6defec9819..1ff2a3a0a8 100644
--- a/calendar/gui/calendar-commands.c
+++ b/calendar/gui/calendar-commands.c
@@ -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 @@ delete_occurrence_cmd (BonoboUIComponent *uic, gpointer data, const gchar *path)
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
diff --git a/calendar/gui/calendar-component.c b/calendar/gui/calendar-component.c
index 03725c560c..ddcff4165c 100644
--- a/calendar/gui/calendar-component.c
+++ b/calendar/gui/calendar-component.c
@@ -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 @@ struct _CalendarComponentPrivate {
char *config_directory;
GConfClient *gconf_client;
+ int gconf_notify_id;
ESourceList *source_list;
GSList *source_selection;
@@ -435,6 +438,25 @@ config_primary_selection_changed_cb (GConfClient *client, guint id, GConfEntry *
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 FALSE;
+}
+
+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
@@ -582,6 +604,24 @@ impl_upgradeFromVersion (PortableServer_Servant servant,
}
static void
+init_calendar_publishing (CalendarComponent *calendar_component)
+{
+ guint idle_id = 0;
+ 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_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,
@@ -629,6 +669,9 @@ impl_createControls (PortableServer_Servant servant,
gtk_widget_show (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",
diff --git a/calendar/gui/calendar-config-keys.h b/calendar/gui/calendar-config-keys.h
index ebe16b6539..bdcad1476e 100644
--- a/calendar/gui/calendar-config-keys.h
+++ b/calendar/gui/calendar-config-keys.h
@@ -70,6 +70,9 @@ G_BEGIN_DECLS
#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
diff --git a/calendar/gui/calendar-config.c b/calendar/gui/calendar-config.c
index fea9311b2c..55317a4bd3 100644
--- a/calendar/gui/calendar-config.c
+++ b/calendar/gui/calendar-config.c
@@ -1025,3 +1025,16 @@ calendar_config_get_hide_completed_tasks_sexp (void)
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);
+}
diff --git a/calendar/gui/calendar-config.h b/calendar/gui/calendar-config.h
index ff34febd91..ac9affce00 100644
--- a/calendar/gui/calendar-config.h
+++ b/calendar/gui/calendar-config.h
@@ -202,6 +202,9 @@ void calendar_config_set_default_reminder_interval (int interval);
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. */
diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am
index 18a83fb4de..bd6876f63b 100644
--- a/calendar/gui/dialogs/Makefile.am
+++ b/calendar/gui/dialogs/Makefile.am
@@ -78,7 +78,9 @@ libcal_dialogs_la_SOURCES = \
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 @@ glade_DATA = \
recurrence-page.glade \
schedule-page.glade \
task-details-page.glade \
- task-page.glade
-
+ task-page.glade \
+ url-editor-dialog.glade
CLEANFILES = $(BUILT_SOURCES)
diff --git a/calendar/gui/dialogs/cal-prefs-dialog.c b/calendar/gui/dialogs/cal-prefs-dialog.c
index 83363a3ac0..635c665cc1 100644
--- a/calendar/gui/dialogs/cal-prefs-dialog.c
+++ b/calendar/gui/dialogs/cal-prefs-dialog.c
@@ -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 @@ static const int default_reminder_units_map[] = {
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_end_of_day_changed (GtkWidget *button, void *data);
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 @@ setup_changes (DialogData *dialog_data,
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 @@ get_widgets (DialogData *data)
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 @@ get_widgets (DialogData *data)
&& 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 @@ cal_prefs_dialog_create_time_edit (void)
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 @@ init_widgets (DialogData *dialog_data)
"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 @@ set_color_picker (GtkWidget *picker, const char *spec)
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 @@ show_config (DialogData *dialog_data)
/* Task list */
show_task_list_config (dialog_data);
+
+ /* Free/Busy */
+ show_fb_config (dialog_data);
/* Other page */
@@ -605,6 +965,41 @@ spec_from_picker (GtkWidget *picker)
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 @@ update_config (DialogData *dialog_data)
/* Task list */
update_task_list_config (dialog_data);
+
+ /* Free/Busy */
+ update_fb_config (dialog_data);
/* Other page */
diff --git a/calendar/gui/dialogs/cal-prefs-dialog.glade b/calendar/gui/dialogs/cal-prefs-dialog.glade
index d566368611..5f74153dda 100644
--- a/calendar/gui/dialogs/cal-prefs-dialog.glade
+++ b/calendar/gui/dialogs/cal-prefs-dialog.glade
@@ -891,7 +891,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>
@@ -1305,6 +1304,274 @@
<property name="type">tab</property>
</packing>
</child>
+
+ <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="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 Publishing</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>
</widget>
<packing>
<property name="padding">0</property>
diff --git a/calendar/gui/dialogs/cal-prefs-dialog.h b/calendar/gui/dialogs/cal-prefs-dialog.h
index db6f5a75fa..8905cb618b 100644
--- a/calendar/gui/dialogs/cal-prefs-dialog.h
+++ b/calendar/gui/dialogs/cal-prefs-dialog.h
@@ -30,10 +30,69 @@
#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);
G_END_DECLS
diff --git a/calendar/gui/dialogs/url-editor-dialog.c b/calendar/gui/dialogs/url-editor-dialog.c
new file mode 100644
index 0000000000..ec1e493402
--- /dev/null
+++ b/calendar/gui/dialogs/url-editor-dialog.c
@@ -0,0 +1,360 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Author :
+ * Gary Ekker <gekker@novell.com>
+ *
+ * Copyright 2004 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ * UrlEditorDialog - a GtkObject which handles a libglade-loaded dialog
+ * to edit the calendar preference settings.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "cal-prefs-dialog.h"
+#include "url-editor-dialog.h"
+
+#include <gtk/gtk.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtktogglebutton.h>
+#include <libgnomeui/gnome-color-picker.h>
+#include <glade/glade.h>
+#include <gal/util/e-util.h>
+#include <e-util/e-dialog-widgets.h>
+#include <widgets/misc/e-dateedit.h>
+#include <stdlib.h>
+#include <string.h>
+
+static gboolean get_widgets (UrlDialogData *data);
+static void init_widgets (UrlDialogData *data);
+
+static void url_editor_dialog_fb_url_changed (GtkEntry *url_entry, void *data);
+static void url_editor_dialog_fb_daily_toggled (GtkWidget *button, void *data);
+static void url_editor_dialog_fb_url_activated (GtkEntry *url_entry, void *data);
+static void url_editor_dialog_fb_ok_enable (GtkWidget *widget, void *data);
+
+/**
+ * url_editor_dialog_new:
+ *
+ * Creates a new #UrlEditorDialog.
+ *
+ * Return value: a new #UrlEditorDialog.
+ **/
+gboolean
+url_editor_dialog_new (DialogData *dialog_data, EPublishUri *uri)
+{
+ int b;
+
+ UrlDialogData *url_dlg_data = g_new0 (UrlDialogData, 1);
+ url_dlg_data->xml = glade_xml_new (EVOLUTION_GLADEDIR "/url-editor-dialog.glade", NULL, NULL);
+ if (!url_dlg_data->xml) {
+ g_message ("url_editor_dialog_construct(): Could not load the Glade XML file!");
+ return FALSE;
+ }
+
+ if (!get_widgets (url_dlg_data)) {
+ g_message ("url_editor_dialog_construct(): Could not find all widgets in the XML file!");
+ return FALSE;
+ }
+
+ url_dlg_data->url_dialog = (GtkWidget *) dialog_data;
+ url_dlg_data->url_data = uri;
+
+ init_widgets (url_dlg_data);
+ if (uri->location && uri->username && uri->password) {
+ if (strlen(uri->location) != 0) {
+ gtk_entry_set_text (url_dlg_data->url_entry,
+ uri->location);
+ }
+ if (strlen(uri->username) != 0) {
+ gtk_entry_set_text (url_dlg_data->username_entry,
+ uri->username);
+ }
+ if (strlen(uri->password) != 0) {
+ gtk_entry_set_text (url_dlg_data->password_entry,
+ uri->password);
+
+ e_dialog_toggle_set (url_dlg_data->remember_pw, TRUE);
+ } else {
+ e_dialog_toggle_set (url_dlg_data->remember_pw, FALSE);
+ }
+
+ switch (uri->publish_freq) {
+ case URI_PUBLISH_DAILY:
+ e_dialog_radio_set (url_dlg_data->daily,
+ URI_PUBLISH_DAILY,
+ pub_frequency_type_map);
+ break;
+ case URI_PUBLISH_WEEKLY:
+ e_dialog_radio_set (url_dlg_data->daily,
+ URI_PUBLISH_WEEKLY,
+ pub_frequency_type_map);
+ break;
+ case URI_PUBLISH_USER:
+ default:
+ e_dialog_radio_set (url_dlg_data->daily,
+ URI_PUBLISH_USER,
+ pub_frequency_type_map);
+ }
+ }
+ dialog_data->url_editor=TRUE;
+ dialog_data->url_editor_dlg = (GtkWidget *) url_dlg_data;
+ gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, FALSE);
+
+ b = gtk_dialog_run ((GtkDialog *) url_dlg_data->url_editor);
+
+ if (b == GTK_RESPONSE_OK) {
+ if ((GtkEntry *) url_dlg_data->url_entry) {
+ url_editor_dialog_fb_url_activated (url_dlg_data->url_entry, url_dlg_data);
+ url_dlg_data->url_data->username = g_strdup (gtk_entry_get_text ((GtkEntry *) url_dlg_data->username_entry));
+ if (e_dialog_toggle_get (url_dlg_data->remember_pw))
+ url_dlg_data->url_data->password = g_strdup (gtk_entry_get_text ((GtkEntry *) url_dlg_data->password_entry));
+ }
+ }
+
+ gtk_widget_destroy (url_dlg_data->url_editor);
+ g_object_unref (url_dlg_data->xml);
+ g_free (url_dlg_data);
+ url_dlg_data = NULL;
+
+ return FALSE;
+}
+
+static gboolean
+get_widgets (UrlDialogData *data)
+{
+#define GW(name) glade_xml_get_widget (data->xml, name)
+
+ data->url_editor = GW ("url_editor");
+ data->url_dialog = GW ("fb_dialog");
+ data->url_entry = GTK_ENTRY (GW ("url_entry"));
+ data->daily = GW ("daily");
+ data->weekly = GW ("weekly");
+ data->user_publish = GW ("user_publish");
+ data->scrolled_window = GW ("scrolled_window");
+ data->username_entry = GTK_ENTRY (GW ("username_entry"));
+ data->password_entry = GTK_ENTRY (GW ("password_entry"));
+ data->remember_pw = GW ("remember_pw");
+ data->cancel = GW ("cancel");
+ data->ok = GW ("ok");
+
+#undef GW
+
+ return (data ->url_editor
+ && data->url_entry
+ && data->daily
+ && data->weekly
+ && data->user_publish
+ && data->scrolled_window
+ && data->username_entry
+ && data->password_entry
+ && data->remember_pw
+ && data->cancel
+ && data->ok);
+}
+
+static void
+selection_changed_callback (ESourceSelector *selector,
+ void *data)
+{
+ UrlDialogData *url_dlg_data = (UrlDialogData *) data;
+ GSList *selection = e_source_selector_get_selection (selector);
+
+ if (selection != NULL) {
+ GSList *p, *l = NULL;
+
+ for (p = selection; p != NULL; p = p->next) {
+ ESource *source = E_SOURCE(p->data);
+ gchar* source_uid = g_strdup(e_source_peek_uid(source));
+
+ l = g_slist_append (l, source_uid);
+ }
+ url_dlg_data->url_data->calendars = l;
+ }
+
+ e_source_selector_free_selection (selection);
+ gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, TRUE);
+}
+
+/* Connects any necessary signal handlers. */
+static void
+init_widgets (UrlDialogData *url_dlg_data)
+{
+ GtkWidget *selector;
+ ESourceList *source_list;
+ GConfClient *gconf_client;
+ GSList *p;
+
+ g_signal_connect (url_dlg_data->url_entry, "changed",
+ G_CALLBACK (url_editor_dialog_fb_url_changed),
+ url_dlg_data);
+
+ g_signal_connect (url_dlg_data->username_entry, "changed",
+ G_CALLBACK (url_editor_dialog_fb_ok_enable),
+ url_dlg_data);
+
+ g_signal_connect (url_dlg_data->password_entry, "changed",
+ G_CALLBACK (url_editor_dialog_fb_ok_enable),
+ url_dlg_data);
+
+ g_signal_connect (url_dlg_data->remember_pw, "toggled",
+ G_CALLBACK (url_editor_dialog_fb_ok_enable),
+ url_dlg_data);
+
+ g_signal_connect (url_dlg_data->url_entry, "activate",
+ G_CALLBACK (url_editor_dialog_fb_url_activated),
+ url_dlg_data);
+
+ g_signal_connect (url_dlg_data->daily, "toggled",
+ G_CALLBACK (url_editor_dialog_fb_daily_toggled),
+ url_dlg_data);
+
+ g_signal_connect (url_dlg_data->weekly, "toggled",
+ G_CALLBACK (url_editor_dialog_fb_daily_toggled),
+ url_dlg_data);
+
+ g_signal_connect (url_dlg_data->user_publish, "toggled",
+ G_CALLBACK (url_editor_dialog_fb_daily_toggled),
+ url_dlg_data);
+
+
+ if (url_dlg_data->url_data->calendars) {
+ ESource *source;
+
+ gconf_client = gconf_client_get_default ();
+ source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/calendar/sources");
+ selector = e_source_selector_new (source_list);
+
+ p = url_dlg_data->url_data->calendars;
+ for (; p != NULL; p = p->next) {
+ gchar *source_uid;
+
+ source_uid = g_strdup (p->data);
+ source = e_source_list_peek_source_by_uid (source_list, source_uid);
+ e_source_selector_select_source ((ESourceSelector *)selector, source);
+ g_free (source_uid);
+ }
+ } else {
+ gconf_client = gconf_client_get_default ();
+ source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/calendar/sources");
+ selector = e_source_selector_new (source_list);
+ }
+ e_source_selector_show_selection ((ESourceSelector *) selector, TRUE);
+ g_signal_connect (selector, "selection_changed",
+ G_CALLBACK (selection_changed_callback),
+ url_dlg_data);
+
+ gtk_widget_show (selector);
+ gtk_container_add (GTK_CONTAINER (url_dlg_data->scrolled_window),
+ selector);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (url_dlg_data->scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (url_dlg_data->scrolled_window),
+ GTK_SHADOW_IN);
+
+ gtk_widget_show (url_dlg_data->scrolled_window);
+}
+
+static void
+url_editor_dialog_fb_daily_toggled (GtkWidget *button,
+ void *data)
+{
+ UrlDialogData *url_dlg_data = (UrlDialogData *) data;
+ enum publish_frequency frequency;
+
+ frequency = e_dialog_radio_get (url_dlg_data->daily,
+ pub_frequency_type_map);
+ url_dlg_data->url_data->publish_freq = frequency;
+ gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, TRUE);
+}
+
+static gboolean
+is_valid_url (const gchar *url)
+{
+ const gchar *p = url;
+
+ if (strlen (url) == 0) {
+ return FALSE;
+ }
+ while (*p) {
+ if ((*p == '\\') || (*p == ' ')) {
+ return FALSE;
+ }
+ p++;
+ }
+ return TRUE;
+}
+
+static void
+url_editor_dialog_fb_url_activated (GtkEntry *url_entry, void *data)
+{
+ UrlDialogData *url_dlg_data = (UrlDialogData *) data;
+
+ url_dlg_data->url_data->location = g_strdup (gtk_entry_get_text ((GtkEntry *) url_entry));
+}
+
+static void
+url_editor_dialog_fb_url_changed (GtkEntry *url_entry, void *data)
+{
+ UrlDialogData *url_dlg_data = (UrlDialogData *) data;
+ DialogData *url_dialog = (DialogData *) url_dlg_data->url_dialog;
+
+ const gchar *entry_contents;
+ GtkListStore *model;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ model = (GtkListStore *) gtk_tree_view_get_model (url_dialog->url_list);
+
+ entry_contents = gtk_entry_get_text ((GtkEntry *) url_entry);
+ if (!is_valid_url (entry_contents)) {
+ gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, FALSE);
+ return;
+ }
+ /* duplicate check */
+ valid = gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter);
+ while (valid) {
+ gchar *url_name;
+ gtk_tree_model_get ((GtkTreeModel *) model, &iter,
+ URL_LIST_LOCATION_COLUMN, &url_name,
+ -1);
+
+ if (!strcasecmp (url_name, entry_contents)) {
+ gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, FALSE);
+ return;
+ }
+ valid = gtk_tree_model_iter_next ((GtkTreeModel *) model, &iter);
+ }
+ /* valid and unique */
+ gtk_widget_set_sensitive (GTK_WIDGET (url_dlg_data->ok), TRUE);
+ gtk_widget_grab_default (GTK_WIDGET (url_dlg_data->ok));
+ gtk_entry_set_activates_default ((GtkEntry*) url_dlg_data->url_entry,
+ TRUE);
+}
+
+static void url_editor_dialog_fb_ok_enable (GtkWidget *widget, void *data) {
+ UrlDialogData *url_dlg_data = (UrlDialogData *) data;
+
+ gtk_widget_set_sensitive (GTK_WIDGET (url_dlg_data->ok), TRUE);
+}
diff --git a/calendar/gui/dialogs/url-editor-dialog.glade b/calendar/gui/dialogs/url-editor-dialog.glade
new file mode 100644
index 0000000000..3685e69bd1
--- /dev/null
+++ b/calendar/gui/dialogs/url-editor-dialog.glade
@@ -0,0 +1,501 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="gnome"/>
+
+<widget class="GtkDialog" id="url_editor">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Free/Busy Editor</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ok">
+ <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-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox9">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">URL:</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.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="GtkEntry" id="url_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label26">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Free/Busy Publishing Location</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="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">6</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox12">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="daily">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Daily</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="weekly">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Weekly</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">daily</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="user_publish">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">User Publishes</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">daily</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label25">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Publishing Frequency</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="type">label_item</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>
+
+ <child>
+ <widget class="GtkVBox" id="vbox11">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame4">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolled_window">
+ <property name="height_request">150</property>
+ <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>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label28">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Calendars selected for publishing</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="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame3">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Login name:</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</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Password:</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</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="username_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="password_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">False</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="remember_pw">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Remember password</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label15">
+ <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</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label27">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Authentication Credentials for HTTP Server</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="type">label_item</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>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/calendar/gui/dialogs/url-editor-dialog.h b/calendar/gui/dialogs/url-editor-dialog.h
new file mode 100644
index 0000000000..a769ef6b80
--- /dev/null
+++ b/calendar/gui/dialogs/url-editor-dialog.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Author :
+ * Gary Ekker <gekker@novell.com>
+ *
+ * Copyright 2004, Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ * UrlEditorDialog - a GtkObject which handles a libglade-loaded dialog
+ * to edit the calendar preference settings.
+ */
+
+#ifndef _URL_EDITOR_DIALOG_H_
+#define _URL_EDITOR_DIALOG_H_
+
+G_BEGIN_DECLS
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include "cal-prefs-dialog.h"
+#include "widgets/misc/e-source-selector.h"
+
+struct _UrlDialogData {
+ /* Glade XML data */
+ GladeXML *xml;
+ GtkWidget *url_editor;
+ GtkWidget *url_dialog;
+
+ GtkEntry *url_entry;
+ GtkWidget *daily;
+ GtkWidget *weekly;
+ GtkWidget *user_publish;
+
+ GtkWidget *scrolled_window;
+
+ GtkEntry *username_entry;
+ GtkEntry *password_entry;
+ GtkWidget *remember_pw;
+
+ GtkWidget *cancel;
+ GtkWidget *ok;
+ EPublishUri *url_data;
+};
+typedef struct _UrlDialogData UrlDialogData;
+
+gboolean
+url_editor_dialog_new (DialogData *dialog_data, EPublishUri *pub_uri);
+
+G_END_DECLS
+
+#endif /* _URL_EDITOR_DIALOG_H_ */
diff --git a/calendar/gui/e-cal-view.c b/calendar/gui/e-cal-view.c
index 1aade80154..9ff5f500e3 100644
--- a/calendar/gui/e-cal-view.c
+++ b/calendar/gui/e-cal-view.c
@@ -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 @@ on_forward (GtkWidget *widget, gpointer user_data)
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
diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c
index 1aade80154..9ff5f500e3 100644
--- a/calendar/gui/e-calendar-view.c
+++ b/calendar/gui/e-calendar-view.c
@@ -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 @@ on_forward (GtkWidget *widget, gpointer user_data)
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
diff --git a/calendar/gui/e-pub-utils.c b/calendar/gui/e-pub-utils.c
new file mode 100644
index 0000000000..2d6cce62ec
--- /dev/null
+++ b/calendar/gui/e-pub-utils.c
@@ -0,0 +1,310 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Evolution calendar Free/Busy utilities and types
+ *
+ * Copyright (C) 2004 Ximian, Inc.
+ *
+ * Author: Gary Ekker <gekker@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-list.h>
+#include <libecal/e-cal-time-util.h>
+#include "calendar-config.h"
+#include "common/authentication.h"
+#include "itip-utils.h"
+#include "e-pub-utils.h"
+
+void
+e_pub_uri_from_xml (EPublishUri *uri, const gchar *xml)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root, p;
+ xmlChar *location, *enabled, *frequency;
+ xmlChar *username, *password, *publish_time;
+ GSList *l = NULL;
+
+ uri->location = NULL;
+ doc = xmlParseDoc ((char *)xml);
+ if (doc == NULL) {
+ uri->location = NULL;
+ return;
+ }
+
+ root = doc->children;
+ if (strcmp (root->name, "uri") != 0) {
+ return;
+ }
+ location = xmlGetProp (root, "location");
+ enabled = xmlGetProp (root, "enabled");
+ frequency = xmlGetProp (root, "frequency");
+ username = xmlGetProp (root, "username");
+ password = xmlGetProp (root, "password");
+ publish_time = xmlGetProp (root, "publish_time");
+
+ if (location != NULL)
+ uri->location = g_strdup (location);
+ if (enabled != NULL)
+ uri->enabled = atoi (enabled);
+ if (frequency != NULL)
+ uri->publish_freq = atoi (frequency);
+ if (username != NULL)
+ uri->username = g_strdup (username);
+ if (password != NULL)
+ uri->password = g_strdup (password);
+ if (publish_time != NULL)
+ uri->last_pub_time = g_strdup (publish_time);
+
+ for (p = root->children; p != NULL; p = p->next) {
+ xmlChar *uid = xmlGetProp (p, "uid");
+
+ l = g_slist_append (l, uid);
+ }
+ uri->calendars = l;
+
+ xmlFree(location);
+ xmlFree(enabled);
+ xmlFreeDoc(doc);
+ return;
+}
+
+gchar *
+e_pub_uri_to_xml (EPublishUri *uri)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ gchar *enabled, *frequency;
+ GSList *cals = NULL;
+ xmlChar *xml_buffer;
+ char *returned_buffer;
+ int xml_buffer_size;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+ g_return_val_if_fail (uri->location != NULL, NULL);
+
+ doc = xmlNewDoc ("1.0");
+
+ root = xmlNewDocNode (doc, NULL, "uri", NULL);
+ enabled = g_strdup_printf ("%d", uri->enabled);
+ frequency = g_strdup_printf ("%d", uri->publish_freq);
+ xmlSetProp (root, "location", uri->location);
+ xmlSetProp (root, "enabled", enabled);
+ xmlSetProp (root, "frequency", frequency);
+ xmlSetProp (root, "username", uri->username);
+ xmlSetProp (root, "password", uri->password);
+ xmlSetProp (root, "publish_time", uri->last_pub_time);
+
+ for (cals = uri->calendars; cals != NULL; cals = cals->next) {
+ xmlNodePtr node;
+
+ node = xmlNewChild (root, NULL, "source", NULL);
+ xmlSetProp (node, "uid", cals->data);
+ }
+ xmlDocSetRootElement (doc, root);
+
+ xmlDocDumpMemory (doc, &xml_buffer, &xml_buffer_size);
+ xmlFreeDoc (doc);
+
+ returned_buffer = g_malloc (xml_buffer_size + 1);
+ memcpy (returned_buffer, xml_buffer, xml_buffer_size);
+ returned_buffer [xml_buffer_size] = '\0';
+ xmlFree (xml_buffer);
+ g_free (enabled);
+
+ return returned_buffer;
+}
+
+static gboolean
+is_publish_time (EPublishUri *uri) {
+ icaltimezone *utc;
+ struct icaltimetype current_itt, adjust_itt;
+
+ if (!uri->last_pub_time) {
+ utc = icaltimezone_get_utc_timezone ();
+ current_itt = icaltime_current_time_with_zone (utc);
+ uri->last_pub_time = g_strdup (icaltime_as_ical_string (current_itt));
+ return TRUE;
+
+ } else {
+ if (strlen (uri->last_pub_time) == 0) {
+ uri->last_pub_time = g_strdup (icaltime_as_ical_string (current_itt));
+ return TRUE;
+ }
+
+ utc = icaltimezone_get_utc_timezone ();
+ current_itt = icaltime_current_time_with_zone (utc);
+ adjust_itt = icaltime_from_string (uri->last_pub_time);
+
+ switch (uri->publish_freq) {
+ case URI_PUBLISH_DAILY:
+ icaltime_adjust (&adjust_itt, 1, 0, 0, 0);
+ if (icaltime_compare_date_only (adjust_itt, current_itt ) < 0) {
+ uri->last_pub_time = g_strdup (icaltime_as_ical_string (current_itt));
+ return TRUE;
+ }
+ break;
+ case URI_PUBLISH_WEEKLY:
+ icaltime_adjust (&adjust_itt, 7, 0, 0, 0);
+ if (icaltime_compare_date_only (adjust_itt, current_itt ) < 0) {
+ uri->last_pub_time = g_strdup (icaltime_as_ical_string (current_itt));
+ return TRUE;
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+just_published (gchar *last_pub_time) {
+ icaltimezone *utc;
+ struct icaltimetype pubtime_itt, adjust_itt;
+
+ if (strlen (last_pub_time) != 0) {
+ utc = icaltimezone_get_utc_timezone ();
+ pubtime_itt = icaltime_from_string (last_pub_time);
+ adjust_itt = icaltime_current_time_with_zone (utc);
+ icaltime_adjust (&adjust_itt, 0, 0, 0, 3);
+ if (icaltime_compare_date_only (pubtime_itt, adjust_itt) < 0)
+ return TRUE;
+ }
+
+
+ return FALSE;
+}
+
+void
+e_pub_publish (gboolean publish) {
+ icaltimezone *utc;
+ time_t start = time (NULL), end;
+ GSList *uri_config_list, *l, *uri_list = NULL;
+ ESourceList *source_list;
+ GConfClient *gconf_client;
+ gboolean published = FALSE;
+
+ gconf_client = gconf_client_get_default ();
+ source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/calendar/sources");
+
+ utc = icaltimezone_get_utc_timezone ();
+ start = time_day_begin_with_zone (start, utc);
+ end = time_add_week_with_zone (start, 6, utc);
+
+ uri_config_list = calendar_config_get_free_busy ();
+
+ for (l = uri_config_list; l != NULL; l = l->next) {
+ GSList *p =NULL;
+ EPublishUri *uri;
+ ECalComponent *clone = NULL;
+ gboolean cloned = FALSE;
+ ECal *client = NULL;
+ gchar *xml = (gchar *)uri_config_list->data;
+
+ uri = g_new0 (EPublishUri, 1);
+ e_pub_uri_from_xml (uri, xml);
+
+ /* kludge to safeguard against loop from gconf update */
+ if (just_published (uri->last_pub_time))
+ return;
+
+ /* TODO: make sure we're online */
+ /* skip this url if it isn't enabled or if it is manual */
+ if (!uri->enabled) {
+ uri_config_list = g_slist_next (uri_config_list);
+ continue;
+ }
+
+ if (!publish) {
+ /* a g_idle publish, make sure we are not set to user only */
+ if (uri->publish_freq == URI_PUBLISH_USER) {
+ uri_config_list = g_slist_next (uri_config_list);
+ continue;
+ }
+
+ /* If not is it time to publish again? */
+ publish = is_publish_time (uri);
+
+ }
+
+ /* User published or config change */
+ if (publish) {
+ /* We still need to set the last_pub_time */
+ uri->last_pub_time = 0;
+ is_publish_time (uri);
+
+ for (p = uri->calendars; p != NULL; p = p->next) {
+ GList *comp_list = NULL;
+ gchar *source_uid;
+ ESource * source;
+
+ source_uid = g_strdup (p->data);
+ source = e_source_list_peek_source_by_uid (source_list, source_uid);
+
+ client = auth_new_cal_from_uri (e_source_get_uri (source), E_CAL_SOURCE_TYPE_EVENT);
+
+ if (!client) {
+ g_warning (G_STRLOC ": Could not publish Free/Busy: Calendar backend no longer exists");
+
+ continue;
+ }
+
+ e_cal_open (client, TRUE, NULL);
+
+ if (e_cal_get_free_busy ((ECal *) client, NULL,
+ start, end,
+ &comp_list, NULL)) {
+ GList *l;
+
+ for (l = comp_list; l; l = l->next) {
+ ECalComponent *comp = E_CAL_COMPONENT (l->data);
+
+ cloned = itip_publish_begin (comp, (ECal *) client, cloned, &clone);
+ g_object_unref (comp);
+ }
+ g_list_free (comp_list);
+ }
+
+ g_object_unref (client);
+
+ g_free (source_uid);
+ }
+
+ published = itip_publish_comp ((ECal *) client,
+ uri->location,
+ uri->username,
+ uri->password, &clone);
+
+ g_slist_free (p);
+ }
+ xml = e_pub_uri_to_xml (uri);
+ if (xml != NULL) {
+ uri_list = g_slist_append (uri_list, xml);
+ }
+ g_free (uri);
+ }
+
+ if (published) {
+ /* Update gconf so we have the last_pub_time */
+ calendar_config_set_free_busy (uri_list);
+ }
+
+ g_slist_free (uri_config_list);
+ g_slist_free (uri_list);
+}
diff --git a/calendar/gui/e-pub-utils.h b/calendar/gui/e-pub-utils.h
new file mode 100644
index 0000000000..03dcd97c98
--- /dev/null
+++ b/calendar/gui/e-pub-utils.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Evolution calendar Free/Busy utilities and types
+ *
+ * Copyright (C) 2004 Ximian, Inc.
+ *
+ * Author: Gary Ekker <gekker@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef E_CAL_FB_UTIL_H
+#define E_CAL_FB_UTIL_H
+
+#include <glib.h>
+#include <libxml/tree.h>
+
+G_BEGIN_DECLS
+
+enum publish_frequency{
+ URI_PUBLISH_DAILY,
+ URI_PUBLISH_WEEKLY,
+ URI_PUBLISH_USER
+};
+
+static const int pub_frequency_type_map[] = {
+ URI_PUBLISH_DAILY,
+ URI_PUBLISH_WEEKLY,
+ URI_PUBLISH_USER,
+ -1
+};
+
+struct _EPublishUri {
+ gint enabled;
+ gchar *location;
+ gint publish_freq;
+ gchar *username;
+ gchar *password;
+ GSList *calendars;
+ gchar *last_pub_time;
+};
+
+typedef struct _EPublishUri EPublishUri;
+
+void e_pub_uri_from_xml (EPublishUri *uri, const gchar *xml);
+gchar *e_pub_uri_to_xml (EPublishUri *uri);
+void e_pub_publish (gboolean publish) ;
+
+G_END_DECLS
+
+#endif
diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c
index 30e95dbcfe..b47232cc7f 100644
--- a/calendar/gui/itip-utils.c
+++ b/calendar/gui/itip-utils.c
@@ -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,220 @@ itip_send_comp (ECalComponentItipMethod method, ECalComponent *send_comp,
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);
+ g_object_unref (session);
+ 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");
+ g_object_unref (session);
+ 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));
+ g_object_unref (session);
+ return FALSE;
+ }
+
+ soup_uri_free (real_uri);
+ g_object_unref (session);
+
+ return TRUE;
+}
diff --git a/calendar/gui/itip-utils.h b/calendar/gui/itip-utils.h
index cf9dd37643..936adfec8e 100644
--- a/calendar/gui/itip-utils.h
+++ b/calendar/gui/itip-utils.h
@@ -31,5 +31,10 @@ const gchar *itip_strip_mailto (const gchar *address);
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