From 21743ac2cfa2d2ddcd539e9b7695cc8dd720ef36 Mon Sep 17 00:00:00 2001 From: Ettore Perazzoli Date: Tue, 21 Oct 2003 18:51:30 +0000 Subject: Merge new-ui-branch into the trunk. svn path=/trunk/; revision=22966 --- calendar/gui/dialogs/alarm-page.c | 16 +- calendar/gui/dialogs/comp-editor-util.c | 1 - calendar/gui/dialogs/comp-editor.c | 40 +- calendar/gui/dialogs/delete-error.c | 25 +- calendar/gui/dialogs/delete-error.h | 2 +- calendar/gui/dialogs/e-delegate-dialog.c | 26 +- calendar/gui/dialogs/event-editor.c | 5 +- calendar/gui/dialogs/event-page.c | 23 +- calendar/gui/dialogs/meeting-page.c | 12 +- calendar/gui/dialogs/meeting-page.etspec | 21 + calendar/gui/dialogs/new-calendar.c | 150 +++ calendar/gui/dialogs/new-calendar.glade | 193 +++ calendar/gui/dialogs/new-calendar.h | 28 + calendar/gui/dialogs/recurrence-page.c | 6 +- calendar/gui/dialogs/schedule-page.c | 23 +- calendar/gui/dialogs/task-editor.c | 5 +- calendar/gui/dialogs/task-page.c | 17 +- calendar/idl/evolution-calendar.idl | 275 ++-- calendar/importers/icalendar-importer.c | 102 +- calendar/pcs/Makefile.am | 19 +- calendar/pcs/cal-backend-file-events.c | 145 ++ calendar/pcs/cal-backend-file-events.h | 61 + calendar/pcs/cal-backend-file-todos.c | 135 ++ calendar/pcs/cal-backend-file-todos.h | 61 + calendar/pcs/cal-backend-file.c | 1646 +++++++++++------------ calendar/pcs/cal-backend-file.h | 12 +- calendar/pcs/cal-backend-object-sexp.c | 1007 ++++++++++++++ calendar/pcs/cal-backend-object-sexp.h | 67 + calendar/pcs/cal-backend-sync.c | 611 +++++++++ calendar/pcs/cal-backend-sync.h | 146 ++ calendar/pcs/cal-backend-util.c | 30 - calendar/pcs/cal-backend-util.h | 7 - calendar/pcs/cal-backend.c | 956 ++++++------- calendar/pcs/cal-backend.h | 218 ++- calendar/pcs/cal-common.h | 6 + calendar/pcs/cal-factory.c | 627 ++------- calendar/pcs/cal-factory.h | 12 +- calendar/pcs/cal.c | 1259 +++++++++++------- calendar/pcs/cal.h | 42 +- calendar/pcs/job.c | 98 -- calendar/pcs/job.h | 35 - calendar/pcs/query-backend.c | 361 ----- calendar/pcs/query-backend.h | 55 - calendar/pcs/query.c | 1843 +++++--------------------- calendar/pcs/query.h | 47 +- camel/ChangeLog | 47 + camel/camel-arg.c | 4 + camel/camel-arg.h | 1 + camel/camel-object.c | 9 + camel/camel-provider.c | 4 +- camel/camel-provider.h | 5 +- camel/camel-store.c | 23 +- camel/providers/local/camel-local-folder.c | 24 +- camel/providers/local/camel-local-folder.h | 2 +- camel/providers/local/camel-local-provider.c | 10 +- composer/ChangeLog | 34 + composer/e-msg-composer-hdrs.c | 71 +- composer/e-msg-composer-hdrs.h | 16 +- composer/e-msg-composer.c | 90 +- composer/e-msg-composer.h | 14 +- composer/evolution-composer.c | 20 +- data/evolution.desktop.in | 4 +- e-util/.cvsignore | 1 + e-util/ChangeLog | 143 ++ e-util/Makefile.am | 14 + e-util/e-account-list.c | 3 + e-util/e-account-list.h | 1 + e-util/e-account.c | 29 +- e-util/e-account.h | 1 - e-util/e-source-group.c | 605 +++++++++ e-util/e-source-group.h | 102 ++ e-util/e-source-list.c | 524 ++++++++ e-util/e-source-list.h | 88 ++ e-util/e-source.c | 458 +++++++ e-util/e-source.h | 91 ++ e-util/e-uid.c | 61 + e-util/e-uid.h | 28 + e-util/test-source-list.c | 524 ++++++++ filter/ChangeLog | 19 + filter/filter-folder.c | 29 +- filter/libfilter-i18n.h | 44 +- filter/vfolder-rule.c | 8 +- help/C/.cvsignore | 2 + help/es/apx-authors.sgml | 2 +- help/es/apx-bugs.sgml | 2 +- help/es/apx-fdl.sgml | 2 +- help/es/apx-gloss.sgml | 2 +- help/es/apx-gpl.sgml | 2 +- help/es/config-prefs.sgml | 2 +- help/es/config-sync.sgml | 2 +- help/es/evolution.sgml | 2 +- help/es/menuref.sgml | 2 +- help/es/preface.sgml | 2 +- help/es/usage-calendar.sgml | 2 +- help/es/usage-contact.sgml | 2 +- help/es/usage-exchange.sgml | 2 +- help/es/usage-exec-summary.sgml | 2 +- help/es/usage-mail-org.sgml | 2 +- help/es/usage-mail.sgml | 2 +- help/es/usage-mainwindow.sgml | 2 +- help/es/usage-print.sgml | 2 +- help/es/usage-sync.sgml | 2 +- libical/ChangeLog | 6 + 103 files changed, 8467 insertions(+), 5206 deletions(-) create mode 100644 calendar/gui/dialogs/meeting-page.etspec create mode 100644 calendar/gui/dialogs/new-calendar.c create mode 100644 calendar/gui/dialogs/new-calendar.glade create mode 100644 calendar/gui/dialogs/new-calendar.h create mode 100644 calendar/pcs/cal-backend-file-events.c create mode 100644 calendar/pcs/cal-backend-file-events.h create mode 100644 calendar/pcs/cal-backend-file-todos.c create mode 100644 calendar/pcs/cal-backend-file-todos.h create mode 100644 calendar/pcs/cal-backend-object-sexp.c create mode 100644 calendar/pcs/cal-backend-object-sexp.h create mode 100644 calendar/pcs/cal-backend-sync.c create mode 100644 calendar/pcs/cal-backend-sync.h delete mode 100644 calendar/pcs/job.c delete mode 100644 calendar/pcs/job.h delete mode 100644 calendar/pcs/query-backend.c delete mode 100644 calendar/pcs/query-backend.h create mode 100644 e-util/e-source-group.c create mode 100644 e-util/e-source-group.h create mode 100644 e-util/e-source-list.c create mode 100644 e-util/e-source-list.h create mode 100644 e-util/e-source.c create mode 100644 e-util/e-source.h create mode 100644 e-util/e-uid.c create mode 100644 e-util/e-uid.h create mode 100644 e-util/test-source-list.c diff --git a/calendar/gui/dialogs/alarm-page.c b/calendar/gui/dialogs/alarm-page.c index 785734ad8c..919ed9a2c8 100644 --- a/calendar/gui/dialogs/alarm-page.c +++ b/calendar/gui/dialogs/alarm-page.c @@ -677,10 +677,9 @@ add_clicked_cb (GtkButton *button, gpointer data) action = e_dialog_option_menu_get (priv->action, action_map); cal_component_alarm_set_action (alarm, action); if (action == CAL_ALARM_EMAIL && !cal_component_alarm_has_attendees (alarm)) { - const char *email; + char *email; - email = cal_client_get_alarm_email_address (COMP_EDITOR_PAGE (apage)->client); - if (email != NULL) { + if (!cal_client_get_alarm_email_address (COMP_EDITOR_PAGE (apage)->client, &email, NULL)) { CalComponentAttendee *a; GSList attendee_list; @@ -689,6 +688,7 @@ add_clicked_cb (GtkButton *button, gpointer data) attendee_list.data = a; attendee_list.next = NULL; cal_component_alarm_set_attendee_list (alarm, &attendee_list); + g_free (email); g_free (a); } } @@ -741,7 +741,7 @@ button_options_clicked_cb (GtkWidget *widget, gpointer data) AlarmPage *apage; AlarmPagePrivate *priv; gboolean repeat; - const char *email; + char *email; apage = ALARM_PAGE (data); priv = apage->priv; @@ -751,9 +751,11 @@ button_options_clicked_cb (GtkWidget *widget, gpointer data) repeat = !cal_client_get_static_capability (COMP_EDITOR_PAGE (apage)->client, CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT); - email = cal_client_get_alarm_email_address (COMP_EDITOR_PAGE (apage)->client); - if (!alarm_options_dialog_run (priv->alarm, email, repeat)) - g_message ("button_options_clicked_cb(): Could not create the alarm options dialog"); + + if (cal_client_get_alarm_email_address (COMP_EDITOR_PAGE (apage)->client, &email, NULL)) { + if (!alarm_options_dialog_run (priv->alarm, email, repeat)) + g_message ("button_options_clicked_cb(): Could not create the alarm options dialog"); + } } /* Hooks the widget signals */ diff --git a/calendar/gui/dialogs/comp-editor-util.c b/calendar/gui/dialogs/comp-editor-util.c index ce3cbc42f6..d06234edda 100644 --- a/calendar/gui/dialogs/comp-editor-util.c +++ b/calendar/gui/dialogs/comp-editor-util.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include "../calendar-config.h" diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index f9c9919338..2bbcf92df3 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -41,6 +41,7 @@ #include #include #include "../print.h" +#include "../comp-util.h" #include "save-comp.h" #include "delete-comp.h" #include "send-comp.h" @@ -294,7 +295,8 @@ save_comp (CompEditor *editor) CompEditorPrivate *priv; CalComponent *clone; GList *l; - CalClientResult result; + gboolean result; + GError *error = NULL; priv = editor->priv; @@ -321,32 +323,24 @@ save_comp (CompEditor *editor) priv->updating = TRUE; - if (cal_component_is_instance (priv->comp)) - result = cal_client_update_object_with_mod (priv->client, priv->comp, priv->mod); - else - result = cal_client_update_object (priv->client, priv->comp); - if (result != CAL_CLIENT_RESULT_SUCCESS) { + if (!cal_comp_is_on_server (priv->comp, priv->client)) { + result = cal_client_create_object (priv->client, cal_component_get_icalcomponent (priv->comp), NULL, &error); + } else { + result = cal_client_modify_object (priv->client, cal_component_get_icalcomponent (priv->comp), priv->mod, &error); + } + + if (!result) { GtkWidget *dlg; char *msg; - switch (result) { - case CAL_CLIENT_RESULT_INVALID_OBJECT : - msg = g_strdup (_("Could not update invalid object")); - break; - case CAL_CLIENT_RESULT_NOT_FOUND : - msg = g_strdup (_("Object not found, not updated")); - break; - case CAL_CLIENT_RESULT_PERMISSION_DENIED : - msg = g_strdup (_("You don't have permissions to update this object")); - break; - default : - msg = g_strdup (_("Could not update object")); - break; - } + msg = g_strdup (error ? error->message : _("Could not update object")); dlg = gnome_error_dialog (msg); gnome_dialog_run_and_close (GNOME_DIALOG (dlg)); + g_free (msg); + if (error) + g_error_free (error); return FALSE; } else { @@ -391,7 +385,7 @@ delete_comp (CompEditor *editor) cal_component_get_uid (priv->comp, &uid); priv->updating = TRUE; - cal_client_remove_object (priv->client, uid); + cal_client_remove_object (priv->client, uid, NULL); priv->updating = FALSE; close_dialog (editor); } @@ -1442,7 +1436,6 @@ obj_updated_cb (CalClient *client, const char *uid, gpointer data) CompEditor *editor = COMP_EDITOR (data); CompEditorPrivate *priv; CalComponent *comp = NULL; - CalClientGetStatus status; const char *edit_uid; priv = editor->priv; @@ -1453,8 +1446,7 @@ obj_updated_cb (CalClient *client, const char *uid, gpointer data) if (changed_component_dialog ((GtkWindow *) editor, priv->comp, FALSE, priv->changed)) { icalcomponent *icalcomp; - status = cal_client_get_object (priv->client, uid, &icalcomp); - if (status == CAL_CLIENT_GET_SUCCESS) { + if (!cal_client_get_object (priv->client, uid, NULL, &icalcomp, NULL)) { comp = cal_component_new (); if (cal_component_set_icalcomponent (comp, icalcomp)) comp_editor_edit_comp (editor, comp); diff --git a/calendar/gui/dialogs/delete-error.c b/calendar/gui/dialogs/delete-error.c index 947aab1e97..edbcaf9880 100644 --- a/calendar/gui/dialogs/delete-error.c +++ b/calendar/gui/dialogs/delete-error.c @@ -38,13 +38,16 @@ * **/ void -delete_error_dialog (CalClientResult result, CalComponentVType vtype) +delete_error_dialog (GError *error, CalComponentVType vtype) { GtkWidget *dialog; const char *str; - switch (result) { - case CAL_CLIENT_RESULT_CORBA_ERROR: + if (!error) + return; + + switch (error->code) { + case E_CALENDAR_STATUS_CORBA_EXCEPTION: switch (vtype) { case CAL_COMPONENT_EVENT: str = _("The event could not be deleted due to a corba error"); @@ -60,7 +63,7 @@ delete_error_dialog (CalClientResult result, CalComponentVType vtype) break; } break; - case CAL_CLIENT_RESULT_PERMISSION_DENIED: + case E_CALENDAR_STATUS_PERMISSION_DENIED: switch (vtype) { case CAL_COMPONENT_EVENT: str = _("The event could not be deleted because permission was denied"); @@ -76,24 +79,24 @@ delete_error_dialog (CalClientResult result, CalComponentVType vtype) break; } break; - case CAL_CLIENT_RESULT_INVALID_OBJECT: + case E_CALENDAR_STATUS_OTHER_ERROR: switch (vtype) { case CAL_COMPONENT_EVENT: - str = _("The event could not be deleted because it was invalid"); + str = _("The event could not be deleted due to an error"); break; case CAL_COMPONENT_TODO: - str = _("The task could not be deleted because it was invalid"); + str = _("The task could not be deleted due to an error"); break; case CAL_COMPONENT_JOURNAL: - str = _("The journal entry could not be deleted because it was invalid"); + str = _("The journal entry could not be deleted due to an error"); break; default: - str = _("The item could not be deleted because it was invalid"); + str = _("The item could not be deleted due to an error"); break; } break; - case CAL_CLIENT_RESULT_SUCCESS: - case CAL_CLIENT_RESULT_NOT_FOUND: + case E_CALENDAR_STATUS_OK: + case E_CALENDAR_STATUS_OBJECT_NOT_FOUND: default: /* If not found, we don't care - its gone anyhow */ return; diff --git a/calendar/gui/dialogs/delete-error.h b/calendar/gui/dialogs/delete-error.h index dcef2fa3be..4ac8cf4515 100644 --- a/calendar/gui/dialogs/delete-error.h +++ b/calendar/gui/dialogs/delete-error.h @@ -25,6 +25,6 @@ #include #include -void delete_error_dialog (CalClientResult result, CalComponentVType vtype); +void delete_error_dialog (GError *error, CalComponentVType vtype); #endif diff --git a/calendar/gui/dialogs/e-delegate-dialog.c b/calendar/gui/dialogs/e-delegate-dialog.c index 85c17bbd4b..709ea41178 100644 --- a/calendar/gui/dialogs/e-delegate-dialog.c +++ b/calendar/gui/dialogs/e-delegate-dialog.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include "Evolution-Addressbook-SelectNames.h" #include "e-delegate-dialog.h" @@ -126,8 +126,8 @@ EDelegateDialog * e_delegate_dialog_construct (EDelegateDialog *edd, const char *name, const char *address) { EDelegateDialogPrivate *priv; - EDestination *dest; - EDestination *destv[2] = {NULL, NULL}; + EABDestination *dest; + EABDestination *destv[2] = {NULL, NULL}; Bonobo_Control corba_control; CORBA_Environment ev; char *str; @@ -178,13 +178,13 @@ e_delegate_dialog_construct (EDelegateDialog *edd, const char *name, const char gtk_widget_show (priv->entry); gtk_box_pack_start (GTK_BOX (priv->hbox), priv->entry, TRUE, TRUE, 6); - dest = e_destination_new (); + dest = eab_destination_new (); destv[0] = dest; if (name != NULL && *name) - e_destination_set_name (dest, name); + eab_destination_set_name (dest, name); if (address != NULL && *address) - e_destination_set_email (dest, address); - str = e_destination_exportv(destv); + eab_destination_set_email (dest, address); + str = eab_destination_exportv(destv); bonobo_widget_set_property (BONOBO_WIDGET (priv->entry), "destinations", TC_CORBA_string, str, NULL); g_free(str); g_object_unref((dest)); @@ -256,7 +256,7 @@ char * e_delegate_dialog_get_delegate (EDelegateDialog *edd) { EDelegateDialogPrivate *priv; - EDestination **destv; + EABDestination **destv; char *string = NULL; g_return_val_if_fail (edd != NULL, NULL); @@ -265,11 +265,11 @@ e_delegate_dialog_get_delegate (EDelegateDialog *edd) priv = edd->priv; bonobo_widget_get_property (BONOBO_WIDGET (priv->entry), "destinations", TC_CORBA_string, &string, NULL); - destv = e_destination_importv (string); + destv = eab_destination_importv (string); if (destv && destv[0] != NULL) { g_free (priv->address); - priv->address = g_strdup (e_destination_get_email (destv[0])); + priv->address = g_strdup (eab_destination_get_email (destv[0])); g_free (destv); } @@ -283,7 +283,7 @@ char * e_delegate_dialog_get_delegate_name (EDelegateDialog *edd) { EDelegateDialogPrivate *priv; - EDestination **destv; + EABDestination **destv; char *string = NULL; g_return_val_if_fail (edd != NULL, NULL); @@ -292,13 +292,13 @@ e_delegate_dialog_get_delegate_name (EDelegateDialog *edd) priv = edd->priv; bonobo_widget_get_property (BONOBO_WIDGET (priv->entry), "destinations", TC_CORBA_string, &string, NULL); - destv = e_destination_importv (string); + destv = eab_destination_importv (string); g_message ("importv: [%s]", string); if (destv && destv[0] != NULL) { g_free (priv->name); - priv->name = g_strdup (e_destination_get_name (destv[0])); + priv->name = g_strdup (eab_destination_get_name (destv[0])); g_free (destv); } diff --git a/calendar/gui/dialogs/event-editor.c b/calendar/gui/dialogs/event-editor.c index 978a2dbb22..861a52c203 100644 --- a/calendar/gui/dialogs/event-editor.c +++ b/calendar/gui/dialogs/event-editor.c @@ -122,13 +122,14 @@ static void set_menu_sens (EventEditor *ee) { EventEditorPrivate *priv; - gboolean sens, existing, user, read_only; + gboolean sens, existing, user, read_only = TRUE; priv = ee->priv; existing = comp_editor_get_existing_org (COMP_EDITOR (ee)); user = comp_editor_get_user_org (COMP_EDITOR (ee)); - read_only = cal_client_is_read_only (comp_editor_get_cal_client (COMP_EDITOR (ee))); + + cal_client_is_read_only (comp_editor_get_cal_client (COMP_EDITOR (ee)), &read_only, NULL); sens = priv->meeting_shown; comp_editor_set_ui_prop (COMP_EDITOR (ee), diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c index b55e67dedd..8813081f4d 100644 --- a/calendar/gui/dialogs/event-page.c +++ b/calendar/gui/dialogs/event-page.c @@ -270,7 +270,6 @@ update_time (EventPage *epage, CalComponentDateTime *start_date, CalComponentDat EventPagePrivate *priv; struct icaltimetype *start_tt, *end_tt, implied_tt; icaltimezone *start_zone = NULL, *end_zone = NULL; - CalClientGetStatus status; gboolean all_day_event; priv = epage->priv; @@ -280,24 +279,22 @@ update_time (EventPage *epage, CalComponentDateTime *start_date, CalComponentDat first. */ start_zone = icaltimezone_get_builtin_timezone_from_tzid (start_date->tzid); if (!start_zone) { - status = cal_client_get_timezone (COMP_EDITOR_PAGE (epage)->client, - start_date->tzid, - &start_zone); /* FIXME: Handle error better. */ - if (status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (COMP_EDITOR_PAGE (epage)->client, + start_date->tzid, &start_zone, NULL)) { g_warning ("Couldn't get timezone from server: %s", - start_date->tzid ? start_date->tzid : ""); + start_date->tzid ? start_date->tzid : ""); + } } end_zone = icaltimezone_get_builtin_timezone_from_tzid (end_date->tzid); if (!end_zone) { - status = cal_client_get_timezone (COMP_EDITOR_PAGE (epage)->client, - end_date->tzid, - &end_zone); - /* FIXME: Handle error better. */ - if (status != CAL_CLIENT_GET_SUCCESS) - g_warning ("Couldn't get timezone from server: %s", - end_date->tzid ? end_date->tzid : ""); + if (!cal_client_get_timezone (COMP_EDITOR_PAGE (epage)->client, + end_date->tzid, &end_zone, NULL)) { + /* FIXME: Handle error better. */ + g_warning ("Couldn't get timezone from server: %s", + end_date->tzid ? end_date->tzid : ""); + } } /* If both times are DATE values, we set the 'All Day Event' checkbox. diff --git a/calendar/gui/dialogs/meeting-page.c b/calendar/gui/dialogs/meeting-page.c index 6c8212e93c..800b0d56c6 100644 --- a/calendar/gui/dialogs/meeting-page.c +++ b/calendar/gui/dialogs/meeting-page.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -693,7 +694,9 @@ meeting_page_construct (MeetingPage *mpage, EMeetingStore *ems, CalClient *client) { MeetingPagePrivate *priv; - const char *backend_address; + ETable *real_table; + gchar *filename; + char *backend_address; EIterator *it; EAccount *def_account; GList *address_strings = NULL, *l; @@ -716,7 +719,8 @@ meeting_page_construct (MeetingPage *mpage, EMeetingStore *ems, } /* Address information */ - backend_address = cal_client_get_cal_address (client); + if (!cal_client_get_cal_address (client, &backend_address, NULL)) + return NULL; priv->accounts = itip_addresses_get (); def_account = itip_addresses_get_default(); @@ -743,7 +747,8 @@ meeting_page_construct (MeetingPage *mpage, EMeetingStore *ems, } } g_object_unref(it); - + g_free (backend_address); + if (address_strings) gtk_combo_set_popdown_strings (GTK_COMBO (priv->organizer), address_strings); else @@ -753,6 +758,7 @@ meeting_page_construct (MeetingPage *mpage, EMeetingStore *ems, g_free (l->data); g_list_free (address_strings); + /* The etable displaying attendees and their status */ g_object_ref((ems)); priv->model = ems; diff --git a/calendar/gui/dialogs/meeting-page.etspec b/calendar/gui/dialogs/meeting-page.etspec new file mode 100644 index 0000000000..96bc480fe9 --- /dev/null +++ b/calendar/gui/dialogs/meeting-page.etspec @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/calendar/gui/dialogs/new-calendar.c b/calendar/gui/dialogs/new-calendar.c new file mode 100644 index 0000000000..aa647b55b2 --- /dev/null +++ b/calendar/gui/dialogs/new-calendar.c @@ -0,0 +1,150 @@ +/* Evolution calendar - Send calendar component dialog + * + * Copyright (C) 2001 Ximian, Inc. + * + * Author: JP Rosevear + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "new-calendar.h" + +static gboolean +create_new_source_with_group (GtkWindow *parent, + ESourceGroup *group, + const char *source_name) +{ + ESource *source; + char *new_dir; + + if (e_source_group_peek_source_by_name (group, source_name)) { + e_notice (parent, GTK_MESSAGE_ERROR, + _("Source with name '%s' already exists in the selected group"), + source_name); + return FALSE; + } + + /* create the new source */ + new_dir = g_build_filename (e_source_group_peek_base_uri (group), + source_name, NULL); + if (e_mkdir_hier (new_dir, 0700)) { + g_free (new_dir); + e_notice (parent, GTK_MESSAGE_ERROR, + _("Could not create directory for new calendar")); + return FALSE; + } + + source = e_source_new (source_name, source_name); + e_source_group_add_source (group, source, -1); + + g_free (new_dir); + + return TRUE; +} + +/** + * new_calendar_dialog + * + * Displays a dialog that allows the user to create a new calendar. + */ +gboolean +new_calendar_dialog (GtkWindow *parent) +{ + GtkWidget *dialog, *cal_group, *cal_name; + GladeXML *xml; + ESourceList *source_list; + GConfClient *gconf_client; + GSList *groups, *sl; + gboolean result = FALSE, retry = TRUE; + + /* load the Glade file */ + xml = glade_xml_new (EVOLUTION_GLADEDIR "/new-calendar.glade", "new-calendar-dialog", NULL); + if (!xml) { + g_warning ("new_calendar_dialog(): cannot load Glade file"); + return FALSE; + } + + dialog = glade_xml_get_widget (xml, "new-calendar-dialog"); + cal_group = glade_xml_get_widget (xml, "calendar-group"); + cal_name = glade_xml_get_widget (xml, "calendar-name"); + + /* set up widgets */ + gconf_client = gconf_client_get_default (); + source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/calendar/sources"); + + groups = e_source_list_peek_groups (source_list); + for (sl = groups; sl != NULL; sl = sl->next) { + GtkWidget *menu_item, *menu; + ESourceGroup *group = sl->data; + + menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (cal_group)); + if (!GTK_IS_MENU (menu)) { + menu = gtk_menu_new (); + gtk_option_menu_set_menu (GTK_OPTION_MENU (cal_group), menu); + gtk_widget_show (menu); + } + + menu_item = gtk_menu_item_new_with_label (e_source_group_peek_name (group)); + gtk_widget_show (menu_item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + } + + if (groups) + gtk_option_menu_set_history (GTK_OPTION_MENU (cal_group), 0); + + /* run the dialog */ + do { + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { + char *name; + + name = gtk_entry_get_text (GTK_ENTRY (cal_name)); + sl = g_slist_nth (groups, gtk_option_menu_get_history (GTK_OPTION_MENU (cal_group))); + if (sl) { + if (create_new_source_with_group (GTK_WINDOW (dialog), + sl->data, + name)) + retry = FALSE; + } else { + e_notice (dialog, GTK_MESSAGE_ERROR, + _("A group must be selected")); + continue; + } + } else + retry = FALSE; /* user pressed Cancel */ + } while (retry); + + /* free memory */ + g_object_unref (gconf_client); + g_object_unref (source_list); + gtk_widget_destroy (dialog); + + /* free memory */ + g_object_unref (xml); + + return result; +} diff --git a/calendar/gui/dialogs/new-calendar.glade b/calendar/gui/dialogs/new-calendar.glade new file mode 100644 index 0000000000..42717a87a8 --- /dev/null +++ b/calendar/gui/dialogs/new-calendar.glade @@ -0,0 +1,193 @@ + + + + + + + + 12 + True + Add New Calendar + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 3 + 3 + False + 6 + 6 + + + + True + Calendar Group + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 1 + 2 + 6 + fill + + + + + + + True + Calendar Name + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 1 + 2 + 2 + 3 + 6 + fill + + + + + + + True + True + -1 + + + 2 + 3 + 1 + 2 + 6 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + + + 2 + 3 + 2 + 3 + 6 + + + + + + + True + <b>Calendar options</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + 3 + 0 + 1 + 6 + + + + + + 0 + True + True + + + + + + + diff --git a/calendar/gui/dialogs/new-calendar.h b/calendar/gui/dialogs/new-calendar.h new file mode 100644 index 0000000000..9890f9e1f8 --- /dev/null +++ b/calendar/gui/dialogs/new-calendar.h @@ -0,0 +1,28 @@ +/* Evolution calendar - Send calendar component dialog + * + * Copyright (C) 2001 Ximian, Inc. + * + * Author: JP Rosevear + * + * 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 NEW_CALENDAR_H +#define NEW_CALENDAR_H + +#include + +gboolean new_calendar_dialog (GtkWindow *parent); + +#endif diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c index 275ba26c44..4599001c27 100644 --- a/calendar/gui/dialogs/recurrence-page.c +++ b/calendar/gui/dialogs/recurrence-page.c @@ -852,7 +852,8 @@ preview_recur (RecurrencePage *rpage) cal_component_get_dtstart (priv->comp, &cdt); if (cdt.tzid != NULL) { - if (cal_client_get_timezone (COMP_EDITOR_PAGE (rpage)->client, cdt.tzid, &zone) != CAL_CLIENT_GET_SUCCESS) + /* FIXME Will cal_client_get_timezone really not return builtin zones? */ + if (!cal_client_get_timezone (COMP_EDITOR_PAGE (rpage)->client, cdt.tzid, &zone, NULL)) zone = icaltimezone_get_builtin_timezone_from_tzid (cdt.tzid); } cal_component_set_dtstart (comp, &cdt); @@ -1448,7 +1449,8 @@ fill_ending_date (RecurrencePage *rpage, struct icalrecurrencetype *r) else if (dt.tzid == NULL) to_zone = icaltimezone_get_utc_timezone (); else - cal_client_get_timezone (client, dt.tzid, &to_zone); + /* FIXME Error checking? */ + cal_client_get_timezone (client, dt.tzid, &to_zone, NULL); from_zone = icaltimezone_get_utc_timezone (); icaltimezone_convert_time (&r->until, from_zone, to_zone); diff --git a/calendar/gui/dialogs/schedule-page.c b/calendar/gui/dialogs/schedule-page.c index 8cad77360b..06c2d57131 100644 --- a/calendar/gui/dialogs/schedule-page.c +++ b/calendar/gui/dialogs/schedule-page.c @@ -208,7 +208,6 @@ update_time (SchedulePage *spage, CalComponentDateTime *start_date, CalComponent SchedulePagePrivate *priv; struct icaltimetype start_tt, end_tt; icaltimezone *start_zone = NULL, *end_zone = NULL; - CalClientGetStatus status; gboolean all_day; priv = spage->priv; @@ -218,24 +217,22 @@ update_time (SchedulePage *spage, CalComponentDateTime *start_date, CalComponent first. */ start_zone = icaltimezone_get_builtin_timezone_from_tzid (start_date->tzid); if (!start_zone) { - status = cal_client_get_timezone (COMP_EDITOR_PAGE (spage)->client, - start_date->tzid, - &start_zone); - /* FIXME: Handle error better. */ - if (status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (COMP_EDITOR_PAGE (spage)->client, + start_date->tzid, &start_zone, NULL)) { + /* FIXME: Handle error better. */ g_warning ("Couldn't get timezone from server: %s", start_date->tzid ? start_date->tzid : ""); + } } end_zone = icaltimezone_get_builtin_timezone_from_tzid (end_date->tzid); if (!end_zone) { - status = cal_client_get_timezone (COMP_EDITOR_PAGE (spage)->client, - end_date->tzid, - &end_zone); - /* FIXME: Handle error better. */ - if (status != CAL_CLIENT_GET_SUCCESS) - g_warning ("Couldn't get timezone from server: %s", - end_date->tzid ? end_date->tzid : ""); + if (!cal_client_get_timezone (COMP_EDITOR_PAGE (spage)->client, + end_date->tzid, &end_zone, NULL)) { + /* FIXME: Handle error better. */ + g_warning ("Couldn't get timezone from server: %s", + end_date->tzid ? end_date->tzid : ""); + } } start_tt = *start_date->value; diff --git a/calendar/gui/dialogs/task-editor.c b/calendar/gui/dialogs/task-editor.c index 4ef971fe85..339fdca80d 100644 --- a/calendar/gui/dialogs/task-editor.c +++ b/calendar/gui/dialogs/task-editor.c @@ -112,13 +112,14 @@ static void set_menu_sens (TaskEditor *te) { TaskEditorPrivate *priv; - gboolean sens, existing, user, read_only; + gboolean sens, existing, user, read_only = TRUE; priv = te->priv; existing = comp_editor_get_existing_org (COMP_EDITOR (te)); user = comp_editor_get_user_org (COMP_EDITOR (te)); - read_only = cal_client_is_read_only (comp_editor_get_cal_client (COMP_EDITOR (te))); + + cal_client_is_read_only (comp_editor_get_cal_client (COMP_EDITOR (te)), &read_only, NULL); sens = cal_client_get_static_capability (comp_editor_get_cal_client (COMP_EDITOR (te)), CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT) diff --git a/calendar/gui/dialogs/task-page.c b/calendar/gui/dialogs/task-page.c index 760b3e6f9e..fb7558ce5a 100644 --- a/calendar/gui/dialogs/task-page.c +++ b/calendar/gui/dialogs/task-page.c @@ -253,7 +253,6 @@ task_page_fill_widgets (CompEditorPage *page, CalComponent *comp) CalComponentText text; CalComponentDateTime d; CalComponentClassification cl; - CalClientGetStatus get_tz_status; GSList *l; const char *categories; icaltimezone *zone, *default_zone; @@ -317,12 +316,10 @@ task_page_fill_widgets (CompEditorPage *page, CalComponent *comp) if (!zone) zone = icaltimezone_get_builtin_timezone_from_tzid (d.tzid); if (!zone) { - get_tz_status = cal_client_get_timezone (page->client, d.tzid, - &zone); - /* FIXME: Handle error better. */ - if (get_tz_status != CAL_CLIENT_GET_SUCCESS) - g_warning ("Couldn't get timezone from server: %s", - d.tzid ? d.tzid : ""); + if (!cal_client_get_timezone (page->client, d.tzid, &zone, NULL)) + /* FIXME: Handle error better. */ + g_warning ("Couldn't get timezone from server: %s", + d.tzid ? d.tzid : ""); } e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (priv->due_timezone), zone); @@ -359,10 +356,8 @@ task_page_fill_widgets (CompEditorPage *page, CalComponent *comp) if (!zone) zone = icaltimezone_get_builtin_timezone_from_tzid (d.tzid); if (!zone) { - get_tz_status = cal_client_get_timezone (page->client, d.tzid, - &zone); - /* FIXME: Handle error better. */ - if (get_tz_status != CAL_CLIENT_GET_SUCCESS) + if (!cal_client_get_timezone (page->client, d.tzid, &zone, NULL)) + /* FIXME: Handle error better. */ g_warning ("Couldn't get timezone from server: %s", d.tzid ? d.tzid : ""); } diff --git a/calendar/idl/evolution-calendar.idl b/calendar/idl/evolution-calendar.idl index 15b27e806a..1b139fc6f5 100644 --- a/calendar/idl/evolution-calendar.idl +++ b/calendar/idl/evolution-calendar.idl @@ -23,9 +23,14 @@ module Calendar { typedef string CalObj; typedef sequence CalObjSeq; + typedef sequence stringlist; + /* A unique identifier for a calendar component */ typedef string CalObjUID; + /* A unique identified for an event recurrence */ + typedef string CalRecurID; + /* Simple sequence of strings */ typedef sequence StringSeq; @@ -66,14 +71,6 @@ module Calendar { const CalObjChangeType ADDED = 1 << 0; const CalObjChangeType MODIFIED = 1 << 1; const CalObjChangeType DELETED = 1 << 2; - - /* Types of alarms */ - enum AlarmType { - MAIL, - PROGRAM, - DISPLAY, - AUDIO - }; /* Used to store a time_t */ typedef unsigned long Time_t; @@ -102,30 +99,39 @@ module Calendar { /* Used to transfer a list of changed components */ typedef sequence CalObjChangeSeq; - /* An alarm trigger instance */ - struct CalAlarmInstance { - CalAlarmUID auid; - Time_t trigger; - Time_t occur_start; - Time_t occur_end; - }; - - /* Used to represent a list of alarm triggers for a single component */ - typedef sequence CalAlarmInstanceSeq; - - /* Alarms for a component */ - struct CalComponentAlarms { - CalObj calobj; - CalAlarmInstanceSeq alarms; - }; - - /* Used to represent a list of components plus their triggers */ - typedef sequence CalComponentAlarmsSeq; - /* Used to represent users and lists of users */ typedef string User; typedef sequence UserList; + enum CallStatus { + Success, + RepositoryOffline, + PermissionDenied, + InvalidRange, + ObjectNotFound, + InvalidObject, + CardIdAlreadyExists, + AuthenticationFailed, + AuthenticationRequired, + UnsupportedField, + UnsupportedMethod, + UnsupportedAuthenticationMethod, + TLSNotAvailable, + NoSuchCal, + + /* These can be returned for successful searches, but + indicate the result set was truncated */ + SearchSizeLimitExceeded, + SearchTimeLimitExceeded, + + InvalidQuery, + QueryRefused, + + CouldNotCancel, + + OtherError + }; + interface Query; interface Listener; @@ -136,134 +142,68 @@ module Calendar { interface Cal : Bonobo::Unknown { exception NotFound {}; exception InvalidRange {}; - exception InvalidObject {}; - exception CouldNotCreate {}; - exception PermissionDenied {}; - exception Busy {string errorMsg;}; /* A calendar is identified by its URI */ readonly attribute string uri; + oneway void open (in boolean only_if_exists); + oneway void remove (); + /* Check write permissions for calendar */ - boolean isReadOnly (); + oneway void isReadOnly (); /* Information on the backend's capabilities */ - string getStaticCapabilities (); + oneway void getStaticCapabilities (); - /* Return the cal address associated with this calendar, - if any. */ - string getCalAddress () - raises (NotFound); + /* Return the cal address associated with this calendar, if any. */ + oneway void getCalAddress (); - string getAlarmEmailAddress () - raises (NotFound); + oneway void getAlarmEmailAddress (); /* Returns the LDAP attribute to get attendees from */ - string getLdapAttribute () - raises (NotFound); + oneway void getLdapAttribute (); /* For going online/offline */ void setMode (in CalMode mode); - - /* Gets the number of components of the specified types */ - long countObjects (in CalObjType type); - /* Get a default object of a given type */ - CalObj getDefaultObject (in CalObjType type); + /* Get a default object of the backend's type */ + oneway void getDefaultObject (); /* Gets a component based on its URI */ - CalObj getObject (in CalObjUID uid) - raises (NotFound); - - /* Sets the default timezone to be used for resolving DATE - and floating DATE-TIME values. */ - void setDefaultTimezone (in CalTimezoneObjUID tzid) - raises (NotFound); + oneway void getObject (in CalObjUID uid, in CalRecurID rid); - /* Gets a VTIMEZONE component based on its TZID */ - CalTimezoneObj getTimezoneObject (in CalTimezoneObjUID tzid) - raises (NotFound); + oneway void getObjectList (in string query); - /* Gets a list of UIDs based on component type */ - CalObjUIDSeq getUIDs (in CalObjType type); + /* Methods for manipulating timezones */ + oneway void getTimezone (in CalTimezoneObjUID tzid); + oneway void addTimezone (in CalTimezoneObj tz); + /* The timezone used to resolve DATE and floating DATE-TIME values. */ + oneway void setDefaultTimezone (in CalTimezoneObjUID tzid); /* Gets a list of components that changed based on object type */ - CalObjChangeSeq getChanges (in CalObjType type, in string change_id); - - /* Gets a list of components that occur or recur in the specified time range */ - CalObjUIDSeq getObjectsInRange (in CalObjType type, - in Time_t start, in Time_t end) - raises (InvalidRange); - - /* Gets a list of the components that have alarms that trigger - * in the specified range of time, and the trigger/occurrence - * structures themselves. - */ - CalComponentAlarmsSeq getAlarmsInRange (in Time_t start, in Time_t end) - raises (NotFound, InvalidRange); + oneway void getChanges (in CalObjType type, in string change_id); /* Returns free/busy objects for the given interval */ - CalObjSeq getFreeBusy (in UserList users, in Time_t start, in Time_t end) - raises (NotFound, InvalidRange); - - /* Gets the alarms for the specified component that trigger in - * the specified time range. - */ - CalComponentAlarms getAlarmsForObject (in CalObjUID uid, - in Time_t start, in Time_t end) - raises (NotFound, InvalidRange); - + oneway void getFreeBusy (in UserList users, in Time_t start, in Time_t end); /* Discards an alarm from a given component */ - void discardAlarm (in CalObjUID uid, in CalAlarmUID auid) - raises (NotFound); - - /* Adds or updates one or more VEVENT/VTODO/VTIMEZONE - * components. The calobj should be a string representation of - * a complete VCALENDAR object (we also support single - * VEVENT/VTODO strings, but that is deprecated). - * - * The VTIMEZONE data will be merged into the calendar, - * possibly by renaming TZIDs (though not for builtin - * VTIMEZONEs, which have unique TZIDs), so don't rely on the - * TZIDs being the same in the new object on the server. - * - * The client should probably immediately free its copy of the - * object after this call, and call getObject to get the - * updated version. - */ - void updateObjects (in CalObj calobj, in CalObjModType mod) - raises (NotFound, InvalidObject, PermissionDenied); + oneway void discardAlarm (in CalObjUID uid, in CalAlarmUID auid); - /* Removes a component */ - void removeObject (in CalObjUID uid, in CalObjModType mod) - raises (NotFound, PermissionDenied); + /* Methods for manipulating iCalendar objects */ + oneway void createObject (in CalObj calobj); + oneway void modifyObject (in CalObj calobj, in CalObjModType mod); + oneway void removeObject (in CalObjUID uid, in CalRecurID rid, in CalObjModType mod); - /* Sends a component */ - CalObj sendObject (in CalObj calobj, out UserList users) - raises (InvalidObject, PermissionDenied, Busy); + /* Methods for getting/sending iCalendar VCALENDARS via iTip/iMip */ + oneway void receiveObjects (in CalObj calobj); + oneway void sendObjects (in CalObj calobj); - /* Initiates a live query of the calendar. Returns a handle - * to the live query itself; changes to components that are - * present in the query are notified to the listener. - */ - Query getQuery (in string sexp, in QueryListener ql) - raises (CouldNotCreate); + /* Query methods */ + oneway void getQuery (in string sexp, in QueryListener ql); }; /* Listener for changes in a calendar */ interface Listener : Bonobo::Unknown { - /* Return status when opening a calendar */ - enum OpenStatus { - SUCCESS, /* All OK */ - ERROR, /* Generic error */ - NOT_FOUND, /* Requested opening in only_if_exists mode - * when the URI did not exist. - */ - METHOD_NOT_SUPPORTED, /* A method handler is not registered */ - PERMISSION_DENIED - }; - /* Return status when setting calendar mode */ enum SetModeStatus { MODE_SET, /* All OK */ @@ -271,62 +211,58 @@ module Calendar { MODE_NOT_SUPPORTED /* Mode not supported */ }; - /* Called from a CalFactory when a calendar is initially opened. - * The listener must remember the cal object. - */ - void notifyCalOpened (in OpenStatus status, in Cal cal); + oneway void notifyReadOnly (in CallStatus status, in boolean read_only); + oneway void notifyCalAddress (in CallStatus status, in string address); + oneway void notifyAlarmEmailAddress (in CallStatus status, in string address); + oneway void notifyLDAPAttribute (in CallStatus status, in string ldap_attribute); + oneway void notifyStaticCapabilities (in CallStatus status, in string capabilities); + + oneway void notifyCalOpened (in CallStatus status); + oneway void notifyCalRemoved (in CallStatus status); - /* Called from a Calendar when the mode is changed */ - void notifyCalSetMode (in SetModeStatus status, in CalMode mode); + oneway void notifyObjectCreated (in CallStatus status, in string uid); + oneway void notifyObjectModified (in CallStatus status); + oneway void notifyObjectRemoved (in CallStatus status); + + oneway void notifyAlarmDiscarded (in CallStatus status); + + oneway void notifyObjectsReceived (in CallStatus status); + oneway void notifyObjectsSent (in CallStatus status); - /* Called from a Calendar when a component is added or changed */ - void notifyObjUpdated (in CalObjUID uid); + oneway void notifyDefaultObjectRequested (in CallStatus status, in CalObj object); + oneway void notifyObjectRequested (in CallStatus status, in CalObj object); + oneway void notifyObjectListRequested (in CallStatus status, in stringlist objects); + oneway void notifyQuery (in CallStatus status, in Query query); + + oneway void notifyTimezoneRequested (in CallStatus status, in CalTimezoneObj tz); + oneway void notifyTimezoneAdded (in CallStatus status, in CalTimezoneObjUID tzid); + oneway void notifyDefaultTimezoneSet (in CallStatus status); - /* Called from a Calendar when a component is removed */ - void notifyObjRemoved (in CalObjUID uid); + oneway void notifyChanges (in CallStatus status, in CalObjChangeSeq changes); + oneway void notifyFreeBusy (in CallStatus status, in CalObjSeq freebusy); + + /* Called from a Calendar when the mode is changed */ + oneway void notifyCalSetMode (in SetModeStatus status, in CalMode mode); /* Called from a Calendar when the list of categories changes */ - void notifyCategoriesChanged (in StringSeq categories); + oneway void notifyCategoriesChanged (in StringSeq categories); /* Called from a Calendar when there is an error not notified otherwise */ - void notifyErrorOccurred (in string message); + oneway void notifyErrorOccurred (in string message); }; /* Handle to a live query on a calendar */ interface Query : Bonobo::Unknown { + oneway void start (); }; /* Listener for changes in a query of a calendar */ interface QueryListener : Bonobo::Unknown { - /* Called when components are added or changed. If - * query_in_progress is true, then the initial query results are - * being populated and the other arguments indicate the - * percentage of completion Otherwise, the percent value is - * unspecified. */ - void notifyObjUpdated (in CalObjUIDSeq uids, - in boolean query_in_progress, - in long n_scanned, - in long total); - - /* Called when a component is removed */ - void notifyObjRemoved (in CalObjUID uid); - - /* Reported when a query ends */ - enum QueryDoneStatus { - SUCCESS, - PARSE_ERROR - }; - - /* Called when the query finishes populating itself some time - * after it is created. Before this is called, - * notifyObjUpdated() may have been called several times to - * indicate which objects are actually in the query, unless the - * status result is a parse error. - */ - void notifyQueryDone (in QueryDoneStatus status, in string error_str); - - /* Called when an evaluation error occurs while performing a query */ - void notifyEvalError (in string error_str); + oneway void notifyObjectsAdded (in stringlist objects); + oneway void notifyObjectsModified (in stringlist objects); + oneway void notifyObjectsRemoved (in CalObjUIDSeq uids); + oneway void notifyQueryProgress (in string message, in short percent); + oneway void notifyQueryDone (in CallStatus status); }; /* A calendar factory, can load and create calendars */ @@ -334,14 +270,9 @@ module Calendar { exception NilListener {}; exception InvalidURI {}; exception UnsupportedMethod {}; - exception PermissionDenied {}; - - /* Open a calendar from an URI */ - void open (in string uri, in boolean only_if_exists, in Listener listener) - raises (NilListener, InvalidURI, UnsupportedMethod, PermissionDenied); - /* List of open URI's */ - StringSeq uriList (in CalMode mode); + Cal getCal (in string uri, in CalObjType type, in Listener listener) + raises (NilListener, InvalidURI, UnsupportedMethod); }; /* Interface to the alarm notification service */ diff --git a/calendar/importers/icalendar-importer.c b/calendar/importers/icalendar-importer.c index 28068c11df..f2dcbd7097 100644 --- a/calendar/importers/icalendar-importer.c +++ b/calendar/importers/icalendar-importer.c @@ -179,6 +179,60 @@ prepare_tasks (icalcomponent *icalcomp, GList *vtodos) g_list_free (vtodos); } +static CalClientResult +update_single_object (CalClient *client, icalcomponent *icalcomp) +{ + char *uid; + icalcomponent *tmp_icalcomp; + + uid = (char *) icalcomponent_get_uid (icalcomp); + + if (cal_client_get_object (client, uid, NULL, &tmp_icalcomp, NULL)) + return cal_client_modify_object (client, icalcomp, CALOBJ_MOD_ALL, NULL) + ? CAL_CLIENT_RESULT_SUCCESS : CAL_CLIENT_RESULT_CORBA_ERROR; + + return cal_client_create_object (client, icalcomp, &uid, NULL) + ? CAL_CLIENT_RESULT_SUCCESS : CAL_CLIENT_RESULT_CORBA_ERROR; +} + +static CalClientResult +update_objects (CalClient *client, icalcomponent *icalcomp) +{ + icalcomponent *subcomp; + icalcomponent_kind kind; + CalClientResult result; + + kind = icalcomponent_isa (icalcomp); + if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT) + return update_single_object (client, icalcomp); + else if (kind != ICAL_VCALENDAR_COMPONENT) + return CAL_CLIENT_RESULT_INVALID_OBJECT; + + subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); + while (subcomp) { + kind = icalcomponent_isa (subcomp); + if (kind == ICAL_VTIMEZONE_COMPONENT) { + icaltimezone *zone; + + zone = icaltimezone_new (); + icaltimezone_set_component (zone, subcomp); + + result = cal_client_add_timezone (client, zone, NULL); + icaltimezone_free (zone, 1); + if (result != CAL_CLIENT_RESULT_SUCCESS) + return result; + } else if (kind == ICAL_VTODO_COMPONENT || + kind == ICAL_VEVENT_COMPONENT) { + result = update_single_object (client, subcomp); + if (result != CAL_CLIENT_RESULT_SUCCESS) + return result; + } + + subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT); + } + + return CAL_CLIENT_RESULT_SUCCESS; +} static void process_item_fn (EvolutionImporter *importer, @@ -220,20 +274,20 @@ process_item_fn (EvolutionImporter *importer, contains just tasks, we strip out the VEVENTs, which do not get imported at all. */ if (ici->folder_contains_events && ici->folder_contains_tasks) { - if (cal_client_update_objects (ici->client, ici->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) + if (update_objects (ici->client, ici->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) result = GNOME_Evolution_ImporterListener_BAD_DATA; } else if (ici->folder_contains_events) { GList *vtodos = prepare_events (ici->icalcomp); - if (cal_client_update_objects (ici->client, ici->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) + if (update_objects (ici->client, ici->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) result = GNOME_Evolution_ImporterListener_BAD_DATA; prepare_tasks (ici->icalcomp, vtodos); - if (cal_client_update_objects (ici->tasks_client, + if (update_objects (ici->tasks_client, ici->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) result = GNOME_Evolution_ImporterListener_BAD_DATA; } else { prepare_tasks (ici->icalcomp, NULL); - if (cal_client_update_objects (ici->client, ici->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) + if (update_objects (ici->client, ici->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) result = GNOME_Evolution_ImporterListener_BAD_DATA; } @@ -312,8 +366,14 @@ load_file_fn (EvolutionImporter *importer, } else real_uri = g_strdup (physical_uri); - if (cal_client_open_calendar (ici->client, real_uri, TRUE) - && cal_client_open_default_tasks (ici->tasks_client, FALSE)) { + /* create CalClient's */ + if (!ici->client) + ici->client = cal_client_new (real_uri, CALOBJ_TYPE_EVENT); + if (!ici->tasks_client) + ici->tasks_client = cal_client_new ("", CALOBJ_TYPE_TODO); /* FIXME */ + + if (cal_client_open (ici->client, TRUE, NULL) + && cal_client_open (ici->tasks_client, FALSE, NULL)) { ici->icalcomp = icalcomp; ret = TRUE; } @@ -334,8 +394,8 @@ ical_importer_new (void) ICalImporter *ici; ici = g_new0 (ICalImporter, 1); - ici->client = cal_client_new (); - ici->tasks_client = cal_client_new (); + ici->client = NULL; + ici->tasks_client = NULL; ici->icalcomp = NULL; ici->importer = evolution_importer_new (support_format_fn, load_file_fn, @@ -458,8 +518,14 @@ vcal_load_file_fn (EvolutionImporter *importer, } else real_uri = g_strdup (physical_uri); - if (cal_client_open_calendar (ici->client, real_uri, TRUE) - && cal_client_open_default_tasks (ici->tasks_client, FALSE)) { + /* create CalClient's */ + if (!ici->client) + ici->client = cal_client_new (real_uri, CALOBJ_TYPE_EVENT); + if (!ici->tasks_client) + ici->tasks_client = cal_client_new ("", CALOBJ_TYPE_TODO); + + if (cal_client_open (ici->client, TRUE, NULL) + && cal_client_open (ici->tasks_client, FALSE, NULL)) { ici->icalcomp = icalcomp; ret = TRUE; } @@ -478,8 +544,8 @@ vcal_importer_new (void) ICalImporter *ici; ici = g_new0 (ICalImporter, 1); - ici->client = cal_client_new (); - ici->tasks_client = cal_client_new (); + ici->client = NULL; + ici->tasks_client = NULL; ici->icalcomp = NULL; ici->importer = evolution_importer_new (vcal_support_format_fn, vcal_load_file_fn, @@ -542,14 +608,14 @@ gnome_calendar_import_data_fn (EvolutionIntelligentImporter *ii, /* Try to open the default calendar & tasks folders. */ if (ici->do_calendar) { - calendar_client = cal_client_new (); - if (!cal_client_open_default_calendar (calendar_client, FALSE)) + calendar_client = cal_client_new ("", CALOBJ_TYPE_EVENT); /* FIXME: use default folder */ + if (!cal_client_open (calendar_client, FALSE, NULL)) goto out; } if (ici->do_tasks) { - tasks_client = cal_client_new (); - if (!cal_client_open_default_tasks (tasks_client, FALSE)) + tasks_client = cal_client_new ("", CALOBJ_TYPE_TODO); /* FIXME: use default folder */ + if (!cal_client_open (tasks_client, FALSE, NULL)) goto out; } @@ -598,7 +664,7 @@ gnome_calendar_import_data_fn (EvolutionIntelligentImporter *ii, /* Import the calendar events. */ /* FIXME: What do intelligent importers do about errors? */ if (ici->do_calendar) - cal_client_update_objects (calendar_client, icalcomp); + update_objects (calendar_client, icalcomp); /* @@ -606,7 +672,7 @@ gnome_calendar_import_data_fn (EvolutionIntelligentImporter *ii, */ prepare_tasks (icalcomp, vtodos); if (ici->do_tasks) - cal_client_update_objects (tasks_client, icalcomp); + update_objects (tasks_client, icalcomp); out: if (icalcomp) diff --git a/calendar/pcs/Makefile.am b/calendar/pcs/Makefile.am index 19b0b66dac..9287ee6a87 100644 --- a/calendar/pcs/Makefile.am +++ b/calendar/pcs/Makefile.am @@ -4,10 +4,17 @@ INCLUDES = \ -I$(top_srcdir)/calendar \ -I$(top_builddir)/calendar \ -I$(top_srcdir)/libical/src \ + -I$(top_builddir)/libical/src \ -I$(top_srcdir)/libwombat \ -I$(top_builddir)/libwombat \ $(EVOLUTION_CALENDAR_CFLAGS) +AM_CFLAGS = \ + -DGTK_DISABLE_DEPRECATED=1 \ + -DGDK_DISABLE_DEPRECATED=1 \ + -DG_DISABLE_DEPRECATED=1 \ + -DGNOME_DISABLE_DEPRECATED=1 + CORBA_GENERATED_H = \ evolution-calendar.h @@ -37,11 +44,11 @@ pcsinclude_HEADERS = \ $(CORBA_GENERATED_H) \ cal.h \ cal-backend.h \ + cal-backend-sync.h \ cal-backend-util.h \ + cal-backend-object-sexp.h\ cal-common.h \ cal-factory.h \ - job.h \ - query-backend.h \ query.h libpcs_a_SOURCES = \ @@ -49,13 +56,17 @@ libpcs_a_SOURCES = \ $(CORBA_GENERATED_C) \ cal.c \ cal-backend.c \ + cal-backend-sync.c \ cal-backend-util.c \ + cal-backend-object-sexp.c\ cal-factory.c \ - job.c \ - query-backend.c \ query.c libpcsfile_a_SOURCES = \ + cal-backend-file-events.c\ + cal-backend-file-events.h\ + cal-backend-file-todos.c\ + cal-backend-file-todos.h\ cal-backend-file.c \ cal-backend-file.h diff --git a/calendar/pcs/cal-backend-file-events.c b/calendar/pcs/cal-backend-file-events.c new file mode 100644 index 0000000000..a7cf56fac6 --- /dev/null +++ b/calendar/pcs/cal-backend-file-events.c @@ -0,0 +1,145 @@ +/* Evolution calendar - iCalendar file backend + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Authors: Federico Mena-Quintero + * Rodrigo Moya + * + * 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 +#include +#include +#include +#include +#include +#include +#include "e-util/e-xml-hash-utils.h" +#include "cal-util/cal-recur.h" +#include "cal-util/cal-util.h" +#include "cal-backend-file-events.h" +#include "cal-backend-util.h" + + + +/* Private part of the CalBackendFileEvents structure */ +struct _CalBackendFileEventsPrivate { +}; + + + +static void cal_backend_file_events_class_init (CalBackendFileEventsClass *class); +static void cal_backend_file_events_init (CalBackendFileEvents *cbfile, CalBackendFileEventsClass *class); +static void cal_backend_file_events_dispose (GObject *object); +static void cal_backend_file_events_finalize (GObject *object); + +static GObjectClass *parent_class; + + + +/** + * cal_backend_file_events_get_type: + * @void: + * + * Registers the #CalBackendFileEvents class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #CalBackendFileEvents class. + **/ +GType +cal_backend_file_events_get_type (void) +{ + static GType cal_backend_file_events_type = 0; + + if (!cal_backend_file_events_type) { + static GTypeInfo info = { + sizeof (CalBackendFileEventsClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cal_backend_file_events_class_init, + NULL, NULL, + sizeof (CalBackendFileEvents), + 0, + (GInstanceInitFunc) cal_backend_file_events_init + }; + cal_backend_file_events_type = g_type_register_static (CAL_BACKEND_FILE_TYPE, + "CalBackendFileEvents", &info, 0); + } + + return cal_backend_file_events_type; +} + +/* Class initialization function for the file backend */ +static void +cal_backend_file_events_class_init (CalBackendFileEventsClass *klass) +{ + GObjectClass *object_class; + CalBackendClass *backend_class; + + object_class = G_OBJECT_CLASS (klass); + backend_class = CAL_BACKEND_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->dispose = cal_backend_file_events_dispose; + object_class->finalize = cal_backend_file_events_finalize; + +// backend_class->get_uri = cal_backend_file_events_get_uri; +} + +/* Object initialization function for the file backend */ +static void +cal_backend_file_events_init (CalBackendFileEvents *cbfile, CalBackendFileEventsClass *class) +{ + CalBackendFileEventsPrivate *priv; + + priv = g_new0 (CalBackendFileEventsPrivate, 1); + cbfile->priv = priv; + + cal_backend_file_set_file_name (CAL_BACKEND_FILE (cbfile), "calendar.ics"); +} + +/* Dispose handler for the file backend */ +static void +cal_backend_file_events_dispose (GObject *object) +{ + CalBackendFileEvents *cbfile; + CalBackendFileEventsPrivate *priv; + + cbfile = CAL_BACKEND_FILE_EVENTS (object); + priv = cbfile->priv; + + if (G_OBJECT_CLASS (parent_class)->dispose) + (* G_OBJECT_CLASS (parent_class)->dispose) (object); +} + +/* Finalize handler for the file backend */ +static void +cal_backend_file_events_finalize (GObject *object) +{ + CalBackendFileEvents *cbfile; + CalBackendFileEventsPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_CAL_BACKEND_FILE_EVENTS (object)); + + cbfile = CAL_BACKEND_FILE_EVENTS (object); + priv = cbfile->priv; + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + diff --git a/calendar/pcs/cal-backend-file-events.h b/calendar/pcs/cal-backend-file-events.h new file mode 100644 index 0000000000..3f812b3e09 --- /dev/null +++ b/calendar/pcs/cal-backend-file-events.h @@ -0,0 +1,61 @@ +/* Evolution calendar - iCalendar file backend + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Author: Federico Mena-Quintero + * + * 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 CAL_BACKEND_FILE_EVENTS_H +#define CAL_BACKEND_FILE_EVENTS_H + +#include "cal-backend-file.h" + +G_BEGIN_DECLS + + + +#define CAL_BACKEND_FILE_EVENTS_TYPE (cal_backend_file_events_get_type ()) +#define CAL_BACKEND_FILE_EVENTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CAL_BACKEND_FILE_EVENTS_TYPE, \ + CalBackendFileEvents)) +#define CAL_BACKEND_FILE_EVENTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CAL_BACKEND_FILE_EVENTS_TYPE, \ + CalBackendFileEventsClass)) +#define IS_CAL_BACKEND_FILE_EVENTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CAL_BACKEND_FILE_EVENTS_TYPE)) +#define IS_CAL_BACKEND_FILE_EVENTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CAL_BACKEND_FILE_EVENTS_TYPE)) + +typedef struct _CalBackendFileEvents CalBackendFileEvents; +typedef struct _CalBackendFileEventsClass CalBackendFileEventsClass; + +typedef struct _CalBackendFileEventsPrivate CalBackendFileEventsPrivate; + +struct _CalBackendFileEvents { + CalBackendFile backend; + + /* Private data */ + CalBackendFileEventsPrivate *priv; +}; + +struct _CalBackendFileEventsClass { + CalBackendFileClass parent_class; +}; + +GType cal_backend_file_events_get_type (void); + + + +G_END_DECLS + +#endif diff --git a/calendar/pcs/cal-backend-file-todos.c b/calendar/pcs/cal-backend-file-todos.c new file mode 100644 index 0000000000..6f56dd1776 --- /dev/null +++ b/calendar/pcs/cal-backend-file-todos.c @@ -0,0 +1,135 @@ +/* Evolution calendar - iCalendar file backend for tasks + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Authors: Federico Mena-Quintero + * Rodrigo Moya + * + * 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 +#include "cal-backend-file-todos.h" + + + +/* Private part of the CalBackendFileTodos structure */ +struct _CalBackendFileTodosPrivate { +}; + + + +static void cal_backend_file_todos_class_init (CalBackendFileTodosClass *class); +static void cal_backend_file_todos_init (CalBackendFileTodos *cbfile, CalBackendFileTodosClass *class); +static void cal_backend_file_todos_dispose (GObject *object); +static void cal_backend_file_todos_finalize (GObject *object); + +static CalBackendFileClass *parent_class; + + + +/** + * cal_backend_file_todos_get_type: + * @void: + * + * Registers the #CalBackendFileTodos class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #CalBackendFileTodos class. + **/ +GType +cal_backend_file_todos_get_type (void) +{ + static GType cal_backend_file_todos_type = 0; + + if (!cal_backend_file_todos_type) { + static GTypeInfo info = { + sizeof (CalBackendFileTodosClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cal_backend_file_todos_class_init, + NULL, NULL, + sizeof (CalBackendFileTodos), + 0, + (GInstanceInitFunc) cal_backend_file_todos_init + }; + cal_backend_file_todos_type = g_type_register_static (CAL_BACKEND_FILE_TYPE, + "CalBackendFileTodos", &info, 0); + } + + return cal_backend_file_todos_type; +} + +/* Class initialization function for the file backend */ +static void +cal_backend_file_todos_class_init (CalBackendFileTodosClass *klass) +{ + GObjectClass *object_class; + CalBackendClass *backend_class; + + object_class = G_OBJECT_CLASS (klass); + backend_class = CAL_BACKEND_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->dispose = cal_backend_file_todos_dispose; + object_class->finalize = cal_backend_file_todos_finalize; + +// backend_class->get_uri = cal_backend_file_todos_get_uri; +} + +/* Object initialization function for the file backend */ +static void +cal_backend_file_todos_init (CalBackendFileTodos *cbfile, CalBackendFileTodosClass *class) +{ + CalBackendFileTodosPrivate *priv; + + priv = g_new0 (CalBackendFileTodosPrivate, 1); + cbfile->priv = priv; + + cal_backend_file_set_file_name (CAL_BACKEND_FILE (cbfile), "tasks.ics"); +} + +/* Dispose handler for the file backend */ +static void +cal_backend_file_todos_dispose (GObject *object) +{ + CalBackendFileTodos *cbfile; + CalBackendFileTodosPrivate *priv; + + cbfile = CAL_BACKEND_FILE_TODOS (object); + priv = cbfile->priv; + + if (G_OBJECT_CLASS (parent_class)->dispose) + (* G_OBJECT_CLASS (parent_class)->dispose) (object); +} + +/* Finalize handler for the file backend */ +static void +cal_backend_file_todos_finalize (GObject *object) +{ + CalBackendFileTodos *cbfile; + CalBackendFileTodosPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_CAL_BACKEND_FILE_TODOS (object)); + + cbfile = CAL_BACKEND_FILE_TODOS (object); + priv = cbfile->priv; + + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + diff --git a/calendar/pcs/cal-backend-file-todos.h b/calendar/pcs/cal-backend-file-todos.h new file mode 100644 index 0000000000..7f17122673 --- /dev/null +++ b/calendar/pcs/cal-backend-file-todos.h @@ -0,0 +1,61 @@ +/* Evolution calendar - iCalendar file backend + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Author: Federico Mena-Quintero + * + * 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 CAL_BACKEND_FILE_TODOS_H +#define CAL_BACKEND_FILE_TODOS_H + +#include "cal-backend-file.h" + +G_BEGIN_DECLS + + + +#define CAL_BACKEND_FILE_TODOS_TYPE (cal_backend_file_todos_get_type ()) +#define CAL_BACKEND_FILE_TODOS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CAL_BACKEND_FILE_TODOS_TYPE, \ + CalBackendFileTodos)) +#define CAL_BACKEND_FILE_TODOS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CAL_BACKEND_FILE_TODOS_TYPE, \ + CalBackendFileTodosClass)) +#define IS_CAL_BACKEND_FILE_TODOS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CAL_BACKEND_FILE_TODOS_TYPE)) +#define IS_CAL_BACKEND_FILE_TODOS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CAL_BACKEND_FILE_TODOS_TYPE)) + +typedef struct _CalBackendFileTodos CalBackendFileTodos; +typedef struct _CalBackendFileTodosClass CalBackendFileTodosClass; + +typedef struct _CalBackendFileTodosPrivate CalBackendFileTodosPrivate; + +struct _CalBackendFileTodos { + CalBackendFile backend; + + /* Private data */ + CalBackendFileTodosPrivate *priv; +}; + +struct _CalBackendFileTodosClass { + CalBackendFileClass parent_class; +}; + +GType cal_backend_file_todos_get_type (void); + + + +G_END_DECLS + +#endif diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c index b26f2fd74c..e5e3abb7c9 100644 --- a/calendar/pcs/cal-backend-file.c +++ b/calendar/pcs/cal-backend-file.c @@ -1,7 +1,6 @@ /* Evolution calendar - iCalendar file backend * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000-2003 Ximian, Inc. * * Authors: Federico Mena-Quintero * Rodrigo Moya @@ -27,38 +26,41 @@ #include #include #include -#include "e-util/e-dbhash.h" +#include "e-util/e-xml-hash-utils.h" #include "cal-util/cal-recur.h" #include "cal-util/cal-util.h" -#include "cal-backend-file.h" +#include "cal-backend-file-events.h" #include "cal-backend-util.h" +#include "cal-backend-object-sexp.h" +/* Placeholder for each component and its recurrences */ +typedef struct { + CalComponent *full_object; + GHashTable *recurrences; +} CalBackendFileObject; + /* Private part of the CalBackendFile structure */ struct _CalBackendFilePrivate { /* URI where the calendar data is stored */ char *uri; + /* Filename in the dir */ + char *file_name; + /* Toplevel VCALENDAR component */ icalcomponent *icalcomp; - /* All the CalComponent objects in the calendar, hashed by UID. The + /* All the objects in the calendar, hashed by UID. The * hash key *is* the uid returned by cal_component_get_uid(); it is not * copied, so don't free it when you remove an object from the hash - * table. + * table. Each item in the hash table is a CalBackendFileObject. */ GHashTable *comp_uid_hash; - /* All event, to-do, and journal components in the calendar; they are - * here just for easy access (i.e. so that you don't have to iterate - * over the comp_uid_hash). If you need *all* the components in the - * calendar, iterate over the hash instead. - */ - GList *events; - GList *todos; - GList *journals; - + GList *comp; + /* Config database handle for free/busy organizer information */ EConfigListener *config_listener; @@ -68,181 +70,29 @@ struct _CalBackendFilePrivate { /* The calendar's default timezone, used for resolving DATE and floating DATE-TIME values. */ icaltimezone *default_zone; + + /* The list of live queries */ + GList *queries; }; -static void cal_backend_file_class_init (CalBackendFileClass *class); -static void cal_backend_file_init (CalBackendFile *cbfile, CalBackendFileClass *class); static void cal_backend_file_dispose (GObject *object); static void cal_backend_file_finalize (GObject *object); -static const char *cal_backend_file_get_uri (CalBackend *backend); -static gboolean cal_backend_file_is_read_only (CalBackend *backend); -static const char *cal_backend_file_get_cal_address (CalBackend *backend); -static const char *cal_backend_file_get_alarm_email_address (CalBackend *backend); -static const char *cal_backend_file_get_ldap_attribute (CalBackend *backend); -static const char *cal_backend_file_get_static_capabilities (CalBackend *backend); -static CalBackendOpenStatus cal_backend_file_open (CalBackend *backend, - const char *uristr, - gboolean only_if_exists); -static gboolean cal_backend_file_is_loaded (CalBackend *backend); -static Query *cal_backend_file_get_query (CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp); - -static CalMode cal_backend_file_get_mode (CalBackend *backend); -static void cal_backend_file_set_mode (CalBackend *backend, CalMode mode); - -static int cal_backend_file_get_n_objects (CalBackend *backend, CalObjType type); -static char *cal_backend_file_get_default_object (CalBackend *backend, CalObjType type); -static CalComponent *cal_backend_file_get_object_component (CalBackend *backend, const char *uid); -static char *cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid); -static GList *cal_backend_file_get_uids (CalBackend *backend, CalObjType type); -static GList *cal_backend_file_get_objects_in_range (CalBackend *backend, CalObjType type, - time_t start, time_t end); -static GList *cal_backend_file_get_free_busy (CalBackend *backend, GList *users, time_t start, time_t end); -static GNOME_Evolution_Calendar_CalObjChangeSeq *cal_backend_file_get_changes ( - CalBackend *backend, CalObjType type, const char *change_id); - -static GNOME_Evolution_Calendar_CalComponentAlarmsSeq *cal_backend_file_get_alarms_in_range ( - CalBackend *backend, time_t start, time_t end); - -static GNOME_Evolution_Calendar_CalComponentAlarms *cal_backend_file_get_alarms_for_object ( - CalBackend *backend, const char *uid, - time_t start, time_t end, gboolean *object_found); - -static CalBackendResult cal_backend_file_discard_alarm (CalBackend *backend, - const char *uid, - const char *auid); - -static CalBackendResult cal_backend_file_update_objects (CalBackend *backend, - const char *calobj, - CalObjModType mod); -static CalBackendResult cal_backend_file_remove_object (CalBackend *backend, const char *uid, CalObjModType mod); - -static CalBackendSendResult cal_backend_file_send_object (CalBackend *backend, - const char *calobj, gchar **new_calobj, - GNOME_Evolution_Calendar_UserList **user_list, - char error_msg[256]); - -static icaltimezone* cal_backend_file_get_timezone (CalBackend *backend, const char *tzid); -static icaltimezone* cal_backend_file_get_default_timezone (CalBackend *backend); -static gboolean cal_backend_file_set_default_timezone (CalBackend *backend, - const char *tzid); - -static CalBackendClass *parent_class; +static CalBackendSyncClass *parent_class; -/** - * cal_backend_file_get_type: - * @void: - * - * Registers the #CalBackendFile class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the #CalBackendFile class. - **/ -GType -cal_backend_file_get_type (void) -{ - static GType cal_backend_file_type = 0; - - if (!cal_backend_file_type) { - static GTypeInfo info = { - sizeof (CalBackendFileClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) cal_backend_file_class_init, - NULL, NULL, - sizeof (CalBackendFile), - 0, - (GInstanceInitFunc) cal_backend_file_init - }; - cal_backend_file_type = g_type_register_static (CAL_BACKEND_TYPE, - "CalBackendFile", &info, 0); - } - - return cal_backend_file_type; -} - -/* Class initialization function for the file backend */ -static void -cal_backend_file_class_init (CalBackendFileClass *class) -{ - GObjectClass *object_class; - CalBackendClass *backend_class; - - object_class = (GObjectClass *) class; - backend_class = (CalBackendClass *) class; - - parent_class = (CalBackendClass *) g_type_class_peek_parent (class); - - object_class->dispose = cal_backend_file_dispose; - object_class->finalize = cal_backend_file_finalize; - - backend_class->get_uri = cal_backend_file_get_uri; - backend_class->is_read_only = cal_backend_file_is_read_only; - backend_class->get_cal_address = cal_backend_file_get_cal_address; - backend_class->get_alarm_email_address = cal_backend_file_get_alarm_email_address; - backend_class->get_ldap_attribute = cal_backend_file_get_ldap_attribute; - backend_class->get_static_capabilities = cal_backend_file_get_static_capabilities; - backend_class->open = cal_backend_file_open; - backend_class->is_loaded = cal_backend_file_is_loaded; - backend_class->get_query = cal_backend_file_get_query; - backend_class->get_mode = cal_backend_file_get_mode; - backend_class->set_mode = cal_backend_file_set_mode; - backend_class->get_n_objects = cal_backend_file_get_n_objects; - backend_class->get_default_object = cal_backend_file_get_default_object; - backend_class->get_object_component = cal_backend_file_get_object_component; - backend_class->get_timezone_object = cal_backend_file_get_timezone_object; - backend_class->get_uids = cal_backend_file_get_uids; - backend_class->get_objects_in_range = cal_backend_file_get_objects_in_range; - backend_class->get_free_busy = cal_backend_file_get_free_busy; - backend_class->get_changes = cal_backend_file_get_changes; - backend_class->get_alarms_in_range = cal_backend_file_get_alarms_in_range; - backend_class->get_alarms_for_object = cal_backend_file_get_alarms_for_object; - backend_class->discard_alarm = cal_backend_file_discard_alarm; - backend_class->update_objects = cal_backend_file_update_objects; - backend_class->remove_object = cal_backend_file_remove_object; - backend_class->send_object = cal_backend_file_send_object; - - backend_class->get_timezone = cal_backend_file_get_timezone; - backend_class->get_default_timezone = cal_backend_file_get_default_timezone; - backend_class->set_default_timezone = cal_backend_file_set_default_timezone; -} - -/* Object initialization function for the file backend */ -static void -cal_backend_file_init (CalBackendFile *cbfile, CalBackendFileClass *class) -{ - CalBackendFilePrivate *priv; - - priv = g_new0 (CalBackendFilePrivate, 1); - cbfile->priv = priv; - - priv->uri = NULL; - priv->icalcomp = NULL; - priv->comp_uid_hash = NULL; - priv->events = NULL; - priv->todos = NULL; - priv->journals = NULL; - - /* The timezone defaults to UTC. */ - priv->default_zone = icaltimezone_get_utc_timezone (); - - priv->config_listener = e_config_listener_new (); -} - /* g_hash_table_foreach() callback to destroy a CalComponent */ static void -free_cal_component (gpointer key, gpointer value, gpointer data) +free_object (gpointer key, gpointer value, gpointer data) { - CalComponent *comp; + CalBackendFileObject *obj_data = value; - comp = CAL_COMPONENT (value); - g_object_unref (comp); + g_object_unref (obj_data->full_object); + g_hash_table_foreach (obj_data->recurrences, (GHFunc) g_object_unref, NULL); + g_hash_table_destroy (obj_data->recurrences); } /* Saves the calendar data */ @@ -340,18 +190,13 @@ cal_backend_file_dispose (GObject *object) } if (priv->comp_uid_hash) { - g_hash_table_foreach (priv->comp_uid_hash, - free_cal_component, NULL); + g_hash_table_foreach (priv->comp_uid_hash, (GHFunc) free_object, NULL); g_hash_table_destroy (priv->comp_uid_hash); priv->comp_uid_hash = NULL; } - g_list_free (priv->events); - g_list_free (priv->todos); - g_list_free (priv->journals); - priv->events = NULL; - priv->todos = NULL; - priv->journals = NULL; + g_list_free (priv->comp); + priv->comp = NULL; if (priv->icalcomp) { icalcomponent_free (priv->icalcomp); @@ -401,72 +246,80 @@ static CalComponent * lookup_component (CalBackendFile *cbfile, const char *uid) { CalBackendFilePrivate *priv; - CalComponent *comp; + CalBackendFileObject *obj_data; priv = cbfile->priv; - comp = g_hash_table_lookup (priv->comp_uid_hash, uid); - - return comp; + /* FIXME: search recurrences also */ + obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid); + return obj_data ? obj_data->full_object : NULL; } /* Calendar backend methods */ -/* Get_uri handler for the file backend */ -static const char * -cal_backend_file_get_uri (CalBackend *backend) -{ - CalBackendFile *cbfile; - CalBackendFilePrivate *priv; - - cbfile = CAL_BACKEND_FILE (backend); - priv = cbfile->priv; - - g_return_val_if_fail (priv->icalcomp != NULL, NULL); - g_assert (priv->uri != NULL); - - return (const char *) priv->uri; -} - /* Is_read_only handler for the file backend */ -static gboolean -cal_backend_file_is_read_only (CalBackend *backend) +static CalBackendSyncStatus +cal_backend_file_is_read_only (CalBackendSync *backend, Cal *cal, gboolean *read_only) { /* we just return FALSE, since all calendars are read-write */ - return FALSE; + *read_only = FALSE; + + return GNOME_Evolution_Calendar_Success; } /* Get_email_address handler for the file backend */ -static const char * -cal_backend_file_get_cal_address (CalBackend *backend) +static CalBackendSyncStatus +cal_backend_file_get_cal_address (CalBackendSync *backend, Cal *cal, char **address) { /* A file backend has no particular email address associated * with it (although that would be a useful feature some day). */ - return NULL; + *address = NULL; + + return GNOME_Evolution_Calendar_Success; } -static const char * -cal_backend_file_get_ldap_attribute (CalBackend *backend) +static CalBackendSyncStatus +cal_backend_file_get_ldap_attribute (CalBackendSync *backend, Cal *cal, char **attribute) { - return NULL; + *attribute = NULL; + + return GNOME_Evolution_Calendar_Success; } -static const char * -cal_backend_file_get_alarm_email_address (CalBackend *backend) +static CalBackendSyncStatus +cal_backend_file_get_alarm_email_address (CalBackendSync *backend, Cal *cal, char **address) { /* A file backend has no particular email address associated * with it (although that would be a useful feature some day). */ - return NULL; + *address = NULL; + + return GNOME_Evolution_Calendar_Success; +} + +static CalBackendSyncStatus +cal_backend_file_get_static_capabilities (CalBackendSync *backend, Cal *cal, char **capabilities) +{ + *capabilities = CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS; + + return GNOME_Evolution_Calendar_Success; } -static const char * -cal_backend_file_get_static_capabilities (CalBackend *backend) +/* function to resolve timezones */ +static icaltimezone * +resolve_tzid (const char *tzid, gpointer user_data) { - return CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS; + icalcomponent *vcalendar_comp = user_data; + + if (!tzid || !tzid[0]) + return NULL; + else if (!strcmp (tzid, "UTC")) + return icaltimezone_get_utc_timezone (); + + return icalcomponent_get_timezone (vcalendar_comp, tzid); } /* Idle handler; we save the calendar since it is dirty */ @@ -506,7 +359,7 @@ static void check_dup_uid (CalBackendFile *cbfile, CalComponent *comp) { CalBackendFilePrivate *priv; - CalComponent *old_comp; + CalBackendFileObject *obj_data; const char *uid; char *new_uid; @@ -514,8 +367,8 @@ check_dup_uid (CalBackendFile *cbfile, CalComponent *comp) cal_component_get_uid (comp, &uid); - old_comp = g_hash_table_lookup (priv->comp_uid_hash, uid); - if (!old_comp) + obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid); + if (!obj_data) return; /* Everything is fine */ g_message ("check_dup_uid(): Got object with duplicated UID `%s', changing it...", uid); @@ -531,6 +384,22 @@ check_dup_uid (CalBackendFile *cbfile, CalComponent *comp) mark_dirty (cbfile); } +static char * +get_rid_string (CalComponent *comp) +{ + CalComponentRange range; + struct icaltimetype tt; + + cal_component_get_recurid (comp, &range); + if (!range.datetime.value) + return "0"; + tt = *range.datetime.value; + cal_component_free_range (&range); + + return icaltime_is_valid_time (tt) && !icaltime_is_null_time (tt) ? + icaltime_as_ical_string (tt) : "0"; +} + /* Tries to add an icalcomponent to the file backend. We only store the objects * of the types we support; all others just remain in the toplevel component so * that we don't lose them. @@ -539,38 +408,27 @@ static void add_component (CalBackendFile *cbfile, CalComponent *comp, gboolean add_to_toplevel) { CalBackendFilePrivate *priv; - GList **list; + CalBackendFileObject *obj_data; const char *uid; GSList *categories; priv = cbfile->priv; - switch (cal_component_get_vtype (comp)) { - case CAL_COMPONENT_EVENT: - list = &priv->events; - break; - - case CAL_COMPONENT_TODO: - list = &priv->todos; - break; - - case CAL_COMPONENT_JOURNAL: - list = &priv->journals; - break; - - default: - g_assert_not_reached (); - return; - } + /* FIXME: check if it's an instance */ /* Ensure that the UID is unique; some broken implementations spit * components with duplicated UIDs. */ check_dup_uid (cbfile, comp); cal_component_get_uid (comp, &uid); - g_hash_table_insert (priv->comp_uid_hash, (char *)uid, comp); - *list = g_list_prepend (*list, comp); + obj_data = g_new0 (CalBackendFileObject, 1); + obj_data->full_object = comp; + obj_data->recurrences = g_hash_table_new (g_str_hash, g_str_equal); + + g_hash_table_insert (priv->comp_uid_hash, (gpointer) uid, obj_data); + + priv->comp = g_list_prepend (priv->comp, comp); /* Put the object in the toplevel component if required */ @@ -599,8 +457,9 @@ remove_component (CalBackendFile *cbfile, CalComponent *comp) CalBackendFilePrivate *priv; icalcomponent *icalcomp; const char *uid; - GList **list, *l; + GList *l; GSList *categories; + CalBackendFileObject *obj_data; priv = cbfile->priv; @@ -614,39 +473,22 @@ remove_component (CalBackendFile *cbfile, CalComponent *comp) /* Remove it from our mapping */ cal_component_get_uid (comp, &uid); + obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid); + if (!obj_data) + return; + g_hash_table_remove (priv->comp_uid_hash, uid); - - switch (cal_component_get_vtype (comp)) { - case CAL_COMPONENT_EVENT: - list = &priv->events; - break; - - case CAL_COMPONENT_TODO: - list = &priv->todos; - break; - - case CAL_COMPONENT_JOURNAL: - list = &priv->journals; - break; - - default: - /* Make the compiler shut up. */ - list = NULL; - g_assert_not_reached (); - } - l = g_list_find (*list, comp); + l = g_list_find (priv->comp, comp); g_assert (l != NULL); - - *list = g_list_remove_link (*list, l); - g_list_free_1 (l); + priv->comp = g_list_delete_link (priv->comp, l); /* Update the set of categories */ cal_component_get_categories_list (comp, &categories); cal_backend_unref_categories (CAL_BACKEND (cbfile), categories); cal_component_free_categories_list (categories); - g_object_unref (comp); + free_object (uid, obj_data, NULL); } /* Scans the toplevel VCALENDAR component and stores the objects it finds */ @@ -686,7 +528,7 @@ scan_vcalendar (CalBackendFile *cbfile) } /* Parses an open iCalendar file and loads it into the backend */ -static CalBackendOpenStatus +static CalBackendSyncStatus open_cal (CalBackendFile *cbfile, const char *uristr) { CalBackendFilePrivate *priv; @@ -696,7 +538,7 @@ open_cal (CalBackendFile *cbfile, const char *uristr) icalcomp = cal_util_parse_ics_file (uristr); if (!icalcomp) - return CAL_BACKEND_OPEN_ERROR; + return GNOME_Evolution_Calendar_OtherError; /* FIXME: should we try to demangle XROOT components and * individual components as well? @@ -704,7 +546,8 @@ open_cal (CalBackendFile *cbfile, const char *uristr) if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) { icalcomponent_free (icalcomp); - return CAL_BACKEND_OPEN_ERROR; + + return GNOME_Evolution_Calendar_OtherError; } priv->icalcomp = icalcomp; @@ -714,10 +557,10 @@ open_cal (CalBackendFile *cbfile, const char *uristr) priv->uri = g_strdup (uristr); - return CAL_BACKEND_OPEN_SUCCESS; + return GNOME_Evolution_Calendar_Success; } -static CalBackendOpenStatus +static CalBackendSyncStatus create_cal (CalBackendFile *cbfile, const char *uristr) { CalBackendFilePrivate *priv; @@ -734,36 +577,37 @@ create_cal (CalBackendFile *cbfile, const char *uristr) mark_dirty (cbfile); - return CAL_BACKEND_OPEN_SUCCESS; + return GNOME_Evolution_Calendar_Success; } -/* Open handler for the file backend */ -static CalBackendOpenStatus -cal_backend_file_open (CalBackend *backend, const char *uristr, gboolean only_if_exists) +static char * +get_uri_string (CalBackend *backend) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; - char *str_uri; + const char *master_uri; + char *full_uri, *str_uri; GnomeVFSURI *uri; - CalBackendOpenStatus status; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; + + master_uri = cal_backend_get_uri (backend); + g_message (G_STRLOC ": Trying to open %s", master_uri); + + /* FIXME Check the error conditions a little more elegantly here */ + if (g_strrstr ("tasks.ics", master_uri) || g_strrstr ("calendar.ics", master_uri)) { + g_warning (G_STRLOC ": Existing file name %s", master_uri); - g_return_val_if_fail (priv->icalcomp == NULL, CAL_BACKEND_OPEN_ERROR); - g_return_val_if_fail (uristr != NULL, CAL_BACKEND_OPEN_ERROR); - - g_assert (priv->uri == NULL); - g_assert (priv->comp_uid_hash == NULL); - - uri = gnome_vfs_uri_new (uristr); - if (!uri) - return CAL_BACKEND_OPEN_ERROR; - - if (!uri->method_string || strcmp (uri->method_string, "file")) { - gnome_vfs_uri_unref (uri); - return CAL_BACKEND_OPEN_ERROR; + return NULL; } + + full_uri = g_strdup_printf ("%s%s%s", master_uri, G_DIR_SEPARATOR_S, priv->file_name); + uri = gnome_vfs_uri_new (full_uri); + g_free (full_uri); + + if (!uri) + return NULL; str_uri = gnome_vfs_uri_to_string (uri, (GNOME_VFS_URI_HIDE_USER_NAME @@ -771,51 +615,94 @@ cal_backend_file_open (CalBackend *backend, const char *uristr, gboolean only_if | GNOME_VFS_URI_HIDE_HOST_NAME | GNOME_VFS_URI_HIDE_HOST_PORT | GNOME_VFS_URI_HIDE_TOPLEVEL_METHOD)); + gnome_vfs_uri_unref (uri); + if (!str_uri || !strlen (str_uri)) { g_free (str_uri); - gnome_vfs_uri_unref (uri); - return CAL_BACKEND_OPEN_ERROR; - } + return NULL; + } + + return str_uri; +} + +/* Open handler for the file backend */ +static CalBackendSyncStatus +cal_backend_file_open (CalBackendSync *backend, Cal *cal, gboolean only_if_exists) +{ + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; + char *str_uri; + CalBackendSyncStatus status; + + cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; + + /* Claim a succesful open if we are already open */ + if (priv->uri && priv->comp_uid_hash) + return GNOME_Evolution_Calendar_Success; + + str_uri = get_uri_string (CAL_BACKEND (backend)); + if (!str_uri) + return GNOME_Evolution_Calendar_OtherError; + if (access (str_uri, R_OK) == 0) status = open_cal (cbfile, str_uri); else { if (only_if_exists) - status = CAL_BACKEND_OPEN_NOT_FOUND; + status = GNOME_Evolution_Calendar_NoSuchCal; else status = create_cal (cbfile, str_uri); } g_free (str_uri); - gnome_vfs_uri_unref (uri); return status; } -/* is_loaded handler for the file backend */ -static gboolean -cal_backend_file_is_loaded (CalBackend *backend) +static CalBackendSyncStatus +cal_backend_file_remove (CalBackendSync *backend, Cal *cal) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; - + char *str_uri; + cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - return (priv->icalcomp != NULL); + str_uri = get_uri_string (CAL_BACKEND (backend)); + if (!str_uri) + return GNOME_Evolution_Calendar_OtherError; + + if (access (str_uri, W_OK) != 0) { + g_free (str_uri); + + return GNOME_Evolution_Calendar_PermissionDenied; + } + + /* FIXME Remove backup file and whole directory too? */ + if (unlink (str_uri) != 0) { + g_free (str_uri); + + return GNOME_Evolution_Calendar_OtherError; + } + + g_free (str_uri); + + return GNOME_Evolution_Calendar_Success; } -/* get_query handler for the file backend */ -static Query * -cal_backend_file_get_query (CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp) +/* is_loaded handler for the file backend */ +static gboolean +cal_backend_file_is_loaded (CalBackend *backend) { CalBackendFile *cbfile; + CalBackendFilePrivate *priv; cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; - return query_new (backend, ql, sexp); + return (priv->icalcomp != NULL); } /* is_remote handler for the file backend */ @@ -841,283 +728,252 @@ cal_backend_file_set_mode (CalBackend *backend, CalMode mode) } -/* Get_n_objects handler for the file backend */ -static int -cal_backend_file_get_n_objects (CalBackend *backend, CalObjType type) -{ - CalBackendFile *cbfile; - CalBackendFilePrivate *priv; - int n; - - cbfile = CAL_BACKEND_FILE (backend); - priv = cbfile->priv; - - g_return_val_if_fail (priv->icalcomp != NULL, -1); - - n = 0; - - if (type & CALOBJ_TYPE_EVENT) - n += g_list_length (priv->events); - - if (type & CALOBJ_TYPE_TODO) - n += g_list_length (priv->todos); - - if (type & CALOBJ_TYPE_JOURNAL) - n += g_list_length (priv->journals); - - return n; -} - -static char * -cal_backend_file_get_default_object (CalBackend *backend, CalObjType type) +static CalBackendSyncStatus +cal_backend_file_get_default_object (CalBackendSync *backend, Cal *cal, char **object) { - CalBackendFile *cbfile; - CalBackendFilePrivate *priv; CalComponent *comp; - char *calobj; - cbfile = CAL_BACKEND_FILE (backend); - priv = cbfile->priv; - comp = cal_component_new (); - - switch (type) { - case CALOBJ_TYPE_EVENT: + + switch (cal_backend_get_kind (CAL_BACKEND (backend))) { + case ICAL_VEVENT_COMPONENT: cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT); break; - case CALOBJ_TYPE_TODO: + case ICAL_VTODO_COMPONENT: cal_component_set_new_vtype (comp, CAL_COMPONENT_TODO); break; - case CALOBJ_TYPE_JOURNAL: + case ICAL_VJOURNAL_COMPONENT: cal_component_set_new_vtype (comp, CAL_COMPONENT_JOURNAL); break; default: g_object_unref (comp); - return NULL; + return GNOME_Evolution_Calendar_ObjectNotFound; } - calobj = cal_component_get_as_string (comp); + *object = cal_component_get_as_string (comp); g_object_unref (comp); - return calobj; + return GNOME_Evolution_Calendar_Success; } /* Get_object_component handler for the file backend */ -static CalComponent * -cal_backend_file_get_object_component (CalBackend *backend, const char *uid) +static CalBackendSyncStatus +cal_backend_file_get_object (CalBackendSync *backend, Cal *cal, const char *uid, const char *rid, char **object) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; + CalComponent *comp; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - g_return_val_if_fail (uid != NULL, NULL); - - g_return_val_if_fail (priv->icalcomp != NULL, NULL); + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_InvalidObject); + g_return_val_if_fail (uid != NULL, GNOME_Evolution_Calendar_ObjectNotFound); g_assert (priv->comp_uid_hash != NULL); - return lookup_component (cbfile, uid); + comp = lookup_component (cbfile, uid); + if (!comp) + return GNOME_Evolution_Calendar_ObjectNotFound; + + if (rid && *rid) { + /* FIXME How to retrieve instance */ + } + + *object = cal_component_get_as_string (comp); + + return GNOME_Evolution_Calendar_Success; } /* Get_timezone_object handler for the file backend */ -static char * -cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid) +static CalBackendSyncStatus +cal_backend_file_get_timezone (CalBackendSync *backend, Cal *cal, const char *tzid, char **object) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; icaltimezone *zone; icalcomponent *icalcomp; - char *ical_string; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - g_return_val_if_fail (tzid != NULL, NULL); + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); + g_return_val_if_fail (tzid != NULL, GNOME_Evolution_Calendar_ObjectNotFound); - g_return_val_if_fail (priv->icalcomp != NULL, NULL); - g_assert (priv->comp_uid_hash != NULL); - - zone = icalcomponent_get_timezone (priv->icalcomp, tzid); - if (!zone) { - zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); - if (!zone) - return NULL; + if (!strcmp (tzid, "UTC")) { + zone = icaltimezone_get_utc_timezone (); + } else { + zone = icalcomponent_get_timezone (priv->icalcomp, tzid); + if (!zone) { + zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); + if (!zone) + return GNOME_Evolution_Calendar_ObjectNotFound; + } } - + icalcomp = icaltimezone_get_component (zone); if (!icalcomp) - return NULL; + return GNOME_Evolution_Calendar_InvalidObject; - ical_string = icalcomponent_as_ical_string (icalcomp); - /* We dup the string; libical owns that memory. */ - if (ical_string) - return g_strdup (ical_string); - else - return NULL; + *object = g_strdup (icalcomponent_as_ical_string (icalcomp)); + + return GNOME_Evolution_Calendar_Success; } -/* Builds a list of UIDs from a list of CalComponent objects */ -static void -build_uids_list (GList **list, GList *components) +/* Add_timezone handler for the file backend */ +static CalBackendSyncStatus +cal_backend_file_add_timezone (CalBackendSync *backend, Cal *cal, const char *tzobj) { - GList *l; + icalcomponent *tz_comp; + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; - for (l = components; l; l = l->next) { - CalComponent *comp; - const char *uid; + cbfile = (CalBackendFile *) backend; - comp = CAL_COMPONENT (l->data); - cal_component_get_uid (comp, &uid); - *list = g_list_prepend (*list, g_strdup (uid)); + g_return_val_if_fail (IS_CAL_BACKEND_FILE (cbfile), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError); + + priv = cbfile->priv; + + tz_comp = icalparser_parse_string (tzobj); + if (!tz_comp) + return GNOME_Evolution_Calendar_InvalidObject; + + if (icalcomponent_isa (tz_comp) == ICAL_VTIMEZONE_COMPONENT) { + icaltimezone *zone; + + zone = icaltimezone_new (); + icaltimezone_set_component (zone, tz_comp); + if (!icalcomponent_get_timezone (priv->icalcomp, icaltimezone_get_tzid (zone))) { + icalcomponent_add_component (priv->icalcomp, tz_comp); + mark_dirty (cbfile); + } + + icaltimezone_free (zone, 1); } + + return GNOME_Evolution_Calendar_Success; } -/* Get_uids handler for the file backend */ -static GList * -cal_backend_file_get_uids (CalBackend *backend, CalObjType type) + +static CalBackendSyncStatus +cal_backend_file_set_default_timezone (CalBackendSync *backend, Cal *cal, const char *tzid) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; - GList *list; + icaltimezone *zone; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - g_return_val_if_fail (priv->icalcomp != NULL, NULL); + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); - list = NULL; + /* Look up the VTIMEZONE in our icalcomponent. */ + zone = icalcomponent_get_timezone (priv->icalcomp, tzid); + if (!zone) + return GNOME_Evolution_Calendar_ObjectNotFound; - if (type & CALOBJ_TYPE_EVENT) - build_uids_list (&list, priv->events); + /* Set the default timezone to it. */ + priv->default_zone = zone; - if (type & CALOBJ_TYPE_TODO) - build_uids_list (&list, priv->todos); - - if (type & CALOBJ_TYPE_JOURNAL) - build_uids_list (&list, priv->journals); - - return list; + return GNOME_Evolution_Calendar_Success; } -/* function to resolve timezones */ -static icaltimezone * -resolve_tzid (const char *tzid, gpointer user_data) -{ - icalcomponent *vcalendar_comp = user_data; - - if (!tzid || !tzid[0]) - return NULL; - else if (!strcmp (tzid, "UTC")) - return icaltimezone_get_utc_timezone (); - - return icalcomponent_get_timezone (vcalendar_comp, tzid); -} +typedef struct { + GList *obj_list; + gboolean search_needed; + const char *query; + CalBackendObjectSExp *obj_sexp; + CalBackend *backend; + icaltimezone *default_zone; +} MatchObjectData; -/* Callback used from cal_recur_generate_instances(); adds the component's UID - * to our hash table. - */ -static gboolean -add_instance (CalComponent *comp, time_t start, time_t end, gpointer data) +static void +match_object_sexp (gpointer key, gpointer value, gpointer data) { - GHashTable *uid_hash; - const char *uid; - const char *old_uid; - - uid_hash = data; - - /* We only care that the component's UID is listed in the hash table; - * that's why we only allow generation of one instance (i.e. return - * FALSE every time). - */ - - cal_component_get_uid (comp, &uid); - - old_uid = g_hash_table_lookup (uid_hash, uid); - if (old_uid) - return FALSE; + CalBackendFileObject *obj_data = value; + MatchObjectData *match_data = data; - g_hash_table_insert (uid_hash, (char *) uid, NULL); - return FALSE; + if ((!match_data->search_needed) || + (cal_backend_object_sexp_match_comp (match_data->obj_sexp, obj_data->full_object, match_data->backend))) { + match_data->obj_list = g_list_append (match_data->obj_list, + cal_component_get_as_string (obj_data->full_object)); + } } -/* Populates a hash table with the UIDs of the components that occur or recur - * within a specific time range. - */ -static void -get_instances_in_range (GHashTable *uid_hash, GList *components, time_t start, time_t end, icaltimezone *default_zone) +/* Get_objects_in_range handler for the file backend */ +static CalBackendSyncStatus +cal_backend_file_get_object_list (CalBackendSync *backend, Cal *cal, const char *sexp, GList **objects) { - GList *l; - - for (l = components; l; l = l->next) { - CalComponent *comp; - icalcomponent *icalcomp, *vcalendar_comp; + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; + MatchObjectData match_data; - comp = CAL_COMPONENT (l->data); + cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; - /* Get the parent VCALENDAR component, so we can resolve - TZIDs. */ - icalcomp = cal_component_get_icalcomponent (comp); - vcalendar_comp = icalcomponent_get_parent (icalcomp); - g_assert (vcalendar_comp != NULL); + g_message (G_STRLOC ": Getting object list (%s)", sexp); - cal_recur_generate_instances (comp, start, end, add_instance, uid_hash, resolve_tzid, vcalendar_comp, default_zone); - } -} + match_data.search_needed = TRUE; + match_data.query = sexp; + match_data.obj_list = NULL; + match_data.backend = CAL_BACKEND (backend); + match_data.default_zone = priv->default_zone; -/* Used from g_hash_table_foreach(), adds a UID from the hash table to our list */ -static void -add_uid_to_list (gpointer key, gpointer value, gpointer data) -{ - GList **list; - const char *uid; - char *uid_copy; + if (!strcmp (sexp, "#t")) + match_data.search_needed = FALSE; - list = data; + match_data.obj_sexp = cal_backend_object_sexp_new (sexp); + if (!match_data.obj_sexp) + return GNOME_Evolution_Calendar_InvalidQuery; - uid = key; - uid_copy = g_strdup (uid); + g_hash_table_foreach (priv->comp_uid_hash, (GHFunc) match_object_sexp, &match_data); - *list = g_list_prepend (*list, uid_copy); + *objects = match_data.obj_list; + + return GNOME_Evolution_Calendar_Success; } -/* Get_objects_in_range handler for the file backend */ -static GList * -cal_backend_file_get_objects_in_range (CalBackend *backend, CalObjType type, - time_t start, time_t end) +/* get_query handler for the file backend */ +static void +cal_backend_file_start_query (CalBackend *backend, Query *query) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; - GList *event_list; - GHashTable *uid_hash; + MatchObjectData match_data; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - g_return_val_if_fail (priv->icalcomp != NULL, NULL); + g_message (G_STRLOC ": Starting query (%s)", query_get_text (query)); - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); + /* try to match all currently existing objects */ + match_data.search_needed = TRUE; + match_data.query = query_get_text (query); + match_data.obj_list = NULL; + match_data.backend = backend; + match_data.default_zone = priv->default_zone; - uid_hash = g_hash_table_new (g_str_hash, g_str_equal); + if (!strcmp (match_data.query, "#t")) + match_data.search_needed = FALSE; - if (type & CALOBJ_TYPE_EVENT) - get_instances_in_range (uid_hash, priv->events, start, end, - priv->default_zone); + match_data.obj_sexp = query_get_object_sexp (query); + if (!match_data.obj_sexp) { + query_notify_query_done (query, GNOME_Evolution_Calendar_InvalidQuery); + return; + } - if (type & CALOBJ_TYPE_TODO) - get_instances_in_range (uid_hash, priv->todos, start, end, - priv->default_zone); + g_hash_table_foreach (priv->comp_uid_hash, (GHFunc) match_object_sexp, &match_data); - if (type & CALOBJ_TYPE_JOURNAL) - get_instances_in_range (uid_hash, priv->journals, start, end, - priv->default_zone); + /* notify listeners of all objects */ + if (match_data.obj_list) { + query_notify_objects_added (query, (const GList *) match_data.obj_list); - event_list = NULL; - g_hash_table_foreach (uid_hash, add_uid_to_list, &event_list); - g_hash_table_destroy (uid_hash); + /* free memory */ + g_list_foreach (match_data.obj_list, (GFunc) g_free, NULL); + g_list_free (match_data.obj_list); + } - return event_list; + query_notify_query_done (query, GNOME_Evolution_Calendar_Success); } static gboolean @@ -1155,10 +1011,11 @@ create_user_free_busy (CalBackendFile *cbfile, const char *address, const char * time_t start, time_t end) { CalBackendFilePrivate *priv; - GList *uids; GList *l; icalcomponent *vfb; icaltimezone *utc_zone; + CalBackendObjectSExp *obj_sexp; + char *query; priv = cbfile->priv; @@ -1181,20 +1038,18 @@ create_user_free_busy (CalBackendFile *cbfile, const char *address, const char * icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone)); /* add all objects in the given interval */ + query = g_strdup_printf ("occur-in-time-range? %lu %lu", start, end); + obj_sexp = cal_backend_object_sexp_new (query); + g_free (query); - uids = cal_backend_get_objects_in_range (CAL_BACKEND (cbfile), - CALOBJ_TYPE_ANY, start, end); - for (l = uids; l != NULL; l = l->next) { - CalComponent *comp; + if (!obj_sexp) + return vfb; + + for (l = priv->comp; l; l = l->next) { + CalComponent *comp = l->data; icalcomponent *icalcomp, *vcalendar_comp; icalproperty *prop; - char *uid = (char *) l->data; - - /* get the component from our internal list */ - comp = lookup_component (cbfile, uid); - if (!comp) - continue; - + icalcomp = cal_component_get_icalcomponent (comp); if (!icalcomp) continue; @@ -1208,7 +1063,10 @@ create_user_free_busy (CalBackendFile *cbfile, const char *address, const char * transp_val == ICAL_TRANSP_TRANSPARENTNOCONFLICT) continue; } - + + if (!cal_backend_object_sexp_match_comp (obj_sexp, l->data, CAL_BACKEND (cbfile))) + continue; + vcalendar_comp = icalcomponent_get_parent (icalcomp); cal_recur_generate_instances (comp, start, end, free_busy_instance, @@ -1216,37 +1074,37 @@ create_user_free_busy (CalBackendFile *cbfile, const char *address, const char * resolve_tzid, vcalendar_comp, priv->default_zone); - } - cal_obj_uid_list_free (uids); return vfb; } /* Get_free_busy handler for the file backend */ -static GList * -cal_backend_file_get_free_busy (CalBackend *backend, GList *users, time_t start, time_t end) +static CalBackendSyncStatus +cal_backend_file_get_free_busy (CalBackendSync *backend, Cal *cal, GList *users, + time_t start, time_t end, GList **freebusy) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; gchar *address, *name; icalcomponent *vfb; char *calobj; - GList *obj_list = NULL; GList *l; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - g_return_val_if_fail (priv->icalcomp != NULL, NULL); - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); + g_return_val_if_fail (start != -1 && end != -1, GNOME_Evolution_Calendar_InvalidRange); + g_return_val_if_fail (start <= end, GNOME_Evolution_Calendar_InvalidRange); + *freebusy = NULL; + if (users == NULL) { if (cal_backend_mail_account_get_default (priv->config_listener, &address, &name)) { vfb = create_user_free_busy (cbfile, address, name, start, end); calobj = icalcomponent_as_ical_string (vfb); - obj_list = g_list_append (obj_list, g_strdup (calobj)); + *freebusy = g_list_append (*freebusy, g_strdup (calobj)); icalcomponent_free (vfb); g_free (address); g_free (name); @@ -1257,34 +1115,31 @@ cal_backend_file_get_free_busy (CalBackend *backend, GList *users, time_t start, if (cal_backend_mail_account_is_valid (priv->config_listener, address, &name)) { vfb = create_user_free_busy (cbfile, address, name, start, end); calobj = icalcomponent_as_ical_string (vfb); - obj_list = g_list_append (obj_list, g_strdup (calobj)); + *freebusy = g_list_append (*freebusy, g_strdup (calobj)); icalcomponent_free (vfb); g_free (name); } } } - return obj_list; + return GNOME_Evolution_Calendar_Success; } typedef struct { - CalBackend *backend; + CalBackendFile *backend; CalObjType type; - GList *changes; - GList *change_ids; + GList *deletes; + EXmlHash *ehash; } CalBackendFileComputeChangesData; static void cal_backend_file_compute_changes_foreach_key (const char *key, gpointer data) { CalBackendFileComputeChangesData *be_data = data; - char *calobj = cal_backend_get_object (be_data->backend, key); - if (calobj == NULL) { + if (!lookup_component (be_data->backend, key)) { CalComponent *comp; - GNOME_Evolution_Calendar_CalObjChange *coc; - char *calobj; comp = cal_component_new (); if (be_data->type == GNOME_Evolution_Calendar_TYPE_TODO) @@ -1293,319 +1148,283 @@ cal_backend_file_compute_changes_foreach_key (const char *key, gpointer data) cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT); cal_component_set_uid (comp, key); - calobj = cal_component_get_as_string (comp); - - coc = GNOME_Evolution_Calendar_CalObjChange__alloc (); - coc->calobj = CORBA_string_dup (calobj); - coc->type = GNOME_Evolution_Calendar_DELETED; - be_data->changes = g_list_prepend (be_data->changes, coc); - be_data->change_ids = g_list_prepend (be_data->change_ids, g_strdup (key)); + be_data->deletes = g_list_prepend (be_data->deletes, cal_component_get_as_string (comp)); - g_free (calobj); - g_object_unref (comp); + e_xmlhash_remove (be_data->ehash, key); } } -static GNOME_Evolution_Calendar_CalObjChangeSeq * -cal_backend_file_compute_changes (CalBackend *backend, CalObjType type, const char *change_id) +static CalBackendSyncStatus +cal_backend_file_compute_changes (CalBackendFile *cbfile, CalObjType type, const char *change_id, + GList **adds, GList **modifies, GList **deletes) { + CalBackendFilePrivate *priv; char *filename; - EDbHash *ehash; + EXmlHash *ehash; CalBackendFileComputeChangesData be_data; - GNOME_Evolution_Calendar_CalObjChangeSeq *seq; - GList *uids, *changes = NULL, *change_ids = NULL; - GList *i, *j; - int n; - - /* Find the changed ids - FIX ME, path should not be hard coded */ - if (type == GNOME_Evolution_Calendar_TYPE_TODO) - filename = g_strdup_printf ("%s/evolution/local/Tasks/%s.db", g_get_home_dir (), change_id); - else - filename = g_strdup_printf ("%s/evolution/local/Calendar/%s.db", g_get_home_dir (), change_id); - ehash = e_dbhash_new (filename); + GList *i; + + priv = cbfile->priv; + + /* FIXME Will this always work? */ + filename = g_strdup_printf ("%s/%s.db", priv->uri, change_id); + ehash = e_xmlhash_new (filename); g_free (filename); - uids = cal_backend_get_uids (backend, type); - /* Calculate adds and modifies */ - for (i = uids; i != NULL; i = i->next) { - GNOME_Evolution_Calendar_CalObjChange *coc; - char *uid = i->data; - char *calobj = cal_backend_get_object (backend, uid); + for (i = priv->comp; i != NULL; i = i->next) { + const char *uid; + char *calobj; + + cal_component_get_uid (i->data, &uid); + calobj = cal_component_get_as_string (i->data); g_assert (calobj != NULL); /* check what type of change has occurred, if any */ - switch (e_dbhash_compare (ehash, uid, calobj)) { - case E_DBHASH_STATUS_SAME: + switch (e_xmlhash_compare (ehash, uid, calobj)) { + case E_XMLHASH_STATUS_SAME: break; - case E_DBHASH_STATUS_NOT_FOUND: - coc = GNOME_Evolution_Calendar_CalObjChange__alloc (); - coc->calobj = CORBA_string_dup (calobj); - coc->type = GNOME_Evolution_Calendar_ADDED; - changes = g_list_prepend (changes, coc); - change_ids = g_list_prepend (change_ids, g_strdup (uid)); + case E_XMLHASH_STATUS_NOT_FOUND: + *adds = g_list_prepend (*adds, g_strdup (calobj)); + e_xmlhash_add (ehash, uid, calobj); break; - case E_DBHASH_STATUS_DIFFERENT: - coc = GNOME_Evolution_Calendar_CalObjChange__alloc (); - coc->calobj = CORBA_string_dup (calobj); - coc->type = GNOME_Evolution_Calendar_MODIFIED; - changes = g_list_prepend (changes, coc); - change_ids = g_list_prepend (change_ids, g_strdup (uid)); + case E_XMLHASH_STATUS_DIFFERENT: + *modifies = g_list_prepend (*modifies, g_strdup (calobj)); + e_xmlhash_add (ehash, uid, calobj); break; } + + g_free (calobj); } /* Calculate deletions */ - be_data.backend = backend; + be_data.backend = cbfile; be_data.type = type; - be_data.changes = changes; - be_data.change_ids = change_ids; - e_dbhash_foreach_key (ehash, (EDbHashFunc)cal_backend_file_compute_changes_foreach_key, &be_data); - changes = be_data.changes; - change_ids = be_data.change_ids; - - /* Build the sequence and update the hash */ - n = g_list_length (changes); - - seq = GNOME_Evolution_Calendar_CalObjChangeSeq__alloc (); - seq->_length = n; - seq->_buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalObjChange_allocbuf (n); - CORBA_sequence_set_release (seq, TRUE); - - for (i = changes, j = change_ids, n = 0; i != NULL; i = i->next, j = j->next, n++) { - GNOME_Evolution_Calendar_CalObjChange *coc = i->data; - GNOME_Evolution_Calendar_CalObjChange *seq_coc; - char *uid = j->data; - - /* sequence building */ - seq_coc = &seq->_buffer[n]; - seq_coc->calobj = CORBA_string_dup (coc->calobj); - seq_coc->type = coc->type; - - /* hash updating */ - if (coc->type == GNOME_Evolution_Calendar_ADDED - || coc->type == GNOME_Evolution_Calendar_MODIFIED) { - e_dbhash_add (ehash, uid, coc->calobj); - } else { - e_dbhash_remove (ehash, uid); - } + be_data.deletes = NULL; + be_data.ehash = ehash; + e_xmlhash_foreach_key (ehash, (EXmlHashFunc)cal_backend_file_compute_changes_foreach_key, &be_data); - CORBA_free (coc); - g_free (uid); - } - e_dbhash_write (ehash); - e_dbhash_destroy (ehash); + *deletes = be_data.deletes; - cal_obj_uid_list_free (uids); - g_list_free (change_ids); - g_list_free (changes); + e_xmlhash_write (ehash); + e_xmlhash_destroy (ehash); - return seq; + return GNOME_Evolution_Calendar_Success; } /* Get_changes handler for the file backend */ -static GNOME_Evolution_Calendar_CalObjChangeSeq * -cal_backend_file_get_changes (CalBackend *backend, CalObjType type, const char *change_id) +static CalBackendSyncStatus +cal_backend_file_get_changes (CalBackendSync *backend, Cal *cal, CalObjType type, const char *change_id, + GList **adds, GList **modifies, GList **deletes) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; - return cal_backend_file_compute_changes (backend, type, change_id); + cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; + + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); + g_return_val_if_fail (change_id != NULL, GNOME_Evolution_Calendar_ObjectNotFound); + + return cal_backend_file_compute_changes (cbfile, type, change_id, adds, modifies, deletes); +} + +/* Discard_alarm handler for the file backend */ +static CalBackendSyncStatus +cal_backend_file_discard_alarm (CalBackendSync *backend, Cal *cal, const char *uid, const char *auid) +{ + /* we just do nothing with the alarm */ + return GNOME_Evolution_Calendar_Success; } -/* Get_alarms_in_range handler for the file backend */ -static GNOME_Evolution_Calendar_CalComponentAlarmsSeq * -cal_backend_file_get_alarms_in_range (CalBackend *backend, - time_t start, time_t end) +static CalBackendSyncStatus +cal_backend_file_create_object (CalBackendSync *backend, Cal *cal, const char *calobj, char **uid) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; - int n_comp_alarms; - GSList *comp_alarms; - GSList *l; - int i; - CalAlarmAction omit[] = {-1}; + icalcomponent *icalcomp; + icalcomponent_kind kind; + CalComponent *comp; + const char *comp_uid; + struct icaltimetype current; - GNOME_Evolution_Calendar_CalComponentAlarmsSeq *seq; - cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - g_return_val_if_fail (priv->icalcomp != NULL, NULL); - - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); - - /* Per RFC 2445, only VEVENTs and VTODOs can have alarms */ - - n_comp_alarms = 0; - comp_alarms = NULL; + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); + g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_ObjectNotFound); - n_comp_alarms += cal_util_generate_alarms_for_list (priv->events, start, end, omit, - &comp_alarms, resolve_tzid, - priv->icalcomp, - priv->default_zone); - n_comp_alarms += cal_util_generate_alarms_for_list (priv->todos, start, end, omit, - &comp_alarms, resolve_tzid, - priv->icalcomp, - priv->default_zone); + icalcomp = icalparser_parse_string ((char *) calobj); + if (!icalcomp) + return GNOME_Evolution_Calendar_InvalidObject; - seq = GNOME_Evolution_Calendar_CalComponentAlarmsSeq__alloc (); - CORBA_sequence_set_release (seq, TRUE); - seq->_length = n_comp_alarms; - seq->_buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalComponentAlarms_allocbuf ( - n_comp_alarms); + /* FIXME Check kind with the parent */ + kind = icalcomponent_isa (icalcomp); + if (kind != ICAL_VEVENT_COMPONENT && kind != ICAL_VTODO_COMPONENT) { + icalcomponent_free (icalcomp); + return GNOME_Evolution_Calendar_InvalidObject; + } - for (l = comp_alarms, i = 0; l; l = l->next, i++) { - CalComponentAlarms *alarms; - char *comp_str; + /* Get the UID */ + comp_uid = icalcomponent_get_uid (icalcomp); + + /* check the object is not in our cache */ + if (lookup_component (cbfile, comp_uid)) { + icalcomponent_free (icalcomp); + return GNOME_Evolution_Calendar_CardIdAlreadyExists; + } - alarms = l->data; + /* Create the cal component */ + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomp); - comp_str = cal_component_get_as_string (alarms->comp); - seq->_buffer[i].calobj = CORBA_string_dup (comp_str); - g_free (comp_str); + /* Set the created and last modified times on the component */ + current = icaltime_from_timet (time (NULL), 0); + cal_component_set_created (comp, ¤t); + cal_component_set_last_modified (comp, ¤t); - cal_backend_util_fill_alarm_instances_seq (&seq->_buffer[i].alarms, alarms->alarms); + /* Add the object */ + add_component (cbfile, comp, TRUE); - cal_component_alarms_free (alarms); - } + /* Mark for saving */ + mark_dirty (cbfile); - g_slist_free (comp_alarms); + /* Return the UID */ + if (uid) + *uid = g_strdup (comp_uid); - return seq; + return GNOME_Evolution_Calendar_Success; } -/* Get_alarms_for_object handler for the file backend */ -static GNOME_Evolution_Calendar_CalComponentAlarms * -cal_backend_file_get_alarms_for_object (CalBackend *backend, const char *uid, - time_t start, time_t end, - gboolean *object_found) +static CalBackendSyncStatus +cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *calobj, + CalObjModType mod, char **old_object) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; - CalComponent *comp; - char *comp_str; - GNOME_Evolution_Calendar_CalComponentAlarms *corba_alarms; - CalComponentAlarms *alarms; - CalAlarmAction omit[] = {-1}; + icalcomponent *icalcomp; + icalcomponent_kind kind; + const char *comp_uid; + CalComponent *comp, *old_comp; + struct icaltimetype current; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; + + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); + g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_ObjectNotFound); - g_return_val_if_fail (priv->icalcomp != NULL, NULL); + icalcomp = icalparser_parse_string ((char *) calobj); + if (!icalcomp) + return GNOME_Evolution_Calendar_InvalidObject; + + /* FIXME Check kind with the parent */ + kind = icalcomponent_isa (icalcomp); + if (kind != ICAL_VEVENT_COMPONENT && kind != ICAL_VTODO_COMPONENT) { + icalcomponent_free (icalcomp); + return GNOME_Evolution_Calendar_InvalidObject; + } - g_return_val_if_fail (uid != NULL, NULL); - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); - g_return_val_if_fail (object_found != NULL, NULL); + /* Get the uid */ + comp_uid = icalcomponent_get_uid (icalcomp); - comp = lookup_component (cbfile, uid); - if (!comp) { - *object_found = FALSE; - return NULL; + /* Get the object from our cache */ + if (!(old_comp = lookup_component (cbfile, comp_uid))) { + icalcomponent_free (icalcomp); + return GNOME_Evolution_Calendar_ObjectNotFound; } - *object_found = TRUE; + /* Create the cal component */ + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomp); + + /* Set the last modified time on the component */ + current = icaltime_from_timet (time (NULL), 0); + cal_component_set_last_modified (comp, ¤t); - comp_str = cal_component_get_as_string (comp); - corba_alarms = GNOME_Evolution_Calendar_CalComponentAlarms__alloc (); + /* FIXME we need to handle mod types here */ - corba_alarms->calobj = CORBA_string_dup (comp_str); - g_free (comp_str); + /* Remove the old version */ + remove_component (cbfile, old_comp); - alarms = cal_util_generate_alarms_for_comp (comp, start, end, omit, resolve_tzid, priv->icalcomp, priv->default_zone); - if (alarms) { - cal_backend_util_fill_alarm_instances_seq (&corba_alarms->alarms, alarms->alarms); - cal_component_alarms_free (alarms); - } else - cal_backend_util_fill_alarm_instances_seq (&corba_alarms->alarms, NULL); + /* Add the object */ + add_component (cbfile, comp, TRUE); - return corba_alarms; -} + mark_dirty (cbfile); -/* Discard_alarm handler for the file backend */ -static CalBackendResult -cal_backend_file_discard_alarm (CalBackend *backend, const char *uid, const char *auid) -{ - /* we just do nothing with the alarm */ - return CAL_BACKEND_RESULT_SUCCESS; + if (old_object) + *old_object = cal_component_get_as_string (comp); + + return GNOME_Evolution_Calendar_Success; } -/* Creates a CalComponent for the given icalcomponent and adds it to our - cache. Note that the icalcomponent is not added to the toplevel - icalcomponent here. That needs to be done elsewhere. It returns the uid - of the added component, or NULL if it failed. */ -static const char* -cal_backend_file_update_object (CalBackendFile *cbfile, - icalcomponent *icalcomp) +/* Remove_object handler for the file backend */ +static CalBackendSyncStatus +cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal, const char *uid, const char *rid, + CalObjModType mod, char **object) { - CalComponent *old_comp; + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; CalComponent *comp; - const char *comp_uid; - struct icaltimetype last_modified; - /* Create a CalComponent wrapper for the icalcomponent. */ - comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { - g_object_unref (comp); - return NULL; - } + cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; - /* Get the UID, and check it isn't empty. */ - cal_component_get_uid (comp, &comp_uid); - if (!comp_uid || !comp_uid[0]) { - g_object_unref (comp); - return NULL; - } + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); + g_return_val_if_fail (uid != NULL, GNOME_Evolution_Calendar_ObjectNotFound); - /* Set the LAST-MODIFIED time on the component */ - last_modified = icaltime_from_timet (time (NULL), 0); - cal_component_set_last_modified (comp, &last_modified); - - /* Remove any old version of the component. */ - old_comp = lookup_component (cbfile, comp_uid); - if (old_comp) - remove_component (cbfile, old_comp); + /* FIXME we need to handle mod types here */ - /* Now add the component to our local cache, but we pass FALSE as - the last argument, since the libical component is assumed to have - been added already. */ - add_component (cbfile, comp, FALSE); + comp = lookup_component (cbfile, uid); + if (!comp) + return GNOME_Evolution_Calendar_ObjectNotFound; - return comp_uid; + *object = cal_component_get_as_string (comp); + remove_component (cbfile, comp); + + mark_dirty (cbfile); + + return GNOME_Evolution_Calendar_Success; } -static const char* -cal_backend_file_cancel_object (CalBackendFile *cbfile, - icalcomponent *icalcomp) +static gboolean +cancel_received_object (CalBackendFile *cbfile, icalcomponent *icalcomp) { CalComponent *old_comp; - icalproperty *uid; - const char *comp_uid; - - /* Get the UID, and check it isn't empty. */ - uid = icalcomponent_get_first_property (icalcomp, ICAL_UID_PROPERTY); - if (!uid) - return NULL; - comp_uid = icalproperty_get_uid (uid); - if (!comp_uid || !comp_uid[0]) - return NULL; /* Find the old version of the component. */ - old_comp = lookup_component (cbfile, comp_uid); + old_comp = lookup_component (cbfile, icalcomponent_get_uid (icalcomp)); if (!old_comp) - return NULL; + return FALSE; /* And remove it */ remove_component (cbfile, old_comp); - return comp_uid; + + return TRUE; +} + +typedef struct { + GHashTable *zones; + + gboolean found; +} CalBackendFileTzidData; + +static void +check_tzids (icalparameter *param, void *data) +{ + CalBackendFileTzidData *tzdata = data; + const char *tzid; + + tzid = icalparameter_get_tzid (param); + if (!tzid || g_hash_table_lookup (tzdata->zones, tzid)) + tzdata->found = FALSE; } /* Update_objects handler for the file backend. */ -static CalBackendResult -cal_backend_file_update_objects (CalBackend *backend, const char *calobj, CalObjModType mod) +static CalBackendSyncStatus +cal_backend_file_receive_objects (CalBackendSync *backend, Cal *cal, const char *calobj, + GList **created, GList **modified, GList **removed) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; @@ -1613,143 +1432,153 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj, CalObj icalcomponent_kind kind; icalproperty_method method; icalcomponent *subcomp; - CalBackendResult retval = CAL_BACKEND_RESULT_SUCCESS; - GList *updated_uids = NULL, *removed_uids = NULL, *elem; + GList *comps, *l; + CalBackendFileTzidData tzdata; + CalBackendSyncStatus status = GNOME_Evolution_Calendar_Success; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - g_return_val_if_fail (priv->icalcomp != NULL, CAL_BACKEND_RESULT_INVALID_OBJECT); - - g_return_val_if_fail (calobj != NULL, CAL_BACKEND_RESULT_INVALID_OBJECT); + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_InvalidObject); + g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_InvalidObject); /* Pull the component from the string and ensure that it is sane */ - toplevel_comp = icalparser_parse_string ((char *) calobj); - if (!toplevel_comp) - return CAL_BACKEND_RESULT_INVALID_OBJECT; + return GNOME_Evolution_Calendar_InvalidObject; kind = icalcomponent_isa (toplevel_comp); - - if (kind == ICAL_VEVENT_COMPONENT - || kind == ICAL_VTODO_COMPONENT - || kind == ICAL_VJOURNAL_COMPONENT) { - /* Create a temporary toplevel component and put the VEVENT - or VTODO in it, to simplify the code below. */ + if (kind != ICAL_VCALENDAR_COMPONENT) { + /* If its not a VCALENDAR, make it one to simplify below */ icalcomp = toplevel_comp; toplevel_comp = cal_util_new_top_level (); - icalcomponent_add_component (toplevel_comp, icalcomp); - } else if (kind != ICAL_VCALENDAR_COMPONENT) { - /* We don't support this type of component */ - icalcomponent_free (toplevel_comp); - return CAL_BACKEND_RESULT_INVALID_OBJECT; + icalcomponent_add_component (toplevel_comp, icalcomp); } method = icalcomponent_get_method (toplevel_comp); - /* Step throught the VEVENT/VTODOs being added, create CalComponents - for them, and add them to our cache. */ - subcomp = icalcomponent_get_first_component (toplevel_comp, - ICAL_ANY_COMPONENT); + *created = *modified = *removed = NULL; + + /* Build a list of timezones so we can make sure all the objects have valid info */ + tzdata.zones = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + subcomp = icalcomponent_get_first_component (toplevel_comp, ICAL_VTIMEZONE_COMPONENT); + while (subcomp) { + icaltimezone *zone; + + zone = icaltimezone_new (); + if (icaltimezone_set_component (zone, subcomp)) + g_hash_table_insert (tzdata.zones, g_strdup (icaltimezone_get_tzid (zone)), NULL); + + subcomp = icalcomponent_get_next_component (toplevel_comp, ICAL_VTIMEZONE_COMPONENT); + } + + /* First we make sure all the components are usuable */ + comps = NULL; + subcomp = icalcomponent_get_first_component (toplevel_comp, ICAL_ANY_COMPONENT); while (subcomp) { /* We ignore anything except VEVENT, VTODO and VJOURNAL components. */ icalcomponent_kind child_kind = icalcomponent_isa (subcomp); - if (child_kind == ICAL_VEVENT_COMPONENT - || child_kind == ICAL_VTODO_COMPONENT - || child_kind == ICAL_VJOURNAL_COMPONENT) { - const char *comp_uid; - - if (method == ICAL_METHOD_CANCEL) { - comp_uid = cal_backend_file_cancel_object (cbfile, subcomp); - if (comp_uid) { - removed_uids = g_list_prepend (removed_uids, - g_strdup (comp_uid)); - } else - retval = CAL_BACKEND_RESULT_NOT_FOUND; - } else { - comp_uid = cal_backend_file_update_object (cbfile, subcomp); - if (comp_uid) { - updated_uids = g_list_prepend (updated_uids, - g_strdup (comp_uid)); - } else - retval = CAL_BACKEND_RESULT_INVALID_OBJECT; + + switch (child_kind) { + case ICAL_VEVENT_COMPONENT: + case ICAL_VTODO_COMPONENT: + case ICAL_VJOURNAL_COMPONENT: + tzdata.found = TRUE; + icalcomponent_foreach_tzid (subcomp, check_tzids, &tzdata); + + if (!tzdata.found) { + status = GNOME_Evolution_Calendar_InvalidObject; + goto error; } + + if (!icalcomponent_get_uid (subcomp)) { + status = GNOME_Evolution_Calendar_InvalidObject; + goto error; + } + + comps = g_list_prepend (comps, subcomp); + break; + default: + /* Ignore it */ + break; } - subcomp = icalcomponent_get_next_component (toplevel_comp, - ICAL_ANY_COMPONENT); + + subcomp = icalcomponent_get_next_component (toplevel_comp, ICAL_ANY_COMPONENT); } + /* Now we manipulate the components we care about */ + for (l = comps; l; l = l->next) { + subcomp = l->data; + + switch (method) { + case ICAL_METHOD_PUBLISH: + case ICAL_METHOD_REQUEST: + /* FIXME Need to see the new create/modify stuff before we set this up */ + break; + case ICAL_METHOD_REPLY: + /* FIXME Update the status of the user, if we are the organizer */ + break; + case ICAL_METHOD_ADD: + /* FIXME This should be doable once all the recurid stuff is done */ + break; + case ICAL_METHOD_COUNTER: + status = GNOME_Evolution_Calendar_UnsupportedMethod; + goto error; + break; + case ICAL_METHOD_DECLINECOUNTER: + status = GNOME_Evolution_Calendar_UnsupportedMethod; + goto error; + break; + case ICAL_METHOD_CANCEL: + /* FIXME Do we need to remove the subcomp so it isn't merged? */ + if (cancel_received_object (cbfile, subcomp)) + *removed = g_list_prepend (*removed, g_strdup (icalcomponent_get_uid (subcomp))); + break; + default: + status = GNOME_Evolution_Calendar_UnsupportedMethod; + goto error; + } + } + g_list_free (comps); + /* Merge the iCalendar components with our existing VCALENDAR, resolving any conflicting TZIDs. */ icalcomponent_merge_component (priv->icalcomp, toplevel_comp); mark_dirty (cbfile); - /* Now emit notification signals for all of the added components. - We do this after adding them all to make sure the calendar is in a - stable state before emitting signals. */ - for (elem = updated_uids; elem; elem = elem->next) { - char *comp_uid = elem->data; - cal_backend_notify_update (backend, comp_uid); - g_free (comp_uid); - } - g_list_free (updated_uids); - - for (elem = removed_uids; elem; elem = elem->next) { - char *comp_uid = elem->data; - cal_backend_notify_remove (backend, comp_uid); - g_free (comp_uid); - } - g_list_free (removed_uids); - - return retval; + error: + g_hash_table_destroy (tzdata.zones); + + return status; } +static CalBackendSyncStatus +cal_backend_file_send_objects (CalBackendSync *backend, Cal *cal, const char *calobj) +{ + /* FIXME Put in a util routine to send stuff via email */ + + return GNOME_Evolution_Calendar_Success; +} -/* Remove_object handler for the file backend */ -static CalBackendResult -cal_backend_file_remove_object (CalBackend *backend, const char *uid, CalObjModType mod) +static icaltimezone * +cal_backend_file_internal_get_default_timezone (CalBackend *backend) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; - CalComponent *comp; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; - g_return_val_if_fail (priv->icalcomp != NULL, CAL_BACKEND_RESULT_INVALID_OBJECT); - - g_return_val_if_fail (uid != NULL, CAL_BACKEND_RESULT_NOT_FOUND); - - comp = lookup_component (cbfile, uid); - if (!comp) - return CAL_BACKEND_RESULT_NOT_FOUND; - - remove_component (cbfile, comp); - - mark_dirty (cbfile); - - cal_backend_notify_remove (backend, uid); - - return CAL_BACKEND_RESULT_SUCCESS; -} - -static CalBackendSendResult -cal_backend_file_send_object (CalBackend *backend, const char *calobj, char **new_calobj, - GNOME_Evolution_Calendar_UserList **user_list, char error_msg[256]) -{ - *new_calobj = g_strdup (calobj); - - *user_list = GNOME_Evolution_Calendar_UserList__alloc (); - (*user_list)->_length = 0; + g_return_val_if_fail (priv->icalcomp != NULL, NULL); - return CAL_BACKEND_SEND_SUCCESS; + return priv->default_zone; } -static icaltimezone* -cal_backend_file_get_timezone (CalBackend *backend, const char *tzid) +static icaltimezone * +cal_backend_file_internal_get_timezone (CalBackend *backend, const char *tzid) { CalBackendFile *cbfile; CalBackendFilePrivate *priv; @@ -1771,43 +1600,134 @@ cal_backend_file_get_timezone (CalBackend *backend, const char *tzid) return zone; } - -static icaltimezone* -cal_backend_file_get_default_timezone (CalBackend *backend) +/* Object initialization function for the file backend */ +static void +cal_backend_file_init (CalBackendFile *cbfile, CalBackendFileClass *class) { - CalBackendFile *cbfile; CalBackendFilePrivate *priv; - cbfile = CAL_BACKEND_FILE (backend); - priv = cbfile->priv; + priv = g_new0 (CalBackendFilePrivate, 1); + cbfile->priv = priv; - g_return_val_if_fail (priv->icalcomp != NULL, NULL); + priv->uri = NULL; + priv->file_name = g_strdup ("calendar.ics"); + priv->icalcomp = NULL; + priv->comp_uid_hash = NULL; + priv->comp = NULL; - return priv->default_zone; + /* The timezone defaults to UTC. */ + priv->default_zone = icaltimezone_get_utc_timezone (); + + priv->config_listener = e_config_listener_new (); } +/* Class initialization function for the file backend */ +static void +cal_backend_file_class_init (CalBackendFileClass *class) +{ + GObjectClass *object_class; + CalBackendClass *backend_class; + CalBackendSyncClass *sync_class; -static gboolean -cal_backend_file_set_default_timezone (CalBackend *backend, - const char *tzid) + object_class = (GObjectClass *) class; + backend_class = (CalBackendClass *) class; + sync_class = (CalBackendSyncClass *) class; + + parent_class = (CalBackendSyncClass *) g_type_class_peek_parent (class); + + object_class->dispose = cal_backend_file_dispose; + object_class->finalize = cal_backend_file_finalize; + + sync_class->is_read_only_sync = cal_backend_file_is_read_only; + sync_class->get_cal_address_sync = cal_backend_file_get_cal_address; + sync_class->get_alarm_email_address_sync = cal_backend_file_get_alarm_email_address; + sync_class->get_ldap_attribute_sync = cal_backend_file_get_ldap_attribute; + sync_class->get_static_capabilities_sync = cal_backend_file_get_static_capabilities; + sync_class->open_sync = cal_backend_file_open; + sync_class->remove_sync = cal_backend_file_remove; + sync_class->create_object_sync = cal_backend_file_create_object; + sync_class->modify_object_sync = cal_backend_file_modify_object; + sync_class->remove_object_sync = cal_backend_file_remove_object; + sync_class->discard_alarm_sync = cal_backend_file_discard_alarm; + sync_class->receive_objects_sync = cal_backend_file_receive_objects; + sync_class->send_objects_sync = cal_backend_file_send_objects; + sync_class->get_default_object_sync = cal_backend_file_get_default_object; + sync_class->get_object_sync = cal_backend_file_get_object; + sync_class->get_object_list_sync = cal_backend_file_get_object_list; + sync_class->get_timezone_sync = cal_backend_file_get_timezone; + sync_class->add_timezone_sync = cal_backend_file_add_timezone; + sync_class->set_default_timezone_sync = cal_backend_file_set_default_timezone; + sync_class->get_freebusy_sync = cal_backend_file_get_free_busy; + sync_class->get_changes_sync = cal_backend_file_get_changes; + + backend_class->is_loaded = cal_backend_file_is_loaded; + backend_class->start_query = cal_backend_file_start_query; + backend_class->get_mode = cal_backend_file_get_mode; + backend_class->set_mode = cal_backend_file_set_mode; + + backend_class->internal_get_default_timezone = cal_backend_file_internal_get_default_timezone; + backend_class->internal_get_timezone = cal_backend_file_internal_get_timezone; +} + + +/** + * cal_backend_file_get_type: + * @void: + * + * Registers the #CalBackendFile class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #CalBackendFile class. + **/ +GType +cal_backend_file_get_type (void) +{ + static GType cal_backend_file_type = 0; + + if (!cal_backend_file_type) { + static GTypeInfo info = { + sizeof (CalBackendFileClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cal_backend_file_class_init, + NULL, NULL, + sizeof (CalBackendFile), + 0, + (GInstanceInitFunc) cal_backend_file_init + }; + cal_backend_file_type = g_type_register_static (CAL_TYPE_BACKEND_SYNC, + "CalBackendFile", &info, 0); + } + + return cal_backend_file_type; +} + +void +cal_backend_file_set_file_name (CalBackendFile *cbfile, const char *file_name) { - CalBackendFile *cbfile; CalBackendFilePrivate *priv; - icaltimezone *zone; + + g_return_if_fail (cbfile != NULL); + g_return_if_fail (IS_CAL_BACKEND_FILE (cbfile)); + g_return_if_fail (file_name != NULL); - cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; + + if (priv->file_name) + g_free (priv->file_name); + + priv->file_name = g_strdup (file_name); +} - g_return_val_if_fail (priv->icalcomp != NULL, FALSE); +const char * +cal_backend_file_get_file_name (CalBackendFile *cbfile) +{ + CalBackendFilePrivate *priv; - /* Look up the VTIMEZONE in our icalcomponent. */ - zone = icalcomponent_get_timezone (priv->icalcomp, tzid); - if (!zone) - return FALSE; + g_return_val_if_fail (cbfile != NULL, NULL); + g_return_val_if_fail (IS_CAL_BACKEND_FILE (cbfile), NULL); - /* Set the default timezone to it. */ - priv->default_zone = zone; + priv = cbfile->priv; - return TRUE; + return priv->file_name; } - diff --git a/calendar/pcs/cal-backend-file.h b/calendar/pcs/cal-backend-file.h index 4f79da66de..ebe190cb2a 100644 --- a/calendar/pcs/cal-backend-file.h +++ b/calendar/pcs/cal-backend-file.h @@ -22,7 +22,7 @@ #ifndef CAL_BACKEND_FILE_H #define CAL_BACKEND_FILE_H -#include "pcs/cal-backend.h" +#include "pcs/cal-backend-sync.h" G_BEGIN_DECLS @@ -42,17 +42,21 @@ typedef struct _CalBackendFileClass CalBackendFileClass; typedef struct _CalBackendFilePrivate CalBackendFilePrivate; struct _CalBackendFile { - CalBackend backend; + CalBackendSync backend; /* Private data */ CalBackendFilePrivate *priv; }; struct _CalBackendFileClass { - CalBackendClass parent_class; + CalBackendSyncClass parent_class; }; -GType cal_backend_file_get_type (void); +GType cal_backend_file_get_type (void); + +void cal_backend_file_set_file_name (CalBackendFile *cbfile, + const char *file_name); +const char *cal_backend_file_get_file_name (CalBackendFile *cbfile); diff --git a/calendar/pcs/cal-backend-object-sexp.c b/calendar/pcs/cal-backend-object-sexp.c new file mode 100644 index 0000000000..4bc6b78ebe --- /dev/null +++ b/calendar/pcs/cal-backend-object-sexp.c @@ -0,0 +1,1007 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * cal-backend-card-sexp.c + * Copyright 1999, 2000, 2001, Ximian, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License, version 2, as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include "cal-backend-object-sexp.h" + +static GObjectClass *parent_class; + +typedef struct _SearchContext SearchContext; + +struct _CalBackendObjectSExpPrivate { + ESExp *search_sexp; + char *text; + SearchContext *search_context; +}; + +struct _SearchContext { + CalComponent *comp; + CalBackend *backend; +}; + +static ESExpResult * +func_time_now (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + ESExpResult *result; + + if (argc != 0) { + e_sexp_fatal_error (esexp, _("time-now expects 0 arguments")); + return NULL; + } + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = time (NULL); + + return result; +} + +/* (make-time ISODATE) + * + * ISODATE - string, ISO 8601 date/time representation + * + * Constructs a time_t value for the specified date. + */ +static ESExpResult * +func_make_time (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + const char *str; + time_t t; + ESExpResult *result; + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("make-time expects 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_STRING) { + e_sexp_fatal_error (esexp, _("make-time expects argument 1 " + "to be a string")); + return NULL; + } + str = argv[0]->value.string; + + t = time_from_isodate (str); + if (t == -1) { + e_sexp_fatal_error (esexp, _("make-time argument 1 must be an " + "ISO 8601 date/time string")); + return NULL; + } + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = t; + + return result; +} + +/* (time-add-day TIME N) + * + * TIME - time_t, base time + * N - int, number of days to add + * + * Adds the specified number of days to a time value. + * + * FIXME: TIMEZONES - need to use a timezone or daylight saving changes will + * make the result incorrect. + */ +static ESExpResult * +func_time_add_day (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + ESExpResult *result; + time_t t; + int n; + + if (argc != 2) { + e_sexp_fatal_error (esexp, _("time-add-day expects 2 arguments")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("time-add-day expects argument 1 " + "to be a time_t")); + return NULL; + } + t = argv[0]->value.time; + + if (argv[1]->type != ESEXP_RES_INT) { + e_sexp_fatal_error (esexp, _("time-add-day expects argument 2 " + "to be an integer")); + return NULL; + } + n = argv[1]->value.number; + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = time_add_day (t, n); + + return result; +} + +/* (time-day-begin TIME) + * + * TIME - time_t, base time + * + * Returns the start of the day, according to the local time. + * + * FIXME: TIMEZONES - this uses the current Unix timezone. + */ +static ESExpResult * +func_time_day_begin (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + time_t t; + ESExpResult *result; + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("time-day-begin expects 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("time-day-begin expects argument 1 " + "to be a time_t")); + return NULL; + } + t = argv[0]->value.time; + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = time_day_begin (t); + + return result; +} + +/* (time-day-end TIME) + * + * TIME - time_t, base time + * + * Returns the end of the day, according to the local time. + * + * FIXME: TIMEZONES - this uses the current Unix timezone. + */ +static ESExpResult * +func_time_day_end (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + time_t t; + ESExpResult *result; + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("time-day-end expects 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("time-day-end expects argument 1 " + "to be a time_t")); + return NULL; + } + t = argv[0]->value.time; + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = time_day_end (t); + + return result; +} + +/* (get-vtype) + * + * Returns a string indicating the type of component (VEVENT, VTODO, VJOURNAL, + * VFREEBUSY, VTIMEZONE, UNKNOWN). + */ +static ESExpResult * +func_get_vtype (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + CalComponentVType vtype; + char *str; + ESExpResult *result; + + /* Check argument types */ + + if (argc != 0) { + e_sexp_fatal_error (esexp, _("get-vtype expects 0 arguments")); + return NULL; + } + + /* Get the type */ + + vtype = cal_component_get_vtype (ctx->comp); + + switch (vtype) { + case CAL_COMPONENT_EVENT: + str = g_strdup ("VEVENT"); + break; + + case CAL_COMPONENT_TODO: + str = g_strdup ("VTODO"); + break; + + case CAL_COMPONENT_JOURNAL: + str = g_strdup ("VJOURNAL"); + break; + + case CAL_COMPONENT_FREEBUSY: + str = g_strdup ("VFREEBUSY"); + break; + + case CAL_COMPONENT_TIMEZONE: + str = g_strdup ("VTIMEZONE"); + break; + + default: + str = g_strdup ("UNKNOWN"); + break; + } + + result = e_sexp_result_new (esexp, ESEXP_RES_STRING); + result->value.string = str; + + return result; +} + +/* (occur-in-time-range? START END) + * + * START - time_t, start of the time range + * END - time_t, end of the time range + * + * Returns a boolean indicating whether the component has any occurrences in the + * specified time range. + */ +static ESExpResult * +func_occur_in_time_range (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + time_t start, end, tt; + gboolean occurs; + ESExpResult *result; + CalComponentDateTime dt; + + /* Check argument types */ + + if (argc != 2) { + e_sexp_fatal_error (esexp, _("occur-in-time-range? expects 2 arguments")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("occur-in-time-range? expects argument 1 " + "to be a time_t")); + return NULL; + } + start = argv[0]->value.time; + + if (argv[1]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("occur-in-time-range? expects argument 2 " + "to be a time_t")); + return NULL; + } + end = argv[1]->value.time; + + /* See if the object occurs in the specified time range */ + occurs = FALSE; + + cal_component_get_dtstart (ctx->comp, &dt); + if (dt.value) { + icaltimezone *zone; + + if (dt.tzid) + zone = cal_backend_internal_get_timezone (ctx->backend, dt.tzid); + else + zone = cal_backend_internal_get_default_timezone (ctx->backend); + + tt = icaltime_as_timet_with_zone (*dt.value, zone); + if (tt >= start && tt <= end) + occurs = TRUE; + else { + cal_component_get_dtend (ctx->comp, &dt); + if (dt.value) { + if (dt.tzid) + zone = cal_backend_internal_get_timezone (ctx->backend, dt.tzid); + else + zone = cal_backend_internal_get_default_timezone (ctx->backend); + + tt = icaltime_as_timet_with_zone (*dt.value, zone); + if (tt >= start && tt <= end) + occurs = TRUE; + } + } + } + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = occurs; + + return result; +} + +/* Returns whether a list of CalComponentText items matches the specified string */ +static gboolean +matches_text_list (GSList *text_list, const char *str) +{ + GSList *l; + gboolean matches; + + matches = FALSE; + + for (l = text_list; l; l = l->next) { + CalComponentText *text; + + text = l->data; + g_assert (text->value != NULL); + + if (e_utf8_strstrcasedecomp (text->value, str) != NULL) { + matches = TRUE; + break; + } + } + + return matches; +} + +/* Returns whether the comments in a component matches the specified string */ +static gboolean +matches_comment (CalComponent *comp, const char *str) +{ + GSList *list; + gboolean matches; + + cal_component_get_comment_list (comp, &list); + matches = matches_text_list (list, str); + cal_component_free_text_list (list); + + return matches; +} + +/* Returns whether the description in a component matches the specified string */ +static gboolean +matches_description (CalComponent *comp, const char *str) +{ + GSList *list; + gboolean matches; + + cal_component_get_description_list (comp, &list); + matches = matches_text_list (list, str); + cal_component_free_text_list (list); + + return matches; +} + +/* Returns whether the summary in a component matches the specified string */ +static gboolean +matches_summary (CalComponent *comp, const char *str) +{ + CalComponentText text; + + cal_component_get_summary (comp, &text); + + if (!text.value) + return FALSE; + + return e_utf8_strstrcasedecomp (text.value, str) != NULL; +} + +/* Returns whether any text field in a component matches the specified string */ +static gboolean +matches_any (CalComponent *comp, const char *str) +{ + /* As an optimization, and to make life easier for the individual + * predicate functions, see if we are looking for the empty string right + * away. + */ + if (strlen (str) == 0) + return TRUE; + + return (matches_comment (comp, str) + || matches_description (comp, str) + || matches_summary (comp, str)); +} + +/* (contains? FIELD STR) + * + * FIELD - string, name of field to match (any, comment, description, summary) + * STR - string, match string + * + * Returns a boolean indicating whether the specified field contains the + * specified string. + */ +static ESExpResult * +func_contains (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + const char *field; + const char *str; + gboolean matches; + ESExpResult *result; + + /* Check argument types */ + + if (argc != 2) { + e_sexp_fatal_error (esexp, _("contains? expects 2 arguments")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_STRING) { + e_sexp_fatal_error (esexp, _("contains? expects argument 1 " + "to be a string")); + return NULL; + } + field = argv[0]->value.string; + + if (argv[1]->type != ESEXP_RES_STRING) { + e_sexp_fatal_error (esexp, _("contains? expects argument 2 " + "to be a string")); + return NULL; + } + str = argv[1]->value.string; + + /* See if it matches */ + + if (strcmp (field, "any") == 0) + matches = matches_any (ctx->comp, str); + else if (strcmp (field, "comment") == 0) + matches = matches_comment (ctx->comp, str); + else if (strcmp (field, "description") == 0) + matches = matches_description (ctx->comp, str); + else if (strcmp (field, "summary") == 0) + matches = matches_summary (ctx->comp, str); + else { + e_sexp_fatal_error (esexp, _("contains? expects argument 1 to " + "be one of \"any\", \"summary\", \"description\"")); + return NULL; + } + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = matches; + + return result; +} + +/* (has-alarms? #f|#t) + * + * A boolean value for components that have/dont have alarms. + * + * Returns: a boolean indicating whether the component has alarms or not. + */ +static ESExpResult * +func_has_alarms (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *result; + gboolean has_to_have_alarms; + + /* Check argument types */ + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("has-alarms? expects at least 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_BOOL) { + e_sexp_fatal_error (esexp, _("has-alarms? excepts argument to be a boolean")); + return NULL; + } + + has_to_have_alarms = argv[0]->value.bool; + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + + if (has_to_have_alarms && cal_component_has_alarms (ctx->comp)) + result->value.bool = TRUE; + else if (!has_to_have_alarms && !cal_component_has_alarms (ctx->comp)) + result->value.bool = TRUE; + else + result->value.bool = FALSE; + + return result; +} + +/* (has-categories? STR+) + * (has-categories? #f) + * + * STR - At least one string specifying a category + * Or you can specify a single #f (boolean false) value for components + * that have no categories assigned to them ("unfiled"). + * + * Returns a boolean indicating whether the component has all the specified + * categories. + */ +static ESExpResult * +func_has_categories (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + gboolean unfiled; + int i; + GSList *categories; + gboolean matches; + ESExpResult *result; + + /* Check argument types */ + + if (argc < 1) { + e_sexp_fatal_error (esexp, _("has-categories? expects at least 1 argument")); + return NULL; + } + + if (argc == 1 && argv[0]->type == ESEXP_RES_BOOL) + unfiled = TRUE; + else + unfiled = FALSE; + + if (!unfiled) + for (i = 0; i < argc; i++) + if (argv[i]->type != ESEXP_RES_STRING) { + e_sexp_fatal_error (esexp, _("has-categories? expects all arguments " + "to be strings or one and only one " + "argument to be a boolean false (#f)")); + return NULL; + } + + /* Search categories. First, if there are no categories we return + * whether unfiled components are supposed to match. + */ + + cal_component_get_categories_list (ctx->comp, &categories); + if (!categories) { + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = unfiled; + + return result; + } + + /* Otherwise, we *do* have categories but unfiled components were + * requested, so this component does not match. + */ + if (unfiled) { + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = FALSE; + + return result; + } + + matches = TRUE; + + for (i = 0; i < argc; i++) { + const char *sought; + GSList *l; + gboolean has_category; + + sought = argv[i]->value.string; + + has_category = FALSE; + + for (l = categories; l; l = l->next) { + const char *category; + + category = l->data; + + if (strcmp (category, sought) == 0) { + has_category = TRUE; + break; + } + } + + if (!has_category) { + matches = FALSE; + break; + } + } + + cal_component_free_categories_list (categories); + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = matches; + + return result; +} + +/* (is-completed?) + * + * Returns a boolean indicating whether the component is completed (i.e. has + * a COMPLETED property. This is really only useful for TODO components. + */ +static ESExpResult * +func_is_completed (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *result; + struct icaltimetype *t; + gboolean complete = FALSE; + + /* Check argument types */ + + if (argc != 0) { + e_sexp_fatal_error (esexp, _("is-completed? expects 0 arguments")); + return NULL; + } + + cal_component_get_completed (ctx->comp, &t); + if (t) { + complete = TRUE; + cal_component_free_icaltimetype (t); + } + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = complete; + + return result; +} + +/* (completed-before? TIME) + * + * TIME - time_t + * + * Returns a boolean indicating whether the component was completed on or + * before the given time (i.e. it checks the COMPLETED property). + * This is really only useful for TODO components. + */ +static ESExpResult * +func_completed_before (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *result; + struct icaltimetype *tt; + icaltimezone *zone; + gboolean retval = FALSE; + time_t before_time, completed_time; + + /* Check argument types */ + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("completed-before? expects 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("completed-before? expects argument 1 " + "to be a time_t")); + return NULL; + } + before_time = argv[0]->value.time; + + cal_component_get_completed (ctx->comp, &tt); + if (tt) { + /* COMPLETED must be in UTC. */ + zone = icaltimezone_get_utc_timezone (); + completed_time = icaltime_as_timet_with_zone (*tt, zone); + +#if 0 + g_print ("Query Time : %s", ctime (&before_time)); + g_print ("Completed Time: %s", ctime (&completed_time)); +#endif + + /* We want to return TRUE if before_time is after + completed_time. */ + if (difftime (before_time, completed_time) > 0) { +#if 0 + g_print (" Returning TRUE\n"); +#endif + retval = TRUE; + } + + cal_component_free_icaltimetype (tt); + } + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = retval; + + return result; +} + +#if 0 +static struct prop_info { + ECardSimpleField field_id; + const char *query_prop; + const char *ecard_prop; +#define PROP_TYPE_NORMAL 0x01 +#define PROP_TYPE_LIST 0x02 +#define PROP_TYPE_LISTITEM 0x03 +#define PROP_TYPE_ID 0x04 + int prop_type; + gboolean (*list_compare)(ECardSimple *ecard, const char *str, + char *(*compare)(const char*, const char*)); + +} prop_info_table[] = { +#define NORMAL_PROP(f,q,e) {f, q, e, PROP_TYPE_NORMAL, NULL} +#define ID_PROP {0, "id", NULL, PROP_TYPE_ID, NULL} +#define LIST_PROP(q,e,c) {0, q, e, PROP_TYPE_LIST, c} + + /* query prop, ecard prop, type, list compare function */ + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_FILE_AS, "file_as", "file_as" ), + LIST_PROP ( "full_name", "full_name", compare_name), /* not really a list, but we need to compare both full and surname */ + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_URL, "url", "url" ), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_MAILER, "mailer", "mailer"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ORG, "org", "org"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ORG_UNIT, "org_unit", "org_unit"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_OFFICE, "office", "office"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_TITLE, "title", "title"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ROLE, "role", "role"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_MANAGER, "manager", "manager"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ASSISTANT, "assistant", "assistant"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_NICKNAME, "nickname", "nickname"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_SPOUSE, "spouse", "spouse" ), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_NOTE, "note", "note"), + ID_PROP, + LIST_PROP ( "email", "email", compare_email ), + LIST_PROP ( "phone", "phone", compare_phone ), + LIST_PROP ( "address", "address", compare_address ), + LIST_PROP ( "category", "category", compare_category ), + LIST_PROP ( "arbitrary", "arbitrary", compare_arbitrary ) +}; +static int num_prop_infos = sizeof(prop_info_table) / sizeof(prop_info_table[0]); + +static ESExpResult * +entry_compare(SearchContext *ctx, struct _ESExp *f, + int argc, struct _ESExpResult **argv, + char *(*compare)(const char*, const char*)) +{ + ESExpResult *r; + int truth = FALSE; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname; + struct prop_info *info = NULL; + int i; + gboolean any_field; + + propname = argv[0]->value.string; + + any_field = !strcmp(propname, "x-evolution-any-field"); + for (i = 0; i < num_prop_infos; i ++) { + if (any_field + || !strcmp (prop_info_table[i].query_prop, propname)) { + info = &prop_info_table[i]; + + if (info->prop_type == PROP_TYPE_NORMAL) { + char *prop = NULL; + /* searches where the query's property + maps directly to an ecard property */ + + prop = e_card_simple_get (ctx->card, info->field_id); + + if (prop && compare(prop, argv[1]->value.string)) { + truth = TRUE; + } + if ((!prop) && compare("", argv[1]->value.string)) { + truth = TRUE; + } + g_free (prop); + } else if (info->prop_type == PROP_TYPE_LIST) { + /* the special searches that match any of the list elements */ + truth = info->list_compare (ctx->card, argv[1]->value.string, compare); + } else if (info->prop_type == PROP_TYPE_ID) { + const char *prop = NULL; + /* searches where the query's property + maps directly to an ecard property */ + + prop = e_card_get_id (ctx->card->card); + + if (prop && compare(prop, argv[1]->value.string)) { + truth = TRUE; + } + if ((!prop) && compare("", argv[1]->value.string)) { + truth = TRUE; + } + } + + /* if we're looking at all fields and find a match, + or if we're just looking at this one field, + break. */ + if ((any_field && truth) + || !any_field) + break; + } + } + + } + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = truth; + + return r; +} +#endif + +/* 'builtin' functions */ +static struct { + char *name; + ESExpFunc *func; + int type; /* set to 1 if a function can perform shortcut evaluation, or + doesn't execute everything, 0 otherwise */ +} symbols[] = { + /* Time-related functions */ + { "time-now", func_time_now, 0 }, + { "make-time", func_make_time, 0 }, + { "time-add-day", func_time_add_day, 0 }, + { "time-day-begin", func_time_day_begin, 0 }, + { "time-day-end", func_time_day_end, 0 }, + + /* Component-related functions */ + { "get-vtype", func_get_vtype, 0 }, + { "occur-in-time-range?", func_occur_in_time_range, 0 }, + { "contains?", func_contains, 0 }, + { "has-alarms?", func_has_alarms, 0 }, + { "has-categories?", func_has_categories, 0 }, + { "is-completed?", func_is_completed, 0 }, + { "completed-before?", func_completed_before, 0 } +}; + +gboolean +cal_backend_object_sexp_match_comp (CalBackendObjectSExp *sexp, CalComponent *comp, CalBackend *backend) +{ + ESExpResult *r; + gboolean retval; + + sexp->priv->search_context->comp = g_object_ref (comp); + sexp->priv->search_context->backend = g_object_ref (backend); + + /* if it's not a valid vcard why is it in our db? :) */ + if (!sexp->priv->search_context->comp) + return FALSE; + + r = e_sexp_eval(sexp->priv->search_sexp); + + retval = (r && r->type == ESEXP_RES_BOOL && r->value.bool); + + g_object_unref (sexp->priv->search_context->comp); + g_object_unref (sexp->priv->search_context->backend); + + e_sexp_result_free(sexp->priv->search_sexp, r); + + return retval; +} + +gboolean +cal_backend_object_sexp_match_object (CalBackendObjectSExp *sexp, const char *object, CalBackend *backend) +{ + CalComponent *comp; + icalcomponent *icalcomp; + gboolean retval; + + icalcomp = icalcomponent_new_from_string ((char *) object); + if (!icalcomp) + return FALSE; + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomp); + + retval = cal_backend_object_sexp_match_comp (sexp, comp, backend); + + g_object_unref (comp); + + return retval; +} + + + +/** + * cal_backend_card_sexp_new: + */ +CalBackendObjectSExp * +cal_backend_object_sexp_new (const char *text) +{ + CalBackendObjectSExp *sexp = g_object_new (CAL_TYPE_BACKEND_OBJECT_SEXP, NULL); + int esexp_error; + int i; + + sexp->priv->search_sexp = e_sexp_new(); + sexp->priv->text = g_strdup (text); + + for(i=0;ipriv->search_sexp, 0, symbols[i].name, + (ESExpIFunc *)symbols[i].func, sexp->priv->search_context); + } else { + e_sexp_add_function(sexp->priv->search_sexp, 0, symbols[i].name, + symbols[i].func, sexp->priv->search_context); + } + } + + e_sexp_input_text(sexp->priv->search_sexp, text, strlen(text)); + esexp_error = e_sexp_parse(sexp->priv->search_sexp); + + if (esexp_error == -1) { + g_object_unref (sexp); + sexp = NULL; + } + + return sexp; +} + +const char * +cal_backend_object_sexp_text (CalBackendObjectSExp *sexp) +{ + CalBackendObjectSExpPrivate *priv; + + g_return_val_if_fail (sexp != NULL, NULL); + g_return_val_if_fail (CAL_IS_BACKEND_OBJECT_SEXP (sexp), NULL); + + priv = sexp->priv; + + return priv->text; +} + +static void +cal_backend_object_sexp_dispose (GObject *object) +{ + CalBackendObjectSExp *sexp = CAL_BACKEND_OBJECT_SEXP (object); + + if (sexp->priv) { + e_sexp_unref(sexp->priv->search_sexp); + + g_free (sexp->priv->text); + + g_free (sexp->priv->search_context); + g_free (sexp->priv); + sexp->priv = NULL; + } + + if (G_OBJECT_CLASS (parent_class)->dispose) + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +cal_backend_object_sexp_class_init (CalBackendObjectSExpClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + /* Set the virtual methods. */ + + object_class->dispose = cal_backend_object_sexp_dispose; +} + +static void +cal_backend_object_sexp_init (CalBackendObjectSExp *sexp) +{ + CalBackendObjectSExpPrivate *priv; + + priv = g_new0 (CalBackendObjectSExpPrivate, 1); + + sexp->priv = priv; + priv->search_context = g_new (SearchContext, 1); +} + +/** + * cal_backend_object_sexp_get_type: + */ +GType +cal_backend_object_sexp_get_type (void) +{ + static GType type = 0; + + if (! type) { + GTypeInfo info = { + sizeof (CalBackendObjectSExpClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) cal_backend_object_sexp_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CalBackendObjectSExp), + 0, /* n_preallocs */ + (GInstanceInitFunc) cal_backend_object_sexp_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, "CalBackendObjectSExp", &info, 0); + } + + return type; +} diff --git a/calendar/pcs/cal-backend-object-sexp.h b/calendar/pcs/cal-backend-object-sexp.h new file mode 100644 index 0000000000..dbac3b6abc --- /dev/null +++ b/calendar/pcs/cal-backend-object-sexp.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * cal-backend-card-sexp.h + * Copyright 2000, 2001, Ximian, Inc. + * + * Authors: + * Chris Lahey + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License, version 2, as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __CAL_BACKEND_OBJECT_SEXP_H__ +#define __CAL_BACKEND_OBJECT_SEXP_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define CAL_TYPE_BACKEND_OBJECT_SEXP (cal_backend_object_sexp_get_type ()) +#define CAL_BACKEND_OBJECT_SEXP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CAL_TYPE_BACKEND_OBJECT_SEXP, CalBackendObjectSExp)) +#define CAL_BACKEND_OBJECT_SEXP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CAL_BACKEND_TYPE, CalBackendObjectSExpClass)) +#define CAL_IS_BACKEND_OBJECT_SEXP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CAL_TYPE_BACKEND_OBJECT_SEXP)) +#define CAL_IS_BACKEND_OBJECT_SEXP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CAL_TYPE_BACKEND_OBJECT_SEXP)) +#define CAL_BACKEND_OBJECT_SEXP_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), CAL_TYPE_BACKEND_OBJECT_SEXP, CALBackendObjectSExpClass)) + +typedef struct _CalBackendObjectSExpPrivate CalBackendObjectSExpPrivate; + +struct _CalBackendObjectSExp { + GObject parent_object; + + CalBackendObjectSExpPrivate *priv; +}; + +struct _CalBackendObjectSExpClass { + GObjectClass parent_class; +}; + +GType cal_backend_object_sexp_get_type (void); +CalBackendObjectSExp *cal_backend_object_sexp_new (const char *text); +const char *cal_backend_object_sexp_text (CalBackendObjectSExp *sexp); + + +gboolean cal_backend_object_sexp_match_object (CalBackendObjectSExp *sexp, + const char *object, + CalBackend *backend); +gboolean cal_backend_object_sexp_match_comp (CalBackendObjectSExp *sexp, + CalComponent *comp, + CalBackend *backend); + +G_END_DECLS + +#endif /* __CAL_BACKEND_OBJECT_SEXP_H__ */ diff --git a/calendar/pcs/cal-backend-sync.c b/calendar/pcs/cal-backend-sync.c new file mode 100644 index 0000000000..2a807ef689 --- /dev/null +++ b/calendar/pcs/cal-backend-sync.c @@ -0,0 +1,611 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Author: + * Chris Toshok (toshok@ximian.com) + * + * Copyright (C) 2003, Ximian, Inc. + */ + +#ifdef CONFIG_H +#include +#endif + +#include "cal-backend-sync.h" + +struct _CalBackendSyncPrivate { + int mumble; +}; + +static GObjectClass *parent_class; + +G_LOCK_DEFINE_STATIC (cal_sync_mutex); +#define SYNC_LOCK() G_LOCK (cal_sync_mutex) +#define SYNC_UNLOCK() G_UNLOCK (cal_sync_mutex) + +CalBackendSyncStatus +cal_backend_sync_is_read_only (CalBackendSync *backend, Cal *cal, gboolean *read_only) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (read_only, GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->is_read_only_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->is_read_only_sync) (backend, cal, read_only); +} + +CalBackendSyncStatus +cal_backend_sync_get_cal_address (CalBackendSync *backend, Cal *cal, char **address) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (address, GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_cal_address_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_cal_address_sync) (backend, cal, address); +} + +CalBackendSyncStatus +cal_backend_sync_get_alarm_email_address (CalBackendSync *backend, Cal *cal, char **address) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (address, GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_alarm_email_address_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_alarm_email_address_sync) (backend, cal, address); +} + +CalBackendSyncStatus +cal_backend_sync_get_ldap_attribute (CalBackendSync *backend, Cal *cal, char **attribute) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (attribute, GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_ldap_attribute_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_ldap_attribute_sync) (backend, cal, attribute); +} + +CalBackendSyncStatus +cal_backend_sync_get_static_capabilities (CalBackendSync *backend, Cal *cal, char **capabilities) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (capabilities, GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_static_capabilities_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_static_capabilities_sync) (backend, cal, capabilities); +} + +CalBackendSyncStatus +cal_backend_sync_open (CalBackendSync *backend, Cal *cal, gboolean only_if_exists) +{ + CalBackendSyncStatus status; + + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->open_sync); + + SYNC_LOCK (); + + status = (* CAL_BACKEND_SYNC_GET_CLASS (backend)->open_sync) (backend, cal, only_if_exists); + + SYNC_UNLOCK (); + + return status; +} + +CalBackendSyncStatus +cal_backend_sync_remove (CalBackendSync *backend, Cal *cal) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->remove_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->remove_sync) (backend, cal); +} + +CalBackendSyncStatus +cal_backend_sync_create_object (CalBackendSync *backend, Cal *cal, const char *calobj, char **uid) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->create_object_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->create_object_sync) (backend, cal, calobj, uid); +} + +CalBackendSyncStatus +cal_backend_sync_modify_object (CalBackendSync *backend, Cal *cal, const char *calobj, + CalObjModType mod, char **old_object) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->modify_object_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->modify_object_sync) (backend, cal, + calobj, mod, old_object); +} + +CalBackendSyncStatus +cal_backend_sync_remove_object (CalBackendSync *backend, Cal *cal, const char *uid, const char *rid, + CalObjModType mod, char **object) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->remove_object_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->remove_object_sync) (backend, cal, uid, rid, mod, object); +} + +CalBackendSyncStatus +cal_backend_sync_discard_alarm (CalBackendSync *backend, Cal *cal, const char *uid, const char *auid) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->discard_alarm_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->discard_alarm_sync) (backend, cal, uid, auid); +} + +CalBackendSyncStatus +cal_backend_sync_receive_objects (CalBackendSync *backend, Cal *cal, const char *calobj, + GList **created, GList **modified, GList **removed) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->receive_objects_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->receive_objects_sync) (backend, cal, calobj, + created, modified, removed); +} + +CalBackendSyncStatus +cal_backend_sync_send_objects (CalBackendSync *backend, Cal *cal, const char *calobj) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->send_objects_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->send_objects_sync) (backend, cal, calobj); +} + +CalBackendSyncStatus +cal_backend_sync_get_default_object (CalBackendSync *backend, Cal *cal, char **object) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (object, GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_default_object_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_default_object_sync) (backend, cal, object); +} + +CalBackendSyncStatus +cal_backend_sync_get_object (CalBackendSync *backend, Cal *cal, const char *uid, const char *rid, char **object) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (object, GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_object_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_object_sync) (backend, cal, uid, rid, object); +} + +CalBackendSyncStatus +cal_backend_sync_get_object_list (CalBackendSync *backend, Cal *cal, const char *sexp, GList **objects) +{ + g_return_val_if_fail (backend && CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + g_return_val_if_fail (objects, GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_object_list_sync); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_object_list_sync) (backend, cal, sexp, objects); +} + +CalBackendSyncStatus +cal_backend_sync_get_timezone (CalBackendSync *backend, Cal *cal, const char *tzid, char **object) +{ + g_return_val_if_fail (CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_timezone_sync != NULL); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_timezone_sync) (backend, cal, tzid, object); +} + +CalBackendSyncStatus +cal_backend_sync_add_timezone (CalBackendSync *backend, Cal *cal, const char *tzobj) +{ + g_return_val_if_fail (CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->add_timezone_sync != NULL); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->add_timezone_sync) (backend, cal, tzobj); +} + +CalBackendSyncStatus +cal_backend_sync_set_default_timezone (CalBackendSync *backend, Cal *cal, const char *tzid) +{ + g_return_val_if_fail (CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->set_default_timezone_sync != NULL); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->set_default_timezone_sync) (backend, cal, tzid); +} + + +CalBackendSyncStatus +cal_backend_sync_get_changes (CalBackendSync *backend, Cal *cal, CalObjType type, const char *change_id, + GList **adds, GList **modifies, GList **deletes) +{ + g_return_val_if_fail (CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_changes_sync != NULL); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_changes_sync) (backend, cal, type, change_id, + adds, modifies, deletes); +} + +CalBackendSyncStatus +cal_backend_sync_get_free_busy (CalBackendSync *backend, Cal *cal, GList *users, + time_t start, time_t end, GList **freebusy) +{ + g_return_val_if_fail (CAL_IS_BACKEND_SYNC (backend), GNOME_Evolution_Calendar_OtherError); + + g_assert (CAL_BACKEND_SYNC_GET_CLASS (backend)->get_freebusy_sync != NULL); + + return (* CAL_BACKEND_SYNC_GET_CLASS (backend)->get_freebusy_sync) (backend, cal, users, + start, end, freebusy); +} + + +static void +_cal_backend_is_read_only (CalBackend *backend, Cal *cal) +{ + CalBackendSyncStatus status; + gboolean read_only; + + status = cal_backend_sync_is_read_only (CAL_BACKEND_SYNC (backend), cal, &read_only); + + cal_notify_read_only (cal, status, read_only); +} + +static void +_cal_backend_get_cal_address (CalBackend *backend, Cal *cal) +{ + CalBackendSyncStatus status; + char *address; + + status = cal_backend_sync_get_cal_address (CAL_BACKEND_SYNC (backend), cal, &address); + + cal_notify_cal_address (cal, status, address); + + g_free (address); +} + +static void +_cal_backend_get_alarm_email_address (CalBackend *backend, Cal *cal) +{ + CalBackendSyncStatus status; + char *address; + + status = cal_backend_sync_get_cal_address (CAL_BACKEND_SYNC (backend), cal, &address); + + cal_notify_alarm_email_address (cal, status, address); + + g_free (address); +} + +static void +_cal_backend_get_ldap_attribute (CalBackend *backend, Cal *cal) +{ + CalBackendSyncStatus status; + char *attribute; + + status = cal_backend_sync_get_cal_address (CAL_BACKEND_SYNC (backend), cal, &attribute); + + cal_notify_ldap_attribute (cal, status, attribute); + + g_free (attribute); +} + +static void +_cal_backend_get_static_capabilities (CalBackend *backend, Cal *cal) +{ + CalBackendSyncStatus status; + char *capabilities; + + status = cal_backend_sync_get_cal_address (CAL_BACKEND_SYNC (backend), cal, &capabilities); + + cal_notify_static_capabilities (cal, status, capabilities); + + g_free (capabilities); +} + +static void +_cal_backend_open (CalBackend *backend, Cal *cal, gboolean only_if_exists) +{ + CalBackendSyncStatus status; + + status = cal_backend_sync_open (CAL_BACKEND_SYNC (backend), cal, only_if_exists); + + cal_notify_open (cal, status); +} + +static void +_cal_backend_remove (CalBackend *backend, Cal *cal) +{ + CalBackendSyncStatus status; + + status = cal_backend_sync_remove (CAL_BACKEND_SYNC (backend), cal); + + cal_notify_remove (cal, status); +} + +static void +_cal_backend_create_object (CalBackend *backend, Cal *cal, const char *calobj) +{ + CalBackendSyncStatus status; + char *uid = NULL; + + status = cal_backend_sync_create_object (CAL_BACKEND_SYNC (backend), cal, calobj, &uid); + + cal_notify_object_created (cal, status, uid, calobj); + + if (uid) + g_free (uid); +} + +static void +_cal_backend_modify_object (CalBackend *backend, Cal *cal, const char *calobj, CalObjModType mod) +{ + CalBackendSyncStatus status; + char *old_object; + + status = cal_backend_sync_modify_object (CAL_BACKEND_SYNC (backend), cal, + calobj, mod, &old_object); + + cal_notify_object_modified (cal, status, old_object, calobj); +} + +static void +_cal_backend_remove_object (CalBackend *backend, Cal *cal, const char *uid, const char *rid, CalObjModType mod) +{ + CalBackendSyncStatus status; + char *object; + + status = cal_backend_sync_remove_object (CAL_BACKEND_SYNC (backend), cal, uid, rid, mod, &object); + + cal_notify_object_removed (cal, status, uid, object); +} + +static void +_cal_backend_discard_alarm (CalBackend *backend, Cal *cal, const char *uid, const char *auid) +{ + CalBackendSyncStatus status; + + status = cal_backend_sync_discard_alarm (CAL_BACKEND_SYNC (backend), cal, uid, auid); + + cal_notify_alarm_discarded (cal, status); +} + +static void +_cal_backend_receive_objects (CalBackend *backend, Cal *cal, const char *calobj) +{ + CalBackendSyncStatus status; + GList *created = NULL, *modified = NULL, *removed = NULL; + + status = cal_backend_sync_receive_objects (CAL_BACKEND_SYNC (backend), cal, calobj, + &created, &modified, &removed); + + cal_notify_objects_received (cal, status, created, modified, removed); +} + +static void +_cal_backend_send_objects (CalBackend *backend, Cal *cal, const char *calobj) +{ + CalBackendSyncStatus status; + + status = cal_backend_sync_send_objects (CAL_BACKEND_SYNC (backend), cal, calobj); + + cal_notify_objects_sent (cal, status); +} + +static void +_cal_backend_get_default_object (CalBackend *backend, Cal *cal) +{ + CalBackendSyncStatus status; + char *object = NULL; + + status = cal_backend_sync_get_default_object (CAL_BACKEND_SYNC (backend), cal, &object); + + cal_notify_default_object (cal, status, object); + + g_free (object); +} + +static void +_cal_backend_get_object (CalBackend *backend, Cal *cal, const char *uid, const char *rid) +{ + CalBackendSyncStatus status; + char *object = NULL; + + status = cal_backend_sync_get_object (CAL_BACKEND_SYNC (backend), cal, uid, rid, &object); + + cal_notify_object (cal, status, object); + + g_free (object); +} + +static void +_cal_backend_get_object_list (CalBackend *backend, Cal *cal, const char *sexp) +{ + CalBackendSyncStatus status; + GList *objects, *l; + + status = cal_backend_sync_get_object_list (CAL_BACKEND_SYNC (backend), cal, sexp, &objects); + + cal_notify_object_list (cal, status, objects); + + for (l = objects; l; l = l->next) + g_free (l->data); + g_list_free (objects); +} + +static void +_cal_backend_get_timezone (CalBackend *backend, Cal *cal, const char *tzid) +{ + CalBackendSyncStatus status; + char *object = NULL; + + status = cal_backend_sync_get_timezone (CAL_BACKEND_SYNC (backend), cal, tzid, &object); + + cal_notify_timezone_requested (cal, status, object); +} + +static void +_cal_backend_add_timezone (CalBackend *backend, Cal *cal, const char *tzobj) +{ + CalBackendSyncStatus status; + + status = cal_backend_sync_add_timezone (CAL_BACKEND_SYNC (backend), cal, tzobj); + + cal_notify_timezone_added (cal, status, tzobj); +} + +static void +_cal_backend_set_default_timezone (CalBackend *backend, Cal *cal, const char *tzid) +{ + CalBackendSyncStatus status; + + status = cal_backend_sync_set_default_timezone (CAL_BACKEND_SYNC (backend), cal, tzid); + + cal_notify_default_timezone_set (cal, status); +} + +static void +_cal_backend_get_changes (CalBackend *backend, Cal *cal, CalObjType type, const char *change_id) +{ + CalBackendSyncStatus status; + GList *adds = NULL, *modifies = NULL, *deletes = NULL, *l; + + status = cal_backend_sync_get_changes (CAL_BACKEND_SYNC (backend), cal, type, change_id, + &adds, &modifies, &deletes); + + cal_notify_changes (cal, status, adds, modifies, deletes); + + for (l = adds; l; l = l->next) + g_free (l->data); + g_list_free (adds); + + for (l = modifies; l; l = l->next) + g_free (l->data); + g_list_free (modifies); + + for (l = deletes; l; l = l->next) + g_free (l->data); + g_list_free (deletes); +} + +static void +_cal_backend_get_free_busy (CalBackend *backend, Cal *cal, GList *users, time_t start, time_t end) +{ + CalBackendSyncStatus status; + GList *freebusy = NULL, *l; + + status = cal_backend_sync_get_free_busy (CAL_BACKEND_SYNC (backend), cal, users, start, end, &freebusy); + + cal_notify_free_busy (cal, status, freebusy); + + for (l = freebusy; l; l = l->next) + g_free (l->data); + g_list_free (freebusy); +} + +static void +cal_backend_sync_init (CalBackendSync *backend) +{ + CalBackendSyncPrivate *priv; + + priv = g_new0 (CalBackendSyncPrivate, 1); + + backend->priv = priv; +} + +static void +cal_backend_sync_dispose (GObject *object) +{ + CalBackendSync *backend; + + backend = CAL_BACKEND_SYNC (object); + + if (backend->priv) { + g_free (backend->priv); + + backend->priv = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +cal_backend_sync_class_init (CalBackendSyncClass *klass) +{ + GObjectClass *object_class; + CalBackendClass *backend_class = CAL_BACKEND_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class = (GObjectClass *) klass; + + backend_class->is_read_only = _cal_backend_is_read_only; + backend_class->get_cal_address = _cal_backend_get_cal_address; + backend_class->get_alarm_email_address = _cal_backend_get_alarm_email_address; + backend_class->get_ldap_attribute = _cal_backend_get_ldap_attribute; + backend_class->get_static_capabilities = _cal_backend_get_static_capabilities; + backend_class->open = _cal_backend_open; + backend_class->remove = _cal_backend_remove; + backend_class->create_object = _cal_backend_create_object; + backend_class->modify_object = _cal_backend_modify_object; + backend_class->remove_object = _cal_backend_remove_object; + backend_class->discard_alarm = _cal_backend_discard_alarm; + backend_class->receive_objects = _cal_backend_receive_objects; + backend_class->send_objects = _cal_backend_send_objects; + backend_class->get_default_object = _cal_backend_get_default_object; + backend_class->get_object = _cal_backend_get_object; + backend_class->get_object_list = _cal_backend_get_object_list; + backend_class->get_timezone = _cal_backend_get_timezone; + backend_class->add_timezone = _cal_backend_add_timezone; + backend_class->set_default_timezone = _cal_backend_set_default_timezone; + backend_class->get_changes = _cal_backend_get_changes; + backend_class->get_free_busy = _cal_backend_get_free_busy; + + object_class->dispose = cal_backend_sync_dispose; +} + +/** + * cal_backend_get_type: + */ +GType +cal_backend_sync_get_type (void) +{ + static GType type = 0; + + if (! type) { + GTypeInfo info = { + sizeof (CalBackendSyncClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) cal_backend_sync_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CalBackendSync), + 0, /* n_preallocs */ + (GInstanceInitFunc) cal_backend_sync_init + }; + + type = g_type_register_static (CAL_BACKEND_TYPE, "CalBackendSync", &info, 0); + } + + return type; +} diff --git a/calendar/pcs/cal-backend-sync.h b/calendar/pcs/cal-backend-sync.h new file mode 100644 index 0000000000..ead49fa4b7 --- /dev/null +++ b/calendar/pcs/cal-backend-sync.h @@ -0,0 +1,146 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + */ + +#ifndef __Cal_BACKEND_SYNC_H__ +#define __Cal_BACKEND_SYNC_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define CAL_TYPE_BACKEND_SYNC (cal_backend_sync_get_type ()) +#define CAL_BACKEND_SYNC(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CAL_TYPE_BACKEND_SYNC, CalBackendSync)) +#define CAL_BACKEND_SYNC_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CAL_TYPE_BACKEND_SYNC, CalBackendSyncClass)) +#define CAL_IS_BACKEND_SYNC(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CAL_TYPE_BACKEND_SYNC)) +#define CAL_IS_BACKEND_SYNC_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CAL_TYPE_BACKEND_SYNC)) +#define CAL_BACKEND_SYNC_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), CAL_TYPE_BACKEND_SYNC, CalBackendSyncClass)) +typedef struct _CalBackendSync CalBackendSync; +typedef struct _CalBackendSyncClass CalBackendSyncClass; +typedef struct _CalBackendSyncPrivate CalBackendSyncPrivate; + +typedef GNOME_Evolution_Calendar_CallStatus CalBackendSyncStatus; + +struct _CalBackendSync { + CalBackend parent_object; + + CalBackendSyncPrivate *priv; +}; + +struct _CalBackendSyncClass { + CalBackendClass parent_class; + + /* Virtual methods */ + CalBackendSyncStatus (*is_read_only_sync) (CalBackendSync *backend, Cal *cal, gboolean *read_only); + CalBackendSyncStatus (*get_cal_address_sync) (CalBackendSync *backend, Cal *cal, char **address); + CalBackendSyncStatus (*get_alarm_email_address_sync) (CalBackendSync *backend, Cal *cal, char **address); + CalBackendSyncStatus (*get_ldap_attribute_sync) (CalBackendSync *backend, Cal *cal, char **attribute); + CalBackendSyncStatus (*get_static_capabilities_sync) (CalBackendSync *backend, Cal *cal, char **capabilities); + + CalBackendSyncStatus (*open_sync) (CalBackendSync *backend, Cal *cal, gboolean only_if_exists); + CalBackendSyncStatus (*remove_sync) (CalBackendSync *backend, Cal *cal); + + CalBackendSyncStatus (*create_object_sync) (CalBackendSync *backend, Cal *cal, const char *calobj, char **uid); + CalBackendSyncStatus (*modify_object_sync) (CalBackendSync *backend, Cal *cal, const char *calobj, CalObjModType mod, char **old_object); + CalBackendSyncStatus (*remove_object_sync) (CalBackendSync *backend, Cal *cal, const char *uid, const char *rid, CalObjModType mod, char **object); + + CalBackendSyncStatus (*discard_alarm_sync) (CalBackendSync *backend, Cal *cal, const char *uid, const char *auid); + + CalBackendSyncStatus (*receive_objects_sync) (CalBackendSync *backend, Cal *cal, const char *calobj, GList **created, GList **modified, GList **removed); + CalBackendSyncStatus (*send_objects_sync) (CalBackendSync *backend, Cal *cal, const char *calobj); + + CalBackendSyncStatus (*get_default_object_sync) (CalBackendSync *backend, Cal *cal, char **object); + CalBackendSyncStatus (*get_object_sync) (CalBackendSync *backend, Cal *cal, const char *uid, const char *rid, char **object); + CalBackendSyncStatus (*get_object_list_sync) (CalBackendSync *backend, Cal *cal, const char *sexp, GList **objects); + + CalBackendSyncStatus (*get_timezone_sync) (CalBackendSync *backend, Cal *cal, const char *tzid, char **object); + CalBackendSyncStatus (*add_timezone_sync) (CalBackendSync *backend, Cal *cal, const char *tzobj); + CalBackendSyncStatus (*set_default_timezone_sync) (CalBackendSync *backend, Cal *cal, const char *tzid); + + CalBackendSyncStatus (*get_changes_sync) (CalBackendSync *backend, Cal *cal, CalObjType type, const char *change_id, GList **adds, GList **modifies, GList **deletes); + CalBackendSyncStatus (*get_freebusy_sync) (CalBackendSync *backend, Cal *cal, GList *users, time_t start, time_t end, GList **freebusy); + + /* Padding for future expansion */ + void (*_cal_reserved0) (void); + void (*_cal_reserved1) (void); + void (*_cal_reserved2) (void); + void (*_cal_reserved3) (void); + void (*_cal_reserved4) (void); + +}; + +typedef CalBackendSync * (*CalBackendSyncFactoryFn) (void); +GType cal_backend_sync_get_type (void); +CalBackendSyncStatus cal_backend_sync_is_read_only (CalBackendSync *backend, + Cal *cal, + gboolean *read_only); +CalBackendSyncStatus cal_backend_sync_get_cal_address (CalBackendSync *backend, + Cal *cal, + char **address); +CalBackendSyncStatus cal_backend_sync_get_alarm_email_address (CalBackendSync *backend, + Cal *cal, + char **address); +CalBackendSyncStatus cal_backend_sync_get_ldap_attribute (CalBackendSync *backend, + Cal *cal, + char **attribute); +CalBackendSyncStatus cal_backend_sync_get_static_capabilities (CalBackendSync *backend, + Cal *cal, + char **capabiliites); +CalBackendSyncStatus cal_backend_sync_open (CalBackendSync *backend, + Cal *cal, + gboolean only_if_exists); +CalBackendSyncStatus cal_backend_sync_remove (CalBackendSync *backend, + Cal *cal); +CalBackendSyncStatus cal_backend_sync_create_object (CalBackendSync *backend, + Cal *cal, + const char *calobj, + char **uid); +CalBackendSyncStatus cal_backend_sync_modify_object (CalBackendSync *backend, + Cal *cal, + const char *calobj, + CalObjModType mod, + char **old_object); +CalBackendSyncStatus cal_backend_sync_remove_object (CalBackendSync *backend, + Cal *cal, + const char *uid, + const char *rid, + CalObjModType mod, + char **object); +CalBackendSyncStatus cal_backend_sync_discard_alarm (CalBackendSync *backend, Cal *cal, const char *uid, const char *auid); + +CalBackendSyncStatus cal_backend_sync_receive_objects (CalBackendSync *backend, + Cal *cal, + const char *calobj, + GList **created, + GList **modified, + GList **removed); +CalBackendSyncStatus cal_backend_sync_send_objects (CalBackendSync *backend, + Cal *cal, + const char *calobj); +CalBackendSyncStatus cal_backend_sync_get_default_object (CalBackendSync *backend, + Cal *cal, + char **object); + +CalBackendSyncStatus cal_backend_sync_get_object (CalBackendSync *backend, + Cal *cal, + const char *uid, + const char *rid, + char **object); + +CalBackendSyncStatus cal_backend_sync_get_object_list (CalBackendSync *backend, + Cal *cal, + const char *sexp, + GList **objects); + +CalBackendSyncStatus cal_backend_sync_get_timezone (CalBackendSync *backend, Cal *cal, const char *tzid, char **object); +CalBackendSyncStatus cal_backend_sync_add_timezone (CalBackendSync *backend, Cal *cal, const char *tzobj); +CalBackendSyncStatus cal_backend_sync_set_default_timezone (CalBackendSync *backend, Cal *cal, const char *tzid); + +CalBackendSyncStatus cal_backend_sync_get_changes (CalBackendSync *backend, Cal *cal, CalObjType type, const char *change_id, GList **adds, GList **modifies, GList **deletes); +CalBackendSyncStatus cal_backend_sync_get_free_busy (CalBackendSync *backend, Cal *cal, GList *users, time_t start, time_t end, GList **freebusy); + +G_END_DECLS + +#endif /* ! __CAL_BACKEND_SYNC_H__ */ diff --git a/calendar/pcs/cal-backend-util.c b/calendar/pcs/cal-backend-util.c index ad39bfcc38..86bf761878 100644 --- a/calendar/pcs/cal-backend-util.c +++ b/calendar/pcs/cal-backend-util.c @@ -26,36 +26,6 @@ static EAccountList *accounts; -void -cal_backend_util_fill_alarm_instances_seq (GNOME_Evolution_Calendar_CalAlarmInstanceSeq *seq, - GSList *alarms) -{ - int n_alarms; - GSList *l; - int i; - - g_return_if_fail (seq != NULL); - - n_alarms = g_slist_length (alarms); - - CORBA_sequence_set_release (seq, TRUE); - seq->_length = n_alarms; - seq->_buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalAlarmInstance_allocbuf (n_alarms); - - for (l = alarms, i = 0; l; l = l->next, i++) { - CalAlarmInstance *instance; - GNOME_Evolution_Calendar_CalAlarmInstance *corba_instance; - - instance = l->data; - corba_instance = seq->_buffer + i; - - corba_instance->auid = CORBA_string_dup (instance->auid); - corba_instance->trigger = (long) instance->trigger; - corba_instance->occur_start = (long) instance->occur_start; - corba_instance->occur_end = (long) instance->occur_end; - } -} - gboolean cal_backend_mail_account_get_default (EConfigListener *db, char **address, diff --git a/calendar/pcs/cal-backend-util.h b/calendar/pcs/cal-backend-util.h index 6ce9d59807..228179b8c7 100644 --- a/calendar/pcs/cal-backend-util.h +++ b/calendar/pcs/cal-backend-util.h @@ -28,13 +28,6 @@ G_BEGIN_DECLS -/* - * CORBA utility functions - */ - -void cal_backend_util_fill_alarm_instances_seq ( - GNOME_Evolution_Calendar_CalAlarmInstanceSeq *seq, GSList *alarms); - /* * Functions for accessing mail configuration */ diff --git a/calendar/pcs/cal-backend.c b/calendar/pcs/cal-backend.c index 1d6330346c..ae5be6829e 100644 --- a/calendar/pcs/cal-backend.c +++ b/calendar/pcs/cal-backend.c @@ -43,9 +43,19 @@ typedef struct { /* Private part of the CalBackend structure */ struct _CalBackendPrivate { - /* List of Cal objects with their listeners */ + /* The uri for this backend */ + char *uri; + + /* The kind of components for this backend */ + icalcomponent_kind kind; + + /* List of Cal objects */ + GMutex *clients_mutex; GList *clients; + GMutex *queries_mutex; + EList *queries; + /* Hash table of live categories, temporary hash of * added/removed categories, and idle handler for sending * category_changed. @@ -55,13 +65,18 @@ struct _CalBackendPrivate { guint category_idle_id; }; +/* Property IDs */ +enum props { + PROP_0, + PROP_URI, + PROP_KIND +}; + /* Signal IDs */ enum { LAST_CLIENT_GONE, - CAL_ADDED, OPENED, - OBJ_UPDATED, - OBJ_REMOVED, + REMOVED, LAST_SIGNAL }; static guint cal_backend_signals[LAST_SIGNAL]; @@ -70,8 +85,6 @@ static void cal_backend_class_init (CalBackendClass *class); static void cal_backend_init (CalBackend *backend); static void cal_backend_finalize (GObject *object); -static char *get_object (CalBackend *backend, const char *uid); - static void notify_categories_changed (CalBackend *backend); #define CLASS(backend) (CAL_BACKEND_CLASS (G_OBJECT_GET_CLASS (backend))) @@ -111,6 +124,51 @@ cal_backend_get_type (void) return cal_backend_type; } +static void +cal_backend_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + CalBackend *backend; + CalBackendPrivate *priv; + + backend = CAL_BACKEND (object); + priv = backend->priv; + + switch (property_id) { + case PROP_URI: + g_free (priv->uri); + priv->uri = g_value_dup_string (value); + break; + case PROP_KIND: + priv->kind = g_value_get_ulong (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +cal_backend_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + CalBackend *backend; + CalBackendPrivate *priv; + + backend = CAL_BACKEND (object); + priv = backend->priv; + + switch (property_id) { + case PROP_URI: + g_value_set_string (value, cal_backend_get_uri (backend)); + break; + case PROP_KIND: + g_value_set_ulong (value, cal_backend_get_kind (backend)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + /* Class initialization function for the calendar backend */ static void cal_backend_class_init (CalBackendClass *class) @@ -121,6 +179,21 @@ cal_backend_class_init (CalBackendClass *class) object_class = (GObjectClass *) class; + object_class->set_property = cal_backend_set_property; + object_class->get_property = cal_backend_get_property; + object_class->finalize = cal_backend_finalize; + + g_object_class_install_property (object_class, PROP_URI, + g_param_spec_string ("uri", NULL, NULL, "", + G_PARAM_READABLE | G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, PROP_KIND, + g_param_spec_ulong ("kind", NULL, NULL, + ICAL_NO_COMPONENT, ICAL_XLICMIMEPART_COMPONENT, + ICAL_NO_COMPONENT, + G_PARAM_READABLE | G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT_ONLY)); cal_backend_signals[LAST_CLIENT_GONE] = g_signal_new ("last_client_gone", G_TYPE_FROM_CLASS (class), @@ -129,15 +202,6 @@ cal_backend_class_init (CalBackendClass *class) NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - cal_backend_signals[CAL_ADDED] = - g_signal_new ("cal_added", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalBackendClass, cal_added), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); cal_backend_signals[OPENED] = g_signal_new ("opened", G_TYPE_FROM_CLASS (class), @@ -147,56 +211,43 @@ cal_backend_class_init (CalBackendClass *class) g_cclosure_marshal_VOID__ENUM, G_TYPE_NONE, 1, G_TYPE_INT); - cal_backend_signals[OBJ_UPDATED] = - g_signal_new ("obj_updated", + cal_backend_signals[REMOVED] = + g_signal_new ("removed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalBackendClass, obj_updated), + G_STRUCT_OFFSET (CalBackendClass, removed), NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - cal_backend_signals[OBJ_REMOVED] = - g_signal_new ("obj_removed", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (CalBackendClass, obj_removed), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, + g_cclosure_marshal_VOID__ENUM, G_TYPE_NONE, 1, - G_TYPE_STRING); - - object_class->finalize = cal_backend_finalize; + G_TYPE_INT); class->last_client_gone = NULL; class->opened = NULL; class->obj_updated = NULL; - class->obj_removed = NULL; - class->get_uri = NULL; class->get_cal_address = NULL; class->get_alarm_email_address = NULL; class->get_static_capabilities = NULL; class->open = NULL; class->is_loaded = NULL; class->is_read_only = NULL; - class->get_query = NULL; + class->start_query = NULL; class->get_mode = NULL; class->set_mode = NULL; - class->get_n_objects = NULL; - class->get_object = get_object; - class->get_object_component = NULL; - class->get_timezone_object = NULL; - class->get_uids = NULL; - class->get_objects_in_range = NULL; + class->get_object = NULL; + class->get_default_object = NULL; + class->get_object_list = NULL; class->get_free_busy = NULL; class->get_changes = NULL; - class->get_alarms_in_range = NULL; - class->get_alarms_for_object = NULL; class->discard_alarm = NULL; - class->update_objects = NULL; + class->create_object = NULL; + class->modify_object = NULL; class->remove_object = NULL; - class->send_object = NULL; + class->receive_objects = NULL; + class->send_objects = NULL; + class->get_timezone = NULL; + class->add_timezone = NULL; + class->set_default_timezone = NULL; } /* Object initialization func for the calendar backend */ @@ -208,6 +259,13 @@ cal_backend_init (CalBackend *backend) priv = g_new0 (CalBackendPrivate, 1); backend->priv = priv; + priv->clients = NULL; + priv->clients_mutex = g_mutex_new (); + + /* FIXME bonobo_object_ref/unref? */ + priv->queries = e_list_new((EListCopyFunc) g_object_ref, (EListFreeFunc) g_object_unref, NULL); + priv->queries_mutex = g_mutex_new (); + priv->categories = g_hash_table_new (g_str_hash, g_str_equal); priv->changed_categories = g_hash_table_new (g_str_hash, g_str_equal); } @@ -242,12 +300,17 @@ cal_backend_finalize (GObject *object) g_assert (priv->clients == NULL); + g_object_unref (priv->queries); + g_hash_table_foreach_remove (priv->changed_categories, prune_changed_categories, NULL); g_hash_table_destroy (priv->changed_categories); g_hash_table_foreach (priv->categories, free_category_cb, NULL); g_hash_table_destroy (priv->categories); + g_mutex_free (priv->clients_mutex); + g_mutex_free (priv->queries_mutex); + if (priv->category_idle_id) g_source_remove (priv->category_idle_id); @@ -270,108 +333,177 @@ cal_backend_finalize (GObject *object) const char * cal_backend_get_uri (CalBackend *backend) { + CalBackendPrivate *priv; + g_return_val_if_fail (backend != NULL, NULL); g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_assert (CLASS (backend)->get_uri != NULL); - return (* CLASS (backend)->get_uri) (backend); + priv = backend->priv; + + return priv->uri; } -/** - * cal_backend_get_cal_address: - * @backend: A calendar backend. - * - * Queries the cal address associated with a calendar backend, which - * must already have an open calendar. - * - * Return value: The cal address associated with the calendar. - **/ -const char * -cal_backend_get_cal_address (CalBackend *backend) +icalcomponent_kind +cal_backend_get_kind (CalBackend *backend) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + CalBackendPrivate *priv; + + g_return_val_if_fail (backend != NULL, ICAL_NO_COMPONENT); + g_return_val_if_fail (IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT); - g_assert (CLASS (backend)->get_cal_address != NULL); - return (* CLASS (backend)->get_cal_address) (backend); + priv = backend->priv; + + return priv->kind; } -const char * -cal_backend_get_alarm_email_address (CalBackend *backend) +static void +cal_destroy_cb (gpointer data, GObject *where_cal_was) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + CalBackend *backend = CAL_BACKEND (data); - g_assert (CLASS (backend)->get_alarm_email_address != NULL); - return (* CLASS (backend)->get_alarm_email_address) (backend); + cal_backend_remove_client (backend, (Cal *) where_cal_was); } -const char * -cal_backend_get_ldap_attribute (CalBackend *backend) +static void +listener_died_cb (gpointer cnx, gpointer data) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + Cal *cal = CAL (data); - g_assert (CLASS (backend)->get_ldap_attribute != NULL); - return (* CLASS (backend)->get_ldap_attribute) (backend); + cal_backend_remove_client (cal_get_backend (cal), cal); } -const char * -cal_backend_get_static_capabilities (CalBackend *backend) +static void +last_client_gone (CalBackend *backend) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + g_signal_emit (backend, cal_backend_signals[LAST_CLIENT_GONE], 0); +} - g_assert (CLASS (backend)->get_static_capabilities != NULL); - return (* CLASS (backend)->get_static_capabilities) (backend); +void +cal_backend_add_client (CalBackend *backend, Cal *cal) +{ + CalBackendPrivate *priv; + + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = backend->priv; + + bonobo_object_set_immortal (BONOBO_OBJECT (cal), TRUE); + + g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend); + + ORBit_small_listen_for_broken (cal_get_listener (cal), G_CALLBACK (listener_died_cb), cal); + + g_mutex_lock (priv->clients_mutex); + priv->clients = g_list_append (priv->clients, cal); + g_mutex_unlock (priv->clients_mutex); + + /* Tell the new client about the list of categories. + * (Ends up telling all the other clients too, but *shrug*.) + */ + /* FIXME This doesn't seem right at all */ + notify_categories_changed (backend); } -/* Callback used when a Cal is destroyed */ -static void -cal_destroy_cb (gpointer data, GObject *where_cal_was) +void +cal_backend_remove_client (CalBackend *backend, Cal *cal) { - CalBackend *backend = CAL_BACKEND (data); - CalBackendPrivate *priv = backend->priv; + CalBackendPrivate *priv; + + /* XXX this needs a bit more thinking wrt the mutex - we + should be holding it when we check to see if clients is + NULL */ + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); - priv->clients = g_list_remove (priv->clients, where_cal_was); + priv = backend->priv; + + /* Disconnect */ + g_mutex_lock (priv->clients_mutex); + priv->clients = g_list_remove (priv->clients, cal); + g_mutex_unlock (priv->clients_mutex); /* When all clients go away, notify the parent factory about it so that * it may decide whether to kill the backend or not. */ if (!priv->clients) - cal_backend_last_client_gone (backend); + last_client_gone (backend); +} + +void +cal_backend_add_query (CalBackend *backend, Query *query) +{ + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + + g_mutex_lock (backend->priv->queries_mutex); + + e_list_append (backend->priv->queries, query); + + g_mutex_unlock (backend->priv->queries_mutex); +} + +EList * +cal_backend_get_queries (CalBackend *backend) +{ + g_return_val_if_fail (backend != NULL, NULL); + g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + + return g_object_ref (backend->priv->queries); } + /** - * cal_backend_add_cal: + * cal_backend_get_cal_address: * @backend: A calendar backend. - * @cal: A calendar client interface object. * - * Adds a calendar client interface object to a calendar @backend. - * The calendar backend must already have an open calendar. + * Queries the cal address associated with a calendar backend, which + * must already have an open calendar. + * + * Return value: The cal address associated with the calendar. **/ void -cal_backend_add_cal (CalBackend *backend, Cal *cal) +cal_backend_get_cal_address (CalBackend *backend, Cal *cal) { - CalBackendPrivate *priv = backend->priv; + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_assert (CLASS (backend)->get_cal_address != NULL); + (* CLASS (backend)->get_cal_address) (backend, cal); +} + +void +cal_backend_get_alarm_email_address (CalBackend *backend, Cal *cal) +{ g_return_if_fail (backend != NULL); g_return_if_fail (IS_CAL_BACKEND (backend)); - g_return_if_fail (IS_CAL (cal)); - /* we do not keep a (strong) reference to the Cal since the - * Calendar user agent owns it */ - g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend); + g_assert (CLASS (backend)->get_alarm_email_address != NULL); + (* CLASS (backend)->get_alarm_email_address) (backend, cal); +} - priv->clients = g_list_prepend (priv->clients, cal); +void +cal_backend_get_ldap_attribute (CalBackend *backend, Cal *cal) +{ + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); - /* Tell the new client about the list of categories. - * (Ends up telling all the other clients too, but *shrug*.) - */ - notify_categories_changed (backend); + g_assert (CLASS (backend)->get_ldap_attribute != NULL); + (* CLASS (backend)->get_ldap_attribute) (backend, cal); +} - /* notify backend that a new Cal has been added */ - g_signal_emit (backend, cal_backend_signals[CAL_ADDED], 0, cal); +void +cal_backend_get_static_capabilities (CalBackend *backend, Cal *cal) +{ + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + + g_assert (CLASS (backend)->get_static_capabilities != NULL); + (* CLASS (backend)->get_static_capabilities) (backend, cal); } /** @@ -387,19 +519,24 @@ cal_backend_add_cal (CalBackend *backend, Cal *cal) * * Return value: An operation status code. **/ -CalBackendOpenStatus -cal_backend_open (CalBackend *backend, const char *uristr, gboolean only_if_exists) +void +cal_backend_open (CalBackend *backend, Cal *cal, gboolean only_if_exists) { - CalBackendOpenStatus result; - - g_return_val_if_fail (backend != NULL, CAL_BACKEND_OPEN_ERROR); - g_return_val_if_fail (IS_CAL_BACKEND (backend), CAL_BACKEND_OPEN_ERROR); - g_return_val_if_fail (uristr != NULL, CAL_BACKEND_OPEN_ERROR); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); g_assert (CLASS (backend)->open != NULL); - result = (* CLASS (backend)->open) (backend, uristr, only_if_exists); + (* CLASS (backend)->open) (backend, cal, only_if_exists); +} - return result; +void +cal_backend_remove (CalBackend *backend, Cal *cal) +{ + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + + g_assert (CLASS (backend)->remove != NULL); + (* CLASS (backend)->remove) (backend, cal); } /** @@ -433,44 +570,24 @@ cal_backend_is_loaded (CalBackend *backend) * * Return value: TRUE if the calendar is read only, FALSE otherwise. */ -gboolean -cal_backend_is_read_only (CalBackend *backend) +void +cal_backend_is_read_only (CalBackend *backend, Cal *cal) { - gboolean result; - - g_return_val_if_fail (backend != NULL, FALSE); - g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); g_assert (CLASS (backend)->is_read_only != NULL); - result = (* CLASS (backend)->is_read_only) (backend); - - return result; + (* CLASS (backend)->is_read_only) (backend, cal); } -/** - * cal_backend_get_query: - * @backend: A calendar backend. - * @ql: The query listener. - * @sexp: Search expression. - * - * Create a query object for this backend. - */ -Query * -cal_backend_get_query (CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp) +void +cal_backend_start_query (CalBackend *backend, Query *query) { - Query *result; - - g_return_val_if_fail (backend != NULL, FALSE); - g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE); - - if (CLASS (backend)->get_query != NULL) - result = (* CLASS (backend)->get_query) (backend, ql, sexp); - else - result = query_new (backend, ql, sexp); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); - return result; + g_assert (CLASS (backend)->start_query != NULL); + (* CLASS (backend)->start_query) (backend, query); } /** @@ -514,206 +631,56 @@ cal_backend_set_mode (CalBackend *backend, CalMode mode) (* CLASS (backend)->set_mode) (backend, mode); } -/** - * cal_backend_get_n_objects: - * @backend: A calendar backend. - * @type: Types of objects that will be included in the count. - * - * Queries the number of calendar objects of a particular type. - * - * Return value: Number of objects of the specified @type. - **/ -int -cal_backend_get_n_objects (CalBackend *backend, CalObjType type) -{ - g_return_val_if_fail (backend != NULL, -1); - g_return_val_if_fail (IS_CAL_BACKEND (backend), -1); - - g_assert (CLASS (backend)->get_n_objects != NULL); - return (* CLASS (backend)->get_n_objects) (backend, type); -} - -/* Default cal_backend_get_object implementation */ -static char * -get_object (CalBackend *backend, const char *uid) -{ - CalComponent *comp; - - comp = cal_backend_get_object_component (backend, uid); - if (!comp) - return NULL; - - return cal_component_get_as_string (comp); -} - -char * -cal_backend_get_default_object (CalBackend *backend, CalObjType type) +void +cal_backend_get_default_object (CalBackend *backend, Cal *cal) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); g_assert (CLASS (backend)->get_default_object != NULL); - return (* CLASS (backend)->get_default_object) (backend, type); + (* CLASS (backend)->get_default_object) (backend, cal); } /** * cal_backend_get_object: * @backend: A calendar backend. * @uid: Unique identifier for a calendar object. + * @rid: ID for the object's recurrence to get. * * Queries a calendar backend for a calendar object based on its unique - * identifier. + * identifier and its recurrence ID (if a recurrent appointment). * * Return value: The string representation of a complete calendar wrapping the * the sought object, or NULL if no object had the specified UID. **/ -char * -cal_backend_get_object (CalBackend *backend, const char *uid) +void +cal_backend_get_object (CalBackend *backend, Cal *cal, const char *uid, const char *rid) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (uid != NULL, NULL); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (uid != NULL); g_assert (CLASS (backend)->get_object != NULL); - return (* CLASS (backend)->get_object) (backend, uid); + (* CLASS (backend)->get_object) (backend, cal, uid, rid); } /** - * cal_backend_get_object_component: - * @backend: A calendar backend. - * @uid: Unique identifier for a calendar object. - * - * Queries a calendar backend for a calendar object based on its unique - * identifier. It returns the CalComponent rather than the string - * representation. - * - * Return value: The CalComponent of the sought object, or NULL if no object - * had the specified UID. - **/ -CalComponent * -cal_backend_get_object_component (CalBackend *backend, const char *uid) -{ - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (uid != NULL, NULL); - - g_assert (CLASS (backend)->get_object_component != NULL); - return (* CLASS (backend)->get_object_component) (backend, uid); -} - -/** - * cal_backend_get_timezone_object: - * @backend: A calendar backend. - * @tzid: Unique identifier for a calendar VTIMEZONE object. - * - * Queries a calendar backend for a VTIMEZONE calendar object based on its - * unique TZID identifier. - * - * Return value: The string representation of a VTIMEZONE component, or NULL - * if no VTIMEZONE object had the specified TZID. - **/ -char * -cal_backend_get_timezone_object (CalBackend *backend, const char *tzid) -{ - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (tzid != NULL, NULL); - - g_assert (CLASS (backend)->get_timezone_object != NULL); - return (* CLASS (backend)->get_timezone_object) (backend, tzid); -} - -/** - * cal_backend_get_type_by_uid - * @backend: A calendar backend. - * @uid: Unique identifier for a Calendar object. - * - * Returns the type of the object identified by the @uid argument - */ -CalObjType -cal_backend_get_type_by_uid (CalBackend *backend, const char *uid) -{ - icalcomponent *icalcomp; - char *comp_str; - CalObjType type = CAL_COMPONENT_NO_TYPE; - - g_return_val_if_fail (IS_CAL_BACKEND (backend), CAL_COMPONENT_NO_TYPE); - g_return_val_if_fail (uid != NULL, CAL_COMPONENT_NO_TYPE); - - comp_str = cal_backend_get_object (backend, uid); - if (!comp_str) - return CAL_COMPONENT_NO_TYPE; - - icalcomp = icalparser_parse_string (comp_str); - if (icalcomp) { - switch (icalcomponent_isa (icalcomp)) { - case ICAL_VEVENT_COMPONENT : - type = CALOBJ_TYPE_EVENT; - break; - case ICAL_VTODO_COMPONENT : - type = CALOBJ_TYPE_TODO; - break; - case ICAL_VJOURNAL_COMPONENT : - type = CALOBJ_TYPE_JOURNAL; - break; - default : - type = CAL_COMPONENT_NO_TYPE; - } - - icalcomponent_free (icalcomp); - } - - g_free (comp_str); - - return type; -} - -/** - * cal_backend_get_uids: - * @backend: A calendar backend. - * @type: Bitmask with types of objects to return. - * - * Builds a list of unique identifiers corresponding to calendar objects whose - * type matches one of the types specified in the @type flags. - * - * Return value: A list of strings that are the sought UIDs. The list should be - * freed using the cal_obj_uid_list_free() function. - **/ -GList * -cal_backend_get_uids (CalBackend *backend, CalObjType type) -{ - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - - g_assert (CLASS (backend)->get_uids != NULL); - return (* CLASS (backend)->get_uids) (backend, type); -} - - -/** - * cal_backend_get_objects_in_range: - * @backend: A calendar backend. - * @type: Bitmask with types of objects to return. - * @start: Start time for query. - * @end: End time for query. + * cal_backend_get_object_list: + * @backend: + * @type: + * * - * Builds a list of unique identifiers corresponding to calendar objects of the - * specified type that occur or recur within the specified time range. * - * Return value: A list of UID strings. The list should be freed using the - * cal_obj_uid_list_free() function. + * Return value: **/ -GList * -cal_backend_get_objects_in_range (CalBackend *backend, CalObjType type, - time_t start, time_t end) +void +cal_backend_get_object_list (CalBackend *backend, Cal *cal, const char *sexp) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); - g_assert (CLASS (backend)->get_objects_in_range != NULL); - return (* CLASS (backend)->get_objects_in_range) (backend, type, start, end); + g_assert (CLASS (backend)->get_object_list != NULL); + return (* CLASS (backend)->get_object_list) (backend, cal, sexp); } /** @@ -727,16 +694,16 @@ cal_backend_get_objects_in_range (CalBackend *backend, CalObjType type, * * Return value: a list of CalObj's **/ -GList * -cal_backend_get_free_busy (CalBackend *backend, GList *users, time_t start, time_t end) +void +cal_backend_get_free_busy (CalBackend *backend, Cal *cal, GList *users, time_t start, time_t end) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (start != -1 && end != -1); + g_return_if_fail (start <= end); g_assert (CLASS (backend)->get_free_busy != NULL); - return (* CLASS (backend)->get_free_busy) (backend, users, start, end); + (* CLASS (backend)->get_free_busy) (backend, cal, users, start, end); } /** @@ -750,91 +717,15 @@ cal_backend_get_free_busy (CalBackend *backend, GList *users, time_t start, time * * Return value: A list of the objects that changed and the type of change **/ -GNOME_Evolution_Calendar_CalObjChangeSeq * -cal_backend_get_changes (CalBackend *backend, CalObjType type, const char *change_id) +void +cal_backend_get_changes (CalBackend *backend, Cal *cal, CalObjType type, const char *change_id) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (change_id != NULL, NULL); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (change_id != NULL); g_assert (CLASS (backend)->get_changes != NULL); - return (* CLASS (backend)->get_changes) (backend, type, change_id); -} - -/** - * cal_backend_get_alarms_in_range: - * @backend: A calendar backend. - * @start: Start time for query. - * @end: End time for query. - * @valid_range: Return value that says whether the range is valid or not. - * - * Builds a sorted list of the alarms that trigger in the specified time range. - * - * Return value: A sequence of component alarm instances structures, or NULL - * if @valid_range returns FALSE. - **/ -GNOME_Evolution_Calendar_CalComponentAlarmsSeq * -cal_backend_get_alarms_in_range (CalBackend *backend, time_t start, time_t end, - gboolean *valid_range) -{ - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (valid_range != NULL, NULL); - - g_assert (CLASS (backend)->get_alarms_in_range != NULL); - - if (!(start != -1 && end != -1 && start <= end)) { - *valid_range = FALSE; - return NULL; - } else { - *valid_range = TRUE; - return (* CLASS (backend)->get_alarms_in_range) (backend, start, end); - } -} - -/** - * cal_backend_get_alarms_for_object: - * @backend: A calendar backend. - * @uid: Unique identifier for a calendar object. - * @start: Start time for query. - * @end: End time for query. - * @result: Return value for the result code for the operation. - * - * Builds a sorted list of the alarms of the specified event that trigger in a - * particular time range. - * - * Return value: A structure of the component's alarm instances, or NULL if @result - * returns something other than #CAL_BACKEND_GET_ALARMS_SUCCESS. - **/ -GNOME_Evolution_Calendar_CalComponentAlarms * -cal_backend_get_alarms_for_object (CalBackend *backend, const char *uid, - time_t start, time_t end, - CalBackendGetAlarmsForObjectResult *result) -{ - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (uid != NULL, NULL); - g_return_val_if_fail (result != NULL, NULL); - - g_assert (CLASS (backend)->get_alarms_for_object != NULL); - - if (!(start != -1 && end != -1 && start <= end)) { - *result = CAL_BACKEND_GET_ALARMS_INVALID_RANGE; - return NULL; - } else { - gboolean object_found; - GNOME_Evolution_Calendar_CalComponentAlarms *alarms; - - alarms = (* CLASS (backend)->get_alarms_for_object) (backend, uid, start, end, - &object_found); - - if (object_found) - *result = CAL_BACKEND_GET_ALARMS_SUCCESS; - else - *result = CAL_BACKEND_GET_ALARMS_NOT_FOUND; - - return alarms; - } + (* CLASS (backend)->get_changes) (backend, cal, type, change_id); } /** @@ -846,92 +737,82 @@ cal_backend_get_alarms_for_object (CalBackend *backend, const char *uid, * Discards an alarm from the given component. This allows the specific backend * to do whatever is needed to really discard the alarm. * - * Return value: a #CalBackendResult value, which indicates the - * result of the operation. **/ -CalBackendResult -cal_backend_discard_alarm (CalBackend *backend, const char *uid, const char *auid) +void +cal_backend_discard_alarm (CalBackend *backend, Cal *cal, const char *uid, const char *auid) { - g_return_val_if_fail (backend != NULL, CAL_BACKEND_RESULT_NOT_FOUND); - g_return_val_if_fail (IS_CAL_BACKEND (backend), CAL_BACKEND_RESULT_NOT_FOUND); - g_return_val_if_fail (uid != NULL, CAL_BACKEND_RESULT_NOT_FOUND); - g_return_val_if_fail (auid != NULL, CAL_BACKEND_RESULT_NOT_FOUND); - g_return_val_if_fail (CLASS (backend)->discard_alarm != NULL, CAL_BACKEND_RESULT_NOT_FOUND); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (uid != NULL); + g_return_if_fail (auid != NULL); - return (* CLASS (backend)->discard_alarm) (backend, uid, auid); + g_assert (CLASS (backend)->discard_alarm != NULL); + (* CLASS (backend)->discard_alarm) (backend, cal, uid, auid); } -/** - * cal_backend_update_objects: - * @backend: A calendar backend. - * @calobj: String representation of the new calendar object(s). - * - * Updates an object in a calendar backend. It will replace any existing - * object that has the same UID as the specified one. The backend will in - * turn notify all of its clients about the change. - * - * Return value: a #CalBackendResult value, which indicates the - * result of the operation. - **/ -CalBackendResult -cal_backend_update_objects (CalBackend *backend, const char *calobj, CalObjModType mod) +void +cal_backend_create_object (CalBackend *backend, Cal *cal, const char *calobj) +{ + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (calobj != NULL); + + g_assert (CLASS (backend)->create_object != NULL); + (* CLASS (backend)->create_object) (backend, cal, calobj); +} + +void +cal_backend_modify_object (CalBackend *backend, Cal *cal, const char *calobj, CalObjModType mod) { - g_return_val_if_fail (backend != NULL, CAL_BACKEND_RESULT_NOT_FOUND); - g_return_val_if_fail (IS_CAL_BACKEND (backend), CAL_BACKEND_RESULT_NOT_FOUND); - g_return_val_if_fail (calobj != NULL, CAL_BACKEND_RESULT_NOT_FOUND); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (calobj != NULL); - g_assert (CLASS (backend)->update_objects != NULL); - return (* CLASS (backend)->update_objects) (backend, calobj, mod); + g_assert (CLASS (backend)->modify_object != NULL); + (* CLASS (backend)->modify_object) (backend, cal, calobj, mod); } /** * cal_backend_remove_object: * @backend: A calendar backend. * @uid: Unique identifier of the object to remove. + * @rid: A recurrence ID. * * Removes an object in a calendar backend. The backend will notify all of its * clients about the change. * - * Return value: a #CalBackendResult value, which indicates the - * result of the operation. **/ -CalBackendResult -cal_backend_remove_object (CalBackend *backend, const char *uid, CalObjModType mod) +void +cal_backend_remove_object (CalBackend *backend, Cal *cal, const char *uid, const char *rid, CalObjModType mod) { - g_return_val_if_fail (backend != NULL, CAL_BACKEND_RESULT_NOT_FOUND); - g_return_val_if_fail (IS_CAL_BACKEND (backend), CAL_BACKEND_RESULT_NOT_FOUND); - g_return_val_if_fail (uid != NULL, CAL_BACKEND_RESULT_NOT_FOUND); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (uid != NULL); g_assert (CLASS (backend)->remove_object != NULL); - return (* CLASS (backend)->remove_object) (backend, uid, mod); + (* CLASS (backend)->remove_object) (backend, cal, uid, rid, mod); } -CalBackendSendResult -cal_backend_send_object (CalBackend *backend, const char *calobj, char **new_calobj, - GNOME_Evolution_Calendar_UserList **user_list, char error_msg[256]) +void +cal_backend_receive_objects (CalBackend *backend, Cal *cal, const char *calobj) { - g_return_val_if_fail (backend != NULL, CAL_BACKEND_SEND_INVALID_OBJECT); - g_return_val_if_fail (IS_CAL_BACKEND (backend), CAL_BACKEND_SEND_INVALID_OBJECT); - g_return_val_if_fail (calobj != NULL, CAL_BACKEND_SEND_INVALID_OBJECT); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (calobj != NULL); - g_assert (CLASS (backend)->send_object != NULL); - return (* CLASS (backend)->send_object) (backend, calobj, new_calobj, user_list, error_msg); + g_assert (CLASS (backend)->receive_objects != NULL); + return (* CLASS (backend)->receive_objects) (backend, cal, calobj); } -/** - * cal_backend_last_client_gone: - * @backend: A calendar backend. - * - * Emits the "last_client_gone" signal of a calendar backend. This function is - * to be used only by backend implementations. - **/ void -cal_backend_last_client_gone (CalBackend *backend) +cal_backend_send_objects (CalBackend *backend, Cal *cal, const char *calobj) { g_return_if_fail (backend != NULL); g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (calobj != NULL); - g_signal_emit (G_OBJECT (backend), cal_backend_signals[LAST_CLIENT_GONE], 0); + g_assert (CLASS (backend)->send_objects != NULL); + return (* CLASS (backend)->send_objects) (backend, cal, calobj); } /** @@ -943,7 +824,7 @@ cal_backend_last_client_gone (CalBackend *backend) * only by backend implementations. **/ void -cal_backend_opened (CalBackend *backend, CalBackendOpenStatus status) +cal_backend_opened (CalBackend *backend, int status) { g_return_if_fail (backend != NULL); g_return_if_fail (IS_CAL_BACKEND (backend)); @@ -952,45 +833,16 @@ cal_backend_opened (CalBackend *backend, CalBackendOpenStatus status) 0, status); } -/** - * cal_backend_obj_updated: - * @backend: A calendar backend. - * @uid: Unique identifier of the component that was updated. - * - * Emits the "obj_updated" signal of a calendar backend. This function is to be - * used only by backend implementations. - **/ void -cal_backend_obj_updated (CalBackend *backend, const char *uid) +cal_backend_removed (CalBackend *backend, int status) { g_return_if_fail (backend != NULL); g_return_if_fail (IS_CAL_BACKEND (backend)); - g_return_if_fail (uid != NULL); - - g_signal_emit (G_OBJECT (backend), cal_backend_signals[OBJ_UPDATED], - 0, uid); -} -/** - * cal_backend_obj_removed: - * @backend: A calendar backend. - * @uid: Unique identifier of the component that was removed. - * - * Emits the "obj_removed" signal of a calendar backend. This function is to be - * used only by backend implementations. - **/ -void -cal_backend_obj_removed (CalBackend *backend, const char *uid) -{ - g_return_if_fail (backend != NULL); - g_return_if_fail (IS_CAL_BACKEND (backend)); - g_return_if_fail (uid != NULL); - - g_signal_emit (G_OBJECT (backend), cal_backend_signals[OBJ_REMOVED], - 0, uid); + g_signal_emit (G_OBJECT (backend), cal_backend_signals[REMOVED], + 0, status); } - /** * cal_backend_get_timezone: * @backend: A calendar backend. @@ -1002,38 +854,17 @@ cal_backend_obj_removed (CalBackend *backend, const char *uid) * * Returns: The icaltimezone* corresponding to the given TZID, or NULL. **/ -icaltimezone* -cal_backend_get_timezone (CalBackend *backend, const char *tzid) +void +cal_backend_get_timezone (CalBackend *backend, Cal *cal, const char *tzid) { - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (tzid != NULL, NULL); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (tzid != NULL); g_assert (CLASS (backend)->get_timezone != NULL); - return (* CLASS (backend)->get_timezone) (backend, tzid); + (* CLASS (backend)->get_timezone) (backend, cal, tzid); } - -/** - * cal_backend_get_default_timezone: - * @backend: A calendar backend. - * - * Returns the default timezone for the calendar, which is used to resolve - * DATE and floating DATE-TIME values. - * - * Returns: The default icaltimezone* for the calendar. - **/ -icaltimezone* -cal_backend_get_default_timezone (CalBackend *backend) -{ - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - - g_assert (CLASS (backend)->get_default_timezone != NULL); - return (* CLASS (backend)->get_default_timezone) (backend); -} - - /** * cal_backend_set_default_timezone: * @backend: A calendar backend. @@ -1045,75 +876,74 @@ cal_backend_get_default_timezone (CalBackend *backend) * Returns: TRUE if the VTIMEZONE data for the timezone was found, or FALSE if * not. **/ -gboolean -cal_backend_set_default_timezone (CalBackend *backend, const char *tzid) +void +cal_backend_set_default_timezone (CalBackend *backend, Cal *cal, const char *tzid) { - g_return_val_if_fail (backend != NULL, FALSE); - g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE); - g_return_val_if_fail (tzid != NULL, FALSE); + g_return_if_fail (backend != NULL); + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (tzid != NULL); g_assert (CLASS (backend)->set_default_timezone != NULL); - return (* CLASS (backend)->set_default_timezone) (backend, tzid); + (* CLASS (backend)->set_default_timezone) (backend, cal, tzid); } - /** - * cal_backend_notify_mode: + * cal_backend_add_timezone * @backend: A calendar backend. - * @status: Status of the mode set - * @mode: the current mode + * @tzobj: The timezone object, in a string. * - * Notifies each of the backend's listeners about the results of a - * setMode call. - **/ + * Add a timezone object to the given backend. + * + * Returns: TRUE if successful, or FALSE if not. + */ void -cal_backend_notify_mode (CalBackend *backend, - GNOME_Evolution_Calendar_Listener_SetModeStatus status, - GNOME_Evolution_Calendar_CalMode mode) +cal_backend_add_timezone (CalBackend *backend, Cal *cal, const char *tzobj) { - CalBackendPrivate *priv = backend->priv; - GList *l; + g_return_if_fail (IS_CAL_BACKEND (backend)); + g_return_if_fail (tzobj != NULL); + g_return_if_fail (CLASS (backend)->add_timezone != NULL); - for (l = priv->clients; l; l = l->next) - cal_notify_mode (l->data, status, mode); + (* CLASS (backend)->add_timezone) (backend, cal, tzobj); } -/** - * cal_backend_notify_update: - * @backend: A calendar backend. - * @uid: UID of object that was updated. - * - * Notifies each of the backend's listeners about an update to a - * calendar object. - **/ -void -cal_backend_notify_update (CalBackend *backend, const char *uid) +icaltimezone * +cal_backend_internal_get_default_timezone (CalBackend *backend) { - CalBackendPrivate *priv = backend->priv; - GList *l; + g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + g_return_val_if_fail (CLASS (backend)->internal_get_default_timezone != NULL, NULL); - cal_backend_obj_updated (backend, uid); - for (l = priv->clients; l; l = l->next) - cal_notify_update (l->data, uid); + return (* CLASS (backend)->internal_get_default_timezone) (backend); +} + +icaltimezone * +cal_backend_internal_get_timezone (CalBackend *backend, const char *tzid) +{ + g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + g_return_val_if_fail (tzid != NULL, NULL); + g_return_val_if_fail (CLASS (backend)->internal_get_timezone != NULL, NULL); + + return (* CLASS (backend)->internal_get_timezone) (backend, tzid); } /** - * cal_backend_notify_remove: + * cal_backend_notify_mode: * @backend: A calendar backend. - * @uid: UID of object that was removed. - * - * Notifies each of the backend's listeners about a calendar object - * that was removed. + * @status: Status of the mode set + * @mode: the current mode + * + * Notifies each of the backend's listeners about the results of a + * setMode call. **/ void -cal_backend_notify_remove (CalBackend *backend, const char *uid) +cal_backend_notify_mode (CalBackend *backend, + GNOME_Evolution_Calendar_Listener_SetModeStatus status, + GNOME_Evolution_Calendar_CalMode mode) { CalBackendPrivate *priv = backend->priv; GList *l; - cal_backend_obj_removed (backend, uid); for (l = priv->clients; l; l = l->next) - cal_notify_remove (l->data, uid); + cal_notify_mode (l->data, status, mode); } /** diff --git a/calendar/pcs/cal-backend.h b/calendar/pcs/cal-backend.h index 49d8b2d76e..793622cadc 100644 --- a/calendar/pcs/cal-backend.h +++ b/calendar/pcs/cal-backend.h @@ -24,6 +24,7 @@ #ifndef CAL_BACKEND_H #define CAL_BACKEND_H +#include #include #include #include "pcs/evolution-calendar.h" @@ -42,37 +43,6 @@ G_BEGIN_DECLS #define IS_CAL_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CAL_BACKEND_TYPE)) #define IS_CAL_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CAL_BACKEND_TYPE)) -/* Open status values */ -typedef enum { - CAL_BACKEND_OPEN_SUCCESS, /* Loading OK */ - CAL_BACKEND_OPEN_ERROR, /* We need better error reporting in libversit */ - CAL_BACKEND_OPEN_NOT_FOUND, - CAL_BACKEND_OPEN_PERMISSION_DENIED, -} CalBackendOpenStatus; - -/* Update and Remove result values */ -typedef enum { - CAL_BACKEND_RESULT_SUCCESS, - CAL_BACKEND_RESULT_INVALID_OBJECT, - CAL_BACKEND_RESULT_NOT_FOUND, - CAL_BACKEND_RESULT_PERMISSION_DENIED -} CalBackendResult; - -/* Send result values */ -typedef enum { - CAL_BACKEND_SEND_SUCCESS, - CAL_BACKEND_SEND_INVALID_OBJECT, - CAL_BACKEND_SEND_BUSY, - CAL_BACKEND_SEND_PERMISSION_DENIED, -} CalBackendSendResult; - -/* Result codes for ::get_alarms_in_range() */ -typedef enum { - CAL_BACKEND_GET_ALARMS_SUCCESS, - CAL_BACKEND_GET_ALARMS_NOT_FOUND, - CAL_BACKEND_GET_ALARMS_INVALID_RANGE -} CalBackendGetAlarmsForObjectResult; - typedef struct _CalBackendPrivate CalBackendPrivate; struct _CalBackend { @@ -88,153 +58,115 @@ struct _CalBackendClass { void (* last_client_gone) (CalBackend *backend); void (* cal_added) (CalBackend *backend, Cal *cal); - void (* opened) (CalBackend *backend, CalBackendOpenStatus status); + gboolean (* is_loaded) (CalBackend *backend); + + /* FIXME What to pass back here */ + void (* opened) (CalBackend *backend, int status); + void (* removed) (CalBackend *backend, int status); void (* obj_updated) (CalBackend *backend, const char *uid); - void (* obj_removed) (CalBackend *backend, const char *uid); /* Virtual methods */ - const char *(* get_uri) (CalBackend *backend); - - const char *(* get_cal_address) (CalBackend *backend); - const char *(* get_alarm_email_address) (CalBackend *backend); - const char *(* get_ldap_attribute) (CalBackend *backend); - - const char *(* get_static_capabilities) (CalBackend *backend); + void (* is_read_only) (CalBackend *backend, Cal *cal); + void (* get_cal_address) (CalBackend *backend, Cal *cal); + void (* get_alarm_email_address) (CalBackend *backend, Cal *cal); + void (* get_ldap_attribute) (CalBackend *backend, Cal *cal); + void (* get_static_capabilities) (CalBackend *backend, Cal *cal); - CalBackendOpenStatus (* open) (CalBackend *backend, const char *uristr, - gboolean only_if_exists); + void (* open) (CalBackend *backend, Cal *cal, gboolean only_if_exists); + void (* remove) (CalBackend *backend, Cal *cal); - gboolean (* is_loaded) (CalBackend *backend); - gboolean (* is_read_only) (CalBackend *backend); - - Query *(* get_query) (CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp); - - /* Mode relate virtual methods */ - CalMode (* get_mode) (CalBackend *backend); - void (* set_mode) (CalBackend *backend, CalMode mode); - - /* General object acquirement and information related virtual methods */ - int (* get_n_objects) (CalBackend *backend, CalObjType type); - char *(* get_default_object) (CalBackend *backend, CalObjType type); - char *(* get_object) (CalBackend *backend, const char *uid); - CalComponent *(* get_object_component) (CalBackend *backend, const char *uid); - char *(* get_timezone_object) (CalBackend *backend, const char *tzid); - GList *(* get_uids) (CalBackend *backend, CalObjType type); - - GList *(* get_objects_in_range) (CalBackend *backend, CalObjType type, - time_t start, time_t end); - GList *(* get_free_busy) (CalBackend *backend, GList *users, time_t start, time_t end); - - /* Change related virtual methods */ - GNOME_Evolution_Calendar_CalObjChangeSeq * (* get_changes) ( - CalBackend *backend, CalObjType type, const char *change_id); - - /* Alarm related virtual methods */ - GNOME_Evolution_Calendar_CalComponentAlarmsSeq *(* get_alarms_in_range) ( - CalBackend *backend, time_t start, time_t end); - GNOME_Evolution_Calendar_CalComponentAlarms *(* get_alarms_for_object) ( - CalBackend *backend, const char *uid, - time_t start, time_t end, gboolean *object_found); - CalBackendResult (* discard_alarm) (CalBackend *backend, const char *uid, const char *auid); - - /* Object manipulation virtual methods */ - CalBackendResult (* update_objects) (CalBackend *backend, const char *calobj, CalObjModType mod); - CalBackendResult (* remove_object) (CalBackend *backend, const char *uid, CalObjModType mod); - - CalBackendSendResult (* send_object) (CalBackend *backend, const char *calobj, char **new_calobj, - GNOME_Evolution_Calendar_UserList **user_list, - char error_msg[256]); - - /* Timezone related virtual methods */ - icaltimezone *(* get_timezone) (CalBackend *backend, const char *tzid); - icaltimezone *(* get_default_timezone) (CalBackend *backend); - gboolean (* set_default_timezone) (CalBackend *backend, const char *tzid); -}; - -GType cal_backend_get_type (void); - -const char *cal_backend_get_uri (CalBackend *backend); + /* Object related virtual methods */ + void (* create_object) (CalBackend *backend, Cal *cal, const char *calobj); + void (* modify_object) (CalBackend *backend, Cal *cal, const char *calobj, CalObjModType mod); + void (* remove_object) (CalBackend *backend, Cal *cal, const char *uid, const char *rid, CalObjModType mod); -const char *cal_backend_get_cal_address (CalBackend *backend); -const char *cal_backend_get_alarm_email_address (CalBackend *backend); -const char *cal_backend_get_ldap_attribute (CalBackend *backend); + void (* discard_alarm) (CalBackend *backend, Cal *cal, const char *uid, const char *auid); -const char *cal_backend_get_static_capabilities (CalBackend *backend); + void (* receive_objects) (CalBackend *backend, Cal *cal, const char *calobj); + void (* send_objects) (CalBackend *backend, Cal *cal, const char *calobj); -void cal_backend_add_cal (CalBackend *backend, Cal *cal); + void (* get_default_object) (CalBackend *backend, Cal *cal); + void (* get_object) (CalBackend *backend, Cal *cal, const char *uid, const char *rid); + void (* get_object_list) (CalBackend *backend, Cal *cal, const char *sexp); -CalBackendOpenStatus cal_backend_open (CalBackend *backend, const char *uristr, - gboolean only_if_exists); - -gboolean cal_backend_is_loaded (CalBackend *backend); - -gboolean cal_backend_is_read_only (CalBackend *backend); - -Query *cal_backend_get_query (CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp); + /* Timezone related virtual methods */ + void (* get_timezone) (CalBackend *backend, Cal *cal, const char *tzid); + void (* add_timezone) (CalBackend *backend, Cal *cal, const char *object); + void (* set_default_timezone) (CalBackend *backend, Cal *cal, const char *tzid); -CalMode cal_backend_get_mode (CalBackend *backend); -void cal_backend_set_mode (CalBackend *backend, CalMode mode); + void (* start_query) (CalBackend *backend, Query *query); -int cal_backend_get_n_objects (CalBackend *backend, CalObjType type); + /* Mode relate virtual methods */ + CalMode (* get_mode) (CalBackend *backend); + void (* set_mode) (CalBackend *backend, CalMode mode); -char *cal_backend_get_default_object (CalBackend *backend, CalObjType type); + void (* get_free_busy) (CalBackend *backend, Cal *cal, GList *users, time_t start, time_t end); + void (* get_changes) (CalBackend *backend, Cal *cal, CalObjType type, const char *change_id); -char *cal_backend_get_object (CalBackend *backend, const char *uid); + /* Internal methods for use only in the pcs */ + icaltimezone *(* internal_get_default_timezone) (CalBackend *backend); + icaltimezone *(* internal_get_timezone) (CalBackend *backend, const char *tzid); +}; -CalComponent *cal_backend_get_object_component (CalBackend *backend, const char *uid); +GType cal_backend_get_type (void); -gboolean cal_backend_set_default_timezone (CalBackend *backend, const char *tzid); +const char *cal_backend_get_uri (CalBackend *backend); +icalcomponent_kind cal_backend_get_kind (CalBackend *backend); -char *cal_backend_get_timezone_object (CalBackend *backend, const char *tzid); +void cal_backend_add_client (CalBackend *backend, Cal *cal); +void cal_backend_remove_client (CalBackend *backend, Cal *cal); -CalObjType cal_backend_get_type_by_uid (CalBackend *backend, const char *uid); +void cal_backend_add_query (CalBackend *backend, Query *query); +EList *cal_backend_get_queries (CalBackend *backend); -GList *cal_backend_get_uids (CalBackend *backend, CalObjType type); +void cal_backend_is_read_only (CalBackend *backend, Cal *cal); +void cal_backend_get_cal_address (CalBackend *backend, Cal *cal); +void cal_backend_get_alarm_email_address (CalBackend *backend, Cal *cal); +void cal_backend_get_ldap_attribute (CalBackend *backend, Cal *cal); +void cal_backend_get_static_capabilities (CalBackend *backend, Cal *cal); -GList *cal_backend_get_objects_in_range (CalBackend *backend, CalObjType type, - time_t start, time_t end); +void cal_backend_open (CalBackend *backend, Cal *cal, gboolean only_if_exists); +void cal_backend_remove (CalBackend *backend, Cal *cal); -GList *cal_backend_get_free_busy (CalBackend *backend, GList *users, time_t start, time_t end); +void cal_backend_create_object (CalBackend *backend, Cal *cal, const char *calobj); +void cal_backend_modify_object (CalBackend *backend, Cal *cal, const char *calobj, CalObjModType mod); +void cal_backend_remove_object (CalBackend *backend, Cal *cal, const char *uid, const char *rid, CalObjModType mod); -GNOME_Evolution_Calendar_CalObjChangeSeq * cal_backend_get_changes ( - CalBackend *backend, CalObjType type, const char *change_id); +void cal_backend_discard_alarm (CalBackend *backend, Cal *cal, const char *uid, const char *auid); -GNOME_Evolution_Calendar_CalComponentAlarmsSeq *cal_backend_get_alarms_in_range ( - CalBackend *backend, time_t start, time_t end, gboolean *valid_range); +void cal_backend_receive_objects (CalBackend *backend, Cal *cal, const char *calobj); +void cal_backend_send_objects (CalBackend *backend, Cal *cal, const char *calobj); -GNOME_Evolution_Calendar_CalComponentAlarms *cal_backend_get_alarms_for_object ( - CalBackend *backend, const char *uid, - time_t start, time_t end, - CalBackendGetAlarmsForObjectResult *result); +void cal_backend_get_default_object (CalBackend *backend, Cal *cal); +void cal_backend_get_object (CalBackend *backend, Cal *cal, const char *uid, const char *rid); +void cal_backend_get_object_list (CalBackend *backend, Cal *cal, const char *sexp); -CalBackendResult cal_backend_discard_alarm (CalBackend *backend, const char *uid, const char *auid); +gboolean cal_backend_is_loaded (CalBackend *backend); +void cal_backend_start_query (CalBackend *backend, Query *query); -CalBackendResult cal_backend_update_objects (CalBackend *backend, const char *calobj, CalObjModType mod); +CalMode cal_backend_get_mode (CalBackend *backend); +void cal_backend_set_mode (CalBackend *backend, CalMode mode); -CalBackendResult cal_backend_remove_object (CalBackend *backend, const char *uid, CalObjModType mod); +void cal_backend_get_timezone (CalBackend *backend, Cal *cal, const char *tzid); +void cal_backend_add_timezone (CalBackend *backend, Cal *cal, const char *object); +void cal_backend_set_default_timezone (CalBackend *backend, Cal *cal, const char *tzid); -CalBackendSendResult cal_backend_send_object (CalBackend *backend, const char *calobj, char **new_calobj, - GNOME_Evolution_Calendar_UserList **user_list, - char error_msg[256]); +void cal_backend_get_changes (CalBackend *backend, Cal *cal, CalObjType type, const char *change_id); +void cal_backend_get_free_busy (CalBackend *backend, Cal *cal, GList *users, time_t start, time_t end); -icaltimezone* cal_backend_get_timezone (CalBackend *backend, const char *tzid); -icaltimezone* cal_backend_get_default_timezone (CalBackend *backend); +icaltimezone* cal_backend_internal_get_default_timezone (CalBackend *backend); +icaltimezone* cal_backend_internal_get_timezone (CalBackend *backend, const char *tzid); void cal_backend_last_client_gone (CalBackend *backend); -void cal_backend_opened (CalBackend *backend, CalBackendOpenStatus status); -void cal_backend_obj_updated (CalBackend *backend, const char *uid); -void cal_backend_obj_removed (CalBackend *backend, const char *uid); + +/* FIXME what to do about status */ +void cal_backend_opened (CalBackend *backend, int status); +void cal_backend_removed (CalBackend *backend, int status); void cal_backend_notify_mode (CalBackend *backend, GNOME_Evolution_Calendar_Listener_SetModeStatus status, GNOME_Evolution_Calendar_CalMode mode); -void cal_backend_notify_update (CalBackend *backend, const char *uid); -void cal_backend_notify_remove (CalBackend *backend, const char *uid); void cal_backend_notify_error (CalBackend *backend, const char *message); void cal_backend_ref_categories (CalBackend *backend, GSList *categories); void cal_backend_unref_categories (CalBackend *backend, GSList *categories); diff --git a/calendar/pcs/cal-common.h b/calendar/pcs/cal-common.h index 3bf229ee8f..5a588c93c8 100644 --- a/calendar/pcs/cal-common.h +++ b/calendar/pcs/cal-common.h @@ -34,6 +34,12 @@ typedef struct _CalBackendClass CalBackendClass; typedef struct _Cal Cal; typedef struct _CalClass CalClass; +typedef struct _Query Query; +typedef struct _QueryClass QueryClass; + +typedef struct _CalBackendObjectSExp CalBackendObjectSExp; +typedef struct _CalBackendObjectSExpClass CalBackendObjectSExpClass; + G_END_DECLS diff --git a/calendar/pcs/cal-factory.c b/calendar/pcs/cal-factory.c index 48df951544..2f72ec5911 100644 --- a/calendar/pcs/cal-factory.c +++ b/calendar/pcs/cal-factory.c @@ -1,9 +1,10 @@ /* Evolution calendar factory * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000-2003 Ximian, Inc. * - * Author: Federico Mena-Quintero + * Authors: + * Federico Mena-Quintero + * JP Rosevear * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -19,16 +20,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include -#include #include +#include +#include #include "e-util/e-url.h" #include "evolution-calendar.h" -#include "cal.h" #include "cal-backend.h" +#include "cal.h" #include "cal-factory.h" -#include "job.h" #define PARENT_TYPE BONOBO_TYPE_OBJECT #define DEFAULT_CAL_FACTORY_OAF_ID "OAFIID:GNOME_Evolution_Wombat_CalendarFactory" @@ -50,13 +49,6 @@ struct _CalFactoryPrivate { guint registered : 1; }; -typedef struct -{ - CalFactory *factory; - GNOME_Evolution_Calendar_CalMode mode; - GNOME_Evolution_Calendar_StringSeq *list; -} CalFactoryUriData; - /* Signal IDs */ enum SIGNALS { LAST_CALENDAR_GONE, @@ -65,76 +57,61 @@ enum SIGNALS { static guint signals[LAST_SIGNAL]; -/* Frees a method/GType * pair from the methods hash table */ -static void -free_method (gpointer key, gpointer value, gpointer data) +/* Opening calendars */ +static icalcomponent_kind +calobjtype_to_icalkind (const GNOME_Evolution_Calendar_CalObjType type) { - char *method; - GType *type; - - method = key; - type = value; - - g_free (method); - g_free (type); + switch (type){ + case GNOME_Evolution_Calendar_TYPE_EVENT: + return ICAL_VEVENT_COMPONENT; + case GNOME_Evolution_Calendar_TYPE_TODO: + return ICAL_VTODO_COMPONENT; + case GNOME_Evolution_Calendar_TYPE_JOURNAL: + return ICAL_VJOURNAL_COMPONENT; + } + + return ICAL_NO_COMPONENT; } -/* Frees a uri/backend pair from the backends hash table */ -static void -free_backend (gpointer key, gpointer value, gpointer data) +static GType +get_backend_type (GHashTable *methods, const char *method, icalcomponent_kind kind) { - char *uri; - CalBackend *backend; + GHashTable *kinds; + GType type; + + kinds = g_hash_table_lookup (methods, method); + if (!kinds) + return 0; - uri = key; - backend = value; + type = GPOINTER_TO_INT (g_hash_table_lookup (kinds, GINT_TO_POINTER (kind))); - g_free (uri); - g_object_unref (backend); + return type; } -/* Opening calendars */ - /* Looks up a calendar backend in a factory's hash table of uri->cal. If * *non-NULL, orig_uri_return will be set to point to the original key in the * *hash table. */ static CalBackend * -lookup_backend (CalFactory *factory, const char *uristr, char **orig_uri_return) +lookup_backend (CalFactory *factory, const char *uristr) { CalFactoryPrivate *priv; EUri *uri; + CalBackend *backend; char *tmp; - gboolean found; - gpointer orig_key; - gpointer data; priv = factory->priv; uri = e_uri_new (uristr); - if (!uri) { - if (orig_uri_return) - *orig_uri_return = NULL; - + if (!uri) return NULL; - } tmp = e_uri_to_string (uri, FALSE); - found = g_hash_table_lookup_extended (priv->backends, tmp, &orig_key, &data); + backend = g_hash_table_lookup (priv->backends, tmp); g_free (tmp); e_uri_free (uri); - if (found) { - if (orig_uri_return) - *orig_uri_return = orig_key; - - return CAL_BACKEND (data); - } else { - if (orig_uri_return) - *orig_uri_return = NULL; - - return NULL; - } + return backend; } /* Callback used when a backend loses its last connected client */ @@ -145,7 +122,6 @@ backend_last_client_gone_cb (CalBackend *backend, gpointer data) CalFactoryPrivate *priv; CalBackend *ret_backend; const char *uristr; - char *orig_uristr; fprintf (stderr, "backend_last_client_gone_cb() called!\n"); @@ -157,14 +133,11 @@ backend_last_client_gone_cb (CalBackend *backend, gpointer data) uristr = cal_backend_get_uri (backend); g_assert (uristr != NULL); - ret_backend = lookup_backend (factory, uristr, &orig_uristr); + ret_backend = lookup_backend (factory, uristr); g_assert (ret_backend != NULL); g_assert (ret_backend == backend); - g_hash_table_remove (priv->backends, orig_uristr); - g_free (orig_uristr); - - g_object_unref (backend); + g_hash_table_remove (priv->backends, uristr); /* Notify upstream if there are no more backends */ @@ -172,405 +145,92 @@ backend_last_client_gone_cb (CalBackend *backend, gpointer data) g_signal_emit (G_OBJECT (factory), signals[LAST_CALENDAR_GONE], 0); } -/* Adds a backend to the calendar factory's hash table */ -static void -add_backend (CalFactory *factory, const char *uristr, CalBackend *backend) -{ - CalFactoryPrivate *priv; - EUri *uri; - char *tmp; - - priv = factory->priv; - - uri = e_uri_new (uristr); - if (!uri) - return; - - tmp = e_uri_to_string (uri, FALSE); - g_hash_table_insert (priv->backends, tmp, backend); - e_uri_free (uri); - - g_signal_connect (G_OBJECT (backend), "last_client_gone", - G_CALLBACK (backend_last_client_gone_cb), - factory); -} - -/* Tries to launch a backend for the method of the specified URI. If there is - * no such method registered in the factory, it sends the listener the - * MethodNotSupported error code. - */ -static CalBackend * -launch_backend_for_uri (CalFactory *factory, - const char *uristr, - GNOME_Evolution_Calendar_Listener listener) -{ - CalFactoryPrivate *priv; - const char *method; - GType *type; - CalBackend *backend; - EUri *uri; - - priv = factory->priv; - - uri = e_uri_new (uristr); - if (!uri) - return NULL; - - method = uri->protocol; - type = g_hash_table_lookup (priv->methods, method); - e_uri_free (uri); - - if (!type) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyCalOpened ( - listener, - GNOME_Evolution_Calendar_Listener_METHOD_NOT_SUPPORTED, - CORBA_OBJECT_NIL, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("launch_backend_for_uri(): could not notify the listener"); - - CORBA_exception_free (&ev); - return NULL; - } - - backend = g_object_new (*type, NULL); - if (!backend) - g_message ("launch_backend_for_uri(): could not launch the backend"); - - return backend; -} - -/* Opens a calendar backend and puts it in the factory's backend hash table */ -static CalBackend * -open_backend (CalFactory *factory, const char *uristr, gboolean only_if_exists, - GNOME_Evolution_Calendar_Listener listener) -{ - CalFactoryPrivate *priv; - CalBackend *backend; - CalBackendOpenStatus status; - CORBA_Environment ev; - - priv = factory->priv; - - backend = launch_backend_for_uri (factory, uristr, listener); - if (!backend) - return NULL; - - status = cal_backend_open (backend, uristr, only_if_exists); - - switch (status) { - case CAL_BACKEND_OPEN_SUCCESS: - add_backend (factory, uristr, backend); - return backend; - - case CAL_BACKEND_OPEN_ERROR: - g_object_unref (backend); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyCalOpened ( - listener, - GNOME_Evolution_Calendar_Listener_ERROR, - CORBA_OBJECT_NIL, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("open_backend(): could not notify the listener"); - - CORBA_exception_free (&ev); - return NULL; - - case CAL_BACKEND_OPEN_NOT_FOUND: - g_object_unref (backend); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyCalOpened ( - listener, - GNOME_Evolution_Calendar_Listener_NOT_FOUND, - CORBA_OBJECT_NIL, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("open_backend(): could not notify the listener"); - - CORBA_exception_free (&ev); - return NULL; - - case CAL_BACKEND_OPEN_PERMISSION_DENIED : - g_object_unref (backend); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyCalOpened ( - listener, - GNOME_Evolution_Calendar_Listener_PERMISSION_DENIED, - CORBA_OBJECT_NIL, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("open_backend(): could not notify the listener"); - - CORBA_exception_free (&ev); - return NULL; - - default: - g_assert_not_reached (); - return NULL; - } -} - -/* Adds a listener to a calendar backend by creating a calendar client interface - * object. - */ -static void -add_calendar_client (CalFactory *factory, - CalBackend *backend, - GNOME_Evolution_Calendar_Listener listener) -{ - Cal *cal; - CORBA_Environment ev; - - cal = cal_new (backend, listener); - if (!cal) { - g_message ("add_calendar_client(): could not create the calendar client interface"); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyCalOpened ( - listener, - GNOME_Evolution_Calendar_Listener_ERROR, - CORBA_OBJECT_NIL, - &ev); - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("add_calendar_client(): could not notify the listener"); - - CORBA_exception_free (&ev); - return; - } - - cal_backend_add_cal (backend, cal); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyCalOpened ( - listener, - GNOME_Evolution_Calendar_Listener_SUCCESS, - BONOBO_OBJREF (cal), - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_message ("add_calendar_client(): could not notify the listener"); - bonobo_object_unref (BONOBO_OBJECT (cal)); - } - - CORBA_exception_free (&ev); -} - -/* Add a uri to a string list */ -static void -add_uri (gpointer key, gpointer value, gpointer data) -{ - CalFactoryUriData *cfud = data; - CalFactory *factory = cfud->factory; - GNOME_Evolution_Calendar_StringSeq *list = cfud->list; - GNOME_Evolution_Calendar_CalMode mode = cfud->mode; - char *uri_string = key; - CalBackend *backend; - - switch (mode) { - case GNOME_Evolution_Calendar_MODE_LOCAL: - backend = lookup_backend (factory, uri_string, NULL); - if (backend == NULL || cal_backend_get_mode (backend) != CAL_MODE_LOCAL) - return; - break; - case GNOME_Evolution_Calendar_MODE_REMOTE: - backend = lookup_backend (factory, uri_string, NULL); - if (backend == NULL || cal_backend_get_mode (backend) != CAL_MODE_REMOTE) - return; - break; - case GNOME_Evolution_Calendar_MODE_ANY: - break; - } - - list->_buffer[list->_length] = CORBA_string_dup (uri_string); - list->_length++; -} - -/* Job data */ -typedef struct { - CalFactory *factory; - char *uri; - gboolean only_if_exists; - GNOME_Evolution_Calendar_Listener listener; -} OpenJobData; - -/* Job handler for the open calendar command */ -static void -open_fn (gpointer data) -{ - OpenJobData *jd; - CalFactory *factory; - gboolean only_if_exists; - GNOME_Evolution_Calendar_Listener listener; - CalBackend *backend; - CORBA_Environment ev; - char *uri_string; - - jd = data; - g_assert (jd->uri != NULL); - - /* Check the URI */ - uri_string = g_strdup (jd->uri); - g_free (jd->uri); - - only_if_exists = jd->only_if_exists; - factory = jd->factory; - listener = jd->listener; - g_free (jd); - - if (!uri_string) { - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyCalOpened ( - listener, - GNOME_Evolution_Calendar_Listener_ERROR, - CORBA_OBJECT_NIL, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("open_fn(): Could not notify the listener!"); - - CORBA_exception_free (&ev); - goto out; - } - - /* Look up the backend and create it if needed */ - - backend = lookup_backend (factory, uri_string, NULL); - - if (!backend) - backend = open_backend (factory, uri_string, only_if_exists, listener); - - g_free (uri_string); - - if (backend) - add_calendar_client (factory, backend, listener); - - out: - - CORBA_exception_init (&ev); - CORBA_Object_release (listener, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("open_fn(): could not release the listener"); - - CORBA_exception_free (&ev); -} - -static void -impl_CalFactory_open (PortableServer_Servant servant, - const CORBA_char *str_uri, - CORBA_boolean only_if_exists, - GNOME_Evolution_Calendar_Listener listener, - CORBA_Environment *ev) +static GNOME_Evolution_Calendar_Cal +impl_CalFactory_getCal (PortableServer_Servant servant, + const CORBA_char *str_uri, + const GNOME_Evolution_Calendar_CalObjType type, + const GNOME_Evolution_Calendar_Listener listener, + CORBA_Environment *ev) { CalFactory *factory; CalFactoryPrivate *priv; + Cal *cal = CORBA_OBJECT_NIL; + CalBackend *backend; CORBA_Environment ev2; - gboolean result; - OpenJobData *jd; GNOME_Evolution_Calendar_Listener listener_copy; - GType *type; + GType backend_type; EUri *uri; - + char *uri_string; + factory = CAL_FACTORY (bonobo_object_from_servant (servant)); priv = factory->priv; - /* check URI to see if we support it */ - + /* Parse the uri */ uri = e_uri_new (str_uri); if (!uri) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_CalFactory_InvalidURI, - NULL); - return; - } - - type = g_hash_table_lookup (priv->methods, uri->protocol); + bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_InvalidURI); - e_uri_free (uri); - if (!type) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_CalFactory_UnsupportedMethod, - NULL); - return; + return CORBA_OBJECT_NIL; } - - /* duplicate the listener object */ - CORBA_exception_init (&ev2); - result = CORBA_Object_is_nil (listener, &ev2); - - if (ev2._major != CORBA_NO_EXCEPTION || result) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_CalFactory_NilListener, - NULL); - - CORBA_exception_free (&ev2); - return; + uri_string = e_uri_to_string (uri, FALSE); + + /* Find the associated backend type (if any) */ + backend_type = get_backend_type (priv->methods, uri->protocol, calobjtype_to_icalkind (type)); + if (!backend_type) { + /* FIXME Distinguish between method and kind failures? */ + bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_UnsupportedMethod); + goto cleanup; } - CORBA_exception_free (&ev2); - + + /* Duplicate the listener object */ CORBA_exception_init (&ev2); listener_copy = CORBA_Object_duplicate (listener, &ev2); - if (ev2._major != CORBA_NO_EXCEPTION) { - g_message ("CalFactory_open(): could not duplicate the listener"); + if (BONOBO_EX (&ev2)) { + g_warning (G_STRLOC ": could not duplicate the listener"); + bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_NilListener); CORBA_exception_free (&ev2); - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_GNOME_Evolution_Calendar_CalFactory_NilListener, - NULL); - return; + goto cleanup; } - CORBA_exception_free (&ev2); - /* add new asynchronous job */ - jd = g_new (OpenJobData, 1); - jd->factory = factory; - jd->uri = g_strdup (str_uri); - jd->only_if_exists = only_if_exists; - jd->listener = listener_copy; - - job_add (open_fn, jd); -} - -static GNOME_Evolution_Calendar_StringSeq * -impl_CalFactory_uriList (PortableServer_Servant servant, - GNOME_Evolution_Calendar_CalMode mode, - CORBA_Environment *ev) -{ - CalFactory *factory; - CalFactoryPrivate *priv; - CalFactoryUriData cfud; - GNOME_Evolution_Calendar_StringSeq *list; - - factory = CAL_FACTORY (bonobo_object_from_servant (servant)); - priv = factory->priv; - - list = GNOME_Evolution_Calendar_StringSeq__alloc (); - CORBA_sequence_set_release (list, TRUE); - list->_length = 0; - list->_maximum = g_hash_table_size (priv->backends); - list->_buffer = CORBA_sequence_CORBA_string_allocbuf (list->_maximum); + /* Look for an existing backend */ + backend = lookup_backend (factory, uri_string); + if (!backend) { + /* There was no existing backend, create a new one */ + backend = g_object_new (backend_type, "uri", uri_string, "kind", calobjtype_to_icalkind (type), NULL); + if (!backend) { + g_warning (G_STRLOC ": could not instantiate backend"); + bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_UnsupportedMethod); + goto cleanup; + } + + /* Track the backend */ + g_hash_table_insert (priv->backends, g_strdup (uri_string), backend); + + g_signal_connect (G_OBJECT (backend), "last_client_gone", + G_CALLBACK (backend_last_client_gone_cb), + factory); + } + + /* Create the corba calendar */ + cal = cal_new (backend, uri_string, listener); + if (!cal) { + g_warning (G_STRLOC ": could not create the corba calendar"); + bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_UnsupportedMethod); + goto cleanup; + } - cfud.factory = factory; - cfud.mode = mode; - cfud.list = list; - g_hash_table_foreach (priv->backends, add_uri, &cfud); + /* Let the backend know about its clients corba clients */ + cal_backend_add_client (backend, cal); - return list; + cleanup: + e_uri_free (uri); + g_free (uri_string); + return CORBA_Object_duplicate (BONOBO_OBJREF (cal), ev); } @@ -589,7 +249,9 @@ cal_factory_new (void) { CalFactory *factory; - factory = g_object_new (CAL_FACTORY_TYPE, NULL); + factory = g_object_new (CAL_FACTORY_TYPE, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL), + NULL); return factory; } @@ -607,13 +269,10 @@ cal_factory_finalize (GObject *object) factory = CAL_FACTORY (object); priv = factory->priv; - g_hash_table_foreach (priv->methods, free_method, NULL); g_hash_table_destroy (priv->methods); priv->methods = NULL; /* Should we assert that there are no more backends? */ - - g_hash_table_foreach (priv->backends, free_backend, NULL); g_hash_table_destroy (priv->backends); priv->backends = NULL; @@ -652,8 +311,7 @@ cal_factory_class_init (CalFactoryClass *klass) object_class->finalize = cal_factory_finalize; /* Epv methods */ - epv->open = impl_CalFactory_open; - epv->uriList = impl_CalFactory_uriList; + epv->getCal = impl_CalFactory_getCal; } /* Object initialization function for the calendar factory */ @@ -665,8 +323,10 @@ cal_factory_init (CalFactory *factory, CalFactoryClass *klass) priv = g_new0 (CalFactoryPrivate, 1); factory->priv = priv; - priv->methods = g_hash_table_new (g_str_hash, g_str_equal); - priv->backends = g_hash_table_new (g_str_hash, g_str_equal); + priv->methods = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, (GDestroyNotify) g_hash_table_destroy); + priv->backends = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); priv->registered = FALSE; } @@ -675,23 +335,8 @@ BONOBO_TYPE_FUNC_FULL (CalFactory, PARENT_TYPE, cal_factory); -/* Returns the lowercase version of a string */ -static char * -str_tolower (const char *s) -{ - char *str; - unsigned char *p; - - str = g_strdup (s); - for (p = str; *p; p++) - if (isalpha (*p)) - *p = tolower (*p); - - return str; -} - /** - * cal_factory_oaf_register: + * cal_factory_register_storage: * @factory: A calendar factory. * @iid: OAFIID for the factory to be registered. * @@ -701,7 +346,7 @@ str_tolower (const char *s) * Return value: TRUE on success, FALSE otherwise. **/ gboolean -cal_factory_oaf_register (CalFactory *factory, const char *iid) +cal_factory_register_storage (CalFactory *factory, const char *iid) { CalFactoryPrivate *priv; Bonobo_RegistrationResult result; @@ -729,19 +374,16 @@ cal_factory_oaf_register (CalFactory *factory, const char *iid) return TRUE; case Bonobo_ACTIVATION_REG_NOT_LISTED: - g_message ("cal_factory_oaf_register(): Cannot register the calendar factory: " - "not listed"); + g_warning (G_STRLOC ": cannot register the calendar factory (not listed)"); break; case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE: - g_message ("cal_factory_oaf_register(): Cannot register the calendar factory: " - "already active"); + g_warning (G_STRLOC ": cannot register the calendar factory (already active)"); break; case Bonobo_ACTIVATION_REG_ERROR: default: - g_message ("cal_factory_oaf_register(): Cannot register the calendar factory: " - "generic error"); + g_warning (G_STRLOC ": cannot register the calendar factory (generic error)"); break; } @@ -762,12 +404,13 @@ cal_factory_oaf_register (CalFactory *factory, const char *iid) * the appropriate type. **/ void -cal_factory_register_method (CalFactory *factory, const char *method, GType backend_type) +cal_factory_register_method (CalFactory *factory, const char *method, icalcomponent_kind kind, GType backend_type) { CalFactoryPrivate *priv; - GType *type; char *method_str; - + GHashTable *kinds; + GType type; + g_return_if_fail (factory != NULL); g_return_if_fail (IS_CAL_FACTORY (factory)); g_return_if_fail (method != NULL); @@ -776,37 +419,39 @@ cal_factory_register_method (CalFactory *factory, const char *method, GType back priv = factory->priv; - method_str = str_tolower (method); - - type = g_hash_table_lookup (priv->methods, method_str); - if (type) { - g_message ("cal_factory_register_method(): Method `%s' already registered!", - method_str); - g_free (method_str); - return; - } + method_str = g_ascii_strdown (method, -1); - type = g_new (GType, 1); - *type = backend_type; + kinds = g_hash_table_lookup (priv->methods, method_str); + if (kinds) { + type = GPOINTER_TO_INT (g_hash_table_lookup (kinds, GINT_TO_POINTER (kind))); + if (type) { + g_warning (G_STRLOC ": method `%s' already registered", method_str); + g_free (method_str); - g_hash_table_insert (priv->methods, method_str, type); + return; + } + } else { + kinds = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); + g_hash_table_insert (priv->methods, method_str, kinds); + } + + g_hash_table_insert (kinds, GINT_TO_POINTER (kind), GINT_TO_POINTER (backend_type)); } /** - * cal_factory_get_n_backends: + * cal_factory_get_n_backends * @factory: A calendar factory. - * - * Queries the number of running calendar backends in a calendar factory. - * - * Return value: Number of running backends. - **/ + * + * Get the number of backends currently active in the given factory. + * + * Returns: the number of backends. + */ int cal_factory_get_n_backends (CalFactory *factory) { CalFactoryPrivate *priv; - g_return_val_if_fail (factory != NULL, -1); - g_return_val_if_fail (IS_CAL_FACTORY (factory), -1); + g_return_val_if_fail (IS_CAL_FACTORY (factory), 0); priv = factory->priv; return g_hash_table_size (priv->backends); diff --git a/calendar/pcs/cal-factory.h b/calendar/pcs/cal-factory.h index b7c370066b..d6d2b895ed 100644 --- a/calendar/pcs/cal-factory.h +++ b/calendar/pcs/cal-factory.h @@ -22,6 +22,7 @@ #define CAL_FACTORY_H #include +#include #include "pcs/evolution-calendar.h" @@ -60,11 +61,12 @@ struct _CalFactoryClass { GType cal_factory_get_type (void); CalFactory *cal_factory_new (void); -gboolean cal_factory_oaf_register (CalFactory *factory, const char *iid); -void cal_factory_register_method (CalFactory *factory, - const char *method, - GType backend_type); -int cal_factory_get_n_backends (CalFactory *factory); +gboolean cal_factory_register_storage (CalFactory *factory, const char *iid); +void cal_factory_register_method (CalFactory *factory, + const char *method, + icalcomponent_kind kind, + GType backend_type); +int cal_factory_get_n_backends (CalFactory *factory); void cal_factory_dump_active_backends (CalFactory *factory); G_END_DECLS diff --git a/calendar/pcs/cal.c b/calendar/pcs/cal.c index 0f20d88186..a88e9a146c 100644 --- a/calendar/pcs/cal.c +++ b/calendar/pcs/cal.c @@ -25,10 +25,10 @@ #endif #include +#include #include -#include "cal.h" #include "cal-backend.h" -#include "query.h" +#include "cal.h" #define PARENT_TYPE BONOBO_TYPE_OBJECT @@ -43,7 +43,6 @@ struct _CalPrivate { GNOME_Evolution_Calendar_Listener listener; }; - /* Cal::get_uri method */ static CORBA_char * impl_Cal_get_uri (PortableServer_Servant servant, @@ -63,8 +62,35 @@ impl_Cal_get_uri (PortableServer_Servant servant, return str_uri_copy; } +static void +impl_Cal_open (PortableServer_Servant servant, + CORBA_boolean only_if_exists, + CORBA_Environment *ev) +{ + Cal *cal; + CalPrivate *priv; + + cal = CAL (bonobo_object_from_servant (servant)); + priv = cal->priv; + + cal_backend_open (priv->backend, cal, only_if_exists); +} + +static void +impl_Cal_remove (PortableServer_Servant servant, + CORBA_Environment *ev) +{ + Cal *cal; + CalPrivate *priv; + + cal = CAL (bonobo_object_from_servant (servant)); + priv = cal->priv; + + cal_backend_remove (priv->backend, cal); +} + /* Cal::isReadOnly method */ -static CORBA_boolean +static void impl_Cal_isReadOnly (PortableServer_Servant servant, CORBA_Environment *ev) { @@ -74,109 +100,63 @@ impl_Cal_isReadOnly (PortableServer_Servant servant, cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - return cal_backend_is_read_only (priv->backend); + cal_backend_is_read_only (priv->backend, cal); } /* Cal::getEmailAddress method */ -static CORBA_char * +static void impl_Cal_getCalAddress (PortableServer_Servant servant, - CORBA_Environment *ev) + CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - const char *str_cal_address; - CORBA_char *str_cal_address_copy; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - str_cal_address = cal_backend_get_cal_address (priv->backend); - if (str_cal_address == NULL) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - return CORBA_OBJECT_NIL; - } - - str_cal_address_copy = CORBA_string_dup (str_cal_address); - - return str_cal_address_copy; + cal_backend_get_cal_address (priv->backend, cal); } /* Cal::get_alarm_email_address method */ -static CORBA_char * +static void impl_Cal_getAlarmEmailAddress (PortableServer_Servant servant, CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - const char *str_email_address; - CORBA_char *str_email_address_copy; - + cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - - str_email_address = cal_backend_get_alarm_email_address (priv->backend); - if (str_email_address == NULL) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - return CORBA_OBJECT_NIL; - } - str_email_address_copy = CORBA_string_dup (str_email_address); - - return str_email_address_copy; + cal_backend_get_alarm_email_address (priv->backend, cal); } /* Cal::get_ldap_attribute method */ -static CORBA_char * +static void impl_Cal_getLdapAttribute (PortableServer_Servant servant, CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - const char *str_ldap_attr; - CORBA_char *str_ldap_attr_copy; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - str_ldap_attr = cal_backend_get_ldap_attribute (priv->backend); - if (str_ldap_attr == NULL) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - return CORBA_OBJECT_NIL; - } - - str_ldap_attr_copy = CORBA_string_dup (str_ldap_attr); - - return str_ldap_attr_copy; + cal_backend_get_ldap_attribute (priv->backend, cal); } /* Cal::getSchedulingInformation method */ -static CORBA_char * +static void impl_Cal_getStaticCapabilities (PortableServer_Servant servant, CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - const char *cap; - CORBA_char *cap_copy; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - cap = cal_backend_get_static_capabilities (priv->backend); - cap_copy = CORBA_string_dup (cap == NULL ? "" : cap); - - return cap_copy; -} - -/* Converts a calendar object type from its CORBA representation to our own - * representation. - */ -static CalObjType -uncorba_obj_type (GNOME_Evolution_Calendar_CalObjType type) -{ - return (((type & GNOME_Evolution_Calendar_TYPE_EVENT) ? CALOBJ_TYPE_EVENT : 0) - | ((type & GNOME_Evolution_Calendar_TYPE_TODO) ? CALOBJ_TYPE_TODO : 0) - | ((type & GNOME_Evolution_Calendar_TYPE_JOURNAL) ? CALOBJ_TYPE_JOURNAL : 0)); + cal_backend_get_static_capabilities (priv->backend, cal); } /* Cal::setMode method */ @@ -194,208 +174,68 @@ impl_Cal_setMode (PortableServer_Servant servant, cal_backend_set_mode (priv->backend, mode); } -/* Cal::countObjects method */ -static CORBA_long -impl_Cal_countObjects (PortableServer_Servant servant, - GNOME_Evolution_Calendar_CalObjType type, - CORBA_Environment *ev) -{ - Cal *cal; - CalPrivate *priv; - int t; - int n; - - cal = CAL (bonobo_object_from_servant (servant)); - priv = cal->priv; - - t = uncorba_obj_type (type); - n = cal_backend_get_n_objects (priv->backend, t); - return n; -} - -static GNOME_Evolution_Calendar_CalObj +static void impl_Cal_getDefaultObject (PortableServer_Servant servant, - GNOME_Evolution_Calendar_CalObjType type, - CORBA_Environment *ev) + CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - GNOME_Evolution_Calendar_CalObj calobj_copy; - char *calobj; - cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - calobj = cal_backend_get_default_object (priv->backend, type); - calobj_copy = CORBA_string_dup (calobj); - g_free (calobj); - - return calobj_copy; + cal_backend_get_default_object (priv->backend, cal); } /* Cal::getObject method */ -static GNOME_Evolution_Calendar_CalObj +static void impl_Cal_getObject (PortableServer_Servant servant, const CORBA_char *uid, + const CORBA_char *rid, CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - char *calobj; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - calobj = cal_backend_get_object (priv->backend, uid); - - if (calobj) { - CORBA_char *calobj_copy; - - calobj_copy = CORBA_string_dup (calobj); - g_free (calobj); - return calobj_copy; - } else { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - - return NULL; - } -} - -static GNOME_Evolution_Calendar_CalObjUIDSeq * -build_uid_seq (GList *uids) -{ - GNOME_Evolution_Calendar_CalObjUIDSeq *seq; - GList *l; - int n, i; - - n = g_list_length (uids); - - seq = GNOME_Evolution_Calendar_CalObjUIDSeq__alloc (); - CORBA_sequence_set_release (seq, TRUE); - seq->_length = n; - seq->_buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalObjUID_allocbuf (n); - - /* Fill the sequence */ - - for (i = 0, l = uids; l; i++, l = l->next) { - char *uid; - - uid = l->data; - seq->_buffer[i] = CORBA_string_dup (uid); - } - - return seq; + cal_backend_get_object (priv->backend, cal, uid, rid); } -/* Cal::getUIDs method */ -static GNOME_Evolution_Calendar_CalObjUIDSeq * -impl_Cal_getUIDs (PortableServer_Servant servant, - GNOME_Evolution_Calendar_CalObjType type, - CORBA_Environment *ev) +/* Cal::getObjectsInRange method */ +static void +impl_Cal_getObjectList (PortableServer_Servant servant, + const CORBA_char *query, + CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - GList *uids; - GNOME_Evolution_Calendar_CalObjUIDSeq *seq; - int t; - + cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - t = uncorba_obj_type (type); - - uids = cal_backend_get_uids (priv->backend, t); - seq = build_uid_seq (uids); - - cal_obj_uid_list_free (uids); - - return seq; + cal_backend_get_object_list (priv->backend, cal, query); } /* Cal::getChanges method */ -static GNOME_Evolution_Calendar_CalObjChangeSeq * +static void impl_Cal_getChanges (PortableServer_Servant servant, GNOME_Evolution_Calendar_CalObjType type, const CORBA_char *change_id, CORBA_Environment *ev) { - Cal *cal; - CalPrivate *priv; - int t; - - cal = CAL (bonobo_object_from_servant (servant)); - priv = cal->priv; - - t = uncorba_obj_type (type); - - return cal_backend_get_changes (priv->backend, t, change_id); -} - -/* Cal::getObjectsInRange method */ -static GNOME_Evolution_Calendar_CalObjUIDSeq * -impl_Cal_getObjectsInRange (PortableServer_Servant servant, - GNOME_Evolution_Calendar_CalObjType type, - GNOME_Evolution_Calendar_Time_t start, - GNOME_Evolution_Calendar_Time_t end, - CORBA_Environment *ev) -{ - Cal *cal; - CalPrivate *priv; - int t; - time_t t_start, t_end; - GNOME_Evolution_Calendar_CalObjUIDSeq *seq; - GList *uids; - - cal = CAL (bonobo_object_from_servant (servant)); - priv = cal->priv; - - t = uncorba_obj_type (type); - t_start = (time_t) start; - t_end = (time_t) end; - - if (t_start > t_end || t_start == -1 || t_end == -1) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_InvalidRange); - return NULL; - } - - uids = cal_backend_get_objects_in_range (priv->backend, t, t_start, t_end); - seq = build_uid_seq (uids); - - cal_obj_uid_list_free (uids); - - return seq; -} - -static GNOME_Evolution_Calendar_CalObjSeq * -build_fb_seq (GList *obj_list) -{ - GNOME_Evolution_Calendar_CalObjSeq *seq; - GList *l; - int n, i; - - n = g_list_length (obj_list); - - seq = GNOME_Evolution_Calendar_CalObjSeq__alloc (); - CORBA_sequence_set_release (seq, TRUE); - seq->_maximum = n; - seq->_length = n; - seq->_buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalObj_allocbuf (n); + Cal *cal; + CalPrivate *priv; - /* Fill the sequence */ + cal = CAL (bonobo_object_from_servant (servant)); + priv = cal->priv; - for (i = 0, l = obj_list; l; i++, l = l->next) { - char *calobj; - - calobj = l->data; - seq->_buffer[i] = CORBA_string_dup (calobj); - } - - return seq; + cal_backend_get_changes (priv->backend, cal, type, change_id); } /* Cal::getFreeBusy method */ -static GNOME_Evolution_Calendar_CalObjSeq * +static void impl_Cal_getFreeBusy (PortableServer_Servant servant, const GNOME_Evolution_Calendar_UserList *user_list, const GNOME_Evolution_Calendar_Time_t start, @@ -404,22 +244,11 @@ impl_Cal_getFreeBusy (PortableServer_Servant servant, { Cal *cal; CalPrivate *priv; - time_t t_start, t_end; GList *users = NULL; - GList *obj_list; - GNOME_Evolution_Calendar_CalObjSeq *seq; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - t_start = (time_t) start; - t_end = (time_t) end; - - if (t_start > t_end || t_start == -1 || t_end == -1) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_InvalidRange); - return build_fb_seq (NULL); - } - /* convert the CORBA user list to a GList */ if (user_list) { int i; @@ -429,297 +258,181 @@ impl_Cal_getFreeBusy (PortableServer_Servant servant, } /* call the backend's get_free_busy method */ - obj_list = cal_backend_get_free_busy (priv->backend, users, t_start, t_end); - seq = build_fb_seq (obj_list); - g_list_free (users); - - if (obj_list == NULL) - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - - return seq; + cal_backend_get_free_busy (priv->backend, cal, users, start, end); } -/* Cal::getAlarmsInRange method */ -static GNOME_Evolution_Calendar_CalComponentAlarmsSeq * -impl_Cal_getAlarmsInRange (PortableServer_Servant servant, - GNOME_Evolution_Calendar_Time_t start, - GNOME_Evolution_Calendar_Time_t end, - CORBA_Environment *ev) +/* Cal::discardAlarm method */ +static void +impl_Cal_discardAlarm (PortableServer_Servant servant, + const CORBA_char *uid, + const CORBA_char *auid, + CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - time_t t_start, t_end; - gboolean valid_range; - GNOME_Evolution_Calendar_CalComponentAlarmsSeq *seq; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - t_start = (time_t) start; - t_end = (time_t) end; - - seq = cal_backend_get_alarms_in_range (priv->backend, t_start, t_end, &valid_range); - if (!valid_range) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_InvalidRange); - return NULL; - } - - if (!seq) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - return NULL; - } - - return seq; + cal_backend_discard_alarm (priv->backend, cal, uid, auid); } -/* Cal::getAlarmsForObject method */ -static GNOME_Evolution_Calendar_CalComponentAlarms * -impl_Cal_getAlarmsForObject (PortableServer_Servant servant, - const CORBA_char *uid, - GNOME_Evolution_Calendar_Time_t start, - GNOME_Evolution_Calendar_Time_t end, - CORBA_Environment * ev) +static void +impl_Cal_createObject (PortableServer_Servant servant, + const CORBA_char *calobj, + CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - time_t t_start, t_end; - GNOME_Evolution_Calendar_CalComponentAlarms *alarms; - CalBackendGetAlarmsForObjectResult result; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - t_start = (time_t) start; - t_end = (time_t) end; - - alarms = cal_backend_get_alarms_for_object (priv->backend, uid, t_start, t_end, &result); - - switch (result) { - case CAL_BACKEND_GET_ALARMS_SUCCESS: - return alarms; - - case CAL_BACKEND_GET_ALARMS_NOT_FOUND: - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - return NULL; - - case CAL_BACKEND_GET_ALARMS_INVALID_RANGE: - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_InvalidRange); - return NULL; - - default: - g_assert_not_reached (); - return NULL; - } + cal_backend_create_object (priv->backend, cal, calobj); } -/* Cal::discardAlarm method */ static void -impl_Cal_discardAlarm (PortableServer_Servant servant, - const CORBA_char *uid, - const CORBA_char *auid, +impl_Cal_modifyObject (PortableServer_Servant servant, + const CORBA_char *calobj, + const GNOME_Evolution_Calendar_CalObjModType mod, CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - CalBackendResult result; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - result = cal_backend_discard_alarm (priv->backend, uid, auid); - if (result == CAL_BACKEND_RESULT_NOT_FOUND) - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); + cal_backend_modify_object (priv->backend, cal, calobj, mod); } -/* Cal::updateObjects method */ +/* Cal::removeObject method */ static void -impl_Cal_updateObjects (PortableServer_Servant servant, - const CORBA_char *calobj, - const GNOME_Evolution_Calendar_CalObjModType mod, - CORBA_Environment *ev) +impl_Cal_removeObject (PortableServer_Servant servant, + const CORBA_char *uid, + const CORBA_char *rid, + const GNOME_Evolution_Calendar_CalObjModType mod, + CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - CalBackendResult result; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - result = cal_backend_update_objects (priv->backend, calobj, mod); - switch (result) { - case CAL_BACKEND_RESULT_INVALID_OBJECT : - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject); - break; - case CAL_BACKEND_RESULT_NOT_FOUND : - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - break; - case CAL_BACKEND_RESULT_PERMISSION_DENIED : - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_PermissionDenied); - break; - default : - break; - } + cal_backend_remove_object (priv->backend, cal, uid, rid, mod); } -/* Cal::removeObject method */ static void -impl_Cal_removeObject (PortableServer_Servant servant, - const CORBA_char *uid, - const GNOME_Evolution_Calendar_CalObjModType mod, - CORBA_Environment *ev) +impl_Cal_receiveObjects (PortableServer_Servant servant, const CORBA_char *calobj, CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - CalBackendResult result; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - result = cal_backend_remove_object (priv->backend, uid, mod); - switch (result) { - case CAL_BACKEND_RESULT_INVALID_OBJECT : - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject); - break; - case CAL_BACKEND_RESULT_NOT_FOUND : - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - break; - case CAL_BACKEND_RESULT_PERMISSION_DENIED : - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_PermissionDenied); - break; - default : - break; - } + cal_backend_receive_objects (priv->backend, cal, calobj); } -/* Cal::sendObject method */ -static GNOME_Evolution_Calendar_CalObj -impl_Cal_sendObject (PortableServer_Servant servant, - const CORBA_char *calobj, - GNOME_Evolution_Calendar_UserList **user_list, - CORBA_Environment *ev) +static void +impl_Cal_sendObjects (PortableServer_Servant servant, const CORBA_char *calobj, CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - CORBA_char *calobj_copy; - char *new_calobj; - GNOME_Evolution_Calendar_Cal_Busy *err; - CalBackendSendResult result; - char error_msg[256]; - + cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - result = cal_backend_send_object (priv->backend, calobj, &new_calobj, user_list, error_msg); - switch (result) { - case CAL_BACKEND_SEND_SUCCESS: - calobj_copy = CORBA_string_dup (new_calobj); - g_free (new_calobj); - - return calobj_copy; - - case CAL_BACKEND_SEND_INVALID_OBJECT: - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject); - break; - - case CAL_BACKEND_SEND_BUSY: - err = GNOME_Evolution_Calendar_Cal_Busy__alloc (); - err->errorMsg = CORBA_string_dup (error_msg); - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, ex_GNOME_Evolution_Calendar_Cal_Busy, err); - break; - - case CAL_BACKEND_SEND_PERMISSION_DENIED: - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_PermissionDenied); - break; - - default : - g_assert_not_reached (); - } - - return NULL; + cal_backend_send_objects (priv->backend, cal, calobj); } /* Cal::getQuery implementation */ -static GNOME_Evolution_Calendar_Query +static void impl_Cal_getQuery (PortableServer_Servant servant, const CORBA_char *sexp, GNOME_Evolution_Calendar_QueryListener ql, CORBA_Environment *ev) { + Cal *cal; CalPrivate *priv; Query *query; - CORBA_Environment ev2; - GNOME_Evolution_Calendar_Query query_copy; - + CalBackendObjectSExp *obj_sexp; + cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - query = cal_backend_get_query (priv->backend, ql, sexp); - if (!query) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_CouldNotCreate); - return CORBA_OBJECT_NIL; + /* we handle this entirely here, since it doesn't require any + backend involvement now that we have pas_book_view_start to + actually kick off the search. */ + + obj_sexp = cal_backend_object_sexp_new (sexp); + if (!obj_sexp) { + cal_notify_query (cal, GNOME_Evolution_Calendar_InvalidQuery, NULL); + + return; } - CORBA_exception_init (&ev2); - query_copy = CORBA_Object_duplicate (BONOBO_OBJREF (query), &ev2); - if (BONOBO_EX (&ev2)) { - bonobo_object_unref (query); - CORBA_exception_free (&ev2); - g_message ("Cal_get_query(): Could not duplicate the query reference"); - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_CouldNotCreate); - return CORBA_OBJECT_NIL; + query = query_new (priv->backend, ql, obj_sexp); + if (!query) { + g_object_unref (obj_sexp); + cal_notify_query (cal, GNOME_Evolution_Calendar_OtherError, NULL); + + return; } - CORBA_exception_free (&ev2); + cal_backend_add_query (priv->backend, query); - return query_copy; + cal_notify_query (cal, GNOME_Evolution_Calendar_Success, query); + + g_object_unref (query); } -/* Cal::setDefaultTimezone method */ + +/* Cal::getTimezone method */ static void -impl_Cal_setDefaultTimezone (PortableServer_Servant servant, - const CORBA_char *tzid, - CORBA_Environment *ev) +impl_Cal_getTimezone (PortableServer_Servant servant, + const CORBA_char *tzid, + CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - gboolean zone_set; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - zone_set = cal_backend_set_default_timezone (priv->backend, tzid); - - if (!zone_set) { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - } + cal_backend_get_timezone (priv->backend, cal, tzid); } -/* Cal::getTimezoneObject method */ -static GNOME_Evolution_Calendar_CalObj -impl_Cal_getTimezoneObject (PortableServer_Servant servant, - const CORBA_char *tzid, - CORBA_Environment *ev) +/* Cal::addTimezone method */ +static void +impl_Cal_addTimezone (PortableServer_Servant servant, + const CORBA_char *tz, + CORBA_Environment *ev) { Cal *cal; CalPrivate *priv; - char *calobj; cal = CAL (bonobo_object_from_servant (servant)); priv = cal->priv; - calobj = cal_backend_get_timezone_object (priv->backend, tzid); + cal_backend_add_timezone (priv->backend, cal, tz); +} + +/* Cal::setDefaultTimezone method */ +static void +impl_Cal_setDefaultTimezone (PortableServer_Servant servant, + const CORBA_char *tzid, + CORBA_Environment *ev) +{ + Cal *cal; + CalPrivate *priv; - if (calobj) { - CORBA_char *calobj_copy; + cal = CAL (bonobo_object_from_servant (servant)); + priv = cal->priv; - calobj_copy = CORBA_string_dup (calobj); - g_free (calobj); - return calobj_copy; - } else { - bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound); - return NULL; - } + cal_backend_set_default_timezone (priv->backend, cal, tzid); } /** @@ -762,7 +475,7 @@ cal_construct (Cal *cal, CORBA_exception_free (&ev); priv->backend = backend; - + return cal; } @@ -778,18 +491,20 @@ cal_construct (Cal *cal, * if its corresponding CORBA object could not be created. **/ Cal * -cal_new (CalBackend *backend, GNOME_Evolution_Calendar_Listener listener) +cal_new (CalBackend *backend, const char *uri, GNOME_Evolution_Calendar_Listener listener) { Cal *cal, *retval; g_return_val_if_fail (backend != NULL, NULL); g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - cal = CAL (g_object_new (CAL_TYPE, NULL)); + cal = CAL (g_object_new (CAL_TYPE, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL), + NULL)); retval = cal_construct (cal, backend, listener); if (!retval) { - g_message ("cal_new(): could not construct the calendar client interface"); + g_message (G_STRLOC ": could not construct the calendar client interface"); bonobo_object_unref (BONOBO_OBJECT (cal)); return NULL; } @@ -797,6 +512,24 @@ cal_new (CalBackend *backend, GNOME_Evolution_Calendar_Listener listener) return retval; } +CalBackend * +cal_get_backend (Cal *cal) +{ + g_return_val_if_fail (cal != NULL, NULL); + g_return_val_if_fail (IS_CAL (cal), NULL); + + return cal->priv->backend; +} + +GNOME_Evolution_Calendar_Listener +cal_get_listener (Cal *cal) +{ + g_return_val_if_fail (cal != NULL, NULL); + g_return_val_if_fail (IS_CAL (cal), NULL); + + return cal->priv->listener; +} + /* Destroy handler for the calendar */ static void cal_finalize (GObject *object) @@ -812,11 +545,11 @@ cal_finalize (GObject *object) priv = cal->priv; priv->backend = NULL; - + CORBA_exception_init (&ev); bonobo_object_release_unref (priv->listener, &ev); if (BONOBO_EX (&ev)) - g_message ("cal_destroy(): could not release the listener"); + g_message (G_STRLOC ": could not release the listener"); priv->listener = NULL; CORBA_exception_free (&ev); @@ -843,27 +576,28 @@ cal_class_init (CalClass *klass) /* Epv methods */ epv->_get_uri = impl_Cal_get_uri; + epv->open = impl_Cal_open; + epv->remove = impl_Cal_remove; epv->isReadOnly = impl_Cal_isReadOnly; epv->getCalAddress = impl_Cal_getCalAddress; epv->getAlarmEmailAddress = impl_Cal_getAlarmEmailAddress; epv->getLdapAttribute = impl_Cal_getLdapAttribute; epv->getStaticCapabilities = impl_Cal_getStaticCapabilities; epv->setMode = impl_Cal_setMode; - epv->countObjects = impl_Cal_countObjects; epv->getDefaultObject = impl_Cal_getDefaultObject; epv->getObject = impl_Cal_getObject; + epv->getTimezone = impl_Cal_getTimezone; + epv->addTimezone = impl_Cal_addTimezone; epv->setDefaultTimezone = impl_Cal_setDefaultTimezone; - epv->getTimezoneObject = impl_Cal_getTimezoneObject; - epv->getUIDs = impl_Cal_getUIDs; + epv->getObjectList = impl_Cal_getObjectList; epv->getChanges = impl_Cal_getChanges; - epv->getObjectsInRange = impl_Cal_getObjectsInRange; epv->getFreeBusy = impl_Cal_getFreeBusy; - epv->getAlarmsInRange = impl_Cal_getAlarmsInRange; - epv->getAlarmsForObject = impl_Cal_getAlarmsForObject; epv->discardAlarm = impl_Cal_discardAlarm; - epv->updateObjects = impl_Cal_updateObjects; + epv->createObject = impl_Cal_createObject; + epv->modifyObject = impl_Cal_modifyObject; epv->removeObject = impl_Cal_removeObject; - epv->sendObject = impl_Cal_sendObject; + epv->receiveObjects = impl_Cal_receiveObjects; + epv->sendObjects = impl_Cal_sendObjects; epv->getQuery = impl_Cal_getQuery; } @@ -882,18 +616,8 @@ cal_init (Cal *cal, CalClass *klass) BONOBO_TYPE_FUNC_FULL (Cal, GNOME_Evolution_Calendar_Cal, PARENT_TYPE, cal); -/** - * cal_notify_mode: - * @cal: A calendar client interface. - * @status: Status of the mode set. - * @mode: The current mode. - * - * Notifys the listener of the results of a setMode call. - **/ -void -cal_notify_mode (Cal *cal, - GNOME_Evolution_Calendar_Listener_SetModeStatus status, - GNOME_Evolution_Calendar_CalMode mode) +void +cal_notify_read_only (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, gboolean read_only) { CalPrivate *priv; CORBA_Environment ev; @@ -905,75 +629,648 @@ cal_notify_mode (Cal *cal, g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyCalSetMode (priv->listener, status, mode, &ev); + GNOME_Evolution_Calendar_Listener_notifyReadOnly (priv->listener, status, read_only, &ev); if (BONOBO_EX (&ev)) - g_message ("cal_notify_mode(): could not notify the listener " - "about a mode change"); + g_message (G_STRLOC ": could not notify the listener of read only"); CORBA_exception_free (&ev); } -/** - * cal_notify_update: - * @cal: A calendar client interface. - * @uid: UID of object that was updated. - * - * Notifies a listener attached to a calendar client interface object about an - * update to a calendar object. - **/ -void -cal_notify_update (Cal *cal, const char *uid) +void +cal_notify_cal_address (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *address) { CalPrivate *priv; CORBA_Environment ev; g_return_if_fail (cal != NULL); g_return_if_fail (IS_CAL (cal)); - g_return_if_fail (uid != NULL); priv = cal->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyObjUpdated (priv->listener, (char *) uid, &ev); + GNOME_Evolution_Calendar_Listener_notifyCalAddress (priv->listener, status, address ? address : "", &ev); if (BONOBO_EX (&ev)) - g_message ("cal_notify_update(): could not notify the listener " - "about an updated object"); + g_message (G_STRLOC ": could not notify the listener of cal address"); - CORBA_exception_free (&ev); + CORBA_exception_free (&ev); } -/** - * cal_notify_remove: +void +cal_notify_alarm_email_address (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *address) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyAlarmEmailAddress (priv->listener, status, address ? address : "", &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of alarm address"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_ldap_attribute (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *attribute) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyLDAPAttribute (priv->listener, status, attribute ? attribute : "", &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of ldap attribute"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_static_capabilities (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *capabilities) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyStaticCapabilities (priv->listener, status, + capabilities ? capabilities : "", &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of static capabilities"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_open (Cal *cal, GNOME_Evolution_Calendar_CallStatus status) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyCalOpened (priv->listener, status, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of open"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_remove (Cal *cal, GNOME_Evolution_Calendar_CallStatus status) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyCalRemoved (priv->listener, status, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of remove"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_object_created (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + const char *uid, const char *object) +{ + CalPrivate *priv; + EList *queries; + EIterator *iter; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + queries = cal_backend_get_queries (priv->backend); + iter = e_list_get_iterator (queries); + + while (e_iterator_is_valid (iter)) { + Query *query = QUERY (e_iterator_get (iter)); + + bonobo_object_dup_ref (BONOBO_OBJREF (query), NULL); + + if (!query_object_matches (query, object)) + continue; + + query_notify_objects_added_1 (query, object); + + bonobo_object_release_unref (BONOBO_OBJREF (query), NULL); + + e_iterator_next (iter); + } + g_object_unref (iter); + g_object_unref (queries); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyObjectCreated (priv->listener, status, uid ? uid : "", &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of object creation"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_object_modified (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + const char *old_object, const char *object) +{ + CalPrivate *priv; + EList *queries; + EIterator *iter; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + queries = cal_backend_get_queries (priv->backend); + iter = e_list_get_iterator (queries); + + while (e_iterator_is_valid (iter)) { + Query *query = QUERY (e_iterator_get (iter)); + gboolean old_match, new_match; + + bonobo_object_dup_ref (BONOBO_OBJREF (query), NULL); + + old_match = query_object_matches (query, old_object); + new_match = query_object_matches (query, object); + if (old_match && new_match) + query_notify_objects_modified_1 (query, object); + else if (new_match) + query_notify_objects_added_1 (query, object); + else /* if (old_match) */ { + icalcomponent *comp; + + comp = icalcomponent_new_from_string ((char *)old_object); + query_notify_objects_removed_1 (query, icalcomponent_get_uid (comp)); + icalcomponent_free (comp); + } + query_notify_query_done (query, GNOME_Evolution_Calendar_Success); + + bonobo_object_release_unref (BONOBO_OBJREF (query), NULL); + + e_iterator_next (iter); + } + g_object_unref (iter); + g_object_unref (queries); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyObjectModified (priv->listener, status, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of object creation"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_object_removed (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + const char *uid, const char *object) +{ + CalPrivate *priv; + EList *queries; + EIterator *iter; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + queries = cal_backend_get_queries (priv->backend); + iter = e_list_get_iterator (queries); + + while (e_iterator_is_valid (iter)) { + Query *query = QUERY (e_iterator_get (iter)); + + bonobo_object_dup_ref (BONOBO_OBJREF (query), NULL); + + if (!query_object_matches (query, object)) + continue; + + query_notify_objects_removed_1 (query, uid); + + bonobo_object_release_unref (BONOBO_OBJREF (query), NULL); + + e_iterator_next (iter); + } + g_object_unref (iter); + g_object_unref (queries); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyObjectRemoved (priv->listener, status, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of object removal"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_objects_received (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + GList *created, GList *modified, GList *removed) +{ + CalPrivate *priv; + EList *queries; + EIterator *iter; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + queries = cal_backend_get_queries (priv->backend); + iter = e_list_get_iterator (queries); + + while (e_iterator_is_valid (iter)) { + Query *query = QUERY (e_iterator_get (iter)); + + bonobo_object_dup_ref (BONOBO_OBJREF (query), NULL); + + query_notify_objects_added (query, created); + query_notify_objects_modified (query, modified); + query_notify_objects_removed (query, removed); + + bonobo_object_release_unref (BONOBO_OBJREF (query), NULL); + + e_iterator_next (iter); + } + g_object_unref (iter); + g_object_unref (queries); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyObjectsReceived (priv->listener, status, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of objects received"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_alarm_discarded (Cal *cal, GNOME_Evolution_Calendar_CallStatus status) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyAlarmDiscarded (priv->listener, status, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of alarm discarded"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_objects_sent (Cal *cal, GNOME_Evolution_Calendar_CallStatus status) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyObjectsSent (priv->listener, status, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of objects sent"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_default_object (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, char *object) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Listener_notifyDefaultObjectRequested (priv->listener, status, + object ? object : "", &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of default object"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_object (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, char *object) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + + GNOME_Evolution_Calendar_Listener_notifyObjectRequested (priv->listener, status, + object ? object : "", &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of object"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_object_list (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, GList *objects) +{ + CalPrivate *priv; + CORBA_Environment ev; + GNOME_Evolution_Calendar_stringlist seq; + GList *l; + int i; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + + seq._maximum = g_list_length (objects); + seq._length = 0; + seq._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (seq._maximum); + + for (l = objects, i = 0; l; l = l->next, i++) { + seq._buffer[i] = CORBA_string_dup (l->data); + seq._length++; + } + + GNOME_Evolution_Calendar_Listener_notifyObjectListRequested (priv->listener, status, &seq, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of object list"); + + CORBA_exception_free (&ev); + + CORBA_free(seq._buffer); +} + +void +cal_notify_query (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, Query *query) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyQuery (priv->listener, status, BONOBO_OBJREF (query), &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of query"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_timezone_requested (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *object) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyTimezoneRequested (priv->listener, status, object ? object : "", &ev); + + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of timezone requested"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_timezone_added (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *tzid) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyTimezoneAdded (priv->listener, status, tzid, &ev); + + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of timezone added"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_default_timezone_set (Cal *cal, GNOME_Evolution_Calendar_CallStatus status) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyDefaultTimezoneSet (priv->listener, status, &ev); + + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of default timezone set"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_changes (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + GList *adds, GList *modifies, GList *deletes) +{ + CalPrivate *priv; + CORBA_Environment ev; + GNOME_Evolution_Calendar_CalObjChangeSeq seq; + GList *l; + int n, i; + + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + n = g_list_length (adds) + g_list_length (modifies) + g_list_length (deletes); + seq._maximum = n; + seq._length = n; + seq._buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalObjChange_allocbuf (n); + + i = 0; + for (l = adds; l; i++, l = l->next) { + GNOME_Evolution_Calendar_CalObjChange *change = &seq._buffer[i]; + + change->calobj = CORBA_string_dup (l->data); + change->type = GNOME_Evolution_Calendar_ADDED; + } + + for (l = modifies; l; i++, l = l->next) { + GNOME_Evolution_Calendar_CalObjChange *change = &seq._buffer[i]; + + change->calobj = CORBA_string_dup (l->data); + change->type = GNOME_Evolution_Calendar_MODIFIED; + } + + for (l = deletes; l; i++, l = l->next) { + GNOME_Evolution_Calendar_CalObjChange *change = &seq._buffer[i]; + + change->calobj = CORBA_string_dup (l->data); + change->type = GNOME_Evolution_Calendar_DELETED; + } + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyDefaultTimezoneSet (priv->listener, status, &ev); + + CORBA_free (seq._buffer); + + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of default timezone set"); + + CORBA_exception_free (&ev); +} + +void +cal_notify_free_busy (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, GList *freebusy) +{ + CalPrivate *priv; + CORBA_Environment ev; + GNOME_Evolution_Calendar_CalObjSeq seq; + GList *l; + int n, i; + + g_return_if_fail (IS_CAL (cal)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + n = g_list_length (freebusy); + seq._maximum = n; + seq._length = n; + seq._buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalObj_allocbuf (n); + + for (i = 0, l = freebusy; l; i++, l = l->next) + seq._buffer[i] = CORBA_string_dup (l->data); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyDefaultTimezoneSet (priv->listener, status, &ev); + + CORBA_free (seq._buffer); + + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of freebusy"); + + CORBA_exception_free (&ev); +} + +/** + * cal_notify_mode: * @cal: A calendar client interface. - * @uid: UID of object that was removed. + * @status: Status of the mode set. + * @mode: The current mode. * - * Notifies a listener attached to a calendar client interface object about a - * calendar object that was removed. + * Notifys the listener of the results of a setMode call. **/ void -cal_notify_remove (Cal *cal, const char *uid) +cal_notify_mode (Cal *cal, + GNOME_Evolution_Calendar_Listener_SetModeStatus status, + GNOME_Evolution_Calendar_CalMode mode) { CalPrivate *priv; CORBA_Environment ev; g_return_if_fail (cal != NULL); g_return_if_fail (IS_CAL (cal)); - g_return_if_fail (uid != NULL); priv = cal->priv; g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_Listener_notifyObjRemoved (priv->listener, (char *) uid, &ev); + GNOME_Evolution_Calendar_Listener_notifyCalSetMode (priv->listener, status, mode, &ev); if (BONOBO_EX (&ev)) - g_message ("cal_notify_remove(): could not notify the listener " - "about a removed object"); + g_message ("cal_notify_mode(): could not notify the listener " + "about a mode change"); - CORBA_exception_free (&ev); + CORBA_exception_free (&ev); } /** diff --git a/calendar/pcs/cal.h b/calendar/pcs/cal.h index 35f64f278f..52d8589ab2 100644 --- a/calendar/pcs/cal.h +++ b/calendar/pcs/cal.h @@ -26,6 +26,7 @@ #include #include "pcs/evolution-calendar.h" #include "pcs/cal-common.h" +#include "pcs/query.h" G_BEGIN_DECLS @@ -58,13 +59,48 @@ Cal *cal_construct (Cal *cal, CalBackend *backend, GNOME_Evolution_Calendar_Listener listener); -Cal *cal_new (CalBackend *backend, GNOME_Evolution_Calendar_Listener listener); +Cal *cal_new (CalBackend *backend, const char *uri, GNOME_Evolution_Calendar_Listener listener); + +CalBackend *cal_get_backend (Cal *cal); +GNOME_Evolution_Calendar_Listener cal_get_listener (Cal *cal); + +void cal_notify_read_only (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, gboolean read_only); +void cal_notify_cal_address (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *address); +void cal_notify_alarm_email_address (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *address); +void cal_notify_ldap_attribute (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *attribute); +void cal_notify_static_capabilities (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *capabilities); + +void cal_notify_open (Cal *cal, GNOME_Evolution_Calendar_CallStatus status); +void cal_notify_remove (Cal *cal, GNOME_Evolution_Calendar_CallStatus status); + +void cal_notify_object_created (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + const char *uid, const char *object); +void cal_notify_object_modified (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + const char *old_object, const char *object); +void cal_notify_object_removed (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + const char *uid, const char *object); +void cal_notify_alarm_discarded (Cal *cal, GNOME_Evolution_Calendar_CallStatus status); + +void cal_notify_objects_received (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, + GList *created, GList *modified, GList *removed); +void cal_notify_objects_sent (Cal *cal, GNOME_Evolution_Calendar_CallStatus status); + +void cal_notify_default_object (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, char *object); +void cal_notify_object (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, char *object); +void cal_notify_object_list (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, GList *objects); + +void cal_notify_query (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, Query *query); + +void cal_notify_timezone_requested (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *object); +void cal_notify_timezone_added (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *tzid); +void cal_notify_default_timezone_set (Cal *cal, GNOME_Evolution_Calendar_CallStatus status); + +void cal_notify_changes (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, GList *adds, GList *modifies, GList *deletes); +void cal_notify_free_busy (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, GList *freebusy); void cal_notify_mode (Cal *cal, GNOME_Evolution_Calendar_Listener_SetModeStatus status, GNOME_Evolution_Calendar_CalMode mode); -void cal_notify_update (Cal *cal, const char *uid); -void cal_notify_remove (Cal *cal, const char *uid); void cal_notify_error (Cal *cal, const char *message); void cal_notify_categories_changed (Cal *cal, GNOME_Evolution_Calendar_StringSeq *categories); diff --git a/calendar/pcs/job.c b/calendar/pcs/job.c deleted file mode 100644 index 584f1a6f38..0000000000 --- a/calendar/pcs/job.c +++ /dev/null @@ -1,98 +0,0 @@ -/* GNOME personal calendar server - job manager - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. - * - * Author: Federico Mena-Quintero - * - * 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 -#include "job.h" - - - -/* The job list */ - -typedef struct { - JobFunc func; - gpointer data; -} Job; - -static GSList *jobs_head; -static GSList *jobs_tail; - -static guint jobs_idle_id; - - - -/* Runs a job and dequeues it */ -static gboolean -run_job (gpointer data) -{ - Job *job; - GSList *l; - - g_assert (jobs_head != NULL); - - job = jobs_head->data; - (* job->func) (job->data); - g_free (job); - - l = jobs_head; - jobs_head = g_slist_remove_link (jobs_head, jobs_head); - g_slist_free_1 (l); - - if (!jobs_head) { - jobs_tail = NULL; - jobs_idle_id = 0; - return FALSE; - } else - return TRUE; -} - -/** - * job_add: - * @func: Function to run the job. - * @data: Data to pass to @function. - * - * Adds a job to the queue. The job will automatically be run asynchronously. - **/ -void -job_add (JobFunc func, gpointer data) -{ - Job *job; - - g_return_if_fail (func != NULL); - - job = g_new (Job, 1); - job->func = func; - job->data = data; - - if (!jobs_head) { - g_assert (jobs_tail == NULL); - g_assert (jobs_idle_id == 0); - - jobs_head = g_slist_append (NULL, job); - jobs_tail = jobs_head; - - jobs_idle_id = g_idle_add (run_job, NULL); - } else { - g_assert (jobs_tail != NULL); - g_assert (jobs_idle_id != 0); - - jobs_tail = g_slist_append (jobs_tail, job)->next; - } -} diff --git a/calendar/pcs/job.h b/calendar/pcs/job.h deleted file mode 100644 index 07e3371f89..0000000000 --- a/calendar/pcs/job.h +++ /dev/null @@ -1,35 +0,0 @@ -/* GNOME personal calendar server - job manager - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. - * - * Author: Federico Mena-Quintero - * - * 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 JOB_H -#define JOB_H - -#include - - - -typedef void (* JobFunc) (gpointer data); - -void job_add (JobFunc func, gpointer data); - - - -#endif diff --git a/calendar/pcs/query-backend.c b/calendar/pcs/query-backend.c deleted file mode 100644 index 7d6cca041a..0000000000 --- a/calendar/pcs/query-backend.c +++ /dev/null @@ -1,361 +0,0 @@ -/* Evolution calendar - Backend cache for calendar queries. - * - * Copyright (C) 2001 Ximian, Inc. - * - * Author: Rodrigo Moya - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include "query.h" -#include "query-backend.h" - -static void query_backend_class_init (QueryBackendClass *klass); -static void query_backend_init (QueryBackend *qb, QueryBackendClass *klass); -static void query_backend_finalize (GObject *object); - -typedef struct { - CalComponent *comp; -} QueryBackendComponent; - -/* Private part of the QueryBackend structure */ -struct _QueryBackendPrivate { - char *uri; - CalBackend *backend; - GHashTable *components; - GList *queries; -}; - -static GHashTable *loaded_backends = NULL; -static GObjectClass *parent_class = NULL; - -/* Class initialization function for the backend cache */ -static void -query_backend_class_init (QueryBackendClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->finalize = query_backend_finalize; -} - -/* Object initialization function for the backend cache */ -static void -query_backend_init (QueryBackend *qb, QueryBackendClass *klass) -{ - QueryBackendPrivate *priv; - - priv = g_new0 (QueryBackendPrivate, 1); - qb->priv = priv; - - priv->uri = NULL; - priv->backend = NULL; - priv->components = g_hash_table_new (g_str_hash, g_str_equal); - priv->queries = NULL; -} - -static void -free_hash_comp_cb (gpointer key, gpointer value, gpointer user_data) -{ - g_free (key); - g_object_unref (value); -} - -/* Finalize handler for the backend cache */ -static void -query_backend_finalize (GObject *object) -{ - QueryBackend *qb = (QueryBackend *) object; - - g_return_if_fail (object != NULL); - g_return_if_fail (IS_QUERY_BACKEND (qb)); - - /* remove the QueryBackend from the internal hash table */ - g_hash_table_remove (loaded_backends, qb->priv->uri); - if (g_hash_table_size (loaded_backends) == 0) { - g_hash_table_destroy (loaded_backends); - loaded_backends = NULL; - } - - /* free memory */ - qb->priv->backend = NULL; - - g_free (qb->priv->uri); - qb->priv->uri = NULL; - - g_hash_table_foreach (qb->priv->components, (GHFunc) free_hash_comp_cb, NULL); - g_hash_table_destroy (qb->priv->components); - qb->priv->components = NULL; - - g_list_free (qb->priv->queries); - qb->priv->queries = NULL; - - g_free (qb->priv); - qb->priv = NULL; - - if (G_OBJECT_CLASS (parent_class)->finalize) - (* G_OBJECT_CLASS (parent_class)->finalize) (object); -} - -/** - * query_backend_get_type: - * @void: - * - * Registers the #QueryBackend class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the #QueryBackend class. - **/ -GType -query_backend_get_type (void) -{ - static GType type = 0; - - if (!type) { - static GTypeInfo info = { - sizeof (QueryBackendClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) query_backend_class_init, - NULL, NULL, - sizeof (QueryBackend), - 0, - (GInstanceInitFunc) query_backend_init - }; - type = g_type_register_static (G_TYPE_OBJECT, "QueryBackend", &info, 0); - } - - return type; -} - -static void -backend_destroyed_cb (gpointer user_data, GObject *where_backend_was) -{ - QueryBackend *qb = (QueryBackend *) user_data; - - g_return_if_fail (IS_QUERY_BACKEND (qb)); - - g_object_unref (qb); -} - -static void -object_updated_cb (CalBackend *backend, const char *uid, gpointer user_data) -{ - gpointer orig_key, orig_value; - const char *tmp_uid; - CalComponent *comp; - icalcomponent *icalcomp; - char *comp_str; - QueryBackend *qb = (QueryBackend *) user_data; - - g_return_if_fail (IS_QUERY_BACKEND (qb)); - - if (g_hash_table_lookup_extended (qb->priv->components, uid, &orig_key, &orig_value)) { - g_hash_table_remove (qb->priv->components, uid); - g_free (orig_key); - g_object_unref (orig_value); - } - - comp_str = cal_backend_get_object (qb->priv->backend, uid); - if (!comp_str) - return; - - icalcomp = icalparser_parse_string (comp_str); - g_free (comp_str); - if (icalcomp) { - comp = cal_component_new (); - if (!cal_component_set_icalcomponent (comp, icalcomp)) { - icalcomponent_free (icalcomp); - g_object_unref (comp); - return; - } - - cal_component_get_uid (comp, &tmp_uid); - if (!uid || !*uid) { - g_object_unref (comp); - } else - g_hash_table_insert (qb->priv->components, g_strdup (tmp_uid), comp); - } -} - -static void -object_removed_cb (CalBackend *backend, const char *uid, gpointer user_data) -{ - gpointer orig_key, orig_value; - QueryBackend *qb = (QueryBackend *) user_data; - - g_return_if_fail (IS_QUERY_BACKEND (qb)); - - if (g_hash_table_lookup_extended (qb->priv->components, uid, &orig_key, &orig_value)) { - g_hash_table_remove (qb->priv->components, uid); - g_free (orig_key); - g_object_unref (orig_value); - } -} - -static void -query_destroyed_cb (gpointer user_data, GObject *where_the_object_was) -{ - Query *query = (Query *) where_the_object_was; - QueryBackend *qb = (QueryBackend *) user_data; - - g_return_if_fail (IS_QUERY (query)); - g_return_if_fail (IS_QUERY_BACKEND (qb)); - - qb->priv->queries = g_list_remove (qb->priv->queries, query); -} - -static void -foreach_uid_cb (gpointer data, gpointer user_data) -{ - QueryBackend *qb = (QueryBackend *) user_data; - - g_return_if_fail (data != NULL); - g_return_if_fail (IS_QUERY_BACKEND (qb)); - - object_updated_cb (qb->priv->backend, (const char *) data, qb); -} - -/** - * query_backend_new - * @query: The #Query object that issues the query. - * @backend: A #CalBackend object. - * - * Create a new #QueryBackend instance, which is a class to - * have a cache of objects for the calendar queries, so that - * we don't have to ask the calendar backend to get the objects - * everytime. - * - * Returns: the newly-created object. - */ -QueryBackend * -query_backend_new (Query *query, CalBackend *backend) -{ - QueryBackend *qb = NULL; - - g_return_val_if_fail (IS_QUERY (query), NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - - if (!loaded_backends) - loaded_backends = g_hash_table_new (g_str_hash, g_str_equal); - - /* see if we already have the backend loaded */ - qb = g_hash_table_lookup (loaded_backends, - cal_backend_get_uri (backend)); - if (!qb) { - GList *uidlist; - - qb = g_object_new (QUERY_BACKEND_TYPE, NULL); - - qb->priv->uri = g_strdup (cal_backend_get_uri (backend)); - qb->priv->backend = backend; - - /* load all UIDs */ - uidlist = cal_backend_get_uids (backend, CALOBJ_TYPE_ANY); - g_list_foreach (uidlist, foreach_uid_cb, qb); - cal_obj_uid_list_free (uidlist); - - g_object_weak_ref (G_OBJECT (backend), backend_destroyed_cb, qb); - g_signal_connect (G_OBJECT (backend), "obj_updated", - G_CALLBACK (object_updated_cb), qb); - g_signal_connect (G_OBJECT (backend), "obj_removed", - G_CALLBACK (object_removed_cb), qb); - - g_hash_table_insert (loaded_backends, qb->priv->uri, qb); - } - - qb->priv->queries = g_list_append (qb->priv->queries, query); - g_object_weak_ref (G_OBJECT (query), query_destroyed_cb, qb); - - return qb; -} - -typedef struct { - GList *uidlist; - CalObjType type; -} GetUidsData; - -static void -uid_hash_cb (gpointer key, gpointer value, gpointer user_data) -{ - CalComponentVType vtype; - char *uid = (char *) key; - CalComponent *comp = (CalComponent *) value; - GetUidsData *uids_data = (GetUidsData *) user_data; - - g_return_if_fail (uid != NULL); - g_return_if_fail (IS_CAL_COMPONENT (comp)); - g_return_if_fail (uids_data != NULL); - - vtype = cal_component_get_vtype (comp); - if (vtype == CAL_COMPONENT_EVENT && uids_data->type == CALOBJ_TYPE_EVENT) - uids_data->uidlist = g_list_append (uids_data->uidlist, g_strdup (uid)); - else if (vtype == CAL_COMPONENT_TODO && uids_data->type == CALOBJ_TYPE_TODO) - uids_data->uidlist = g_list_append (uids_data->uidlist, g_strdup (uid)); - else if (vtype == CAL_COMPONENT_JOURNAL && uids_data->type == CALOBJ_TYPE_JOURNAL) - uids_data->uidlist = g_list_append (uids_data->uidlist, g_strdup (uid)); - else if (uids_data->type == CALOBJ_TYPE_ANY) - uids_data->uidlist = g_list_append (uids_data->uidlist, g_strdup (uid)); -} - -/** - * query_backend_get_uids - * @qb: A #QueryBackend type. - * @type: Type of objects to get the UIDs for. - * - * Get a list of all UIDs for objects of the given type out from - * the specified #QueryBackend object. - * - * Returns: a GList of UIDs, which should be freed, when no longer needed, - * via a call to cal_obj_uid_list_free. - */ -GList * -query_backend_get_uids (QueryBackend *qb, CalObjType type) -{ - GetUidsData uids_data; - - g_return_val_if_fail (IS_QUERY_BACKEND (qb), NULL); - - uids_data.uidlist = NULL; - uids_data.type = type; - g_hash_table_foreach (qb->priv->components, (GHFunc) uid_hash_cb, &uids_data); - - return uids_data.uidlist; -} - -/** - * query_backend_get_object_component - * @qb: A #QueryBackend object. - * @uid: UID of the object to retrieve. - * - * Get a #CalComponent from the given #QueryBackend. - * - * Returns: the component if found, NULL otherwise. - */ -CalComponent * -query_backend_get_object_component (QueryBackend *qb, const char *uid) -{ - g_return_val_if_fail (IS_QUERY_BACKEND (qb), NULL); - g_return_val_if_fail (uid != NULL, NULL); - - return g_hash_table_lookup (qb->priv->components, uid); -} diff --git a/calendar/pcs/query-backend.h b/calendar/pcs/query-backend.h deleted file mode 100644 index a6d9b5d8aa..0000000000 --- a/calendar/pcs/query-backend.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Evolution calendar - Backend cache for calendar queries. - * - * Copyright (C) 2001 Ximian, Inc. - * - * Author: Rodrigo Moya - * - * 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 QUERY_BACKEND_H -#define QUERY_BACKEND_H - -#include "cal-backend.h" -#include "query.h" - -G_BEGIN_DECLS - -#define QUERY_BACKEND_TYPE (query_backend_get_type ()) -#define QUERY_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), QUERY_BACKEND_TYPE, QueryBackend)) -#define QUERY_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), QUERY_BACKEND_TYPE, QueryBackendClass)) -#define IS_QUERY_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), QUERY_BACKEND_TYPE)) -#define IS_QUERY_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), QUERY_BACKEND_TYPE)) - -typedef struct _QueryBackendPrivate QueryBackendPrivate; - -typedef struct { - GObject object; - - /* Private data */ - QueryBackendPrivate *priv; -} QueryBackend; - -typedef struct { - GObjectClass parent; -} QueryBackendClass; - -GType query_backend_get_type (void); -QueryBackend *query_backend_new (Query *query, CalBackend *backend); -GList *query_backend_get_uids (QueryBackend *qb, CalObjType type); -CalComponent *query_backend_get_object_component (QueryBackend *qb, const char *uid); - -G_END_DECLS - -#endif diff --git a/calendar/pcs/query.c b/calendar/pcs/query.c index 41853c1a47..6f3d417a32 100644 --- a/calendar/pcs/query.c +++ b/calendar/pcs/query.c @@ -30,68 +30,28 @@ #include #include #include +#include #include #include #include "cal-backend.h" #include "query.h" -#include "query-backend.h" -typedef struct { - Query *query; - GNOME_Evolution_Calendar_QueryListener ql; - guint tid; -} StartCachedQueryInfo; - -/* States of a query */ -typedef enum { - QUERY_WAIT_FOR_BACKEND, /* the query is not populated and the backend is not loaded */ - QUERY_START_PENDING, /* the query is not populated yet, but the backend is loaded */ - QUERY_IN_PROGRESS, /* the query is populated; components are still being processed */ - QUERY_DONE, /* the query is done, but still accepts object changes */ - QUERY_PARSE_ERROR /* a parse error occurred when initially creating the ESexp */ -} QueryState; - /* Private part of the Query structure */ struct _QueryPrivate { /* The backend we are monitoring */ CalBackend *backend; - /* The cache backend */ - QueryBackend *qb; - - /* The default timezone for the calendar. */ - icaltimezone *default_zone; - - /* Listeners to which we report changes in the live query */ - GList *listeners; - GList *component_listeners; + /* The listener we report to */ + GNOME_Evolution_Calendar_QueryListener listener; + EComponentListener *component_listener; /* Sexp that defines the query */ - char *sexp; - ESExp *esexp; - - /* Timeout handler ID for asynchronous queries and current state of the query */ - guint timeout_id; - QueryState state; - - GList *cached_timeouts; - - /* List of UIDs that we still have to process */ - GList *pending_uids; - int n_pending; - int pending_total; - - /* Table of the UIDs we know do match the query */ - GHashTable *uids; - - /* The next component that will be handled in e_sexp_eval(); put here - * just because the query object itself is the esexp context. - */ - CalComponent *next_comp; + CalBackendObjectSExp *sexp; }; + static void query_class_init (QueryClass *class); @@ -99,7 +59,6 @@ static void query_init (Query *query, QueryClass *class); static void query_finalize (GObject *object); static BonoboObjectClass *parent_class; -static GList *cached_queries = NULL; @@ -108,1626 +67,434 @@ BONOBO_TYPE_FUNC_FULL (Query, BONOBO_TYPE_OBJECT, query); -/* Class initialization function for the live search query */ -static void -query_class_init (QueryClass *class) -{ - GObjectClass *object_class; +/* Property IDs */ +enum props { + PROP_0, + PROP_BACKEND, + PROP_LISTENER, + PROP_SEXP +}; - object_class = (GObjectClass *) class; - parent_class = g_type_class_peek_parent (class); +static void +listener_died_cb (EComponentListener *cl, gpointer data) +{ + Query *query = QUERY (data); + QueryPrivate *priv; - object_class->finalize = query_finalize; + priv = query->priv; - /* The Query interface (ha ha! query interface!) has no methods, so we - * don't need to fiddle with the epv. - */ + g_object_unref (priv->component_listener); + priv->component_listener = NULL; + + bonobo_object_release_unref (priv->listener, NULL); + priv->listener = NULL; } -/* Object initialization function for the live search query */ static void -query_init (Query *query, QueryClass *class) +impl_Query_start (PortableServer_Servant servant, CORBA_Environment *ev) { + Query *query; QueryPrivate *priv; - priv = g_new0 (QueryPrivate, 1); - query->priv = priv; - - priv->backend = NULL; - priv->qb = NULL; - priv->default_zone = NULL; - priv->listeners = NULL; - priv->component_listeners = NULL; - priv->sexp = NULL; - - priv->timeout_id = 0; - priv->state = QUERY_WAIT_FOR_BACKEND; - - priv->cached_timeouts = NULL; - - priv->pending_uids = NULL; - priv->uids = g_hash_table_new (g_str_hash, g_str_equal); + query = QUERY (bonobo_object_from_servant (servant)); + priv = query->priv; - priv->next_comp = NULL; + cal_backend_start_query (priv->backend, query); } -/* Used from g_hash_table_foreach(); frees a UID */ static void -free_uid_cb (gpointer key, gpointer value, gpointer data) +query_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { - char *uid; + Query *query; + QueryPrivate *priv; + CORBA_Environment ev; + + query = QUERY (object); + priv = query->priv; + + switch (property_id) { + case PROP_BACKEND: + priv->backend = CAL_BACKEND (g_value_dup_object (value)); + break; + case PROP_LISTENER: + CORBA_exception_init (&ev); + priv->listener = CORBA_Object_duplicate (g_value_get_pointer (value), &ev); + CORBA_exception_free (&ev); - uid = key; - g_free (uid); + priv->component_listener = e_component_listener_new (priv->listener); + g_signal_connect (G_OBJECT (priv->component_listener), "component_died", + G_CALLBACK (listener_died_cb), query); + break; + case PROP_SEXP: + priv->sexp = CAL_BACKEND_OBJECT_SEXP (g_value_dup_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } } -/* Finalize handler for the live search query */ static void -query_finalize (GObject *object) +query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { Query *query; QueryPrivate *priv; - - g_return_if_fail (object != NULL); - g_return_if_fail (IS_QUERY (object)); - + query = QUERY (object); priv = query->priv; - if (priv->backend) { - /* If we are waiting for the backend to be opened, we'll be - * connected to its "opened" signal. If we are in the middle of - * a query or if we are just waiting for object update - * notifications, we'll have the "obj_removed" and "obj_updated" - * connections. Otherwise, we are either in a parse error state - * or waiting for the query to be populated, and in both cases - * we have no signal connections. - */ - if (priv->state == QUERY_WAIT_FOR_BACKEND - || priv->state == QUERY_IN_PROGRESS || priv->state == QUERY_DONE) - g_signal_handlers_disconnect_matched (G_OBJECT (priv->backend), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, query); - - g_object_unref (priv->backend); - priv->backend = NULL; + switch (property_id) { + case PROP_BACKEND: + g_value_set_object (value, priv->backend); + case PROP_LISTENER: + g_value_set_pointer (value, priv->listener); + break; + case PROP_SEXP: + g_value_set_object (value, priv->sexp); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; } +} - priv->qb = NULL; - - if (priv->listeners != NULL) { - CORBA_Environment ev; - GList *l; - - CORBA_exception_init (&ev); - for (l = priv->listeners; l != NULL; l = l->next) { - bonobo_object_release_unref (l->data, &ev); - - if (BONOBO_EX (&ev)) - g_message ("query_destroy(): Could not unref the listener\n"); - } +/* Class initialization function for the live search query */ +static void +query_class_init (QueryClass *klass) +{ + GObjectClass *object_class; + POA_GNOME_Evolution_Calendar_Query__epv *epv = &klass->epv; + GParamSpec *param; + + object_class = (GObjectClass *) klass; - CORBA_exception_free (&ev); + parent_class = g_type_class_peek_parent (klass); - g_list_free (priv->listeners); - priv->listeners = NULL; - } + object_class->set_property = query_set_property; + object_class->get_property = query_get_property; + object_class->finalize = query_finalize; - if (priv->component_listeners != NULL) { - g_list_foreach (priv->component_listeners, (GFunc) g_object_unref, NULL); - g_list_free (priv->component_listeners); - priv->component_listeners = NULL; - } + epv->start = impl_Query_start; - if (priv->sexp) { - g_free (priv->sexp); - priv->sexp = NULL; - } + param = g_param_spec_object ("backend", NULL, NULL, CAL_BACKEND_TYPE, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_BACKEND, param); + param = g_param_spec_pointer ("listener", NULL, NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_LISTENER, param); + param = g_param_spec_object ("sexp", NULL, NULL, CAL_TYPE_BACKEND_OBJECT_SEXP, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_SEXP, param); +} - if (priv->esexp) { - e_sexp_unref (priv->esexp); - priv->esexp = NULL; - } +/* Object initialization function for the live search query */ +static void +query_init (Query *query, QueryClass *class) +{ + QueryPrivate *priv; - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + priv = g_new0 (QueryPrivate, 1); + query->priv = priv; - if (priv->cached_timeouts) { - GList *l; + priv->backend = NULL; + priv->listener = NULL; + priv->component_listener = NULL; + priv->sexp = NULL; +} - for (l = priv->cached_timeouts; l != NULL; l = l->next) - g_source_remove (GPOINTER_TO_INT (l->data)); +/* Finalize handler for the live search query */ +static void +query_finalize (GObject *object) +{ + Query *query; + QueryPrivate *priv; - g_list_free (priv->cached_timeouts); - priv->cached_timeouts = NULL; - } + g_return_if_fail (object != NULL); + g_return_if_fail (IS_QUERY (object)); - if (priv->pending_uids) { - GList *l; + query = QUERY (object); + priv = query->priv; - for (l = priv->pending_uids; l; l = l->next) { - char *uid; + if (priv->backend) + g_object_unref (priv->backend); - uid = l->data; - g_assert (uid != NULL); - g_free (uid); - } + if (priv->listener != NULL) + bonobo_object_release_unref (priv->listener, NULL); - g_list_free (priv->pending_uids); - priv->pending_uids = NULL; - priv->n_pending = 0; - } + if (priv->component_listener != NULL) + g_object_unref (priv->component_listener); - g_hash_table_foreach (priv->uids, free_uid_cb, NULL); - g_hash_table_destroy (priv->uids); - priv->uids = NULL; + if (priv->sexp) + g_object_unref (priv->sexp); g_free (priv); - query->priv = NULL; if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); } - - -/* E-Sexp functions */ - -/* (time-now) - * - * Returns a time_t of time (NULL). - */ -static ESExpResult * -func_time_now (ESExp *esexp, int argc, ESExpResult **argv, void *data) +/** + * query_new: + * @backend: Calendar backend that the query object will monitor. + * @ql: Listener for query results. + * @sexp: Sexp that defines the query. + * + * Creates a new query engine object that monitors a calendar backend. + * + * Return value: A newly-created query object, or NULL on failure. + **/ +Query * +query_new (CalBackend *backend, + GNOME_Evolution_Calendar_QueryListener ql, + CalBackendObjectSExp *sexp) { - ESExpResult *result; - - if (argc != 0) { - e_sexp_fatal_error (esexp, _("time-now expects 0 arguments")); - return NULL; - } + Query *query; - result = e_sexp_result_new (esexp, ESEXP_RES_TIME); - result->value.time = time (NULL); + query = g_object_new (QUERY_TYPE, "backend", backend, "listener", ql, + "sexp", sexp, NULL); - return result; + return query; } -/* (make-time ISODATE) +/** + * query_get_sexp + * @query: A #Query object. * - * ISODATE - string, ISO 8601 date/time representation + * Get the expression used for the given query. * - * Constructs a time_t value for the specified date. + * Returns: the query expression used to search. */ -static ESExpResult * -func_make_time (ESExp *esexp, int argc, ESExpResult **argv, void *data) +const char * +query_get_text (Query *query) { - const char *str; - time_t t; - ESExpResult *result; - - if (argc != 1) { - e_sexp_fatal_error (esexp, _("make-time expects 1 argument")); - return NULL; - } - - if (argv[0]->type != ESEXP_RES_STRING) { - e_sexp_fatal_error (esexp, _("make-time expects argument 1 " - "to be a string")); - return NULL; - } - str = argv[0]->value.string; - - t = time_from_isodate (str); - if (t == -1) { - e_sexp_fatal_error (esexp, _("make-time argument 1 must be an " - "ISO 8601 date/time string")); - return NULL; - } - - result = e_sexp_result_new (esexp, ESEXP_RES_TIME); - result->value.time = t; + g_return_val_if_fail (IS_QUERY (query), NULL); - return result; + return cal_backend_object_sexp_text (query->priv->sexp); } -/* (time-add-day TIME N) - * - * TIME - time_t, base time - * N - int, number of days to add - * - * Adds the specified number of days to a time value. - * - * FIXME: TIMEZONES - need to use a timezone or daylight saving changes will - * make the result incorrect. - */ -static ESExpResult * -func_time_add_day (ESExp *esexp, int argc, ESExpResult **argv, void *data) +CalBackendObjectSExp * +query_get_object_sexp (Query *query) { - ESExpResult *result; - time_t t; - int n; - - if (argc != 2) { - e_sexp_fatal_error (esexp, _("time-add-day expects 2 arguments")); - return NULL; - } + g_return_val_if_fail (IS_QUERY (query), NULL); - if (argv[0]->type != ESEXP_RES_TIME) { - e_sexp_fatal_error (esexp, _("time-add-day expects argument 1 " - "to be a time_t")); - return NULL; - } - t = argv[0]->value.time; + return query->priv->sexp; +} - if (argv[1]->type != ESEXP_RES_INT) { - e_sexp_fatal_error (esexp, _("time-add-day expects argument 2 " - "to be an integer")); - return NULL; - } - n = argv[1]->value.number; +gboolean +query_object_matches (Query *query, const char *object) +{ + QueryPrivate *priv; - result = e_sexp_result_new (esexp, ESEXP_RES_TIME); - result->value.time = time_add_day (t, n); + g_return_val_if_fail (query != NULL, FALSE); + g_return_val_if_fail (IS_QUERY (query), FALSE); + g_return_val_if_fail (object != NULL, FALSE); - return result; + priv = query->priv; + + return cal_backend_object_sexp_match_object (priv->sexp, object, priv->backend); } -/* (time-day-begin TIME) - * - * TIME - time_t, base time - * - * Returns the start of the day, according to the local time. - * - * FIXME: TIMEZONES - this uses the current Unix timezone. - */ -static ESExpResult * -func_time_day_begin (ESExp *esexp, int argc, ESExpResult **argv, void *data) +void +query_notify_objects_added (Query *query, const GList *objects) { - time_t t; - ESExpResult *result; - - if (argc != 1) { - e_sexp_fatal_error (esexp, _("time-day-begin expects 1 argument")); - return NULL; - } - - if (argv[0]->type != ESEXP_RES_TIME) { - e_sexp_fatal_error (esexp, _("time-day-begin expects argument 1 " - "to be a time_t")); - return NULL; - } - t = argv[0]->value.time; + QueryPrivate *priv; + GNOME_Evolution_Calendar_stringlist obj_list; + CORBA_Environment ev; + const GList *l; + int num_objs, i; + + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); - result = e_sexp_result_new (esexp, ESEXP_RES_TIME); - result->value.time = time_day_begin (t); + priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); - return result; -} + num_objs = g_list_length ((GList*)objects); + obj_list._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (num_objs); + obj_list._maximum = num_objs; + obj_list._length = num_objs; -/* (time-day-end TIME) - * - * TIME - time_t, base time - * - * Returns the end of the day, according to the local time. - * - * FIXME: TIMEZONES - this uses the current Unix timezone. - */ -static ESExpResult * -func_time_day_end (ESExp *esexp, int argc, ESExpResult **argv, void *data) -{ - time_t t; - ESExpResult *result; + for (l = objects, i = 0; l; l = l->next, i++) + obj_list._buffer[i] = CORBA_string_dup (l->data); - if (argc != 1) { - e_sexp_fatal_error (esexp, _("time-day-end expects 1 argument")); - return NULL; - } + GNOME_Evolution_Calendar_QueryListener_notifyObjectsAdded (priv->listener, &obj_list, &ev); - if (argv[0]->type != ESEXP_RES_TIME) { - e_sexp_fatal_error (esexp, _("time-day-end expects argument 1 " - "to be a time_t")); - return NULL; - } - t = argv[0]->value.time; + CORBA_free (obj_list._buffer); - result = e_sexp_result_new (esexp, ESEXP_RES_TIME); - result->value.time = time_day_end (t); + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of object addition"); - return result; + CORBA_exception_free (&ev); } -/* (get-vtype) - * - * Returns a string indicating the type of component (VEVENT, VTODO, VJOURNAL, - * VFREEBUSY, VTIMEZONE, UNKNOWN). - */ -static ESExpResult * -func_get_vtype (ESExp *esexp, int argc, ESExpResult **argv, void *data) +void +query_notify_objects_added_1 (Query *query, const char *object) { - Query *query; QueryPrivate *priv; - CalComponent *comp; - CalComponentVType vtype; - char *str; - ESExpResult *result; + GList objects; + + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); - query = QUERY (data); priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); - g_assert (priv->next_comp != NULL); - comp = priv->next_comp; - - /* Check argument types */ - - if (argc != 0) { - e_sexp_fatal_error (esexp, _("get-vtype expects 0 arguments")); - return NULL; - } - - /* Get the type */ + objects.next = objects.prev = NULL; + objects.data = (gpointer)object; - vtype = cal_component_get_vtype (comp); + query_notify_objects_added (query, &objects); +} - switch (vtype) { - case CAL_COMPONENT_EVENT: - str = g_strdup ("VEVENT"); - break; +void +query_notify_objects_modified (Query *query, const GList *objects) +{ + QueryPrivate *priv; + GNOME_Evolution_Calendar_CalObjUIDSeq obj_list; + CORBA_Environment ev; + const GList *l; + int num_objs, i; + + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); - case CAL_COMPONENT_TODO: - str = g_strdup ("VTODO"); - break; + priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); - case CAL_COMPONENT_JOURNAL: - str = g_strdup ("VJOURNAL"); - break; + num_objs = g_list_length ((GList*)objects); + obj_list._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (num_objs); + obj_list._maximum = num_objs; + obj_list._length = num_objs; - case CAL_COMPONENT_FREEBUSY: - str = g_strdup ("VFREEBUSY"); - break; + for (l = objects, i = 0; l; l = l->next, i++) + obj_list._buffer[i] = CORBA_string_dup (l->data); - case CAL_COMPONENT_TIMEZONE: - str = g_strdup ("VTIMEZONE"); - break; + GNOME_Evolution_Calendar_QueryListener_notifyObjectsModified (priv->listener, &obj_list, &ev); - default: - str = g_strdup ("UNKNOWN"); - break; - } + CORBA_free (obj_list._buffer); - result = e_sexp_result_new (esexp, ESEXP_RES_STRING); - result->value.string = str; + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of object modification"); - return result; + CORBA_exception_free (&ev); } -/* Sets a boolean value in the data to TRUE; called from - * cal_recur_generate_instances() to indicate that at least one instance occurs - * in the sought time range. We always return FALSE because we want the - * recurrence engine to finish as soon as possible. - */ -static gboolean -instance_occur_cb (CalComponent *comp, time_t start, time_t end, gpointer data) +void +query_notify_objects_modified_1 (Query *query, const char *object) { - gboolean *occurs; - - occurs = data; - *occurs = TRUE; - - return FALSE; -} + QueryPrivate *priv; + GList objects; + + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); -/* Call the backend function to get a timezone from a TZID. */ -static icaltimezone* -resolve_tzid (const char *tzid, gpointer data) -{ - Query *query = data; + priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); - if (!tzid || !tzid[0]) - return NULL; - else - return cal_backend_get_timezone (query->priv->backend, tzid); + objects.next = objects.prev = NULL; + objects.data = (gpointer)object; + + query_notify_objects_modified (query, &objects); } - -/* (occur-in-time-range? START END) - * - * START - time_t, start of the time range - * END - time_t, end of the time range - * - * Returns a boolean indicating whether the component has any occurrences in the - * specified time range. - */ -static ESExpResult * -func_occur_in_time_range (ESExp *esexp, int argc, ESExpResult **argv, void *data) +void +query_notify_objects_removed (Query *query, const GList *uids) { - Query *query; QueryPrivate *priv; - CalComponent *comp; - time_t start, end; - gboolean occurs; - ESExpResult *result; + GNOME_Evolution_Calendar_CalObjUIDSeq uid_list; + CORBA_Environment ev; + const GList *l; + int num_uids, i; + + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); - query = QUERY (data); priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); - g_assert (priv->next_comp != NULL); - comp = priv->next_comp; - - /* Check argument types */ - - if (argc != 2) { - e_sexp_fatal_error (esexp, _("occur-in-time-range? expects 2 arguments")); - return NULL; - } - - if (argv[0]->type != ESEXP_RES_TIME) { - e_sexp_fatal_error (esexp, _("occur-in-time-range? expects argument 1 " - "to be a time_t")); - return NULL; - } - start = argv[0]->value.time; + num_uids = g_list_length ((GList*)uids); + uid_list._buffer = GNOME_Evolution_Calendar_CalObjUIDSeq_allocbuf (num_uids); + uid_list._maximum = num_uids; + uid_list._length = num_uids; - if (argv[1]->type != ESEXP_RES_TIME) { - e_sexp_fatal_error (esexp, _("occur-in-time-range? expects argument 2 " - "to be a time_t")); - return NULL; - } - end = argv[1]->value.time; + for (l = uids, i = 0; l; l = l->next, i ++) + uid_list._buffer[i] = CORBA_string_dup (l->data); - /* See if there is at least one instance in that range */ + GNOME_Evolution_Calendar_QueryListener_notifyObjectsRemoved (priv->listener, &uid_list, &ev); - occurs = FALSE; + CORBA_free (uid_list._buffer); - cal_recur_generate_instances (comp, start, end, - instance_occur_cb, &occurs, - resolve_tzid, query, priv->default_zone); + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of object removal"); - result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); - result->value.bool = occurs; - return result; + CORBA_exception_free (&ev); } -/* Returns whether a list of CalComponentText items matches the specified string */ -static gboolean -matches_text_list (GSList *text_list, const char *str) +void +query_notify_objects_removed_1 (Query *query, const char *uid) { - GSList *l; - gboolean matches; - - matches = FALSE; - - for (l = text_list; l; l = l->next) { - CalComponentText *text; - - text = l->data; - g_assert (text->value != NULL); + QueryPrivate *priv; + GList uids; + + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); - if (e_utf8_strstrcasedecomp (text->value, str) != NULL) { - matches = TRUE; - break; - } - } + priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); - return matches; + uids.next = uids.prev = NULL; + uids.data = (gpointer)uid; + + query_notify_objects_modified (query, &uids); } -/* Returns whether the comments in a component matches the specified string */ -static gboolean -matches_comment (CalComponent *comp, const char *str) +void +query_notify_query_progress (Query *query, const char *message, int percent) { - GSList *list; - gboolean matches; + QueryPrivate *priv; + CORBA_Environment ev; - cal_component_get_comment_list (comp, &list); - matches = matches_text_list (list, str); - cal_component_free_text_list (list); + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); - return matches; -} + priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); -/* Returns whether the description in a component matches the specified string */ -static gboolean -matches_description (CalComponent *comp, const char *str) -{ - GSList *list; - gboolean matches; + GNOME_Evolution_Calendar_QueryListener_notifyQueryProgress (priv->listener, message, percent, &ev); - cal_component_get_description_list (comp, &list); - matches = matches_text_list (list, str); - cal_component_free_text_list (list); + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of query progress"); - return matches; + CORBA_exception_free (&ev); } -/* Returns whether the summary in a component matches the specified string */ -static gboolean -matches_summary (CalComponent *comp, const char *str) +void +query_notify_query_done (Query *query, GNOME_Evolution_Calendar_CallStatus status) { - CalComponentText text; - - cal_component_get_summary (comp, &text); + QueryPrivate *priv; + CORBA_Environment ev; - if (!text.value) - return FALSE; + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); - return e_utf8_strstrcasedecomp (text.value, str) != NULL; -} + priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); -/* Returns whether any text field in a component matches the specified string */ -static gboolean -matches_any (CalComponent *comp, const char *str) -{ - /* As an optimization, and to make life easier for the individual - * predicate functions, see if we are looking for the empty string right - * away. - */ - if (strlen (str) == 0) - return TRUE; - - return (matches_comment (comp, str) - || matches_description (comp, str) - || matches_summary (comp, str)); -} + GNOME_Evolution_Calendar_QueryListener_notifyQueryDone (priv->listener, status, &ev); -/* (contains? FIELD STR) - * - * FIELD - string, name of field to match (any, comment, description, summary) - * STR - string, match string - * - * Returns a boolean indicating whether the specified field contains the - * specified string. - */ -static ESExpResult * -func_contains (ESExp *esexp, int argc, ESExpResult **argv, void *data) -{ - Query *query; - QueryPrivate *priv; - CalComponent *comp; - const char *field; - const char *str; - gboolean matches; - ESExpResult *result; - - query = QUERY (data); - priv = query->priv; - - g_assert (priv->next_comp != NULL); - comp = priv->next_comp; - - /* Check argument types */ - - if (argc != 2) { - e_sexp_fatal_error (esexp, _("contains? expects 2 arguments")); - return NULL; - } - - if (argv[0]->type != ESEXP_RES_STRING) { - e_sexp_fatal_error (esexp, _("contains? expects argument 1 " - "to be a string")); - return NULL; - } - field = argv[0]->value.string; - - if (argv[1]->type != ESEXP_RES_STRING) { - e_sexp_fatal_error (esexp, _("contains? expects argument 2 " - "to be a string")); - return NULL; - } - str = argv[1]->value.string; - - /* See if it matches */ - - if (strcmp (field, "any") == 0) - matches = matches_any (comp, str); - else if (strcmp (field, "comment") == 0) - matches = matches_comment (comp, str); - else if (strcmp (field, "description") == 0) - matches = matches_description (comp, str); - else if (strcmp (field, "summary") == 0) - matches = matches_summary (comp, str); - else { - e_sexp_fatal_error (esexp, _("contains? expects argument 1 to " - "be one of \"any\", \"summary\", \"description\"")); - return NULL; - } - - result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); - result->value.bool = matches; - - return result; -} - -/* (has-categories? STR+) - * (has-categories? #f) - * - * STR - At least one string specifying a category - * Or you can specify a single #f (boolean false) value for components - * that have no categories assigned to them ("unfiled"). - * - * Returns a boolean indicating whether the component has all the specified - * categories. - */ -static ESExpResult * -func_has_categories (ESExp *esexp, int argc, ESExpResult **argv, void *data) -{ - Query *query; - QueryPrivate *priv; - CalComponent *comp; - gboolean unfiled; - int i; - GSList *categories; - gboolean matches; - ESExpResult *result; - - query = QUERY (data); - priv = query->priv; - - g_assert (priv->next_comp != NULL); - comp = priv->next_comp; - - /* Check argument types */ - - if (argc < 1) { - e_sexp_fatal_error (esexp, _("has-categories? expects at least 1 argument")); - return NULL; - } - - if (argc == 1 && argv[0]->type == ESEXP_RES_BOOL) - unfiled = TRUE; - else - unfiled = FALSE; - - if (!unfiled) - for (i = 0; i < argc; i++) - if (argv[i]->type != ESEXP_RES_STRING) { - e_sexp_fatal_error (esexp, _("has-categories? expects all arguments " - "to be strings or one and only one " - "argument to be a boolean false (#f)")); - return NULL; - } - - /* Search categories. First, if there are no categories we return - * whether unfiled components are supposed to match. - */ - - cal_component_get_categories_list (comp, &categories); - if (!categories) { - result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); - result->value.bool = unfiled; - - return result; - } - - /* Otherwise, we *do* have categories but unfiled components were - * requested, so this component does not match. - */ - if (unfiled) { - result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); - result->value.bool = FALSE; - - return result; - } - - matches = TRUE; - - for (i = 0; i < argc; i++) { - const char *sought; - GSList *l; - gboolean has_category; - - sought = argv[i]->value.string; - - has_category = FALSE; - - for (l = categories; l; l = l->next) { - const char *category; - - category = l->data; - - if (strcmp (category, sought) == 0) { - has_category = TRUE; - break; - } - } - - if (!has_category) { - matches = FALSE; - break; - } - } - - cal_component_free_categories_list (categories); - - result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); - result->value.bool = matches; - - return result; -} - -/* (is-completed?) - * - * Returns a boolean indicating whether the component is completed (i.e. has - * a COMPLETED property. This is really only useful for TODO components. - */ -static ESExpResult * -func_is_completed (ESExp *esexp, int argc, ESExpResult **argv, void *data) -{ - Query *query; - QueryPrivate *priv; - CalComponent *comp; - ESExpResult *result; - struct icaltimetype *t; - gboolean complete = FALSE; - - query = QUERY (data); - priv = query->priv; - - g_assert (priv->next_comp != NULL); - comp = priv->next_comp; - - /* Check argument types */ - - if (argc != 0) { - e_sexp_fatal_error (esexp, _("is-completed? expects 0 arguments")); - return NULL; - } - - cal_component_get_completed (comp, &t); - if (t) { - complete = TRUE; - cal_component_free_icaltimetype (t); - } - - result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); - result->value.bool = complete; - - return result; -} - -/* (completed-before? TIME) - * - * TIME - time_t - * - * Returns a boolean indicating whether the component was completed on or - * before the given time (i.e. it checks the COMPLETED property). - * This is really only useful for TODO components. - */ -static ESExpResult * -func_completed_before (ESExp *esexp, int argc, ESExpResult **argv, void *data) -{ - Query *query; - QueryPrivate *priv; - CalComponent *comp; - ESExpResult *result; - struct icaltimetype *tt; - icaltimezone *zone; - gboolean retval = FALSE; - time_t before_time, completed_time; - - query = QUERY (data); - priv = query->priv; - - g_assert (priv->next_comp != NULL); - comp = priv->next_comp; - - /* Check argument types */ - - if (argc != 1) { - e_sexp_fatal_error (esexp, _("completed-before? expects 1 argument")); - return NULL; - } - - if (argv[0]->type != ESEXP_RES_TIME) { - e_sexp_fatal_error (esexp, _("completed-before? expects argument 1 " - "to be a time_t")); - return NULL; - } - before_time = argv[0]->value.time; - - cal_component_get_completed (comp, &tt); - if (tt) { - /* COMPLETED must be in UTC. */ - zone = icaltimezone_get_utc_timezone (); - completed_time = icaltime_as_timet_with_zone (*tt, zone); - -#if 0 - g_print ("Query Time : %s", ctime (&before_time)); - g_print ("Completed Time: %s", ctime (&completed_time)); -#endif - - /* We want to return TRUE if before_time is after - completed_time. */ - if (difftime (before_time, completed_time) > 0) { -#if 0 - g_print (" Returning TRUE\n"); -#endif - retval = TRUE; - } - - cal_component_free_icaltimetype (tt); - } - - result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); - result->value.bool = retval; - - return result; -} - - - -/* Adds a component to our the UIDs hash table and notifies the client */ -static void -add_component (Query *query, const char *uid, gboolean query_in_progress, int n_scanned, int total) -{ - QueryPrivate *priv; - char *old_uid; - CORBA_Environment ev; - GList *l; - - if (query_in_progress) - g_assert (n_scanned > 0 || n_scanned <= total); - - priv = query->priv; - - if (g_hash_table_lookup_extended (priv->uids, uid, (gpointer *) &old_uid, NULL)) { - g_hash_table_remove (priv->uids, old_uid); - g_free (old_uid); - } - - g_hash_table_insert (priv->uids, g_strdup (uid), NULL); - - CORBA_exception_init (&ev); - for (l = priv->listeners; l != NULL; l = l->next) { - GNOME_Evolution_Calendar_CalObjUIDSeq *corba_uids; - - corba_uids = GNOME_Evolution_Calendar_CalObjUIDSeq__alloc (); - CORBA_sequence_set_release (corba_uids, TRUE); - corba_uids->_buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalObjUID_allocbuf (1); - corba_uids->_length = 1; - corba_uids->_buffer[0] = CORBA_string_dup (uid); - - GNOME_Evolution_Calendar_QueryListener_notifyObjUpdated ( - l->data, - corba_uids, - query_in_progress, - n_scanned, - total, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("add_component(): Could not notify the listener of an " - "updated component"); - - CORBA_free (corba_uids); - } + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of query completion"); CORBA_exception_free (&ev); } - -/* Removes a component from our the UIDs hash table and notifies the client */ -static void -remove_component (Query *query, const char *uid) -{ - QueryPrivate *priv; - char *old_uid; - CORBA_Environment ev; - GList *l; - - priv = query->priv; - - if (!g_hash_table_lookup_extended (priv->uids, uid, (gpointer *) &old_uid, NULL)) - return; - - /* The component did match the query before but it no longer does, so we - * have to notify the client. - */ - - g_hash_table_remove (priv->uids, old_uid); - g_free (old_uid); - - CORBA_exception_init (&ev); - for (l = priv->listeners; l != NULL; l = l->next) { - GNOME_Evolution_Calendar_QueryListener_notifyObjRemoved ( - l->data, - (char *) uid, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("remove_component(): Could not notify the listener of a " - "removed component"); - } - - CORBA_exception_free (&ev); -} - -/* Removes a component from the list of pending UIDs */ -static void -remove_from_pending (Query *query, const char *remove_uid) -{ - QueryPrivate *priv; - GList *l; - - priv = query->priv; - - for (l = priv->pending_uids; l; l = l->next) { - char *uid; - - g_assert (priv->n_pending > 0); - - uid = l->data; - if (strcmp (remove_uid, uid)) - continue; - - g_free (uid); - - priv->pending_uids = g_list_remove_link (priv->pending_uids, l); - g_list_free_1 (l); - priv->n_pending--; - - g_assert ((priv->pending_uids && priv->n_pending != 0) - || (!priv->pending_uids && priv->n_pending == 0)); - - break; - } -} - -static struct { - char *name; - ESExpFunc *func; -} functions[] = { - /* Time-related functions */ - { "time-now", func_time_now }, - { "make-time", func_make_time }, - { "time-add-day", func_time_add_day }, - { "time-day-begin", func_time_day_begin }, - { "time-day-end", func_time_day_end }, - - /* Component-related functions */ - { "get-vtype", func_get_vtype }, - { "occur-in-time-range?", func_occur_in_time_range }, - { "contains?", func_contains }, - { "has-categories?", func_has_categories }, - { "is-completed?", func_is_completed }, - { "completed-before?", func_completed_before } -}; - -/* Initializes a sexp by interning our own symbols */ -static ESExp * -create_sexp (Query *query) -{ - ESExp *esexp; - int i; - - esexp = e_sexp_new (); - - for (i = 0; i < (sizeof (functions) / sizeof (functions[0])); i++) - e_sexp_add_function (esexp, 0, functions[i].name, functions[i].func, query); - - return esexp; -} - -/* Creates the ESexp and parses the esexp. If a parse error occurs, it sets the - * query state to QUERY_PARSE_ERROR and returns FALSE. - */ -static gboolean -parse_sexp (Query *query) -{ - QueryPrivate *priv; - - priv = query->priv; - - /* Compile the query string */ - - priv->esexp = create_sexp (query); - - g_assert (priv->sexp != NULL); - e_sexp_input_text (priv->esexp, priv->sexp, strlen (priv->sexp)); - - if (e_sexp_parse (priv->esexp) == -1) { - const char *error_str; - CORBA_Environment ev; - GList *l; - - priv->state = QUERY_PARSE_ERROR; - - /* Report the error to the listeners */ - - error_str = e_sexp_error (priv->esexp); - g_assert (error_str != NULL); - - CORBA_exception_init (&ev); - for (l = priv->listeners; l != NULL; l = l->next) { - GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( - l->data, - GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR, - error_str, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("parse_sexp(): Could not notify the listener of " - "a parse error"); - } - - CORBA_exception_free (&ev); - - e_sexp_unref (priv->esexp); - priv->esexp = NULL; - - /* remove the query from the list of cached queries */ - cached_queries = g_list_remove (cached_queries, query); - bonobo_object_unref (BONOBO_OBJECT (query)); - - return FALSE; - } - - return TRUE; -} - -/* Evaluates the query sexp on the specified component and notifies the listener - * as appropriate. - */ -static void -match_component (Query *query, const char *uid, - gboolean query_in_progress, int n_scanned, int total) -{ - QueryPrivate *priv; - CalComponent *comp; - ESExpResult *result; - - priv = query->priv; - - g_assert (priv->state == QUERY_IN_PROGRESS || priv->state == QUERY_DONE); - g_assert (priv->esexp != NULL); - - comp = query_backend_get_object_component (priv->qb, uid); - if (!comp) - return; - - /* Eval the sexp */ - - g_assert (priv->next_comp == NULL); - - priv->next_comp = comp; - result = e_sexp_eval (priv->esexp); - priv->next_comp = NULL; - - if (!result) { - const char *error_str; - CORBA_Environment ev; - GList *l; - - error_str = e_sexp_error (priv->esexp); - g_assert (error_str != NULL); - - CORBA_exception_init (&ev); - for (l = priv->listeners; l != NULL; l = l->next) { - GNOME_Evolution_Calendar_QueryListener_notifyEvalError ( - l->data, - error_str, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("match_component(): Could not notify the listener of " - "an evaluation error"); - } - - CORBA_exception_free (&ev); - return; - } else if (result->type != ESEXP_RES_BOOL) { - CORBA_Environment ev; - GList *l; - - CORBA_exception_init (&ev); - for (l = priv->listeners; l != NULL; l = l->next) { - GNOME_Evolution_Calendar_QueryListener_notifyEvalError ( - l->data, - _("Evaluation of the search expression did not yield a boolean value"), - &ev); - - if (BONOBO_EX (&ev)) - g_message ("match_component(): Could not notify the listener of " - "an unexpected result value type when evaluating the " - "search expression"); - } - - CORBA_exception_free (&ev); - } else { - /* Success; process the component accordingly */ - - if (result->value.bool) - add_component (query, uid, query_in_progress, n_scanned, total); - else - remove_component (query, uid); - } - - e_sexp_result_free (priv->esexp, result); -} - -/* Processes all components that are queued in the list */ -static gboolean -process_components_cb (gpointer data) -{ - Query *query; - QueryPrivate *priv; - char *uid; - GList *l; - CORBA_Environment ev; - - query = QUERY (data); - priv = query->priv; - - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - - bonobo_object_ref (BONOBO_OBJECT (query)); - - while (priv->pending_uids) { - g_assert (priv->n_pending > 0); - - /* Fetch the component */ - - l = priv->pending_uids; - priv->pending_uids = g_list_remove_link (priv->pending_uids, l); - priv->n_pending--; - - g_assert ((priv->pending_uids && priv->n_pending != 0) - || (!priv->pending_uids && priv->n_pending == 0)); - - uid = l->data; - g_assert (uid != NULL); - - g_list_free_1 (l); - - match_component (query, uid, - TRUE, - priv->pending_total - priv->n_pending, - priv->pending_total); - - g_free (uid); - - /* run the main loop, for not blocking */ - if (gtk_events_pending ()) - gtk_main_iteration (); - } - - bonobo_object_unref (BONOBO_OBJECT (query)); - if (!priv || !priv->listeners) - return FALSE; - - /* notify listeners that the query ended */ - priv->state = QUERY_DONE; - - CORBA_exception_init (&ev); - for (l = priv->listeners; l != NULL; l = l->next) { - GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( - l->data, - GNOME_Evolution_Calendar_QueryListener_SUCCESS, - "", - &ev); - - if (BONOBO_EX (&ev)) - g_message ("start_query(): Could not notify the listener of " - "a finished query"); - } - - CORBA_exception_free (&ev); - - return FALSE; -} - -/* Callback used when a component changes in the backend */ -static void -backend_obj_updated_cb (CalBackend *backend, const char *uid, gpointer data) -{ - Query *query; - QueryPrivate *priv; - - query = QUERY (data); - priv = query->priv; - - g_assert (priv->state == QUERY_IN_PROGRESS || priv->state == QUERY_DONE); - - bonobo_object_ref (BONOBO_OBJECT (query)); - - match_component (query, uid, FALSE, 0, 0); - remove_from_pending (query, uid); - - bonobo_object_unref (BONOBO_OBJECT (query)); -} - -/* Callback used when a component is removed from the backend */ -static void -backend_obj_removed_cb (CalBackend *backend, const char *uid, gpointer data) -{ - Query *query; - QueryPrivate *priv; - - query = QUERY (data); - priv = query->priv; - - g_assert (priv->state == QUERY_IN_PROGRESS || priv->state == QUERY_DONE); - - bonobo_object_ref (BONOBO_OBJECT (query)); - - remove_component (query, uid); - remove_from_pending (query, uid); - - bonobo_object_unref (BONOBO_OBJECT (query)); -} - -/* Actually starts the query */ -static void -start_query (Query *query) -{ - QueryPrivate *priv; - - priv = query->priv; - - if (!parse_sexp (query)) - return; - - /* Populate the query with UIDs so that we can process them asynchronously */ - - priv->state = QUERY_IN_PROGRESS; - priv->pending_uids = query_backend_get_uids (priv->qb, CALOBJ_TYPE_ANY); - priv->pending_total = g_list_length (priv->pending_uids); - priv->n_pending = priv->pending_total; - - g_signal_connect (G_OBJECT (priv->backend), "obj_updated", - G_CALLBACK (backend_obj_updated_cb), - query); - g_signal_connect (G_OBJECT (priv->backend), "obj_removed", - G_CALLBACK (backend_obj_removed_cb), - query); - - priv->timeout_id = g_timeout_add (100, (GSourceFunc) process_components_cb, query); -} - -/* Idle handler for starting a query */ -static gboolean -start_query_cb (gpointer data) -{ - Query *query; - QueryPrivate *priv; - - query = QUERY (data); - priv = query->priv; - - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - - if (priv->state == QUERY_START_PENDING) { - priv->state = QUERY_IN_PROGRESS; - start_query (query); - } - - return FALSE; -} - -static void -listener_died_cb (EComponentListener *cl, gpointer data) -{ - QueryPrivate *priv; - Query *query = QUERY (data); - GNOME_Evolution_Calendar_QueryListener ql; - CORBA_Environment ev; - - priv = query->priv; - - ql = e_component_listener_get_component (cl); - priv->listeners = g_list_remove (priv->listeners, ql); - - priv->component_listeners = g_list_remove (priv->component_listeners, cl); - g_object_unref (cl); - - CORBA_exception_init (&ev); - bonobo_object_release_unref (ql, &ev); - - if (BONOBO_EX (&ev)) - g_message ("query_destroy(): Could not unref the listener\n"); - - CORBA_exception_free (&ev); -} - -static void -add_uid_cb (gpointer key, gpointer value, gpointer data) -{ - char *uid = (char *) key; - GList **uidlist = (GList **) data; - - *uidlist = g_list_append (*uidlist, uid); -} - -/* Idle handler for starting a cached query */ -static gboolean -start_cached_query_cb (gpointer data) -{ - CORBA_Environment ev; - QueryPrivate *priv; - EComponentListener *cl; - StartCachedQueryInfo *info = (StartCachedQueryInfo *) data; - - priv = info->query->priv; - - g_source_remove (info->tid); - priv->cached_timeouts = g_list_remove (priv->cached_timeouts, - GINT_TO_POINTER (info->tid)); - - /* if the query hasn't started yet, we add the listener */ - if (priv->state == QUERY_START_PENDING || - priv->state == QUERY_WAIT_FOR_BACKEND) { - priv->listeners = g_list_append (priv->listeners, info->ql); - - cl = e_component_listener_new (info->ql); - priv->component_listeners = g_list_append (priv->component_listeners, cl); - g_signal_connect (G_OBJECT (cl), "component_died", - G_CALLBACK (listener_died_cb), info->query); - } else if (priv->state == QUERY_IN_PROGRESS) { - /* if it's in progress, we re-add the timeout */ - info->tid = g_timeout_add (100, (GSourceFunc) start_cached_query_cb, info); - priv->cached_timeouts = g_list_append (priv->cached_timeouts, - GINT_TO_POINTER (info->tid)); - - return FALSE; - } else if (priv->state == QUERY_PARSE_ERROR) { - /* notify listener of error */ - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( - info->ql, - GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR, - _("Parse error"), - &ev); - - if (BONOBO_EX (&ev)) - g_message ("start_cached_query_cb(): Could not notify the listener of " - "a parse error"); - - CORBA_exception_free (&ev); - - /* remove all traces of this query */ - cached_queries = g_list_remove (cached_queries, info->query); - bonobo_object_unref (BONOBO_OBJECT (info->query)); - } else if (priv->state == QUERY_DONE) { - int len; - GList *uid_list = NULL, *l; - - CORBA_exception_init (&ev); - - /* if the query is done, then we just notify the listener of all the - * UIDS we've got so far, all at once */ - g_hash_table_foreach (priv->uids, (GHFunc) add_uid_cb, &uid_list); - - len = g_list_length (uid_list); - if (len > 0) { - int n; - GNOME_Evolution_Calendar_CalObjUIDSeq *corba_uids; - - corba_uids = GNOME_Evolution_Calendar_CalObjUIDSeq__alloc (); - corba_uids->_length = len; - corba_uids->_maximum = len; - corba_uids->_buffer = CORBA_sequence_GNOME_Evolution_Calendar_CalObjUID_allocbuf (len); - CORBA_sequence_set_release (corba_uids, TRUE); - - for (l = uid_list, n = 0; l != NULL; l = l->next, n++) - corba_uids->_buffer[n] = CORBA_string_dup ((CORBA_char *) l->data); - - GNOME_Evolution_Calendar_QueryListener_notifyObjUpdated ( - info->ql, - corba_uids, - TRUE, - len, - len, &ev); - - if (BONOBO_EX (&ev)) - g_message ("start_cached_query_cb(): Could not notify the listener of all " - "cached components"); - - CORBA_free (corba_uids); - g_list_free (uid_list); - } - - /* setup private data and notify listener that the query ended */ - priv->listeners = g_list_append (priv->listeners, info->ql); - - cl = e_component_listener_new (info->ql); - priv->component_listeners = g_list_append (priv->component_listeners, cl); - g_signal_connect (G_OBJECT (cl), "component_died", - G_CALLBACK (listener_died_cb), info->query); - - GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( - info->ql, - GNOME_Evolution_Calendar_QueryListener_SUCCESS, - "", - &ev); - if (BONOBO_EX (&ev)) - g_message ("start_cached_query_cb(): Could not notify the listener of " - "a finished query"); - - CORBA_exception_free (&ev); - } - - g_free (info); - - return FALSE; -} - -/* Callback used when the backend gets loaded; we just queue the query to be - * started later. - */ -static void -backend_opened_cb (CalBackend *backend, CalBackendOpenStatus status, gpointer data) -{ - Query *query; - QueryPrivate *priv; - - query = QUERY (data); - priv = query->priv; - - g_assert (priv->state == QUERY_WAIT_FOR_BACKEND); - - g_signal_handlers_disconnect_matched (G_OBJECT (priv->backend), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, query); - priv->state = QUERY_START_PENDING; - - if (status == CAL_BACKEND_OPEN_SUCCESS) { - g_assert (cal_backend_is_loaded (backend)); - - priv->timeout_id = g_timeout_add (100, (GSourceFunc) start_query_cb, query); - } -} - -/* Callback used when the backend for a cached query is destroyed */ -static void -backend_destroyed_cb (gpointer data, GObject *where_backend_was) -{ - Query *query; - - query = QUERY (data); - - cached_queries = g_list_remove (cached_queries, query); - bonobo_object_unref (BONOBO_OBJECT (query)); -} - -/** - * query_construct: - * @query: A live search query. - * @backend: Calendar backend that the query object will monitor. - * @ql: Listener for query results. - * @sexp: Sexp that defines the query. - * - * Constructs a #Query object by binding it to a calendar backend and a query - * listener. The @query object will start to populate itself asynchronously and - * call the listener as appropriate. - * - * Return value: The same value as @query, or NULL if the query could not - * be constructed. - **/ -Query * -query_construct (Query *query, - CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp) -{ - QueryPrivate *priv; - CORBA_Environment ev; - EComponentListener *cl; - - g_return_val_if_fail (query != NULL, NULL); - g_return_val_if_fail (IS_QUERY (query), NULL); - g_return_val_if_fail (backend != NULL, NULL); - g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); - g_return_val_if_fail (ql != CORBA_OBJECT_NIL, NULL); - g_return_val_if_fail (sexp != NULL, NULL); - - priv = query->priv; - - CORBA_exception_init (&ev); - priv->listeners = g_list_append (NULL, CORBA_Object_duplicate (ql, &ev)); - if (BONOBO_EX (&ev)) { - g_message ("query_construct(): Could not duplicate the listener"); - priv->listeners = NULL; - CORBA_exception_free (&ev); - return NULL; - } - CORBA_exception_free (&ev); - - cl = e_component_listener_new (ql); - priv->component_listeners = g_list_append (priv->component_listeners, cl); - g_signal_connect (G_OBJECT (cl), "component_died", - G_CALLBACK (listener_died_cb), query); - - priv->backend = backend; - g_object_ref (priv->backend); - - priv->qb = query_backend_new (query, backend); - priv->default_zone = cal_backend_get_default_timezone (backend); - - priv->sexp = g_strdup (sexp); - - /* Queue the query to be started asynchronously */ - - if (cal_backend_is_loaded (priv->backend)) { - priv->state = QUERY_START_PENDING; - - priv->timeout_id = g_timeout_add (100, (GSourceFunc) start_query_cb, query); - } else - g_signal_connect (G_OBJECT (priv->backend), "opened", - G_CALLBACK (backend_opened_cb), - query); - - return query; -} - -/** - * query_new: - * @backend: Calendar backend that the query object will monitor. - * @ql: Listener for query results. - * @sexp: Sexp that defines the query. - * - * Creates a new query engine object that monitors a calendar backend. - * - * Return value: A newly-created query object, or NULL on failure. - **/ -Query * -query_new (CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp) -{ - Query *query; - GList *l; - - /* first, see if we've got this query in our cache */ - for (l = cached_queries; l != NULL; l = l->next) { - query = QUERY (l->data); - - g_assert (query != NULL); - - if (query->priv->backend == backend && - !strcmp (query->priv->sexp, sexp)) { - StartCachedQueryInfo *info; - CORBA_Environment ev; - - info = g_new0 (StartCachedQueryInfo, 1); - info->query = query; - - CORBA_exception_init (&ev); - info->ql = CORBA_Object_duplicate (ql, &ev); - if (BONOBO_EX (&ev)) { - g_message ("query_new(): Could not duplicate listener object"); - g_free (info); - - return NULL; - } - CORBA_exception_free (&ev); - - info->tid = g_timeout_add (100, (GSourceFunc) start_cached_query_cb, info); - query->priv->cached_timeouts = g_list_append (query->priv->cached_timeouts, - GINT_TO_POINTER (info->tid)); - - bonobo_object_ref (BONOBO_OBJECT (query)); - return query; - } - } - - /* not found, so create a new one */ - query = QUERY (g_object_new (QUERY_TYPE, NULL)); - if (!query_construct (query, backend, ql, sexp)) { - bonobo_object_unref (BONOBO_OBJECT (query)); - return NULL; - } - - /* add the new query to our cache */ - g_object_weak_ref (G_OBJECT (query->priv->backend), - backend_destroyed_cb, query); - - bonobo_object_ref (BONOBO_OBJECT (query)); - cached_queries = g_list_append (cached_queries, query); - - return query; -} diff --git a/calendar/pcs/query.h b/calendar/pcs/query.h index 752c29eb40..9c03aa2661 100644 --- a/calendar/pcs/query.h +++ b/calendar/pcs/query.h @@ -24,6 +24,7 @@ #include #include "pcs/cal-common.h" #include "pcs/evolution-calendar.h" +#include "cal-backend-object-sexp.h" G_BEGIN_DECLS @@ -37,31 +38,43 @@ G_BEGIN_DECLS typedef struct _QueryPrivate QueryPrivate; -typedef struct { +struct _Query { BonoboObject xobject; /* Private data */ QueryPrivate *priv; -} Query; +}; -typedef struct { +struct _QueryClass { BonoboObjectClass parent_class; POA_GNOME_Evolution_Calendar_Query__epv epv; -} QueryClass; - -GType query_get_type (void); - -Query *query_construct (Query *query, - CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp); - -Query *query_new (CalBackend *backend, - GNOME_Evolution_Calendar_QueryListener ql, - const char *sexp); - - +}; + +GType query_get_type (void); +Query *query_new (CalBackend *backend, + GNOME_Evolution_Calendar_QueryListener ql, + CalBackendObjectSExp *sexp); +const char *query_get_text (Query *query); +CalBackendObjectSExp *query_get_object_sexp (Query *query); +gboolean query_object_matches (Query *query, const char *object); +void query_notify_objects_added (Query *query, + const GList *objects); +void query_notify_objects_added_1 (Query *query, + const char *object); +void query_notify_objects_modified (Query *query, + const GList *objects); +void query_notify_objects_modified_1 (Query *query, + const char *object); +void query_notify_objects_removed (Query *query, + const GList *uids); +void query_notify_objects_removed_1 (Query *query, + const char *uid); +void query_notify_query_progress (Query *query, + const char *message, + int percent); +void query_notify_query_done (Query *query, + GNOME_Evolution_Calendar_CallStatus status); G_END_DECLS diff --git a/camel/ChangeLog b/camel/ChangeLog index 286058dc8e..343bbf3afb 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,7 +1,43 @@ +2003-10-21 Not Zed + + * providers/local/camel-local-folder.c (local_getv, local_setv): + use the right tag name for the index_body arg. + (local_sync): write any persistent metadata - to make it + persistent. + (camel_local_folder_construct): turn off indexing, for now, it + should be done in local_setv. + + * providers/local/camel-local-folder.h: change body_index to a bool + type. + + * camel-object.c (cobject_state_read, cobject_state_write): handle + bool types + (cobject_state_write): make sure we free all arg types. + + * camel-arg.c (camel_argv_build): + (camel_arggetv_build): handle bool type. + + * camel-arg.h: Added BOO (bool) type. + +2003-10-15 Not Zed + + * camel-store.c (camel_folder_info_build): Fix so we output the + tree in sorted depth-first order, rather in reverse. + 2003-10-16 Jeffrey Stedfast * camel-sasl-kerberos4.c: Fixed a #include. +2003-10-10 Not Zed + + * providers/local/camel-local-provider.c: set the url fragment + flag for local providers. + + * camel-provider.h: Move the URL_PART_NEED bits to the high 16 + bits, to allow for easier changes in the future. Added a + URL_PART_FRAGMENT flag for providers that use fragment = folder + path. + 2003-10-09 Jeffrey Stedfast * camel-mime-utils.c (header_decode_date): Allow timezone offsets @@ -20,6 +56,12 @@ localhost lookup results in a numeric IPv6 host, use the form "[IPv6:]" as specified in rfc2821. Fixes bug #46006. +2003-09-23 Ettore Perazzoli + + * providers/local/camel-local-provider.c: Set the IS_STORAGE bit + in the mbox provider, since it can now contain a hierarchy of + folders. + 2003-09-23 Jeffrey Stedfast * providers/local/camel-mbox-store.c (get_folder): If the CREATE @@ -687,6 +729,11 @@ addr->str to make sure that it is valid UTF-8, if not convert it to UTF-8. Fixes bug #42170. +2003-07-23 Ettore Perazzoli + + * camel-provider.c (camel_provider_init): Print the provider + directory as well, for debugging. + 2003-07-23 Jeffrey Stedfast * camel-mime-message.c (find_best_encoding): Revert my previous diff --git a/camel/camel-arg.c b/camel/camel-arg.c index f8cd048f0a..bcd79bab59 100644 --- a/camel/camel-arg.c +++ b/camel/camel-arg.c @@ -60,6 +60,9 @@ int camel_argv_build(CamelArgV *tv) case CAMEL_ARG_PTR: a->ca_ptr = va_arg(tv->ap, void *); break; + case CAMEL_ARG_BOO: + a->ca_int = va_arg(tv->ap, int) != 0; + break; default: printf("Error, unknown type, truncating result\n"); more = FALSE; @@ -96,6 +99,7 @@ int camel_arggetv_build(CamelArgGetV *tv) *a->ca_object = NULL; break; case CAMEL_ARG_INT: + case CAMEL_ARG_BOO: a->ca_int = va_arg(tv->ap, int *); *a->ca_int = 0; break; diff --git a/camel/camel-arg.h b/camel/camel-arg.h index 1213596457..ebecc0f217 100644 --- a/camel/camel-arg.h +++ b/camel/camel-arg.h @@ -45,6 +45,7 @@ enum camel_arg_t { CAMEL_ARG_DBL = 0x20000000, /* double */ CAMEL_ARG_STR = 0x30000000, /* c string */ CAMEL_ARG_PTR = 0x40000000, /* ptr */ + CAMEL_ARG_BOO = 0x50000000, /* bool */ }; typedef struct _CamelArg CamelArg; diff --git a/camel/camel-object.c b/camel/camel-object.c index 31d458a59d..744e9f7566 100644 --- a/camel/camel-object.c +++ b/camel/camel-object.c @@ -439,6 +439,7 @@ cobject_state_read(CamelObject *obj, FILE *fp) switch(argv->argv[argv->argc].tag & CAMEL_ARG_TYPE) { case CAMEL_ARG_INT: + case CAMEL_ARG_BOO: if (camel_file_util_decode_uint32(fp, &argv->argv[argv->argc].ca_int) == -1) goto cleanup; break; @@ -535,6 +536,7 @@ cobject_state_write(CamelObject *obj, FILE *fp) switch (arg->tag & CAMEL_ARG_TYPE) { case CAMEL_ARG_INT: + case CAMEL_ARG_BOO: if (camel_file_util_encode_uint32(fp, arg->ca_int) == -1) goto abort; break; @@ -547,6 +549,13 @@ cobject_state_write(CamelObject *obj, FILE *fp) res = 0; abort: + for (i=0;iargc;i++) { + CamelArg *arg = &argv->argv[i]; + + if ((argv->argv[i].tag & CAMEL_ARG_TYPE) == CAMEL_ARG_STR) + camel_object_free(obj, arg->tag, arg->ca_str); + } + g_free(argv); g_free(arggetv); diff --git a/camel/camel-provider.c b/camel/camel-provider.c index 9beacc02f0..321b3077cd 100644 --- a/camel/camel-provider.c +++ b/camel/camel-provider.c @@ -70,8 +70,8 @@ camel_provider_init (void) dir = opendir (CAMEL_PROVIDERDIR); if (!dir) { - g_error ("Could not open camel provider directory: %s", - g_strerror (errno)); + g_error ("Could not open camel provider directory (%s): %s", + CAMEL_PROVIDERDIR, g_strerror (errno)); return NULL; } diff --git a/camel/camel-provider.h b/camel/camel-provider.h index edfb424181..98c5a3ed6a 100644 --- a/camel/camel-provider.h +++ b/camel/camel-provider.h @@ -81,7 +81,7 @@ extern char *camel_provider_type_name[CAMEL_NUM_PROVIDER_TYPES]; #define CAMEL_URL_PART_PORT (1 << 4) #define CAMEL_URL_PART_PATH (1 << 5) -#define CAMEL_URL_PART_NEED 6 +#define CAMEL_URL_PART_NEED 8 /* Use these macros to test a provider's url_flags */ #define CAMEL_PROVIDER_ALLOWS(prov, flags) (prov->url_flags & (flags | (flags << CAMEL_URL_PART_NEED))) @@ -102,7 +102,8 @@ extern char *camel_provider_type_name[CAMEL_NUM_PROVIDER_TYPES]; #define CAMEL_URL_NEED_PORT (CAMEL_URL_PART_PORT << CAMEL_URL_PART_NEED) #define CAMEL_URL_NEED_PATH (CAMEL_URL_PART_PATH << CAMEL_URL_PART_NEED) -#define CAMEL_URL_PATH_IS_ABSOLUTE (1 << 12) +#define CAMEL_URL_FRAGMENT_IS_PATH (1 << 30) /* url uses fragment for folder name path, not path */ +#define CAMEL_URL_PATH_IS_ABSOLUTE (1 << 31) #define CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT(prov) (prov->object_types[CAMEL_PROVIDER_STORE] && prov->object_types[CAMEL_PROVIDER_TRANSPORT]) diff --git a/camel/camel-store.c b/camel/camel-store.c index eedc9dfa2a..3c49f312ec 100644 --- a/camel/camel-store.c +++ b/camel/camel-store.c @@ -776,7 +776,7 @@ CamelFolderInfo * camel_folder_info_build (GPtrArray *folders, const char *namespace, char separator, gboolean short_names) { - CamelFolderInfo *fi, *pfi, *top = NULL; + CamelFolderInfo *fi, *pfi, *top = NULL, *tail = NULL; GHashTable *hash; char *name, *p, *pname; int i, nlen; @@ -854,9 +854,15 @@ camel_folder_info_build (GPtrArray *folders, const char *namespace, g_hash_table_insert (hash, pname, pfi); g_ptr_array_add (folders, pfi); } - fi->sibling = pfi->child; + tail = pfi->child; + if (tail == NULL) { + pfi->child = fi; + } else { + while (tail->sibling) + tail = tail->sibling; + tail->sibling = fi; + } fi->parent = pfi; - pfi->child = fi; } else if (!top) top = fi; } @@ -864,13 +870,18 @@ camel_folder_info_build (GPtrArray *folders, const char *namespace, g_hash_table_destroy (hash); /* Link together the top-level folders */ + tail = top; for (i = 0; i < folders->len; i++) { fi = folders->pdata[i]; if (fi->parent || fi == top) continue; - if (top) - fi->sibling = top; - top = fi; + if (tail == NULL) { + tail = fi; + top = fi; + } else { + tail->sibling = fi; + tail = fi; + } } return top; diff --git a/camel/providers/local/camel-local-folder.c b/camel/providers/local/camel-local-folder.c index 608954af94..b774c8b5f6 100644 --- a/camel/providers/local/camel-local-folder.c +++ b/camel/providers/local/camel-local-folder.c @@ -251,7 +251,9 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con } camel_object_set(lf, NULL, CAMEL_OBJECT_STATE_FILE, statepath, NULL); g_free (statepath); - + + lf->flags = flags; + if (camel_object_state_read(lf) == -1) { /* FIXME: load defaults? */ } @@ -269,7 +271,8 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con the old-format 'ibex' files that might be lying around */ unlink(lf->index_path); -#if 0 + /* FIXME: Need to run indexing off of the setv method */ +#if 1 forceindex = FALSE; #else /* if we have no/invalid index file, force it */ @@ -292,8 +295,8 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con camel_text_index_remove(lf->index_path); forceindex = FALSE; } -#endif lf->flags = flags; +#endif folder->summary = (CamelFolderSummary *)CLOCALF_CLASS(lf)->create_summary(lf->summary_path, lf->folder_path, lf->index); if (camel_local_summary_load((CamelLocalSummary *)folder->summary, forceindex, ex) == -1) { @@ -404,7 +407,9 @@ local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) break; } - case CAMEL_LOCAL_FOLDER_INDEX_BODY: + case CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY: + printf("getv:'%s' flags %08x\n", ((CamelFolder *)object)->full_name, ((CamelLocalFolder *)object)->flags); + /* FIXME: remove this from sotre flags */ *arg->ca_int = (((CamelLocalFolder *)folder)->flags & CAMEL_STORE_FOLDER_BODY_INDEX) != 0; break; @@ -431,9 +436,16 @@ local_setv(CamelObject *object, CamelException *ex, CamelArgV *args) tag = arg->tag; switch (tag & CAMEL_ARG_TAG) { - case CAMEL_LOCAL_FOLDER_INDEX_BODY: + case CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY: /* FIXME: implement */ + /* TODO: When turning on (off?) the index, we want to launch a task for it, + and make sure we dont have multiple tasks doing the same job */ printf("setting folder indexing %s\n", arg->ca_int?"on":"off"); + if (arg->ca_int) + ((CamelLocalFolder *)object)->flags |= CAMEL_STORE_FOLDER_BODY_INDEX; + else + ((CamelLocalFolder *)object)->flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX; + printf("setv:'%s' flags %08x\n", ((CamelFolder *)object)->full_name, ((CamelLocalFolder *)object)->flags); break; default: continue; @@ -494,6 +506,8 @@ local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex) if (camel_local_folder_lock(lf, CAMEL_LOCK_WRITE, ex) == -1) return; + camel_object_state_write(lf); + /* if sync fails, we'll pass it up on exit through ex */ camel_local_summary_sync((CamelLocalSummary *)folder->summary, expunge, lf->changes, ex); camel_local_folder_unlock(lf); diff --git a/camel/providers/local/camel-local-folder.h b/camel/providers/local/camel-local-folder.h index 4fb5980a07..73059f03b3 100644 --- a/camel/providers/local/camel-local-folder.h +++ b/camel/providers/local/camel-local-folder.h @@ -47,7 +47,7 @@ enum { }; enum { - CAMEL_LOCAL_FOLDER_INDEX_BODY = CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY | CAMEL_ARG_INT, + CAMEL_LOCAL_FOLDER_INDEX_BODY = CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY | CAMEL_ARG_BOO, }; typedef struct { diff --git a/camel/providers/local/camel-local-provider.c b/camel/providers/local/camel-local-provider.c index 077bc45b5f..a52dfbde5f 100644 --- a/camel/providers/local/camel-local-provider.c +++ b/camel/providers/local/camel-local-provider.c @@ -50,7 +50,7 @@ static CamelProvider mh_provider = { N_("For storing local mail in MH-like mail directories."), "mail", CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_LOCAL, - CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE, + CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE | CAMEL_URL_FRAGMENT_IS_PATH, mh_conf_entries, /* ... */ }; @@ -65,8 +65,8 @@ static CamelProvider mbox_provider = { N_("Local delivery"), N_("For retrieving (moving) local mail from standard mbox formated spools into folders managed by Evolution."), "mail", - CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_LOCAL, - CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE, + CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_LOCAL, + CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE | CAMEL_URL_FRAGMENT_IS_PATH, mbox_conf_entries, /* ... */ }; @@ -84,7 +84,7 @@ static CamelProvider maildir_provider = { N_("For storing local mail in maildir directories."), "mail", CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_LOCAL, - CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE, + CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE | CAMEL_URL_FRAGMENT_IS_PATH, maildir_conf_entries, /* ... */ }; @@ -102,7 +102,7 @@ static CamelProvider spool_provider = { N_("For reading and storing local mail in external standard mbox spool files.\nMay also be used to read a tree of Elm, Pine, or Mutt style folders."), "mail", CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE, - CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE, + CAMEL_URL_NEED_PATH | CAMEL_URL_PATH_IS_ABSOLUTE | CAMEL_URL_FRAGMENT_IS_PATH, spool_conf_entries, /* ... */ }; diff --git a/composer/ChangeLog b/composer/ChangeLog index b698c2cf57..1bc29bb5df 100644 --- a/composer/ChangeLog +++ b/composer/ChangeLog @@ -1,3 +1,37 @@ +2003-10-08 Chris Toshok + + * evolution-composer.c (corba_recipientlist_to_destv): EDestination => + EABDestination, and e_destination => eab_destination. + (impl_Composer_set_headers): same. + + * e-msg-composer.c (update_auto_recipients): EDestination => + EABDestination, and e_destination => eab_destination. + (e_msg_composer_new_with_message): same. + (add_recipients): same. + (handle_mailto): same. + (e_msg_composer_set_headers): same. + (e_msg_composer_get_recipients): same. + (e_msg_composer_get_to): same. + (e_msg_composer_get_cc): same. + (e_msg_composer_get_bcc): same. + + * e-msg-composer.h: EDestination => EABDestination, and + e_destination => eab_destination. + + * e-msg-composer-hdrs.c (set_recipients_from_destv): EDestination + => EABDestination, and e_destination => eab_destination. + (e_msg_composer_hdrs_to_message_internal): same. + (e_msg_composer_hdrs_set_to): same. + (e_msg_composer_hdrs_set_cc): same. + (e_msg_composer_hdrs_set_bcc): same. + (e_msg_composer_hdrs_get_to): same. + (e_msg_composer_hdrs_get_cc): same. + (e_msg_composer_hdrs_get_bcc): same. + (e_msg_composer_hdrs_get_recipients): same. + + * e-msg-composer-hdrs.h: EDestination => EABDestination, and + e_destination => eab_destination. + 2003-09-26 Jeffrey Stedfast * e-msg-composer.c (save): Don't blindly claim that the file diff --git a/composer/e-msg-composer-hdrs.c b/composer/e-msg-composer-hdrs.c index e6d4bebe17..23c24a339a 100644 --- a/composer/e-msg-composer-hdrs.c +++ b/composer/e-msg-composer-hdrs.c @@ -51,7 +51,6 @@ #include "evolution-folder-selector-button.h" #include "e-msg-composer-hdrs.h" #include "mail/mail-config.h" -#include "addressbook/backend/ebook/e-book-util.h" extern EvolutionShellClient *global_shell_client; @@ -837,9 +836,9 @@ e_msg_composer_hdrs_new (BonoboUIComponent *uic, int visible_mask, int visible_f static void set_recipients_from_destv (CamelMimeMessage *msg, - EDestination **to_destv, - EDestination **cc_destv, - EDestination **bcc_destv, + EABDestination **to_destv, + EABDestination **cc_destv, + EABDestination **bcc_destv, gboolean redirect) { CamelInternetAddress *to_addr; @@ -856,12 +855,12 @@ set_recipients_from_destv (CamelMimeMessage *msg, if (to_destv) { for (i = 0; to_destv[i] != NULL; ++i) { - text_addr = e_destination_get_address (to_destv[i]); + text_addr = eab_destination_get_address (to_destv[i]); if (text_addr && *text_addr) { target = to_addr; - if (e_destination_is_evolution_list (to_destv[i]) - && !e_destination_list_show_addresses (to_destv[i])) { + if (eab_destination_is_evolution_list (to_destv[i]) + && !eab_destination_list_show_addresses (to_destv[i])) { target = bcc_addr; seen_hidden_list = TRUE; } @@ -873,11 +872,11 @@ set_recipients_from_destv (CamelMimeMessage *msg, if (cc_destv) { for (i = 0; cc_destv[i] != NULL; ++i) { - text_addr = e_destination_get_address (cc_destv[i]); + text_addr = eab_destination_get_address (cc_destv[i]); if (text_addr && *text_addr) { target = cc_addr; - if (e_destination_is_evolution_list (cc_destv[i]) - && !e_destination_list_show_addresses (cc_destv[i])) { + if (eab_destination_is_evolution_list (cc_destv[i]) + && !eab_destination_list_show_addresses (cc_destv[i])) { target = bcc_addr; seen_hidden_list = TRUE; } @@ -889,7 +888,7 @@ set_recipients_from_destv (CamelMimeMessage *msg, if (bcc_destv) { for (i = 0; bcc_destv[i] != NULL; ++i) { - text_addr = e_destination_get_address (bcc_destv[i]); + text_addr = eab_destination_get_address (bcc_destv[i]); if (text_addr && *text_addr) { camel_address_decode (CAMEL_ADDRESS (bcc_addr), text_addr); } @@ -923,7 +922,7 @@ e_msg_composer_hdrs_to_message_internal (EMsgComposerHdrs *hdrs, CamelMimeMessage *msg, gboolean redirect) { - EDestination **to_destv, **cc_destv, **bcc_destv; + EABDestination **to_destv, **cc_destv, **bcc_destv; CamelInternetAddress *addr; const char *subject; char *header; @@ -959,9 +958,9 @@ e_msg_composer_hdrs_to_message_internal (EMsgComposerHdrs *hdrs, set_recipients_from_destv (msg, to_destv, cc_destv, bcc_destv, redirect); - e_destination_freev (to_destv); - e_destination_freev (cc_destv); - e_destination_freev (bcc_destv); + eab_destination_freev (to_destv); + eab_destination_freev (cc_destv); + eab_destination_freev (bcc_destv); } if (hdrs->visible_mask & E_MSG_COMPOSER_VISIBLE_POSTTO) { @@ -1056,26 +1055,26 @@ e_msg_composer_hdrs_set_reply_to (EMsgComposerHdrs *hdrs, void e_msg_composer_hdrs_set_to (EMsgComposerHdrs *hdrs, - EDestination **to_destv) + EABDestination **to_destv) { char *str; g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs)); - str = e_destination_exportv (to_destv); + str = eab_destination_exportv (to_destv); bonobo_widget_set_property (BONOBO_WIDGET (hdrs->priv->to.entry), "destinations", TC_CORBA_string, str ? str : "", NULL); g_free (str); } void e_msg_composer_hdrs_set_cc (EMsgComposerHdrs *hdrs, - EDestination **cc_destv) + EABDestination **cc_destv) { char *str; g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs)); - str = e_destination_exportv (cc_destv); + str = eab_destination_exportv (cc_destv); bonobo_widget_set_property (BONOBO_WIDGET (hdrs->priv->cc.entry), "destinations", TC_CORBA_string, str ? str :"", NULL); if (str && *str) set_pair_visibility (hdrs, &hdrs->priv->cc, TRUE); @@ -1084,13 +1083,13 @@ e_msg_composer_hdrs_set_cc (EMsgComposerHdrs *hdrs, void e_msg_composer_hdrs_set_bcc (EMsgComposerHdrs *hdrs, - EDestination **bcc_destv) + EABDestination **bcc_destv) { char *str; g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs)); - str = e_destination_exportv (bcc_destv); + str = eab_destination_exportv (bcc_destv); bonobo_widget_set_property (BONOBO_WIDGET (hdrs->priv->bcc.entry), "destinations", TC_CORBA_string, str ? str : "", NULL); if (str && *str) set_pair_visibility (hdrs, &hdrs->priv->bcc, TRUE); @@ -1159,67 +1158,67 @@ e_msg_composer_hdrs_get_reply_to (EMsgComposerHdrs *hdrs) return addr; } -EDestination ** +EABDestination ** e_msg_composer_hdrs_get_to (EMsgComposerHdrs *hdrs) { char *str = NULL; - EDestination **destv = NULL; + EABDestination **destv = NULL; g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL); bonobo_widget_get_property (BONOBO_WIDGET (hdrs->priv->to.entry), "destinations", TC_CORBA_string, &str, NULL); if (str != NULL) { - destv = e_destination_importv (str); + destv = eab_destination_importv (str); g_free (str); } return destv; } -EDestination ** +EABDestination ** e_msg_composer_hdrs_get_cc (EMsgComposerHdrs *hdrs) { char *str = NULL; - EDestination **destv = NULL; + EABDestination **destv = NULL; g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL); bonobo_widget_get_property (BONOBO_WIDGET (hdrs->priv->cc.entry), "destinations", TC_CORBA_string, &str, NULL); if (str != NULL) { - destv = e_destination_importv (str); + destv = eab_destination_importv (str); g_free (str); } return destv; } -EDestination ** +EABDestination ** e_msg_composer_hdrs_get_bcc (EMsgComposerHdrs *hdrs) { char *str = NULL; - EDestination **destv = NULL; + EABDestination **destv = NULL; g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL); bonobo_widget_get_property (BONOBO_WIDGET (hdrs->priv->bcc.entry), "destinations", TC_CORBA_string, &str, NULL); if (str != NULL) { - destv = e_destination_importv (str); + destv = eab_destination_importv (str); g_free (str); } return destv; } -EDestination ** +EABDestination ** e_msg_composer_hdrs_get_recipients (EMsgComposerHdrs *hdrs) { - EDestination **to_destv; - EDestination **cc_destv; - EDestination **bcc_destv; - EDestination **recip_destv; + EABDestination **to_destv; + EABDestination **cc_destv; + EABDestination **bcc_destv; + EABDestination **recip_destv; int i, j, n; g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL); @@ -1237,7 +1236,7 @@ e_msg_composer_hdrs_get_recipients (EMsgComposerHdrs *hdrs) if (n == 0) return NULL; - recip_destv = g_new (EDestination *, n + 1); + recip_destv = g_new (EABDestination *, n + 1); j = 0; diff --git a/composer/e-msg-composer-hdrs.h b/composer/e-msg-composer-hdrs.h index eae32c6ef6..ff39062f19 100644 --- a/composer/e-msg-composer-hdrs.h +++ b/composer/e-msg-composer-hdrs.h @@ -31,7 +31,7 @@ #include #include -#include +#include #ifdef __cplusplus extern "C" { @@ -110,11 +110,11 @@ void e_msg_composer_hdrs_set_from_account (EMsgComposerHdrs *hdrs, void e_msg_composer_hdrs_set_reply_to (EMsgComposerHdrs *hdrs, const char *reply_to); void e_msg_composer_hdrs_set_to (EMsgComposerHdrs *hdrs, - EDestination **to_destv); + EABDestination **to_destv); void e_msg_composer_hdrs_set_cc (EMsgComposerHdrs *hdrs, - EDestination **cc_destv); + EABDestination **cc_destv); void e_msg_composer_hdrs_set_bcc (EMsgComposerHdrs *hdrs, - EDestination **bcc_destv); + EABDestination **bcc_destv); void e_msg_composer_hdrs_set_post_to (EMsgComposerHdrs *hdrs, const char *post_to); void e_msg_composer_hdrs_set_subject (EMsgComposerHdrs *hdrs, @@ -123,10 +123,10 @@ void e_msg_composer_hdrs_set_subject (EMsgComposerHdrs *hdrs, CamelInternetAddress *e_msg_composer_hdrs_get_from (EMsgComposerHdrs *hdrs); CamelInternetAddress *e_msg_composer_hdrs_get_reply_to (EMsgComposerHdrs *hdrs); -EDestination **e_msg_composer_hdrs_get_to (EMsgComposerHdrs *hdrs); -EDestination **e_msg_composer_hdrs_get_cc (EMsgComposerHdrs *hdrs); -EDestination **e_msg_composer_hdrs_get_bcc (EMsgComposerHdrs *hdrs); -EDestination **e_msg_composer_hdrs_get_recipients (EMsgComposerHdrs *hdrs); +EABDestination **e_msg_composer_hdrs_get_to (EMsgComposerHdrs *hdrs); +EABDestination **e_msg_composer_hdrs_get_cc (EMsgComposerHdrs *hdrs); +EABDestination **e_msg_composer_hdrs_get_bcc (EMsgComposerHdrs *hdrs); +EABDestination **e_msg_composer_hdrs_get_recipients (EMsgComposerHdrs *hdrs); char *e_msg_composer_hdrs_get_post_to (EMsgComposerHdrs *hdrs); const char *e_msg_composer_hdrs_get_subject (EMsgComposerHdrs *hdrs); diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index f446229889..d4b06cb2b7 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -2294,7 +2294,7 @@ enum { static void update_auto_recipients (EMsgComposerHdrs *hdrs, int mode, const char *auto_addrs) { - EDestination *dest, **destv = NULL; + EABDestination *dest, **destv = NULL; CamelInternetAddress *iaddr; GList *list, *tail, *node; int i, n = 0; @@ -2310,14 +2310,14 @@ update_auto_recipients (EMsgComposerHdrs *hdrs, int mode, const char *auto_addrs if (!camel_internet_address_get (iaddr, i, &name, &addr)) continue; - dest = e_destination_new (); - e_destination_set_auto_recipient (dest, TRUE); + dest = eab_destination_new (); + eab_destination_set_auto_recipient (dest, TRUE); if (name) - e_destination_set_name (dest, name); + eab_destination_set_name (dest, name); if (addr) - e_destination_set_email (dest, addr); + eab_destination_set_email (dest, addr); node = g_list_alloc (); node->data = dest; @@ -2352,9 +2352,9 @@ update_auto_recipients (EMsgComposerHdrs *hdrs, int mode, const char *auto_addrs if (destv) { for (i = 0; destv[i]; i++) { - if (!e_destination_is_auto_recipient (destv[i])) { + if (!eab_destination_is_auto_recipient (destv[i])) { node = g_list_alloc (); - node->data = e_destination_copy (destv[i]); + node->data = eab_destination_copy (destv[i]); node->next = NULL; if (tail) { @@ -2370,10 +2370,10 @@ update_auto_recipients (EMsgComposerHdrs *hdrs, int mode, const char *auto_addrs } } - e_destination_freev (destv); + eab_destination_freev (destv); } - destv = e_destination_list_to_vector_sized (list, n); + destv = eab_destination_list_to_vector_sized (list, n); g_list_free (list); switch (mode) { @@ -2387,7 +2387,7 @@ update_auto_recipients (EMsgComposerHdrs *hdrs, int mode, const char *auto_addrs g_assert_not_reached (); } - e_destination_freev (destv); + eab_destination_freev (destv); } static void @@ -3580,7 +3580,7 @@ e_msg_composer_new_with_message (CamelMimeMessage *message) const CamelInternetAddress *to, *cc, *bcc; GList *To = NULL, *Cc = NULL, *Bcc = NULL; const char *format, *subject, *postto; - EDestination **Tov, **Ccv, **Bccv; + EABDestination **Tov, **Ccv, **Bccv; GHashTable *auto_cc, *auto_bcc; CamelContentType *content_type; struct _camel_header_raw *headers; @@ -3657,13 +3657,13 @@ e_msg_composer_new_with_message (CamelMimeMessage *message) const char *name, *addr; if (camel_internet_address_get (to, i, &name, &addr)) { - EDestination *dest = e_destination_new (); - e_destination_set_name (dest, name); - e_destination_set_email (dest, addr); + EABDestination *dest = eab_destination_new (); + eab_destination_set_name (dest, name); + eab_destination_set_email (dest, addr); To = g_list_append (To, dest); } } - Tov = e_destination_list_to_vector (To); + Tov = eab_destination_list_to_vector (To); g_list_free (To); len = CAMEL_ADDRESS (cc)->addresses->len; @@ -3671,18 +3671,18 @@ e_msg_composer_new_with_message (CamelMimeMessage *message) const char *name, *addr; if (camel_internet_address_get (cc, i, &name, &addr)) { - EDestination *dest = e_destination_new (); - e_destination_set_name (dest, name); - e_destination_set_email (dest, addr); + EABDestination *dest = eab_destination_new (); + eab_destination_set_name (dest, name); + eab_destination_set_email (dest, addr); if (g_hash_table_lookup (auto_cc, addr)) - e_destination_set_auto_recipient (dest, TRUE); + eab_destination_set_auto_recipient (dest, TRUE); Cc = g_list_append (Cc, dest); } } - Ccv = e_destination_list_to_vector (Cc); + Ccv = eab_destination_list_to_vector (Cc); g_hash_table_foreach (auto_cc, auto_recip_free, NULL); g_hash_table_destroy (auto_cc); g_list_free (Cc); @@ -3692,18 +3692,18 @@ e_msg_composer_new_with_message (CamelMimeMessage *message) const char *name, *addr; if (camel_internet_address_get (bcc, i, &name, &addr)) { - EDestination *dest = e_destination_new (); - e_destination_set_name (dest, name); - e_destination_set_email (dest, addr); + EABDestination *dest = eab_destination_new (); + eab_destination_set_name (dest, name); + eab_destination_set_email (dest, addr); if (g_hash_table_lookup (auto_bcc, addr)) - e_destination_set_auto_recipient (dest, TRUE); + eab_destination_set_auto_recipient (dest, TRUE); Bcc = g_list_append (Bcc, dest); } } - Bccv = e_destination_list_to_vector (Bcc); + Bccv = eab_destination_list_to_vector (Bcc); g_hash_table_foreach (auto_bcc, auto_recip_free, NULL); g_hash_table_destroy (auto_bcc); g_list_free (Bcc); @@ -3719,9 +3719,9 @@ e_msg_composer_new_with_message (CamelMimeMessage *message) g_free (account_name); - e_destination_freev (Tov); - e_destination_freev (Ccv); - e_destination_freev (Bccv); + eab_destination_freev (Tov); + eab_destination_freev (Ccv); + eab_destination_freev (Bccv); /* Restore the format editing preference */ format = camel_medium_get_header (CAMEL_MEDIUM (message), "X-Evolution-Format"); @@ -3843,9 +3843,9 @@ add_recipients (GList *list, const char *recips, gboolean decode) for (i = 0; i < num; i++) { if (camel_internet_address_get (cia, i, &name, &addr)) { - EDestination *dest = e_destination_new (); - e_destination_set_name (dest, name); - e_destination_set_email (dest, addr); + EABDestination *dest = eab_destination_new (); + eab_destination_set_name (dest, name); + eab_destination_set_email (dest, addr); list = g_list_append (list, dest); } @@ -3859,7 +3859,7 @@ handle_mailto (EMsgComposer *composer, const char *mailto) { EMsgComposerHdrs *hdrs; GList *to = NULL, *cc = NULL, *bcc = NULL; - EDestination **tov, **ccv, **bccv; + EABDestination **tov, **ccv, **bccv; char *subject = NULL, *body = NULL; char *header, *content, *buf; size_t nread, nwritten; @@ -3964,9 +3964,9 @@ handle_mailto (EMsgComposer *composer, const char *mailto) g_free (buf); - tov = e_destination_list_to_vector (to); - ccv = e_destination_list_to_vector (cc); - bccv = e_destination_list_to_vector (bcc); + tov = eab_destination_list_to_vector (to); + ccv = eab_destination_list_to_vector (cc); + bccv = eab_destination_list_to_vector (bcc); g_list_free (to); g_list_free (cc); @@ -3978,9 +3978,9 @@ handle_mailto (EMsgComposer *composer, const char *mailto) e_msg_composer_hdrs_set_cc (hdrs, ccv); e_msg_composer_hdrs_set_bcc (hdrs, bccv); - e_destination_freev (tov); - e_destination_freev (ccv); - e_destination_freev (bccv); + eab_destination_freev (tov); + eab_destination_freev (ccv); + eab_destination_freev (bccv); if (subject) { e_msg_composer_hdrs_set_subject (hdrs, subject); @@ -4053,9 +4053,9 @@ e_msg_composer_show_attachments (EMsgComposer *composer, void e_msg_composer_set_headers (EMsgComposer *composer, const char *from, - EDestination **to, - EDestination **cc, - EDestination **bcc, + EABDestination **to, + EABDestination **cc, + EABDestination **bcc, const char *subject) { EMsgComposerHdrs *hdrs; @@ -4829,7 +4829,7 @@ e_msg_composer_set_view_bcc (EMsgComposer *composer, gboolean view_bcc) } -EDestination ** +EABDestination ** e_msg_composer_get_recipients (EMsgComposer *composer) { g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); @@ -4837,7 +4837,7 @@ e_msg_composer_get_recipients (EMsgComposer *composer) return composer->hdrs ? e_msg_composer_hdrs_get_recipients (E_MSG_COMPOSER_HDRS (composer->hdrs)) : NULL; } -EDestination ** +EABDestination ** e_msg_composer_get_to (EMsgComposer *composer) { g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); @@ -4845,7 +4845,7 @@ e_msg_composer_get_to (EMsgComposer *composer) return composer->hdrs ? e_msg_composer_hdrs_get_to (E_MSG_COMPOSER_HDRS (composer->hdrs)) : NULL; } -EDestination ** +EABDestination ** e_msg_composer_get_cc (EMsgComposer *composer) { g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); @@ -4853,7 +4853,7 @@ e_msg_composer_get_cc (EMsgComposer *composer) return composer->hdrs ? e_msg_composer_hdrs_get_cc (E_MSG_COMPOSER_HDRS (composer->hdrs)) : NULL; } -EDestination ** +EABDestination ** e_msg_composer_get_bcc (EMsgComposer *composer) { g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h index e28d8981d5..734b4c8760 100644 --- a/composer/e-msg-composer.h +++ b/composer/e-msg-composer.h @@ -134,9 +134,9 @@ void e_msg_composer_show_attachments (EMsgCo gboolean show); void e_msg_composer_set_headers (EMsgComposer *composer, const char *from, - EDestination **to, - EDestination **cc, - EDestination **bcc, + EABDestination **to, + EABDestination **cc, + EABDestination **bcc, const char *subject); void e_msg_composer_set_body_text (EMsgComposer *composer, const char *text); @@ -173,10 +173,10 @@ gboolean e_msg_composer_get_view_bcc (EMsgCo void e_msg_composer_set_view_bcc (EMsgComposer *composer, gboolean view_bcc); -EDestination **e_msg_composer_get_recipients (EMsgComposer *composer); -EDestination **e_msg_composer_get_to (EMsgComposer *composer); -EDestination **e_msg_composer_get_cc (EMsgComposer *composer); -EDestination **e_msg_composer_get_bcc (EMsgComposer *composer); +EABDestination **e_msg_composer_get_recipients (EMsgComposer *composer); +EABDestination **e_msg_composer_get_to (EMsgComposer *composer); +EABDestination **e_msg_composer_get_cc (EMsgComposer *composer); +EABDestination **e_msg_composer_get_bcc (EMsgComposer *composer); const char *e_msg_composer_get_subject (EMsgComposer *composer); EAccount *e_msg_composer_get_preferred_account (EMsgComposer *composer); diff --git a/composer/evolution-composer.c b/composer/evolution-composer.c index b5c7630de8..31da13c342 100644 --- a/composer/evolution-composer.c +++ b/composer/evolution-composer.c @@ -47,26 +47,26 @@ struct _EvolutionComposerPrivate { }; /* CORBA interface implementation. */ -static EDestination ** +static EABDestination ** corba_recipientlist_to_destv (const GNOME_Evolution_Composer_RecipientList *cl) { GNOME_Evolution_Composer_Recipient *recip; - EDestination **destv; + EABDestination **destv; int i; if (cl->_length == 0) return NULL; - destv = g_new (EDestination *, cl->_length+1); + destv = g_new (EABDestination *, cl->_length+1); for (i = 0; i < cl->_length; ++i) { recip = &(cl->_buffer[i]); - destv[i] = e_destination_new (); + destv[i] = eab_destination_new (); if (*recip->name) - e_destination_set_name (destv[i], recip->name); - e_destination_set_email (destv[i], recip->address); + eab_destination_set_name (destv[i], recip->name); + eab_destination_set_email (destv[i], recip->address); } destv[cl->_length] = NULL; @@ -85,7 +85,7 @@ impl_Composer_set_headers (PortableServer_Servant servant, { BonoboObject *bonobo_object; EvolutionComposer *composer; - EDestination **tov, **ccv, **bccv; + EABDestination **tov, **ccv, **bccv; EAccountList *accounts; EAccount *account; EIterator *iter; @@ -122,9 +122,9 @@ impl_Composer_set_headers (PortableServer_Servant servant, e_msg_composer_set_headers (composer->composer, account->name, tov, ccv, bccv, subject); - e_destination_freev (tov); - e_destination_freev (ccv); - e_destination_freev (bccv); + eab_destination_freev (tov); + eab_destination_freev (ccv); + eab_destination_freev (bccv); } static void diff --git a/data/evolution.desktop.in b/data/evolution.desktop.in index 2fc62f6993..d8fada2802 100644 --- a/data/evolution.desktop.in +++ b/data/evolution.desktop.in @@ -1,8 +1,8 @@ [Desktop Entry] _Name=Ximian Evolution _Comment=The Evolution groupware suite -Exec=evolution-1.4 -Icon=evolution-1.4.png +Exec=evolution-1.5 +Icon=evolution-1.5.png Terminal=false Type=Application Categories=GNOME;Application;Office;X-Red-Hat-Base; diff --git a/e-util/.cvsignore b/e-util/.cvsignore index ea3b8c5ad4..cfb049f0e3 100644 --- a/e-util/.cvsignore +++ b/e-util/.cvsignore @@ -6,3 +6,4 @@ Makefile.in *.la e-util-marshal.c e-util-marshal.h +test-source-list \ No newline at end of file diff --git a/e-util/ChangeLog b/e-util/ChangeLog index fb28623bee..b6bdedd004 100644 --- a/e-util/ChangeLog +++ b/e-util/ChangeLog @@ -3,6 +3,21 @@ * Makefile.am (pilot_compile) [! ENABLE_PILOT_CONDUITS]: Add md5-utils.c so it compiles even if you have no Pilot support. +2003-10-16 Rodrigo Moya + + * e-source-list.c (e_source_list_sync): use gconf_client_notify_remove + instead of g_source_remove for GConf notification IDs. + (impl_finalize): remove the GConf notification also here. + +2003-10-13 Rodrigo Moya + + * e-source-group.[ch] (e_source_group_peek_source_by_name): added + new function. + +2003-10-10 Not Zed + + * e-account-list.c (e_account_list_find): add FIND_UID find type. + 2003-09-26 Jeffrey Stedfast * e-host-utils.c (e_gethostbyaddr_r): IPv6 implementation @@ -21,6 +36,11 @@ * e-host-utils.c (e_gethostbyaddr_r): Work around a bug in glibc 2.3.2's gethostbyaddr_r() implementation. +2003-09-15 Larry Ewing + + * e-source.c (e_source_dump_to_xml_node): make sure declarations + precede the body. + 2003-09-11 Dan Winship * Makefile.am (noinst_LTLIBRARIES): Remove libeutil-static.la and @@ -47,6 +67,129 @@ Editor always gives time validation error for apptmnts in non UTF-8/non ASCII locales. +2003-08-17 Ettore Perazzoli + + * test-source-list.c: No short letter for --key. + +2003-08-15 Ettore Perazzoli + + * e-uid.c: #include + + * test-source-list.c: Add options to display, set and unset the + color as well. + + * e-source.c: New members has_color, color in struct + ESourcePrivate. + (e_source_update_from_xml_node): Parse a color property from the + XML node. Protect from NULL name and relative_uri members as + well. + (e_source_dump_to_xml_node): Set a color property on the XML node. + (e_source_get_color): New. + (e_source_set_color): New. + (e_source_unset_color): New. + (e_source_new_from_xml_node): Use e_source_update_from_xml_node() + instead of getting the data from the XML yourself. + +2003-08-14 Ettore Perazzoli + + Add UIDs to ESource* items so we can distinguish renames from + removals/additions. + + * test-source-list.c: Made --source and --group get UIDs instead + of names. + (on_idle_do_stuff): Updated behavior accordingly. + (dump_list): Print "(No items)" if there are no groups. + (dump_group): Print the UID of the group. + (dump_source): Print the UID of the source. + + * e-source-list.c (load_from_gconf): Match with group UIDs instead + of group names. + (e_source_list_peek_source_by_uid): New. + (e_source_list_peek_source_by_name): Removed. + (e_source_list_peek_group_by_uid): New. + (e_source_list_peek_group_by_name): Removed. + (e_source_list_remove_group_by_uid): New. + (e_source_list_remove_group_by_name): Removed. + (e_source_list_remove_source_by_uid): New. + (e_source_list_remove_source_by_name): Removed. + + * e-source-group.c: New member uid in struct ESourceGroupPrivate. + (impl_finalize): Free it. + (e_source_group_new): Set the uid member using e_uid_new(). + (e_source_group_peek_source_by_uid): New. + (e_source_group_peek_source_by_name): Removed. + (e_source_group_add_source): Check that the UID is unique, instead + of the name. + (e_source_group_remove_source_by_uid): New. + (e_source_group_remove_source_by_name): Removed. + (e_source_group_update_from_xmldoc): Use the UID to figure out + which source has changed, instead of the name. + (e_source_group_uid_from_xmldoc): New. + (e_source_group_name_from_xmldoc): Removed. + (e_source_group_new_from_xmldoc): Set the UID in the new group + from the XML. + (e_source_group_to_xml): Set a UID property in the XML. + + * e-source.c: New member uid in struct ESourcePrivate. + (e_source_new): Initialize using e_uid_new(). + (impl_finalize): Free. + (e_source_peek_uid): New. + (e_source_new_from_xml_node): Set the UID from the XML node. + (e_source_name_from_xml_node): Removed. + (e_source_uid_from_xml_node): New. + (e_source_dump_to_xml_node): Set the "uid" property on the XML + node. + + * e-account.c (e_account_gen_uid): Removed. + (e_account_new): Use e_uid_new() instead of e_account_gen_uid(). + + * e-uid.c (e_uid_new): New file, new function. + +2003-08-13 Ettore Perazzoli + + Fix up the semantics of "changed" signals on GConf changes. + + * e-source-group.c (e_source_group_update_from_xmldoc): Added new + member ignore_source_changed in struct _ESourceGroupPrivate. + (e_source_group_update_from_xmldoc): Increment + ignore_source_changed before calling + e_source_update_from_xml_node(), decrement afterwards. + (source_changed_callback): Only emit "changed" if + ignore_source_changed is zero. + (e_source_group_update_from_xmldoc): Properly emit the "changed" + signal when the base_uri or the name change. + + * e-source-list.c: Changed type of sync_idle_id from gboolean (!) + to int and added new member ignore_group_changed in struct + _ESourceListPrivate. + (load_from_gconf): Increment ignore_group_changed before calling + e_source_group_update_from_xmldoc() and decrement it afterwards. + (group_changed_callback): Only emit the signal if + ignore_group_changed is zero. + + * e-source.c (e_source_update_from_xml_node): Removed arg + emit_signals. Always emit signals. + + * e-source-group.c (e_source_group_update_from_xmldoc): Removed + arg emit_signals. Always emit signals. + (e_source_group_update_from_xml): Likewise. + +2003-08-11 Ettore Perazzoli + + * e-source.c (e_source_set_group): Weak_unref the current group if + not NULL and properly handle the case where a NULL group is being + passed in. + +2003-08-11 Ettore Perazzoli + + * e-source-group.c: New file. + * e-source-group.h: New file. + * e-source-list.h: New file. + * e-source-list.c: New file. + * e-source.c: New file. + * e-source.h: New file. + * test-source-list.c: New file to test the above. + 2003-08-11 Not Zed * e-msgport.c (e_thread_put): check pthread_create return code diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 2a134e14ed..f80e321f0e 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -44,8 +44,12 @@ eutilinclude_HEADERS = \ e-proxy.h \ e-request.h \ e-sexp.h \ + e-source-group.h \ + e-source-list.h \ + e-source.h \ e-time-utils.h \ e-trie.h \ + e-uid.h \ e-url.h \ e-xml-hash-utils.h \ md5-utils.h @@ -78,8 +82,12 @@ libeutil_la_SOURCES = \ e-proxy.c \ e-request.c \ e-sexp.c \ + e-source-group.c \ + e-source-list.c \ + e-source.c \ e-time-utils.c \ e-trie.c \ + e-uid.c \ e-url.c \ e-util-marshal.c \ e-xml-hash-utils.c \ @@ -87,6 +95,12 @@ libeutil_la_SOURCES = \ eggtrayicon.h \ md5-utils.c +noinst_PROGRAMS = \ + test-source-list + +test_source_list_SOURCES = test-source-list.c +test_source_list_LDADD = libeutil.la + MARSHAL_GENERATED = e-util-marshal.c e-util-marshal.h @EVO_MARSHAL_RULE@ diff --git a/e-util/e-account-list.c b/e-util/e-account-list.c index acb9093cb4..d0463a810b 100644 --- a/e-util/e-account-list.c +++ b/e-util/e-account-list.c @@ -447,6 +447,9 @@ e_account_list_find(EAccountList *accounts, e_account_find_t type, const char *k case E_ACCOUNT_FIND_NAME: found = strcmp(account->name, key) == 0; break; + case E_ACCOUNT_FIND_UID: + found = strcmp(account->uid, key) == 0; + break; case E_ACCOUNT_FIND_ID_NAME: if (account->id) found = strcmp(account->id->name, key) == 0; diff --git a/e-util/e-account-list.h b/e-util/e-account-list.h index 2ad0896307..b47efb42ae 100644 --- a/e-util/e-account-list.h +++ b/e-util/e-account-list.h @@ -35,6 +35,7 @@ typedef struct EAccountListPrivate EAccountListPrivate; /* search options for the find command */ typedef enum _e_account_find_t { E_ACCOUNT_FIND_NAME, + E_ACCOUNT_FIND_UID, E_ACCOUNT_FIND_ID_NAME, E_ACCOUNT_FIND_ID_ADDRESS, } e_account_find_t; diff --git a/e-util/e-account.c b/e-util/e-account.c index 510200b723..b6e3cdc57f 100644 --- a/e-util/e-account.c +++ b/e-util/e-account.c @@ -23,9 +23,9 @@ #include "e-account.h" +#include "e-uid.h" + #include -#include -#include #include #include @@ -106,29 +106,6 @@ finalize (GObject *object) E_MAKE_TYPE (e_account, "EAccount", EAccount, class_init, init, PARENT_TYPE) -char * -e_account_gen_uid (void) -{ - static char *hostname; - static int serial; - - if (!hostname) { - static char buffer [512]; - - if ((gethostname (buffer, sizeof (buffer) - 1) == 0) && - (buffer [0] != 0)) - hostname = buffer; - else - hostname = "localhost"; - } - - return g_strdup_printf ("%lu.%lu.%d@%s", - (unsigned long) time (NULL), - (unsigned long) getpid (), - serial++, - hostname); -} - /** * e_account_new: * @@ -141,7 +118,7 @@ e_account_new (void) EAccount *account; account = g_object_new (E_TYPE_ACCOUNT, NULL); - account->uid = e_account_gen_uid (); + account->uid = e_uid_new (); return account; } diff --git a/e-util/e-account.h b/e-util/e-account.h index 78eb70b7a8..ff937b3905 100644 --- a/e-util/e-account.h +++ b/e-util/e-account.h @@ -100,6 +100,5 @@ char *e_account_to_xml (EAccount *account); char *e_account_uid_from_xml (const char *xml); -char *e_account_gen_uid (void); #endif /* __E_ACCOUNT__ */ diff --git a/e-util/e-source-group.c b/e-util/e-source-group.c new file mode 100644 index 0000000000..5fb5a97b23 --- /dev/null +++ b/e-util/e-source-group.c @@ -0,0 +1,605 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-source-group.c + * + * Copyright (C) 2003 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. + * + * Author: Ettore Perazzoli + */ + +#include + +#include "e-source-group.h" + +#include "e-uid.h" +#include "e-util-marshal.h" + +#include + +#include + +#define PARENT_TYPE G_TYPE_OBJECT +static GObjectClass *parent_class = NULL; + + +/* Private members. */ + +struct _ESourceGroupPrivate { + char *uid; + char *name; + char *base_uri; + + GSList *sources; + + gboolean ignore_source_changed; +}; + + +/* Signals. */ + +enum { + CHANGED, + SOURCE_REMOVED, + SOURCE_ADDED, + LAST_SIGNAL +}; +static unsigned int signals[LAST_SIGNAL] = { 0 }; + + +/* Callbacks. */ + +static void +source_changed_callback (ESource *source, + ESourceGroup *group) +{ + if (! group->priv->ignore_source_changed) + g_signal_emit (group, signals[CHANGED], 0); +} + + +/* GObject methods. */ + +static void +impl_dispose (GObject *object) +{ + ESourceGroupPrivate *priv = E_SOURCE_GROUP (object)->priv; + + if (priv->sources != NULL) { + GSList *p; + + for (p = priv->sources; p != NULL; p = p->next) { + ESource *source = E_SOURCE (p->data); + + g_signal_handlers_disconnect_by_func (source, + G_CALLBACK (source_changed_callback), + object); + g_object_unref (source); + } + + g_slist_free (priv->sources); + priv->sources = NULL; + } + + (* G_OBJECT_CLASS (parent_class)->dispose) (object); +} + +static void +impl_finalize (GObject *object) +{ + ESourceGroupPrivate *priv = E_SOURCE_GROUP (object)->priv; + + g_free (priv->uid); + g_free (priv->name); + g_free (priv->base_uri); + g_free (priv); + + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + + +/* Initialization. */ + +static void +class_init (ESourceGroupClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = impl_dispose; + object_class->finalize = impl_finalize; + + parent_class = g_type_class_peek_parent (class); + + signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESourceGroupClass, changed), + NULL, NULL, + e_util_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[SOURCE_ADDED] = + g_signal_new ("source_added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESourceGroupClass, source_added), + NULL, NULL, + e_util_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); + signals[SOURCE_REMOVED] = + g_signal_new ("source_removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESourceGroupClass, source_removed), + NULL, NULL, + e_util_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); +} + +static void +init (ESourceGroup *source_group) +{ + ESourceGroupPrivate *priv; + + priv = g_new0 (ESourceGroupPrivate, 1); + source_group->priv = priv; +} + + +/* Public methods. */ + +ESourceGroup * +e_source_group_new (const char *name, + const char *base_uri) +{ + ESourceGroup *new; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (base_uri != NULL, NULL); + + new = g_object_new (e_source_group_get_type (), NULL); + new->priv->uid = e_uid_new (); + + e_source_group_set_name (new, name); + e_source_group_set_base_uri (new, base_uri); + + return new; +} + +ESourceGroup * +e_source_group_new_from_xml (const char *xml) +{ + xmlDocPtr doc; + ESourceGroup *group; + + doc = xmlParseDoc ((char *) xml); + if (doc == NULL) + return NULL; + + group = e_source_group_new_from_xmldoc (doc); + xmlFreeDoc (doc); + + return group; +} + +ESourceGroup * +e_source_group_new_from_xmldoc (xmlDocPtr doc) +{ + xmlNodePtr root, p; + xmlChar *uid; + xmlChar *name; + xmlChar *base_uri; + ESourceGroup *new = NULL; + + g_return_val_if_fail (doc != NULL, NULL); + + root = doc->children; + if (strcmp (root->name, "group") != 0) + return NULL; + + uid = xmlGetProp (root, "uid"); + name = xmlGetProp (root, "name"); + base_uri = xmlGetProp (root, "base_uri"); + + if (uid == NULL || name == NULL || base_uri == NULL) + goto done; + + new = g_object_new (e_source_group_get_type (), NULL); + new->priv->uid = g_strdup (uid); + + e_source_group_set_name (new, name); + e_source_group_set_base_uri (new, base_uri); + + for (p = root->children; p != NULL; p = p->next) { + ESource *new_source = e_source_new_from_xml_node (p); + e_source_group_add_source (new, new_source, -1); + } + + done: + if (name != NULL) + xmlFree (name); + if (base_uri != NULL) + xmlFree (base_uri); + return new; +} + +gboolean +e_source_group_update_from_xml (ESourceGroup *group, + const char *xml, + gboolean *changed_return) +{ + xmlDocPtr xmldoc; + gboolean success; + + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + g_return_val_if_fail (xml != NULL, FALSE); + + xmldoc = xmlParseDoc ((char *) xml); + + success = e_source_group_update_from_xmldoc (group, xmldoc, changed_return); + + xmlFreeDoc (xmldoc); + + return success; +} + +gboolean +e_source_group_update_from_xmldoc (ESourceGroup *group, + xmlDocPtr doc, + gboolean *changed_return) +{ + GHashTable *new_sources_hash; + GSList *new_sources_list = NULL; + xmlNodePtr root, nodep; + xmlChar *name, *base_uri; + gboolean changed = FALSE; + GSList *p, *q; + + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + g_return_val_if_fail (doc != NULL, FALSE); + + *changed_return = FALSE; + + root = doc->children; + if (strcmp (root->name, "group") != 0) + return FALSE; + + name = xmlGetProp (root, "name"); + if (name == NULL) + return FALSE; + + base_uri = xmlGetProp (root, "base_uri"); + if (base_uri == NULL) { + xmlFree (name); + return FALSE; + } + + if (strcmp (group->priv->name, name) != 0) { + g_free (group->priv->name); + group->priv->name = g_strdup (name); + changed = TRUE; + } + xmlFree (name); + + if (strcmp (group->priv->base_uri, base_uri) != 0) { + g_free (group->priv->base_uri); + group->priv->base_uri = g_strdup (base_uri); + changed = TRUE; + } + xmlFree (base_uri); + + new_sources_hash = g_hash_table_new (g_direct_hash, g_direct_equal); + + for (nodep = root->children; nodep != NULL; nodep = nodep->next) { + ESource *existing_source; + char *uid = e_source_uid_from_xml_node (nodep); + + if (uid == NULL) + continue; + + existing_source = e_source_group_peek_source_by_uid (group, uid); + if (g_hash_table_lookup (new_sources_hash, existing_source) != NULL) + continue; + + if (existing_source == NULL) { + ESource *new_source = e_source_new_from_xml_node (nodep); + + if (new_source != NULL) { + e_source_set_group (new_source, group); + g_signal_connect (new_source, "changed", G_CALLBACK (source_changed_callback), group); + new_sources_list = g_slist_prepend (new_sources_list, new_source); + + g_hash_table_insert (new_sources_hash, new_source, new_source); + + g_signal_emit (group, signals[SOURCE_ADDED], 0, new_source); + changed = TRUE; + } + } else { + gboolean source_changed; + + group->priv->ignore_source_changed ++; + + if (e_source_update_from_xml_node (existing_source, nodep, &source_changed)) { + new_sources_list = g_slist_prepend (new_sources_list, existing_source); + g_object_ref (existing_source); + g_hash_table_insert (new_sources_hash, existing_source, existing_source); + + if (source_changed) + changed = TRUE; + } + + group->priv->ignore_source_changed --; + } + + g_free (uid); + } + + new_sources_list = g_slist_reverse (new_sources_list); + + /* Emit "group_removed" and disconnect the "changed" signal for all the + groups that we haven't found in the new list. */ + q = new_sources_list; + for (p = group->priv->sources; p != NULL; p = p->next) { + ESource *source = E_SOURCE (p->data); + + if (g_hash_table_lookup (new_sources_hash, source) == NULL) { + changed = TRUE; + + g_signal_emit (group, signals[SOURCE_REMOVED], 0, source); + g_signal_handlers_disconnect_by_func (source, source_changed_callback, group); + } + + if (! changed && q != NULL) { + if (q->data != p->data) + changed = TRUE; + q = q->next; + } + } + + g_hash_table_destroy (new_sources_hash); + + /* Replace the original group list with the new one. */ + g_slist_foreach (group->priv->sources, (GFunc) g_object_unref, NULL); + g_slist_free (group->priv->sources); + + group->priv->sources = new_sources_list; + + /* FIXME if the order changes, the function doesn't notice. */ + + if (changed) { + g_signal_emit (group, signals[CHANGED], 0); + *changed_return = TRUE; + } + + return TRUE; /* Success. */ +} + +char * +e_source_group_uid_from_xmldoc (xmlDocPtr doc) +{ + xmlNodePtr root = doc->children; + xmlChar *name; + char *retval; + + if (strcmp (root->name, "group") != 0) + return NULL; + + name = xmlGetProp (root, "uid"); + if (name == NULL) + return NULL; + + retval = g_strdup (name); + xmlFree (name); + return retval; +} + +void +e_source_group_set_name (ESourceGroup *group, + const char *name) +{ + g_return_if_fail (E_IS_SOURCE_GROUP (group)); + g_return_if_fail (name != NULL); + + if (group->priv->name == name) + return; + + g_free (group->priv->name); + group->priv->name = g_strdup (name); + + g_signal_emit (group, signals[CHANGED], 0); +} + +void e_source_group_set_base_uri (ESourceGroup *group, + const char *base_uri) +{ + g_return_if_fail (E_IS_SOURCE_GROUP (group)); + g_return_if_fail (base_uri != NULL); + + if (group->priv->base_uri == base_uri) + return; + + g_free (group->priv->base_uri); + group->priv->base_uri = g_strdup (base_uri); + + g_signal_emit (group, signals[CHANGED], 0); +} + + +const char * +e_source_group_peek_uid (ESourceGroup *group) +{ + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), NULL); + + return group->priv->uid; +} + +const char * +e_source_group_peek_name (ESourceGroup *group) +{ + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), NULL); + + return group->priv->name; +} + +const char * +e_source_group_peek_base_uri (ESourceGroup *group) +{ + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), NULL); + + return group->priv->base_uri; +} + + +GSList * +e_source_group_peek_sources (ESourceGroup *group) +{ + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), NULL); + + return group->priv->sources; +} + +ESource * +e_source_group_peek_source_by_uid (ESourceGroup *group, + const char *uid) +{ + GSList *p; + + for (p = group->priv->sources; p != NULL; p = p->next) { + if (strcmp (e_source_peek_uid (E_SOURCE (p->data)), uid) == 0) + return E_SOURCE (p->data); + } + + return NULL; +} + +ESource * +e_source_group_peek_source_by_name (ESourceGroup *group, + const char *name) +{ + GSList *p; + + for (p = group->priv->sources; p != NULL; p = p->next) { + if (strcmp (e_source_peek_name (E_SOURCE (p->data)), name) == 0) + return E_SOURCE (p->data); + } + + return NULL; +} + +gboolean +e_source_group_add_source (ESourceGroup *group, + ESource *source, + int position) +{ + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + + if (e_source_group_peek_source_by_uid (group, e_source_peek_uid (source)) != NULL) + return FALSE; + + e_source_set_group (source, group); + g_object_ref (source); + + g_signal_connect (source, "changed", G_CALLBACK (source_changed_callback), group); + + group->priv->sources = g_slist_insert (group->priv->sources, source, position); + g_signal_emit (group, signals[SOURCE_ADDED], 0, source); + g_signal_emit (group, signals[CHANGED], 0); + + return TRUE; +} + +gboolean +e_source_group_remove_source (ESourceGroup *group, + ESource *source) +{ + GSList *p; + + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + g_return_val_if_fail (E_IS_SOURCE (source), FALSE); + + for (p = group->priv->sources; p != NULL; p = p->next) { + if (E_SOURCE (p->data) == source) { + group->priv->sources = g_slist_remove_link (group->priv->sources, p); + g_signal_emit (group, signals[SOURCE_REMOVED], 0, source); + g_signal_emit (group, signals[CHANGED], 0); + return TRUE; + } + } + + return FALSE; +} + +gboolean +e_source_group_remove_source_by_uid (ESourceGroup *group, + const char *uid) +{ + GSList *p; + + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + g_return_val_if_fail (uid != NULL, FALSE); + + for (p = group->priv->sources; p != NULL; p = p->next) { + ESource *source = E_SOURCE (p->data); + + if (strcmp (e_source_peek_uid (source), uid) == 0) { + group->priv->sources = g_slist_remove_link (group->priv->sources, p); + g_signal_emit (group, signals[SOURCE_REMOVED], 0, source); + g_signal_emit (group, signals[CHANGED], 0); + return TRUE; + } + } + + return FALSE; +} + + +char * +e_source_group_to_xml (ESourceGroup *group) +{ + xmlDocPtr doc; + xmlNodePtr root; + xmlChar *xml_buffer; + char *returned_buffer; + int xml_buffer_size; + GSList *p; + + doc = xmlNewDoc ("1.0"); + + root = xmlNewDocNode (doc, NULL, "group", NULL); + xmlSetProp (root, "uid", e_source_group_peek_uid (group)); + xmlSetProp (root, "name", e_source_group_peek_name (group)); + xmlSetProp (root, "base_uri", e_source_group_peek_base_uri (group)); + + xmlDocSetRootElement (doc, root); + + for (p = group->priv->sources; p != NULL; p = p->next) + e_source_dump_to_xml_node (E_SOURCE (p->data), 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); + + return returned_buffer; +} + + +E_MAKE_TYPE (e_source_group, "ESourceGroup", ESourceGroup, class_init, init, PARENT_TYPE) diff --git a/e-util/e-source-group.h b/e-util/e-source-group.h new file mode 100644 index 0000000000..bebecba58f --- /dev/null +++ b/e-util/e-source-group.h @@ -0,0 +1,102 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-source-group.h + * + * Copyright (C) 2003 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. + * + * Author: Ettore Perazzoli + */ + +#ifndef _E_SOURCE_GROUP_H_ +#define _E_SOURCE_GROUP_H_ + +#include +#include + +#define E_TYPE_SOURCE_GROUP (e_source_group_get_type ()) +#define E_SOURCE_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_SOURCE_GROUP, ESourceGroup)) +#define E_SOURCE_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_SOURCE_GROUP, ESourceGroupClass)) +#define E_IS_SOURCE_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_SOURCE_GROUP)) +#define E_IS_SOURCE_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_SOURCE_GROUP)) + + +typedef struct _ESourceGroup ESourceGroup; +typedef struct _ESourceGroupPrivate ESourceGroupPrivate; +typedef struct _ESourceGroupClass ESourceGroupClass; + +#include "e-source.h" + +struct _ESourceGroup { + GObject parent; + + ESourceGroupPrivate *priv; +}; + +struct _ESourceGroupClass { + GObjectClass parent_class; + + /* Signals. */ + + void (* changed) (ESourceGroup *group); + + void (* source_removed) (ESourceGroup *source_list, ESource *source); + void (* source_added) (ESourceGroup *source_list, ESource *source); +}; + + +GType e_source_group_get_type (void); + +ESourceGroup *e_source_group_new (const char *name, + const char *base_uri); +ESourceGroup *e_source_group_new_from_xml (const char *xml); +ESourceGroup *e_source_group_new_from_xmldoc (xmlDocPtr doc); + +gboolean e_source_group_update_from_xml (ESourceGroup *group, + const char *xml, + gboolean *changed_return); +gboolean e_source_group_update_from_xmldoc (ESourceGroup *group, + xmlDocPtr doc, + gboolean *changed_return); + +char *e_source_group_uid_from_xmldoc (xmlDocPtr doc); + +void e_source_group_set_name (ESourceGroup *group, + const char *name); +void e_source_group_set_base_uri (ESourceGroup *group, + const char *base_uri); + +const char *e_source_group_peek_uid (ESourceGroup *group); +const char *e_source_group_peek_name (ESourceGroup *group); +const char *e_source_group_peek_base_uri (ESourceGroup *group); + +GSList *e_source_group_peek_sources (ESourceGroup *group); +ESource *e_source_group_peek_source_by_uid (ESourceGroup *group, + const char *source_uid); +ESource *e_source_group_peek_source_by_name (ESourceGroup *group, + const char *source_name); + +gboolean e_source_group_add_source (ESourceGroup *group, + ESource *source, + int position); +gboolean e_source_group_remove_source (ESourceGroup *group, + ESource *source); +gboolean e_source_group_remove_source_by_uid (ESourceGroup *group, + const char *uid); + +char *e_source_group_to_xml (ESourceGroup *group); + + +#endif /* _E_SOURCE_GROUP_H_ */ diff --git a/e-util/e-source-list.c b/e-util/e-source-list.c new file mode 100644 index 0000000000..565df8977e --- /dev/null +++ b/e-util/e-source-list.c @@ -0,0 +1,524 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-source-list.c + * + * Copyright (C) 2003 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. + * + * Author: Ettore Perazzoli + */ + +#include + +#include "e-source-list.h" + +#include "e-util-marshal.h" + +#include +#include + + +#define PARENT_TYPE G_TYPE_OBJECT +static GObjectClass *parent_class = NULL; + +struct _ESourceListPrivate { + GConfClient *gconf_client; + char *gconf_path; + + int gconf_notify_id; + + GSList *groups; + + gboolean ignore_group_changed; + int sync_idle_id; +}; + + +/* Signals. */ + +enum { + CHANGED, + GROUP_REMOVED, + GROUP_ADDED, + LAST_SIGNAL +}; +static unsigned int signals[LAST_SIGNAL] = { 0 }; + + +/* Forward declarations. */ + +static gboolean sync_idle_callback (ESourceList *list); +static void group_changed_callback (ESourceGroup *group, + ESourceList *list); +static void conf_changed_callback (GConfClient *client, + unsigned int connection_id, + GConfEntry *entry, + ESourceList *list); + + +/* Utility functions. */ + +static void +load_from_gconf (ESourceList *list) +{ + GSList *conf_list, *p, *q; + GSList *new_groups_list; + GHashTable *new_groups_hash; + gboolean changed = FALSE; + int pos; + + conf_list = gconf_client_get_list (list->priv->gconf_client, + list->priv->gconf_path, + GCONF_VALUE_STRING, NULL); + + new_groups_list = NULL; + new_groups_hash = g_hash_table_new (g_direct_hash, g_direct_equal); + + for (p = conf_list, pos = 0; p != NULL; p = p->next, pos++) { + const char *xml = p->data; + xmlDocPtr xmldoc = xmlParseDoc ((char *) xml); + char *group_uid = e_source_group_uid_from_xmldoc (xmldoc); + ESourceGroup *existing_group; + + if (group_uid == NULL) + continue; + + existing_group = e_source_list_peek_group_by_uid (list, group_uid); + if (g_hash_table_lookup (new_groups_hash, existing_group) != NULL) + continue; + + if (existing_group == NULL) { + ESourceGroup *new_group = e_source_group_new_from_xmldoc (xmldoc); + + if (new_group != NULL) { + g_signal_connect (new_group, "changed", G_CALLBACK (group_changed_callback), list); + new_groups_list = g_slist_prepend (new_groups_list, new_group); + + g_hash_table_insert (new_groups_hash, new_group, new_group); + g_signal_emit (list, signals[GROUP_ADDED], 0, new_group); + changed = TRUE; + } + } else { + gboolean group_changed; + + list->priv->ignore_group_changed ++; + + if (e_source_group_update_from_xmldoc (existing_group, xmldoc, &group_changed)) { + new_groups_list = g_slist_prepend (new_groups_list, existing_group); + g_object_ref (existing_group); + g_hash_table_insert (new_groups_hash, existing_group, existing_group); + + if (group_changed) + changed = TRUE; + } + + list->priv->ignore_group_changed --; + } + + g_free (group_uid); + } + + new_groups_list = g_slist_reverse (new_groups_list); + + g_slist_foreach (conf_list, (GFunc) g_free, NULL); + g_slist_free (conf_list); + + /* Emit "group_removed" and disconnect the "changed" signal for all the + groups that we haven't found in the new list. Also, check if the + order has changed. */ + q = new_groups_list; + for (p = list->priv->groups; p != NULL; p = p->next) { + ESourceGroup *group = E_SOURCE_GROUP (p->data); + + if (g_hash_table_lookup (new_groups_hash, group) == NULL) { + changed = TRUE; + g_signal_emit (list, signals[GROUP_REMOVED], 0, group); + g_signal_handlers_disconnect_by_func (group, group_changed_callback, list); + } + + if (! changed && q != NULL) { + if (q->data != p->data) + changed = TRUE; + q = q->next; + } + } + + g_hash_table_destroy (new_groups_hash); + + /* Replace the original group list with the new one. */ + + g_slist_foreach (list->priv->groups, (GFunc) g_object_unref, NULL); + g_slist_free (list->priv->groups); + + list->priv->groups = new_groups_list; + + /* FIXME if the order changes, the function doesn't notice. */ + + if (changed) + g_signal_emit (list, signals[CHANGED], 0); +} + +static void +remove_group (ESourceList *list, + ESourceGroup *group) +{ + list->priv->groups = g_slist_remove (list->priv->groups, group); + + g_signal_emit (list, signals[GROUP_REMOVED], 0, group); + g_object_unref (group); + + g_signal_emit (list, signals[CHANGED], 0); +} + + +/* Callbacks. */ + +static gboolean +sync_idle_callback (ESourceList *list) +{ + GError *error = NULL; + + if (! e_source_list_sync (list, &error)) { + g_warning ("Cannot update \"%s\": %s", list->priv->gconf_path, error->message); + g_error_free (error); + } + + return FALSE; +} + +static void +group_changed_callback (ESourceGroup *group, + ESourceList *list) +{ + if (! list->priv->ignore_group_changed) + g_signal_emit (list, signals[CHANGED], 0); + + if (list->priv->sync_idle_id == 0) + list->priv->sync_idle_id = g_idle_add ((GSourceFunc) sync_idle_callback, list); +} + +static void +conf_changed_callback (GConfClient *client, + unsigned int connection_id, + GConfEntry *entry, + ESourceList *list) +{ + load_from_gconf (list); +} + + +/* GObject methods. */ + +static void +impl_dispose (GObject *object) +{ + ESourceListPrivate *priv = E_SOURCE_LIST (object)->priv; + + if (priv->sync_idle_id != 0) { + GError *error = NULL; + + g_source_remove (priv->sync_idle_id); + priv->sync_idle_id = 0; + + if (! e_source_list_sync (E_SOURCE_LIST (object), &error)) + g_warning ("Could not update \"%s\": %s", + priv->gconf_path, error->message); + } + + if (priv->groups != NULL) { + GSList *p; + + for (p = priv->groups; p != NULL; p = p->next) + g_object_unref (p->data); + + g_slist_free (priv->groups); + priv->groups = NULL; + } + + if (priv->gconf_client != NULL) { + if (priv->gconf_notify_id != 0) { + gconf_client_notify_remove (priv->gconf_client, + priv->gconf_notify_id); + priv->gconf_notify_id = 0; + } + + g_object_unref (priv->gconf_client); + priv->gconf_client = NULL; + } + + (* G_OBJECT_CLASS (parent_class)->dispose) (object); +} + +static void +impl_finalize (GObject *object) +{ + ESourceListPrivate *priv = E_SOURCE_LIST (object)->priv; + + if (priv->gconf_notify_id != 0) { + gconf_client_notify_remove (priv->gconf_client, + priv->gconf_notify_id); + priv->gconf_notify_id = 0; + } + + g_free (priv->gconf_path); + g_free (priv); + + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + + +/* Initialization. */ + +static void +class_init (ESourceListClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = impl_dispose; + object_class->finalize = impl_finalize; + + parent_class = g_type_class_peek_parent (class); + + signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESourceListClass, changed), + NULL, NULL, + e_util_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[GROUP_REMOVED] = + g_signal_new ("group_removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESourceListClass, group_removed), + NULL, NULL, + e_util_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[GROUP_ADDED] = + g_signal_new ("group_added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESourceListClass, group_added), + NULL, NULL, + e_util_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_POINTER); +} + +static void +init (ESourceList *source_list) +{ + ESourceListPrivate *priv; + + priv = g_new0 (ESourceListPrivate, 1); + + source_list->priv = priv; +} + + +/* Public methods. */ + +ESourceList * +e_source_list_new (void) +{ + ESourceList *list = g_object_new (e_source_list_get_type (), NULL); + + return list; +} + +ESourceList * +e_source_list_new_for_gconf (GConfClient *client, + const char *path) +{ + ESourceList *list; + + g_return_val_if_fail (GCONF_IS_CLIENT (client), NULL); + g_return_val_if_fail (path != NULL, NULL); + + list = g_object_new (e_source_list_get_type (), NULL); + + list->priv->gconf_path = g_strdup (path); + list->priv->gconf_client = client; + g_object_ref (client); + + gconf_client_add_dir (client, path, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); + + list->priv->gconf_notify_id + = gconf_client_notify_add (client, path, + (GConfClientNotifyFunc) conf_changed_callback, list, + NULL, NULL); + load_from_gconf (list); + + return list; +} + + +GSList * +e_source_list_peek_groups (ESourceList *list) +{ + g_return_val_if_fail (E_IS_SOURCE_LIST (list), NULL); + + return list->priv->groups; +} + +ESourceGroup * +e_source_list_peek_group_by_uid (ESourceList *list, + const char *uid) +{ + GSList *p; + + g_return_val_if_fail (E_IS_SOURCE_LIST (list), NULL); + g_return_val_if_fail (uid != NULL, NULL); + + for (p = list->priv->groups; p != NULL; p = p->next) { + ESourceGroup *group = E_SOURCE_GROUP (p->data); + + if (strcmp (e_source_group_peek_uid (group), uid) == 0) + return group; + } + + return NULL; +} + +ESource * +e_source_list_peek_source_by_uid (ESourceList *list, + const char *group_uid, + const char *source_uid) +{ + ESourceGroup *group; + + g_return_val_if_fail (E_IS_SOURCE_LIST (list), NULL); + g_return_val_if_fail (group_uid != NULL, NULL); + g_return_val_if_fail (source_uid != NULL, NULL); + + group = e_source_list_peek_group_by_uid (list, group_uid); + if (group == NULL) + return NULL; + + return e_source_group_peek_source_by_uid (group, source_uid); +} + + +gboolean +e_source_list_add_group (ESourceList *list, + ESourceGroup *group, + int position) +{ + g_return_val_if_fail (E_IS_SOURCE_LIST (list), FALSE); + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + + if (e_source_list_peek_group_by_uid (list, e_source_group_peek_uid (group)) != NULL) + return FALSE; + + list->priv->groups = g_slist_insert (list->priv->groups, group, position); + g_object_ref (group); + + g_signal_connect (group, "changed", G_CALLBACK (group_changed_callback), list); + + g_signal_emit (list, signals[GROUP_ADDED], 0, group); + g_signal_emit (list, signals[CHANGED], 0); + + return TRUE; +} + +gboolean +e_source_list_remove_group (ESourceList *list, + ESourceGroup *group) +{ + g_return_val_if_fail (E_IS_SOURCE_LIST (list), FALSE); + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + + if (e_source_list_peek_group_by_uid (list, e_source_group_peek_uid (group)) == NULL) + return FALSE; + + remove_group (list, group); + return TRUE; +} + +gboolean +e_source_list_remove_group_by_uid (ESourceList *list, + const char *uid) +{ + ESourceGroup *group; + + g_return_val_if_fail (E_IS_SOURCE_LIST (list), FALSE); + g_return_val_if_fail (uid != NULL, FALSE); + + group = e_source_list_peek_group_by_uid (list, uid); + if (group== NULL) + return FALSE; + + remove_group (list, group); + return TRUE; +} + +gboolean +e_source_list_remove_source_by_uid (ESourceList *list, + const char *group_uid, + const char *source_uid) +{ + ESourceGroup *group; + + g_return_val_if_fail (E_IS_SOURCE_LIST (list), FALSE); + g_return_val_if_fail (group_uid != NULL, FALSE); + g_return_val_if_fail (source_uid != NULL, FALSE); + + group = e_source_list_peek_group_by_uid (list, group_uid); + if (group== NULL) + return FALSE; + + return e_source_group_remove_source_by_uid (group, source_uid); +} + + +gboolean +e_source_list_sync (ESourceList *list, + GError **error) +{ + GSList *conf_list; + GSList *p; + gboolean retval; + + g_return_val_if_fail (E_IS_SOURCE_LIST (list), FALSE); + + conf_list = NULL; + for (p = list->priv->groups; p != NULL; p = p->next) + conf_list = g_slist_prepend (conf_list, e_source_group_to_xml (E_SOURCE_GROUP (p->data))); + conf_list = g_slist_reverse (conf_list); + + retval = gconf_client_set_list (list->priv->gconf_client, + list->priv->gconf_path, + GCONF_VALUE_STRING, + conf_list, + error); + + g_slist_foreach (conf_list, (GFunc) g_free, NULL); + g_slist_free (conf_list); + + if (list->priv->gconf_notify_id != 0) { + gconf_client_notify_remove (list->priv->gconf_client, + list->priv->gconf_notify_id); + list->priv->gconf_notify_id = 0; + } + + return retval; +} + + +E_MAKE_TYPE (e_source_list, "ESourceList", ESourceList, class_init, init, PARENT_TYPE) diff --git a/e-util/e-source-list.h b/e-util/e-source-list.h new file mode 100644 index 0000000000..1985b35d73 --- /dev/null +++ b/e-util/e-source-list.h @@ -0,0 +1,88 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-source-list.h + * + * Copyright (C) 2003 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. + * + * Author: Ettore Perazzoli + */ + +#ifndef _E_SOURCE_LIST_H_ +#define _E_SOURCE_LIST_H_ + +#include +#include + +#include "e-source-group.h" + +#define E_TYPE_SOURCE_LIST (e_source_list_get_type ()) +#define E_SOURCE_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_SOURCE_LIST, ESourceList)) +#define E_SOURCE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_SOURCE_LIST, ESourceListClass)) +#define E_IS_SOURCE_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_SOURCE_LIST)) +#define E_IS_SOURCE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_SOURCE_LIST)) + + +typedef struct _ESourceList ESourceList; +typedef struct _ESourceListPrivate ESourceListPrivate; +typedef struct _ESourceListClass ESourceListClass; + +struct _ESourceList { + GObject parent; + + ESourceListPrivate *priv; +}; + +struct _ESourceListClass { + GObjectClass parent_class; + + /* Signals. */ + + void (* changed) (ESourceList *source_list); + + void (* group_removed) (ESourceList *source_list, ESourceGroup *group); + void (* group_added) (ESourceList *source_list, ESourceGroup *group); +}; + + +GType e_source_list_get_type (void); + +ESourceList *e_source_list_new (void); +ESourceList *e_source_list_new_for_gconf (GConfClient *client, + const char *path); + +GSList *e_source_list_peek_groups (ESourceList *list); +ESourceGroup *e_source_list_peek_group_by_uid (ESourceList *list, + const char *source_group); +ESource *e_source_list_peek_source_by_uid (ESourceList *list, + const char *group_name, + const char *source_name); + +gboolean e_source_list_add_group (ESourceList *list, + ESourceGroup *group, + int position); +gboolean e_source_list_remove_group (ESourceList *list, + ESourceGroup *group); +gboolean e_source_list_remove_group_by_uid (ESourceList *list, + const char *name); +gboolean e_source_list_remove_source_by_uid (ESourceList *list, + const char *group_name, + const char *source_name); + +gboolean e_source_list_sync (ESourceList *list, + GError **error); + + +#endif /* _E_SOURCE_LIST_H_ */ diff --git a/e-util/e-source.c b/e-util/e-source.c new file mode 100644 index 0000000000..cc7742d924 --- /dev/null +++ b/e-util/e-source.c @@ -0,0 +1,458 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-source.c + * + * Copyright (C) 2003 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. + * + * Author: Ettore Perazzoli + */ + +#include + +#include "e-source.h" + +#include "e-util-marshal.h" +#include "e-uid.h" + +#include +#include + + +#define PARENT_TYPE G_TYPE_OBJECT +static GObjectClass *parent_class = NULL; + +#define ES_CLASS(obj) E_SOURCE_CLASS (G_OBJECT_GET_CLASS (obj)) + + +/* String used to put the color in the XML. */ +#define COLOR_FORMAT_STRING "%06x" + + +/* Private members. */ + +struct _ESourcePrivate { + ESourceGroup *group; + + char *uid; + char *name; + char *relative_uri; + + gboolean has_color; + guint32 color; +}; + + +/* Signals. */ + +enum { + CHANGED, + LAST_SIGNAL +}; +static unsigned int signals[LAST_SIGNAL] = { 0 }; + + +/* Callbacks. */ + +static void +group_weak_notify (ESource *source, + GObject **where_the_object_was) +{ + source->priv->group = NULL; + + g_signal_emit (source, signals[CHANGED], 0); +} + + +/* GObject methods. */ + +static void +impl_finalize (GObject *object) +{ + ESourcePrivate *priv = E_SOURCE (object)->priv; + + g_free (priv->uid); + g_free (priv->name); + g_free (priv->relative_uri); + g_free (priv); + + (* G_OBJECT_CLASS (parent_class)->finalize) (object); +} + +static void +impl_dispose (GObject *object) +{ + ESourcePrivate *priv = E_SOURCE (object)->priv; + + if (priv->group != NULL) { + g_object_weak_unref (G_OBJECT (priv->group), (GWeakNotify) group_weak_notify, object); + priv->group = NULL; + } + + (* G_OBJECT_CLASS (parent_class)->dispose) (object); +} + + +/* Initialization. */ + +static void +class_init (ESourceClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = impl_dispose; + object_class->finalize = impl_finalize; + + parent_class = g_type_class_peek_parent (class); + + signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESourceClass, changed), + NULL, NULL, + e_util_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +init (ESource *source) +{ + ESourcePrivate *priv; + + priv = g_new0 (ESourcePrivate, 1); + source->priv = priv; +} + + +/* Public methods. */ + +ESource * +e_source_new (const char *name, + const char *relative_uri) +{ + ESource *source; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (relative_uri != NULL, NULL); + + source = g_object_new (e_source_get_type (), NULL); + source->priv->uid = e_uid_new (); + + e_source_set_name (source, name); + e_source_set_relative_uri (source, relative_uri); + return source; +} + +ESource * +e_source_new_from_xml_node (xmlNodePtr node) +{ + ESource *source; + xmlChar *uid; + + uid = xmlGetProp (node, "uid"); + if (uid == NULL) + return NULL; + + source = g_object_new (e_source_get_type (), NULL); + + source->priv->uid = g_strdup (uid); + xmlFree (uid); + + if (e_source_update_from_xml_node (source, node, NULL)) + return source; + + g_object_unref (source); + return NULL; +} + +/** + * e_source_update_from_xml_node: + * @source: An ESource. + * @node: A pointer to the node to parse. + * + * Update the ESource properties from @node. + * + * Return value: %TRUE if the data in @node was recognized and parsed into + * acceptable values for @source, %FALSE otherwise. + **/ +gboolean +e_source_update_from_xml_node (ESource *source, + xmlNodePtr node, + gboolean *changed_return) +{ + xmlChar *name; + xmlChar *relative_uri; + xmlChar *color_string; + gboolean retval; + gboolean changed = FALSE; + + name = xmlGetProp (node, "name"); + relative_uri = xmlGetProp (node, "relative_uri"); + color_string = xmlGetProp (node, "color"); + + if (name == NULL || relative_uri == NULL) { + retval = FALSE; + goto done; + } + + if (source->priv->name == NULL + || strcmp (name, source->priv->name) != 0 + || source->priv->relative_uri == NULL + || strcmp (relative_uri, source->priv->relative_uri) != 0) { + g_free (source->priv->name); + source->priv->name = g_strdup (name); + + g_free (source->priv->relative_uri); + source->priv->relative_uri = g_strdup (relative_uri); + + changed = TRUE; + } + + if (color_string == NULL) { + if (source->priv->has_color) { + source->priv->has_color = FALSE; + changed = TRUE; + } + } else { + guint32 color = 0; + + sscanf (color_string, COLOR_FORMAT_STRING, &color); + if (! source->priv->has_color || source->priv->color != color) { + source->priv->has_color = TRUE; + source->priv->color = color; + changed = TRUE; + } + } + + retval = TRUE; + + done: + if (changed) + g_signal_emit (source, signals[CHANGED], 0); + + if (changed_return != NULL) + *changed_return = changed; + + if (name != NULL) + xmlFree (name); + if (relative_uri != NULL) + xmlFree (relative_uri); + if (color_string != NULL) + xmlFree (color_string); + + return retval; +} + +/** + * e_source_name_from_xml_node: + * @node: A pointer to an XML node. + * + * Assuming that @node is a valid ESource specification, retrieve the name of + * the source from it. + * + * Return value: Name of the source in the specified @node. The caller must + * free the string. + **/ +char * +e_source_uid_from_xml_node (xmlNodePtr node) +{ + xmlChar *uid = xmlGetProp (node, "uid"); + char *retval; + + if (uid == NULL) + return NULL; + + retval = g_strdup (uid); + xmlFree (uid); + return retval; +} + +void +e_source_set_group (ESource *source, + ESourceGroup *group) +{ + g_return_if_fail (E_IS_SOURCE (source)); + g_return_if_fail (group == NULL || E_IS_SOURCE_GROUP (group)); + + if (source->priv->group == group) + return; + + if (source->priv->group != NULL) + g_object_weak_unref (G_OBJECT (source->priv->group), (GWeakNotify) group_weak_notify, source); + + source->priv->group = group; + if (group != NULL) + g_object_weak_ref (G_OBJECT (group), (GWeakNotify) group_weak_notify, source); + + g_signal_emit (source, signals[CHANGED], 0); +} + +void +e_source_set_name (ESource *source, + const char *name) +{ + g_return_if_fail (E_IS_SOURCE (source)); + + if (source->priv->name == name) + return; + + g_free (source->priv->name); + source->priv->name = g_strdup (name); + + g_signal_emit (source, signals[CHANGED], 0); +} + +void +e_source_set_relative_uri (ESource *source, + const char *relative_uri) +{ + g_return_if_fail (E_IS_SOURCE (source)); + + if (source->priv->relative_uri == relative_uri) + return; + + g_free (source->priv->relative_uri); + source->priv->relative_uri = g_strdup (relative_uri); + + g_signal_emit (source, signals[CHANGED], 0); +} + +void +e_source_set_color (ESource *source, + guint32 color) +{ + g_return_if_fail (E_IS_SOURCE (source)); + + if (source->priv->has_color && source->priv->color == color) + return; + + source->priv->has_color = TRUE; + source->priv->color = color; + + g_signal_emit (source, signals[CHANGED], 0); +} + +void +e_source_unset_color (ESource *source) +{ + g_return_if_fail (E_IS_SOURCE (source)); + + if (! source->priv->has_color) + return; + + source->priv->has_color = FALSE; + g_signal_emit (source, signals[CHANGED], 0); +} + + +ESourceGroup * +e_source_peek_group (ESource *source) +{ + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + + return source->priv->group; +} + +const char * +e_source_peek_uid (ESource *source) +{ + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + + return source->priv->uid; +} + +const char * +e_source_peek_name (ESource *source) +{ + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + + return source->priv->name; +} + +const char * +e_source_peek_relative_uri (ESource *source) +{ + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + + return source->priv->relative_uri; +} + +/** + * e_source_get_color: + * @source: An ESource + * @color_return: Pointer to a variable where the returned color will be + * stored. + * + * If @source has an associated color, return it in *@color_return. + * + * Return value: %TRUE if the @source has a defined color (and hence + * *@color_return was set), %FALSE otherwise. + **/ +gboolean +e_source_get_color (ESource *source, + guint32 *color_return) +{ + g_return_val_if_fail (E_IS_SOURCE (source), FALSE); + + if (! source->priv->has_color) + return FALSE; + + if (color_return != NULL) + *color_return = source->priv->color; + + return TRUE; +} + + +char * +e_source_get_uri (ESource *source) +{ + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + + if (source->priv->group == NULL) + return NULL; + + return g_build_filename (e_source_group_peek_base_uri (source->priv->group), + source->priv->relative_uri, + NULL); +} + + +void +e_source_dump_to_xml_node (ESource *source, + xmlNodePtr parent_node) +{ + gboolean has_color; + guint32 color; + xmlNodePtr node = xmlNewChild (parent_node, NULL, "source", NULL); + + g_return_if_fail (E_IS_SOURCE (source)); + + + xmlSetProp (node, "uid", e_source_peek_uid (source)); + xmlSetProp (node, "name", e_source_peek_name (source)); + xmlSetProp (node, "relative_uri", e_source_peek_relative_uri (source)); + + has_color = e_source_get_color (source, &color); + if (has_color) { + char *color_string = g_strdup_printf (COLOR_FORMAT_STRING, color); + xmlSetProp (node, "color", color_string); + g_free (color_string); + } +} + + +E_MAKE_TYPE (e_source, "ESource", ESource, class_init, init, PARENT_TYPE) diff --git a/e-util/e-source.h b/e-util/e-source.h new file mode 100644 index 0000000000..6060b8b588 --- /dev/null +++ b/e-util/e-source.h @@ -0,0 +1,91 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-source.h + * + * Copyright (C) 2003 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. + * + * Author: Ettore Perazzoli + */ + +#ifndef _E_SOURCE_H_ +#define _E_SOURCE_H_ + +#include +#include + +#define E_TYPE_SOURCE (e_source_get_type ()) +#define E_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_SOURCE, ESource)) +#define E_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_SOURCE, ESourceClass)) +#define E_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_SOURCE)) +#define E_IS_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_SOURCE)) + + +typedef struct _ESource ESource; +typedef struct _ESourcePrivate ESourcePrivate; +typedef struct _ESourceClass ESourceClass; + +#include "e-source-group.h" + +struct _ESource { + GObject parent; + + ESourcePrivate *priv; +}; + +struct _ESourceClass { + GObjectClass parent_class; + + /* Signals. */ + void (* changed) (ESource *source); +}; + + +GType e_source_get_type (void); + +ESource *e_source_new (const char *name, + const char *relative_uri); +ESource *e_source_new_from_xml_node (xmlNodePtr node); + +gboolean e_source_update_from_xml_node (ESource *source, + xmlNodePtr node, + gboolean *changed_return); + +char *e_source_uid_from_xml_node (xmlNodePtr node); + +void e_source_set_group (ESource *source, + ESourceGroup *group); +void e_source_set_name (ESource *source, + const char *name); +void e_source_set_relative_uri (ESource *source, + const char *relative_uri); +void e_source_set_color (ESource *source, + guint32 color); +void e_source_unset_color (ESource *source); + +ESourceGroup *e_source_peek_group (ESource *source); +const char *e_source_peek_uid (ESource *source); +const char *e_source_peek_name (ESource *source); +const char *e_source_peek_relative_uri (ESource *source); +gboolean e_source_get_color (ESource *source, + guint32 *color_return); + +char *e_source_get_uri (ESource *source); + +void e_source_dump_to_xml_node (ESource *source, + xmlNodePtr parent_node); + + +#endif /* _E_SOURCE_H_ */ diff --git a/e-util/e-uid.c b/e-util/e-uid.c new file mode 100644 index 0000000000..90c036e0c1 --- /dev/null +++ b/e-util/e-uid.c @@ -0,0 +1,61 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-uid.c - Unique ID generator. + * + * Copyright (C) 2002 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. + * + * Author: Dan Winship + */ + +#include "e-uid.h" + +#include + +#include +#include +#include + + +/** + * e_uid_new: + * + * Generate a new unique string for use e.g. in account lists. + * + * Return value: the newly generated UID. The caller should free the string + * when it's done with it. + **/ +char * +e_uid_new (void) +{ + static char *hostname; + static int serial; + + if (!hostname) { + static char buffer [512]; + + if ((gethostname (buffer, sizeof (buffer) - 1) == 0) && + (buffer [0] != 0)) + hostname = buffer; + else + hostname = "localhost"; + } + + return g_strdup_printf ("%lu.%lu.%d@%s", + (unsigned long) time (NULL), + (unsigned long) getpid (), + serial++, + hostname); +} diff --git a/e-util/e-uid.h b/e-util/e-uid.h new file mode 100644 index 0000000000..44ec8c0dd9 --- /dev/null +++ b/e-util/e-uid.h @@ -0,0 +1,28 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-uid.h - Unique ID generator. + * + * Copyright (C) 2002 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. + * + * Author: Dan Winship + */ + +#ifndef E_UID_H +#define E_UID_H + +char *e_uid_new (void); + +#endif /* E_UID_H */ diff --git a/e-util/test-source-list.c b/e-util/test-source-list.c new file mode 100644 index 0000000000..7c38436326 --- /dev/null +++ b/e-util/test-source-list.c @@ -0,0 +1,524 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* test-source-list.c - Test for the ESourceList class. + * + * Copyright (C) 2002 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. + * + * Author: Ettore Perazzoli + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-source-list.h" + +#include +#include + + +/* Globals. */ + +static GMainLoop *main_loop = NULL; +static ESourceList *list = NULL; +static int idle_dump_id = 0; + + +/* Options. */ + +static gboolean listen = FALSE; +static gboolean dump = FALSE; +static char *key_arg = "/apps/evolution/test/source_list"; +static char *source_arg = NULL; +static char *group_arg = NULL; +static char *add_group_arg = NULL; +static char *add_source_arg = NULL; +static char *remove_group_arg = NULL; +static char *remove_source_arg = NULL; +static char *set_name_arg = NULL; +static char *set_base_uri_arg = NULL; +static char *set_relative_uri_arg = NULL; +static char *set_color_arg = NULL; +static gboolean unset_color = FALSE; + +static struct poptOption options[] = { + { "key", '\0', POPT_ARG_STRING, &key_arg, 0, + "Name of the GConf key to use", "PATH" }, + { "source", '\0', POPT_ARG_STRING, &source_arg, 0, + "UID of source to apply operation to", "UID" }, + { "group", '\0', POPT_ARG_STRING, &group_arg, 0, + "UID of group to apply operation to", "UID" }, + { "add-group", '\0', POPT_ARG_STRING, &add_group_arg, 0, + "Add group of specified name", "NAME" }, + { "add-source", '\0', POPT_ARG_STRING, &add_source_arg, 0, + "Add source of specified name", "NAME" }, + { "remove-group", '\0', POPT_ARG_STRING, &remove_group_arg, 0, + "Remove group of specified name", "NAME" }, + { "remove-source", '\0', POPT_ARG_STRING, &remove_source_arg, 0, + "Remove source of specified name", "NAME" }, + { "set-name", '\0', POPT_ARG_STRING, &set_name_arg, 0, + "Set name of source or group. When used with --group, it sets the name of a group. " + "When used with both --group and --source, it sets the name of a source.", "NAME" }, + { "set-relative-uri", '\0', POPT_ARG_STRING, &set_relative_uri_arg, 0, + "Set relative URI of a source. Use with --source or --add-source.", "NAME" }, + { "set-base-uri", '\0', POPT_ARG_STRING, &set_base_uri_arg, 0, + "Set base URI of a group. Use with --group or --add-group.", "NAME" }, + { "set-color", '\0', POPT_ARG_STRING, &set_color_arg, 0, + "Set the color of a source. Use with --source or --add-source.", "COLOR (rrggbb)" }, + { "unset-color", '\0', POPT_ARG_NONE, &unset_color, 0, + "Unset the color of a source. Use with --source or --add-source.", NULL }, + { "listen", '\0', POPT_ARG_NONE, &listen, 0, + "Wait and listen for changes.", "" }, + { "dump", '\0', POPT_ARG_NONE, &dump, 0, + "List the current configured sources.", "" }, + POPT_AUTOHELP + { NULL } +}; + + +/* Forward decls. */ +static void group_added_callback (ESourceList *list, ESourceGroup *group); +static void group_removed_callback (ESourceList *list, ESourceGroup *group); +static void source_added_callback (ESourceGroup *group, ESource *source); +static void source_removed_callback (ESourceGroup *group, ESource *source); + + +static void +dump_source (ESource *source) +{ + char *uri = e_source_get_uri (source); + gboolean has_color; + guint32 color; + + g_print ("\tSource %s\n", e_source_peek_uid (source)); + g_print ("\t\tname: %s\n", e_source_peek_name (source)); + g_print ("\t\trelative_uri: %s\n", e_source_peek_relative_uri (source)); + g_print ("\t\tabsolute_uri: %s\n", uri); + + has_color = e_source_get_color (source, &color); + if (has_color) + g_print ("\t\tcolor: %06x\n", color); + + g_free (uri); +} + +static void +dump_group (ESourceGroup *group) +{ + GSList *sources, *p; + + g_print ("Group %s\n", e_source_group_peek_uid (group)); + g_print ("\tname: %s\n", e_source_group_peek_name (group)); + g_print ("\tbase_uri: %s\n", e_source_group_peek_base_uri (group)); + + sources = e_source_group_peek_sources (group); + for (p = sources; p != NULL; p = p->next) { + ESource *source = E_SOURCE (p->data); + + dump_source (source); + + if (e_source_peek_group (source) != group) + g_warning ("\t\t** ERROR ** parent pointer is %p, should be %p", + e_source_peek_group (source), group); + } +} + +static void +dump_list (void) +{ + GSList *groups, *p; + + groups = e_source_list_peek_groups (list); + if (groups == NULL) { + g_print ("(No items)\n"); + return; + } + + for (p = groups; p != NULL; p = p->next) + dump_group (E_SOURCE_GROUP (p->data)); +} + + +static int +idle_dump_callback (void *unused_data) +{ + dump_list (); + idle_dump_id = 0; + + return FALSE; +} + +static void +dump_on_idle (void) +{ + if (idle_dump_id == 0) + idle_dump_id = g_idle_add (idle_dump_callback, NULL); +} + + +static void +source_changed_callback (ESource *source) +{ + static int count = 0; + + g_print ("** Event: source \"%s\" changed (%d)\n", e_source_peek_name (source), ++count); + + dump_on_idle (); +} + +static void +group_changed_callback (ESourceGroup *group) +{ + static int count = 0; + + g_print ("** Event: group \"%s\" changed (%d)\n", e_source_group_peek_name (group), ++count); + + dump_on_idle (); +} + +static void +list_changed_callback (ESourceGroup *group) +{ + static int count = 0; + + g_print ("** Event: list changed (%d)\n", ++count); + + dump_on_idle (); +} + + +static void +connect_source (ESource *source) +{ + g_object_ref (source); + g_signal_connect (source, "changed", G_CALLBACK (source_changed_callback), NULL); +} + +static void +connect_group (ESourceGroup *group) +{ + GSList *sources, *p; + + g_object_ref (group); + g_signal_connect (group, "changed", G_CALLBACK (group_changed_callback), NULL); + g_signal_connect (group, "source_added", G_CALLBACK (source_added_callback), NULL); + g_signal_connect (group, "source_removed", G_CALLBACK (source_removed_callback), NULL); + + sources = e_source_group_peek_sources (group); + for (p = sources; p != NULL; p = p->next) + connect_source (E_SOURCE (p->data)); +} + +static void +connect_list (void) +{ + GSList *groups, *p; + + g_signal_connect (list, "changed", G_CALLBACK (list_changed_callback), NULL); + g_signal_connect (list, "group_added", G_CALLBACK (group_added_callback), NULL); + g_signal_connect (list, "group_removed", G_CALLBACK (group_removed_callback), NULL); + + groups = e_source_list_peek_groups (list); + for (p = groups; p != NULL; p = p->next) + connect_group (E_SOURCE_GROUP (p->data)); +} + +static void +disconnect_group (ESourceGroup *group) +{ + g_signal_handlers_disconnect_by_func (group, G_CALLBACK (group_changed_callback), NULL); + g_signal_handlers_disconnect_by_func (group, G_CALLBACK (source_added_callback), NULL); + + g_object_unref (group); +} + +static void +disconnect_source (ESource *source) +{ + g_signal_handlers_disconnect_by_func (source, G_CALLBACK (source_changed_callback), NULL); + + g_object_unref (source); +} + + +static void +source_added_callback (ESourceGroup *group, + ESource *source) +{ + static int count = 0; + + g_print ("** Event: source \"%s\" added (%d)\n", e_source_peek_name (source), ++count); + + connect_source (source); + dump_on_idle (); +} + +static void +source_removed_callback (ESourceGroup *group, + ESource *source) +{ + static int count = 0; + + g_print ("** Event: source \"%s\" removed (%d)\n", e_source_peek_name (source), ++count); + + disconnect_source (source); + dump_on_idle (); +} + +static void +group_added_callback (ESourceList *list, + ESourceGroup *group) +{ + static int count = 0; + + g_print ("** Event: group \"%s\" added (%d)\n", e_source_group_peek_name (group), ++count); + + connect_group (group); + dump_on_idle (); +} + +static void +group_removed_callback (ESourceList *list, + ESourceGroup *group) +{ + static int count = 0; + + g_print ("** Event: group \"%s\" removed (%d)\n", e_source_group_peek_name (group), ++count); + + disconnect_group (group); + dump_on_idle (); +} + + +static int +on_idle_do_stuff (void *unused_data) +{ + GConfClient *client = gconf_client_get_default (); + ESourceGroup *new_group = NULL; + ESource *new_source = NULL; + + list = e_source_list_new_for_gconf (client, key_arg); + g_object_unref (client); + + if (add_group_arg != NULL) { + if (group_arg != NULL) { + fprintf (stderr, "--add-group and --group cannot be used at the same time.\n"); + exit (1); + } + if (set_base_uri_arg == NULL) { + fprintf (stderr, "When using --add-group, you need to specify a base URI using --set-base-uri.\n"); + exit (1); + } + + new_group = e_source_group_new (add_group_arg, set_base_uri_arg); + e_source_list_add_group (list, new_group, -1); + g_object_unref (new_group); + + e_source_list_sync (list, NULL); + } + + if (remove_group_arg != NULL) { + ESourceGroup *group; + + group = e_source_list_peek_group_by_uid (list, remove_group_arg); + if (group == NULL) { + fprintf (stderr, "No such group \"%s\".\n", remove_group_arg); + exit (1); + } + + e_source_list_remove_group (list, group); + e_source_list_sync (list, NULL); + } + + if (add_source_arg != NULL) { + ESourceGroup *group; + + if (group_arg == NULL && new_group == NULL) { + fprintf (stderr, + "When using --add-source, you need to specify a group using either --group\n" + "or --add-group.\n"); + exit (1); + } + if (set_relative_uri_arg == NULL) { + fprintf (stderr, + "When using --add-source, you need to specify a relative URI using\n" + "--set-relative-uri.\n"); + exit (1); + } + + if (group_arg == NULL) { + group = new_group; + } else { + group = e_source_list_peek_group_by_uid (list, group_arg); + if (group == NULL) { + fprintf (stderr, "No such group \"%s\".\n", group_arg == NULL ? add_group_arg : group_arg); + exit (1); + } + } + + new_source = e_source_new (add_source_arg, set_relative_uri_arg); + e_source_group_add_source (group, new_source, -1); + e_source_list_sync (list, NULL); + } + + if (remove_source_arg != NULL) { + ESource *source; + + if (group_arg == NULL) { + fprintf (stderr, "When using --remove-source, you need to specify a group using --group.\n"); + exit (1); + } + + source = e_source_list_peek_source_by_uid (list, group_arg, remove_source_arg); + if (source == NULL) { + fprintf (stderr, "No such source \"%s\" in group \"%s\".\n", remove_source_arg, group_arg); + exit (1); + } + + e_source_list_remove_source_by_uid (list, group_arg, remove_source_arg); + e_source_list_sync (list, NULL); + } + + if (set_name_arg != NULL) { + if (group_arg == NULL) { + fprintf (stderr, + "When using --set-name, you need to specify a source (using --group and\n" + "--source) or a group (using --group alone).\n"); + exit (1); + } + + if (source_arg != NULL) { + ESource *source = e_source_list_peek_source_by_uid (list, group_arg, source_arg); + + if (source != NULL) { + e_source_set_name (source, set_name_arg); + } else { + fprintf (stderr, "No such source \"%s\" in group \"%s\".\n", source_arg, group_arg); + exit (1); + } + } else { + ESourceGroup *group = e_source_list_peek_group_by_uid (list, group_arg); + + if (group != NULL) { + e_source_group_set_name (group, set_name_arg); + } else { + fprintf (stderr, "No such group \"%s\".\n", group_arg); + exit (1); + } + } + + e_source_list_sync (list, NULL); + } + + if (set_relative_uri_arg != NULL && add_source_arg == NULL) { + ESource *source; + + if (source_arg == NULL || group_arg == NULL) { + fprintf (stderr, + "When using --set-relative-uri, you need to specify a source using --group\n" + "and --source.\n"); + exit (1); + } + + source = e_source_list_peek_source_by_uid (list, group_arg, source_arg); + e_source_set_relative_uri (source, set_relative_uri_arg); + e_source_list_sync (list, NULL); + } + + if (set_color_arg != NULL) { + ESource *source; + guint32 color; + + if (add_source_arg == NULL && (source_arg == NULL || group_arg == NULL)) { + fprintf (stderr, + "When using --set-color, you need to specify a source using --group\n" + "and --source.\n"); + exit (1); + } + + if (add_source_arg != NULL) + source = new_source; + else + source = e_source_list_peek_source_by_uid (list, group_arg, source_arg); + + sscanf (set_color_arg, "%06x", &color); + e_source_set_color (source, color); + e_source_list_sync (list, NULL); + } + + if (unset_color) { + ESource *source; + + if (add_source_arg == NULL && (source_arg == NULL || group_arg == NULL)) { + fprintf (stderr, + "When using --unset-color, you need to specify a source using --group\n" + "and --source.\n"); + exit (1); + } + + if (add_source_arg != NULL) + source = new_source; + else + source = e_source_list_peek_source_by_uid (list, group_arg, source_arg); + + e_source_unset_color (source); + e_source_list_sync (list, NULL); + } + + if (set_base_uri_arg != NULL && add_group_arg == NULL) { + ESourceGroup *group; + + if (group_arg == NULL) { + fprintf (stderr, + "When using --set-base-uri, you need to specify a group using --group.\n"); + exit (1); + } + + group = e_source_list_peek_group_by_uid (list, group_arg); + e_source_group_set_base_uri (group, set_base_uri_arg); + e_source_list_sync (list, NULL); + } + + connect_list (); + + if (dump) + dump_list (); + + if (! listen) + g_main_loop_quit (main_loop); + + return FALSE; +} + + +int +main (int argc, + char **argv) +{ + GnomeProgram *program; + + program = gnome_program_init ("test-source-list", "0.0", + LIBGNOMEUI_MODULE, argc, argv, + GNOME_PARAM_POPT_TABLE, options, + NULL); + + g_idle_add (on_idle_do_stuff, NULL); + + main_loop = g_main_loop_new (NULL, TRUE); + g_main_loop_run (main_loop); + + return 0; +} diff --git a/filter/ChangeLog b/filter/ChangeLog index abcaad596c..0506227e66 100644 --- a/filter/ChangeLog +++ b/filter/ChangeLog @@ -1,3 +1,13 @@ +2003-10-10 Not Zed + + * filter-folder.c (folder_selected): change for + emfolderselectionbutton fixes. + (get_widget): same. + +2003-09-29 Ettore Perazzoli + + * filter-folder.c (get_widget): Use an EMFolderSelectionButton. + 2003-09-22 Jeffrey Stedfast * filter-int.c (get_widget): Listen to the "value-changed" signal @@ -24,6 +34,15 @@ * searchtypes.xml: Added a search-specific types folder. Also contains system searches that cannot be deleted. +2003-08-18 Ettore Perazzoli + + * vfolder-rule.c (source_add): As a temporary measure, don't call + evolution_shell_client_user_select_folder() since this is not done + by the shell anymore. + + * filter-folder.c (get_widget): Return NULL for now, since we + can't get the folder selector button from the shell anymore. + 2003-08-05 Not Zed ** See bug #42636. diff --git a/filter/filter-folder.c b/filter/filter-folder.c index e074c31f6c..c19584484d 100644 --- a/filter/filter-folder.c +++ b/filter/filter-folder.c @@ -31,7 +31,8 @@ #include #include "filter-folder.h" -#include "shell/evolution-folder-selector-button.h" +#include "mail/em-folder-selection-button.h" +#include "mail/mail-component.h" #include "e-util/e-sexp.h" #define d(x) @@ -53,9 +54,6 @@ static void filter_folder_finalise (GObject *obj); static FilterElementClass *parent_class = NULL; -extern EvolutionShellClient *global_shell_client; - - GType filter_folder_get_type (void) { @@ -222,12 +220,13 @@ xml_decode (FilterElement *fe, xmlNodePtr node) } static void -folder_selected (EvolutionFolderSelectorButton *button, - GNOME_Evolution_Folder *folder, - FilterFolder *ff) +folder_selected(EMFolderSelectionButton *button, FilterFolder *ff) { - g_free (ff->uri); - ff->uri = g_strdup (folder->physicalUri); + const char *uri; + + uri = em_folder_selection_button_get_selection(button); + g_free(ff->uri); + ff->uri = uri!=NULL?em_uri_from_camel(uri):NULL; gdk_window_raise (GTK_WIDGET (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_WINDOW))->window); } @@ -235,14 +234,14 @@ folder_selected (EvolutionFolderSelectorButton *button, static GtkWidget * get_widget (FilterElement *fe) { - static const char *allowed_types[] = { "mail/*", NULL }; FilterFolder *ff = (FilterFolder *)fe; GtkWidget *button; - - button = evolution_folder_selector_button_new (global_shell_client, - _("Select Folder"), - ff->uri, - allowed_types); + char *uri; + + uri = em_uri_to_camel(ff->uri); + button = em_folder_selection_button_new (_("Select Folder"), NULL); + em_folder_selection_button_set_selection(EM_FOLDER_SELECTION_BUTTON(button), uri); + g_free(uri); gtk_widget_show (button); g_signal_connect (button, "selected", G_CALLBACK (folder_selected), ff); diff --git a/filter/libfilter-i18n.h b/filter/libfilter-i18n.h index d965e03184..ea7ff03b0e 100644 --- a/filter/libfilter-i18n.h +++ b/filter/libfilter-i18n.h @@ -4,34 +4,17 @@ char *s = N_("Assign Color"); char *s = N_("Assign Score"); char *s = N_("Attachments"); char *s = N_("Beep"); -char *s = N_("contains"); char *s = N_("Copy to Folder"); char *s = N_("Date received"); char *s = N_("Date sent"); char *s = N_("Delete"); char *s = N_("Deleted"); -char *s = N_("does not contain"); -char *s = N_("does not end with"); -char *s = N_("does not exist"); -char *s = N_("does not return"); -char *s = N_("does not sound like"); -char *s = N_("does not start with"); char *s = N_("Do Not Exist"); char *s = N_("Draft"); -char *s = N_("ends with"); char *s = N_("Exist"); -char *s = N_("exists"); char *s = N_("Expression"); char *s = N_("Follow Up"); char *s = N_("Important"); -char *s = N_("is"); -char *s = N_("is after"); -char *s = N_("is before"); -char *s = N_("is Flagged"); -char *s = N_("is greater than"); -char *s = N_("is less than"); -char *s = N_("is not"); -char *s = N_("is not Flagged"); char *s = N_("Label"); char *s = N_("Mailing list"); char *s = N_("Message Body"); @@ -43,19 +26,36 @@ char *s = N_("Read"); char *s = N_("Recipients"); char *s = N_("Regex Match"); char *s = N_("Replied to"); -char *s = N_("returns"); -char *s = N_("returns greater than"); -char *s = N_("returns less than"); char *s = N_("Score"); char *s = N_("Sender"); char *s = N_("Set Status"); char *s = N_("Shell Command"); char *s = N_("Size (kB)"); -char *s = N_("sounds like"); char *s = N_("Source Account"); char *s = N_("Specific header"); -char *s = N_("starts with"); char *s = N_("Status"); char *s = N_("Stop Processing"); char *s = N_("Subject"); char *s = N_("Unset Status"); +char *s = N_("contains"); +char *s = N_("does not contain"); +char *s = N_("does not end with"); +char *s = N_("does not exist"); +char *s = N_("does not return"); +char *s = N_("does not sound like"); +char *s = N_("does not start with"); +char *s = N_("ends with"); +char *s = N_("exists"); +char *s = N_("is Flagged"); +char *s = N_("is after"); +char *s = N_("is before"); +char *s = N_("is greater than"); +char *s = N_("is less than"); +char *s = N_("is not Flagged"); +char *s = N_("is not"); +char *s = N_("is"); +char *s = N_("returns greater than"); +char *s = N_("returns less than"); +char *s = N_("returns"); +char *s = N_("sounds like"); +char *s = N_("starts with"); diff --git a/filter/vfolder-rule.c b/filter/vfolder-rule.c index 26d024c525..91ad0b151c 100644 --- a/filter/vfolder-rule.c +++ b/filter/vfolder-rule.c @@ -46,8 +46,6 @@ static void rule_copy (FilterRule *dest, FilterRule *src); /*static void build_code(FilterRule *, GString *out);*/ static GtkWidget *get_widget(FilterRule *fr, RuleContext *f); -extern EvolutionShellClient *global_shell_client; - static void vfolder_rule_class_init (VfolderRuleClass *klass); static void vfolder_rule_init (VfolderRule *vr); static void vfolder_rule_finalise (GObject *obj); @@ -433,9 +431,13 @@ source_add (GtkWidget *widget, struct _source_data *data) window = gtk_widget_get_toplevel (widget); gtk_widget_set_sensitive (window, FALSE); - + +#if 0 /* EPFIXME */ evolution_shell_client_user_select_folder (global_shell_client, GTK_WINDOW (window), _("Select Folder"), "", allowed_types, &folder); +#else + folder = NULL; +#endif gtk_widget_set_sensitive (window, TRUE); diff --git a/help/C/.cvsignore b/help/C/.cvsignore index 282522db03..c35e90b546 100644 --- a/help/C/.cvsignore +++ b/help/C/.cvsignore @@ -1,2 +1,4 @@ Makefile Makefile.in +evolution-*-C.omf.out +omf_timestamp diff --git a/help/es/apx-authors.sgml b/help/es/apx-authors.sgml index a1069ee6cb..eeda6754fe 100644 --- a/help/es/apx-authors.sgml +++ b/help/es/apx-authors.sgml @@ -1,6 +1,6 @@ - + diff --git a/help/es/apx-bugs.sgml b/help/es/apx-bugs.sgml index 7062bd442e..d0fc39ef65 100644 --- a/help/es/apx-bugs.sgml +++ b/help/es/apx-bugs.sgml @@ -1,6 +1,6 @@ - + diff --git a/help/es/apx-fdl.sgml b/help/es/apx-fdl.sgml index b7dcfe14a9..46814a06cb 100644 --- a/help/es/apx-fdl.sgml +++ b/help/es/apx-fdl.sgml @@ -1,4 +1,4 @@ - + + diff --git a/help/es/apx-gpl.sgml b/help/es/apx-gpl.sgml index e824478de7..bec3c1dbcf 100644 --- a/help/es/apx-gpl.sgml +++ b/help/es/apx-gpl.sgml @@ -1,4 +1,4 @@ - + diff --git a/help/es/config-prefs.sgml b/help/es/config-prefs.sgml index 76bb8c3426..051a3a63b6 100644 --- a/help/es/config-prefs.sgml +++ b/help/es/config-prefs.sgml @@ -1,5 +1,5 @@ - + diff --git a/help/es/config-sync.sgml b/help/es/config-sync.sgml index 59304b2ba2..21ccde614f 100644 --- a/help/es/config-sync.sgml +++ b/help/es/config-sync.sgml @@ -1,4 +1,4 @@ - + diff --git a/help/es/evolution.sgml b/help/es/evolution.sgml index 8e6253924c..382134c0df 100644 --- a/help/es/evolution.sgml +++ b/help/es/evolution.sgml @@ -1,6 +1,6 @@ - + diff --git a/help/es/menuref.sgml b/help/es/menuref.sgml index 1964887159..5d372fed2b 100644 --- a/help/es/menuref.sgml +++ b/help/es/menuref.sgml @@ -1,6 +1,6 @@ - + diff --git a/help/es/preface.sgml b/help/es/preface.sgml index fbb958d346..585a058581 100644 --- a/help/es/preface.sgml +++ b/help/es/preface.sgml @@ -1,6 +1,6 @@ - + diff --git a/help/es/usage-calendar.sgml b/help/es/usage-calendar.sgml index c1680973f0..72a772e65b 100644 --- a/help/es/usage-calendar.sgml +++ b/help/es/usage-calendar.sgml @@ -1,6 +1,6 @@ - + diff --git a/help/es/usage-contact.sgml b/help/es/usage-contact.sgml index 014323bc0a..c54d9f57c0 100644 --- a/help/es/usage-contact.sgml +++ b/help/es/usage-contact.sgml @@ -1,4 +1,4 @@ - + diff --git a/help/es/usage-exchange.sgml b/help/es/usage-exchange.sgml index 79fd24eb1e..ac92bbf93f 100644 --- a/help/es/usage-exchange.sgml +++ b/help/es/usage-exchange.sgml @@ -1,4 +1,4 @@ - + diff --git a/help/es/usage-exec-summary.sgml b/help/es/usage-exec-summary.sgml index 390b4da695..1aa771dd5e 100644 --- a/help/es/usage-exec-summary.sgml +++ b/help/es/usage-exec-summary.sgml @@ -1,6 +1,6 @@ - + diff --git a/help/es/usage-mail-org.sgml b/help/es/usage-mail-org.sgml index 9072eab5e4..55d5b078d0 100644 --- a/help/es/usage-mail-org.sgml +++ b/help/es/usage-mail-org.sgml @@ -1,4 +1,4 @@ - + diff --git a/help/es/usage-mail.sgml b/help/es/usage-mail.sgml index f4ec2068b3..7ad36e4eee 100644 --- a/help/es/usage-mail.sgml +++ b/help/es/usage-mail.sgml @@ -1,4 +1,4 @@ - + diff --git a/help/es/usage-mainwindow.sgml b/help/es/usage-mainwindow.sgml index d7bf49819c..35b582632c 100644 --- a/help/es/usage-mainwindow.sgml +++ b/help/es/usage-mainwindow.sgml @@ -1,6 +1,6 @@ - + diff --git a/help/es/usage-print.sgml b/help/es/usage-print.sgml index 8c6b04e35d..28e67b9551 100644 --- a/help/es/usage-print.sgml +++ b/help/es/usage-print.sgml @@ -1,4 +1,4 @@ - + diff --git a/help/es/usage-sync.sgml b/help/es/usage-sync.sgml index 50c01ca875..de9da3dbcc 100644 --- a/help/es/usage-sync.sgml +++ b/help/es/usage-sync.sgml @@ -1,4 +1,4 @@ - + diff --git a/libical/ChangeLog b/libical/ChangeLog index c6d5919adc..d8655dd243 100644 --- a/libical/ChangeLog +++ b/libical/ChangeLog @@ -1,3 +1,9 @@ +2003-10-15 Rodrigo Moya + + * src/libicalss/icalssyacc.y: re-added missing header. + + * src/libical/ical.h: added from HEAD. + 2003-10-09 Jeffrey Stedfast * src/libical/Makefile.am: Fixed INCLUDES and don't autogenerate -- cgit