diff options
Diffstat (limited to 'calendar')
44 files changed, 5420 insertions, 4926 deletions
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 <bonobo-activation/bonobo-activation.h> #include <bonobo/bonobo-control.h> #include <bonobo/bonobo-widget.h> -#include <ebook/e-destination.h> #include <e-util/e-time-utils.h> #include <cal-util/timeutil.h> #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 <e-util/e-dialog-utils.h> #include <evolution-shell-component-utils.h> #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 <cal-client/cal-client.h> #include <cal-util/cal-component.h> -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 <glade/glade.h> #include <gal/util/e-util.h> #include <widgets/misc/e-map.h> -#include <ebook/e-destination.h> +#include <addressbook/util/eab-destination.h> #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 <glade/glade.h> #include <libgnomeui/gnome-stock-icons.h> #include <gal/util/e-util.h> +#include <gal/e-table/e-table.h> #include <gal/widgets/e-unicode.h> #include <gal/widgets/e-popup-menu.h> #include <gal/widgets/e-gui-utils.h> @@ -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 @@ +<ETableSpecification click-to-add="true" click-to-add-end="true" _click-to-add-message="Click here to add an attendee" draw-grid="true"> + <ETableColumn model_col= "0" _title="Attendee" expansion="2.0" minimum_width="10" resizable="true" cell="string" compare="string"/> + <ETableColumn model_col= "1" _title="Member" expansion="2.0" minimum_width="10" resizable="true" cell="string" compare="string"/> + <ETableColumn model_col= "2" _title="Type" expansion="1.0" minimum_width="10" resizable="true" cell="typeedit" compare="string"/> + <ETableColumn model_col= "3" _title="Role" expansion="1.0" minimum_width="10" resizable="true" cell="roleedit" compare="string"/> + <ETableColumn model_col= "4" _title="RSVP" expansion="1.0" minimum_width="10" resizable="true" cell="rsvpedit" compare="string"/> + <ETableColumn model_col= "5" _title="Delegated To" expansion="2.0" minimum_width="10" resizable="true" cell="string" compare="string"/> + <ETableColumn model_col= "6" _title="Delegated From" expansion="2.0" minimum_width="10" resizable="true" cell="string" compare="string"/> + <ETableColumn model_col= "7" _title="Status" expansion="1.0" minimum_width="10" resizable="true" cell="statusedit" compare="string"/> + <ETableColumn model_col= "8" _title="Common Name" expansion="2.0" minimum_width="10" resizable="true" cell="string" compare="string"/> + <ETableColumn model_col= "9" _title="Language" expansion="2.0" minimum_width="10" resizable="true" cell="string" compare="string"/> + + <ETableState> + <column source="0"/> + <column source="2"/> + <column source="3"/> + <column source="4"/> + <column source="7"/> + <grouping></grouping> + </ETableState> +</ETableSpecification> 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 <jpr@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <bonobo/bonobo-i18n.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkentry.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtkmessagedialog.h> +#include <gtk/gtkoptionmenu.h> +#include <glade/glade.h> +#include <e-util/e-dialog-utils.h> +#include <e-util/e-source-list.h> +#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 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> +<requires lib="gnome"/> + +<widget class="GtkDialog" id="new-calendar-dialog"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="title" translatable="yes">Add New Calendar</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER</property> + <property name="modal">False</property> + <property name="resizable">False</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="cancelbutton1"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="okbutton1"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="label" translatable="yes">Calendar Group</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_padding">6</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="label" translatable="yes">Calendar Name</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_padding">6</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkOptionMenu" id="calendar-group"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">-1</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_padding">6</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="calendar-name"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_padding">6</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Calendar options</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_padding">6</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/calendar/pcs/job.h b/calendar/gui/dialogs/new-calendar.h index 07e3371f89..9890f9e1f8 100644 --- a/calendar/pcs/job.h +++ b/calendar/gui/dialogs/new-calendar.h @@ -1,9 +1,8 @@ -/* GNOME personal calendar server - job manager +/* Evolution calendar - Send calendar component dialog * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2001 Ximian, Inc. * - * Author: Federico Mena-Quintero <federico@ximian.com> + * Author: JP Rosevear <jpr@ximian.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -19,17 +18,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef JOB_H -#define JOB_H +#ifndef NEW_CALENDAR_H +#define NEW_CALENDAR_H -#include <glib.h> +#include <gtk/gtkwindow.h> - - -typedef void (* JobFunc) (gpointer data); - -void job_add (JobFunc func, gpointer data); - - +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<CalObj> CalObjSeq; + typedef sequence<string> 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<string> 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<CalObjChange> 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<CalAlarmInstance> CalAlarmInstanceSeq; - - /* Alarms for a component */ - struct CalComponentAlarms { - CalObj calobj; - CalAlarmInstanceSeq alarms; - }; - - /* Used to represent a list of components plus their triggers */ - typedef sequence<CalComponentAlarms> CalComponentAlarmsSeq; - /* Used to represent users and lists of users */ typedef string User; typedef sequence<User> 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 <federico@ximian.com> + * Rodrigo Moya <rodrigo@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include <string.h> +#include <unistd.h> +#include <bonobo/bonobo-exception.h> +#include <bonobo/bonobo-moniker-util.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs.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-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 <federico@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef 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 <federico@ximian.com> + * Rodrigo Moya <rodrigo@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <libgnome/gnome-i18n.h> +#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 <federico@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef 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 <federico@ximian.com> * Rodrigo Moya <rodrigo@ximian.com> @@ -27,38 +26,41 @@ #include <bonobo/bonobo-moniker-util.h> #include <libgnome/gnome-i18n.h> #include <libgnomevfs/gnome-vfs.h> -#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 const char * -cal_backend_file_get_static_capabilities (CalBackend *backend) +static CalBackendSyncStatus +cal_backend_file_get_static_capabilities (CalBackendSync *backend, Cal *cal, char **capabilities) { - return CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS; + *capabilities = CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS; + + 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); } /* 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) +static CalBackendSyncStatus +cal_backend_file_get_default_object (CalBackendSync *backend, Cal *cal, char **object) { - 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) -{ - 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, NULL); - g_assert (priv->comp_uid_hash != NULL); + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); + g_return_val_if_fail (tzid != NULL, GNOME_Evolution_Calendar_ObjectNotFound); - 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; -} - -/* Builds a list of UIDs from a list of CalComponent objects */ -static void -build_uids_list (GList **list, GList *components) -{ - GList *l; - - for (l = components; l; l = l->next) { - CalComponent *comp; - const char *uid; + *object = g_strdup (icalcomponent_as_ical_string (icalcomp)); - comp = CAL_COMPONENT (l->data); - cal_component_get_uid (comp, &uid); - *list = g_list_prepend (*list, g_strdup (uid)); - } + return GNOME_Evolution_Calendar_Success; } -/* Get_uids handler for the file backend */ -static GList * -cal_backend_file_get_uids (CalBackend *backend, CalObjType type) +/* Add_timezone handler for the file backend */ +static CalBackendSyncStatus +cal_backend_file_add_timezone (CalBackendSync *backend, Cal *cal, const char *tzobj) { + icalcomponent *tz_comp; CalBackendFile *cbfile; CalBackendFilePrivate *priv; - GList *list; - cbfile = CAL_BACKEND_FILE (backend); - priv = cbfile->priv; - - g_return_val_if_fail (priv->icalcomp != NULL, NULL); + cbfile = (CalBackendFile *) backend; - list = NULL; + 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); - if (type & CALOBJ_TYPE_EVENT) - build_uids_list (&list, priv->events); - - if (type & CALOBJ_TYPE_TODO) - build_uids_list (&list, priv->todos); + priv = cbfile->priv; - if (type & CALOBJ_TYPE_JOURNAL) - build_uids_list (&list, priv->journals); + tz_comp = icalparser_parse_string (tzobj); + if (!tz_comp) + return GNOME_Evolution_Calendar_InvalidObject; - return list; -} + if (icalcomponent_isa (tz_comp) == ICAL_VTIMEZONE_COMPONENT) { + icaltimezone *zone; -/* function to resolve timezones */ -static icaltimezone * -resolve_tzid (const char *tzid, gpointer user_data) -{ - icalcomponent *vcalendar_comp = user_data; + 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); + } - if (!tzid || !tzid[0]) - return NULL; - else if (!strcmp (tzid, "UTC")) - return icaltimezone_get_utc_timezone (); + icaltimezone_free (zone, 1); + } - return icalcomponent_get_timezone (vcalendar_comp, tzid); + return GNOME_Evolution_Calendar_Success; } -/* 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 CalBackendSyncStatus +cal_backend_file_set_default_timezone (CalBackendSync *backend, Cal *cal, const char *tzid) { - GHashTable *uid_hash; - const char *uid; - const char *old_uid; + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; + icaltimezone *zone; - uid_hash = data; + cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; - /* 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). - */ + g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal); - cal_component_get_uid (comp, &uid); + /* Look up the VTIMEZONE in our icalcomponent. */ + zone = icalcomponent_get_timezone (priv->icalcomp, tzid); + if (!zone) + return GNOME_Evolution_Calendar_ObjectNotFound; - old_uid = g_hash_table_lookup (uid_hash, uid); - if (old_uid) - return FALSE; + /* Set the default timezone to it. */ + priv->default_zone = zone; - g_hash_table_insert (uid_hash, (char *) uid, NULL); - return FALSE; + return GNOME_Evolution_Calendar_Success; } -/* Populates a hash table with the UIDs of the components that occur or recur - * within a specific time range. - */ +typedef struct { + GList *obj_list; + gboolean search_needed; + const char *query; + CalBackendObjectSExp *obj_sexp; + CalBackend *backend; + icaltimezone *default_zone; +} MatchObjectData; + static void -get_instances_in_range (GHashTable *uid_hash, GList *components, time_t start, time_t end, icaltimezone *default_zone) +match_object_sexp (gpointer key, gpointer value, gpointer data) { - GList *l; - - for (l = components; l; l = l->next) { - CalComponent *comp; - icalcomponent *icalcomp, *vcalendar_comp; - - comp = CAL_COMPONENT (l->data); + CalBackendFileObject *obj_data = value; + MatchObjectData *match_data = data; - /* 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); - - cal_recur_generate_instances (comp, start, end, add_instance, uid_hash, resolve_tzid, vcalendar_comp, default_zone); + 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)); } } -/* 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) +/* 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 **list; - const char *uid; - char *uid_copy; + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; + MatchObjectData match_data; + + cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; - list = data; + g_message (G_STRLOC ": Getting object list (%s)", sexp); - uid = key; - uid_copy = g_strdup (uid); + 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; - *list = g_list_prepend (*list, uid_copy); + if (!strcmp (sexp, "#t")) + match_data.search_needed = FALSE; + + match_data.obj_sexp = cal_backend_object_sexp_new (sexp); + if (!match_data.obj_sexp) + return GNOME_Evolution_Calendar_InvalidQuery; + + g_hash_table_foreach (priv->comp_uid_hash, (GHFunc) match_object_sexp, &match_data); + + *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; + + 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); +} - return cal_backend_file_compute_changes (backend, type, change_id); +/* 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 */ + 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 = 0; - comp_alarms = NULL; - - 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; - 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); + /* 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; + } - comp = lookup_component (cbfile, uid); - if (!comp) { - *object_found = FALSE; - return NULL; + /* Get the uid */ + comp_uid = icalcomponent_get_uid (icalcomp); + + /* 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); + + /* FIXME we need to handle mod types here */ - comp_str = cal_component_get_as_string (comp); - corba_alarms = GNOME_Evolution_Calendar_CalComponentAlarms__alloc (); + /* Remove the old version */ + remove_component (cbfile, old_comp); - corba_alarms->calobj = CORBA_string_dup (comp_str); - g_free (comp_str); + /* Add the object */ + add_component (cbfile, comp, TRUE); - 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); + mark_dirty (cbfile); - return corba_alarms; -} + if (old_object) + *old_object = cal_component_get_as_string (comp); -/* 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; + 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; + + *object = cal_component_get_as_string (comp); + remove_component (cbfile, comp); + + mark_dirty (cbfile); - return comp_uid; + 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 <string.h> +#include <libgnome/gnome-i18n.h> +#include <e-util/e-sexp.h> +#include <gal/widgets/e-unicode.h> +#include <cal-util/timeutil.h> + +#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;i<sizeof(symbols)/sizeof(symbols[0]);i++) { + if (symbols[i].type == 1) { + e_sexp_add_ifunction(sexp->priv->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 <clahey@ximian.com> + * + * 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 <glib.h> +#include <glib-object.h> +#include <pcs/cal-backend.h> +#include <cal-util/cal-component.h> + +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 <config.h> +#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 <glib.h> +#include <pcs/cal-backend.h> +#include <pcs/evolution-calendar.h> + +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 @@ -29,13 +29,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 <e-util/e-list.h> #include <cal-util/cal-util.h> #include <cal-util/cal-component.h> #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 <federico@ximian.com> + * Authors: + * Federico Mena-Quintero <federico@ximian.com> + * JP Rosevear <jpr@ximian.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -19,16 +20,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ -#include <config.h> -#include <ctype.h> -#include <stdio.h> #include <bonobo-activation/bonobo-activation.h> +#include <bonobo/bonobo-exception.h> +#include <bonobo/bonobo-main.h> #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 <bonobo/bonobo-object.h> +#include <libical/ical.h> #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 <libical/ical.h> +#include <bonobo/bonobo-main.h> #include <bonobo/bonobo-exception.h> -#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); + + cal_notify_query (cal, GNOME_Evolution_Calendar_Success, query); - return query_copy; + 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); +} - if (calobj) { - CORBA_char *calobj_copy; +/* Cal::setDefaultTimezone method */ +static void +impl_Cal_setDefaultTimezone (PortableServer_Servant servant, + const CORBA_char *tzid, + CORBA_Environment *ev) +{ + Cal *cal; + CalPrivate *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 = CAL (bonobo_object_from_servant (servant)); + priv = cal->priv; + + 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,50 @@ 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_read_only (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, gboolean read_only) +{ + 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_notifyReadOnly (priv->listener, status, read_only, &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of read only"); + + CORBA_exception_free (&ev); +} + +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)); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyCalAddress (priv->listener, status, address ? address : "", &ev); + + if (BONOBO_EX (&ev)) + g_message (G_STRLOC ": could not notify the listener of cal address"); + + CORBA_exception_free (&ev); +} + void -cal_notify_mode (Cal *cal, - GNOME_Evolution_Calendar_Listener_SetModeStatus status, - GNOME_Evolution_Calendar_CalMode mode) +cal_notify_alarm_email_address (Cal *cal, GNOME_Evolution_Calendar_CallStatus status, const char *address) { CalPrivate *priv; CORBA_Environment ev; @@ -905,75 +671,606 @@ 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_notifyAlarmEmailAddress (priv->listener, status, address ? address : "", &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 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); } -/** - * 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) +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)); - 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_notifyObjectsSent (priv->listener, status, &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 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_remove: + * 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 <bonobo/bonobo-object.h> #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 <federico@ximian.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <config.h> -#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/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 <rodrigo@ximian.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <glib.h> -#include <libgnome/gnome-i18n.h> -#include <cal-util/cal-component.h> -#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 <rodrigo@ximian.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef 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 <gal/widgets/e-unicode.h> #include <e-util/e-component-listener.h> #include <e-util/e-sexp.h> +#include <pcs/cal-backend-object-sexp.h> #include <cal-util/cal-recur.h> #include <cal-util/timeutil.h> #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; - - object_class = (GObjectClass *) class; - - parent_class = g_type_class_peek_parent (class); - - object_class->finalize = query_finalize; +/* Property IDs */ +enum props { + PROP_0, + PROP_BACKEND, + PROP_LISTENER, + PROP_SEXP +}; - /* The Query interface (ha ha! query interface!) has no methods, so we - * don't need to fiddle with the epv. - */ -} -/* Object initialization function for the live search query */ static void -query_init (Query *query, QueryClass *class) +listener_died_cb (EComponentListener *cl, gpointer data) { + Query *query = QUERY (data); 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); - - priv->next_comp = NULL; -} - -/* Used from g_hash_table_foreach(); frees a UID */ -static void -free_uid_cb (gpointer key, gpointer value, gpointer data) -{ - char *uid; + priv = query->priv; - uid = key; - g_free (uid); + g_object_unref (priv->component_listener); + priv->component_listener = NULL; + + bonobo_object_release_unref (priv->listener, NULL); + priv->listener = NULL; } -/* Finalize handler for the live search query */ static void -query_finalize (GObject *object) +impl_Query_start (PortableServer_Servant servant, CORBA_Environment *ev) { Query *query; QueryPrivate *priv; - g_return_if_fail (object != NULL); - g_return_if_fail (IS_QUERY (object)); - - query = QUERY (object); + query = QUERY (bonobo_object_from_servant (servant)); 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; - } - - 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"); - } - - CORBA_exception_free (&ev); - - g_list_free (priv->listeners); - priv->listeners = NULL; - } - - 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; - } - - if (priv->sexp) { - g_free (priv->sexp); - priv->sexp = NULL; - } - - if (priv->esexp) { - e_sexp_unref (priv->esexp); - priv->esexp = NULL; - } - - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } - - if (priv->cached_timeouts) { - GList *l; - - for (l = priv->cached_timeouts; l != NULL; l = l->next) - g_source_remove (GPOINTER_TO_INT (l->data)); - - g_list_free (priv->cached_timeouts); - priv->cached_timeouts = NULL; - } - - if (priv->pending_uids) { - GList *l; - - for (l = priv->pending_uids; l; l = l->next) { - char *uid; - - uid = l->data; - g_assert (uid != NULL); - g_free (uid); - } - - g_list_free (priv->pending_uids); - priv->pending_uids = NULL; - priv->n_pending = 0; - } - - g_hash_table_foreach (priv->uids, free_uid_cb, NULL); - g_hash_table_destroy (priv->uids); - priv->uids = NULL; - - 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) -{ - 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; + cal_backend_start_query (priv->backend, query); } -/* (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) +static void +query_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { Query *query; QueryPrivate *priv; - CalComponent *comp; - CalComponentVType vtype; - char *str; - ESExpResult *result; + CORBA_Environment ev; - query = QUERY (data); + query = QUERY (object); priv = query->priv; - - 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 */ - - vtype = cal_component_get_vtype (comp); - - switch (vtype) { - case CAL_COMPONENT_EVENT: - str = g_strdup ("VEVENT"); - break; - - case CAL_COMPONENT_TODO: - str = g_strdup ("VTODO"); + + 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); - case CAL_COMPONENT_JOURNAL: - str = g_strdup ("VJOURNAL"); + 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 CAL_COMPONENT_FREEBUSY: - str = g_strdup ("VFREEBUSY"); + case PROP_SEXP: + priv->sexp = CAL_BACKEND_OBJECT_SEXP (g_value_dup_object (value)); break; - - case CAL_COMPONENT_TIMEZONE: - str = g_strdup ("VTIMEZONE"); - break; - default: - str = g_strdup ("UNKNOWN"); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } - - result = e_sexp_result_new (esexp, ESEXP_RES_STRING); - result->value.string = str; - - return result; } -/* 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) -{ - gboolean *occurs; - - occurs = data; - *occurs = TRUE; - - return FALSE; -} - -/* Call the backend function to get a timezone from a TZID. */ -static icaltimezone* -resolve_tzid (const char *tzid, gpointer data) -{ - Query *query = data; - - if (!tzid || !tzid[0]) - return NULL; - else - return cal_backend_get_timezone (query->priv->backend, tzid); -} - - -/* (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) +static void +query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { Query *query; QueryPrivate *priv; - CalComponent *comp; - time_t start, end; - gboolean occurs; - ESExpResult *result; - - query = QUERY (data); + + query = QUERY (object); priv = query->priv; - 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; - - 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 there is at least one instance in that range */ - - occurs = FALSE; - - cal_recur_generate_instances (comp, start, end, - instance_occur_cb, &occurs, - resolve_tzid, query, priv->default_zone); - - 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; - } + 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; } - - 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) +/* Class initialization function for the live search query */ +static void +query_class_init (QueryClass *klass) { - CalComponentText text; + GObjectClass *object_class; + POA_GNOME_Evolution_Calendar_Query__epv *epv = &klass->epv; + GParamSpec *param; + + object_class = (GObjectClass *) klass; - cal_component_get_summary (comp, &text); + parent_class = g_type_class_peek_parent (klass); - if (!text.value) - return FALSE; + object_class->set_property = query_set_property; + object_class->get_property = query_get_property; + object_class->finalize = query_finalize; - return e_utf8_strstrcasedecomp (text.value, str) != NULL; -} + epv->start = impl_Query_start; -/* 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)); + 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); } -/* (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) +/* Object initialization function for the live search query */ +static void +query_init (Query *query, QueryClass *class) { - 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; + priv = g_new0 (QueryPrivate, 1); + query->priv = priv; - return result; + priv->backend = NULL; + priv->listener = NULL; + priv->component_listener = NULL; + priv->sexp = NULL; } -/* (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) +/* Finalize handler for the live search query */ +static void +query_finalize (GObject *object) { 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; + g_return_if_fail (object != NULL); + g_return_if_fail (IS_QUERY (object)); - for (l = categories; l; l = l->next) { - const char *category; + query = QUERY (object); + priv = query->priv; - category = l->data; + if (priv->backend) + g_object_unref (priv->backend); - if (strcmp (category, sought) == 0) { - has_category = TRUE; - break; - } - } + if (priv->listener != NULL) + bonobo_object_release_unref (priv->listener, NULL); - if (!has_category) { - matches = FALSE; - break; - } - } + if (priv->component_listener != NULL) + g_object_unref (priv->component_listener); - cal_component_free_categories_list (categories); + if (priv->sexp) + g_object_unref (priv->sexp); - result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); - result->value.bool = matches; + g_free (priv); - return result; + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } -/* (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_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) { 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; + query = g_object_new (QUERY_TYPE, "backend", backend, "listener", ql, + "sexp", sexp, NULL); - return result; + return query; } -/* (completed-before? TIME) +/** + * query_get_sexp + * @query: A #Query object. * - * TIME - time_t + * Get the expression used for the given query. * - * 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. + * Returns: the query expression used to search. */ -static ESExpResult * -func_completed_before (ESExp *esexp, int argc, ESExpResult **argv, void *data) +const char * +query_get_text (Query *query) { - 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); - } + g_return_val_if_fail (IS_QUERY (query), NULL); - CORBA_exception_free (&ev); + return cal_backend_object_sexp_text (query->priv->sexp); } -/* Removes a component from our the UIDs hash table and notifies the client */ -static void -remove_component (Query *query, const char *uid) +CalBackendObjectSExp * +query_get_object_sexp (Query *query) { - 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"); - } + g_return_val_if_fail (IS_QUERY (query), NULL); - CORBA_exception_free (&ev); + return query->priv->sexp; } -/* Removes a component from the list of pending UIDs */ -static void -remove_from_pending (Query *query, const char *remove_uid) +gboolean +query_object_matches (Query *query, const char *object) { QueryPrivate *priv; - GList *l; + + 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); 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; + + return cal_backend_object_sexp_match_object (priv->sexp, object, priv->backend); } -/* 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) +void +query_notify_objects_added (Query *query, const GList *objects) { 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)); priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); - /* 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 */ + 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; - error_str = e_sexp_error (priv->esexp); - g_assert (error_str != NULL); + for (l = objects, i = 0; l; l = l->next, i++) + obj_list._buffer[i] = CORBA_string_dup (l->data); - 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); + GNOME_Evolution_Calendar_QueryListener_notifyObjectsAdded (priv->listener, &obj_list, &ev); - e_sexp_unref (priv->esexp); - priv->esexp = NULL; + CORBA_free (obj_list._buffer); - /* 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; - } + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of object addition"); - return TRUE; + CORBA_exception_free (&ev); } -/* 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) +void +query_notify_objects_added_1 (Query *query, const char *object) { QueryPrivate *priv; - CalComponent *comp; - ESExpResult *result; + GList objects; + + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); - 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 */ + objects.next = objects.prev = NULL; + objects.data = (gpointer)object; - 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); + query_notify_objects_added (query, &objects); } -/* Processes all components that are queued in the list */ -static gboolean -process_components_cb (gpointer data) +void +query_notify_objects_modified (Query *query, const GList *objects) { - Query *query; QueryPrivate *priv; - char *uid; - GList *l; + 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)); - query = QUERY (data); priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); - 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); + 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; - /* run the main loop, for not blocking */ - if (gtk_events_pending ()) - gtk_main_iteration (); - } + for (l = objects, i = 0; l; l = l->next, i++) + obj_list._buffer[i] = CORBA_string_dup (l->data); - bonobo_object_unref (BONOBO_OBJECT (query)); - if (!priv || !priv->listeners) - return FALSE; + GNOME_Evolution_Calendar_QueryListener_notifyObjectsModified (priv->listener, &obj_list, &ev); - /* notify listeners that the query ended */ - priv->state = QUERY_DONE; + CORBA_free (obj_list._buffer); - 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"); - } + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of object modification"); 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) +void +query_notify_objects_modified_1 (Query *query, const char *object) { - Query *query; QueryPrivate *priv; + 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->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)); + objects.next = objects.prev = NULL; + objects.data = (gpointer)object; + + query_notify_objects_modified (query, &objects); } -/* Callback used when a component is removed from the backend */ -static void -backend_obj_removed_cb (CalBackend *backend, const char *uid, gpointer data) +void +query_notify_objects_removed (Query *query, const GList *uids) { - Query *query; QueryPrivate *priv; + 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->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; + 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; - priv = query->priv; + for (l = uids, i = 0; l; l = l->next, i ++) + uid_list._buffer[i] = CORBA_string_dup (l->data); - if (!parse_sexp (query)) - return; + GNOME_Evolution_Calendar_QueryListener_notifyObjectsRemoved (priv->listener, &uid_list, &ev); - /* Populate the query with UIDs so that we can process them asynchronously */ + CORBA_free (uid_list._buffer); - 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; + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of object removal"); - 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); + CORBA_exception_free (&ev); } -/* Idle handler for starting a query */ -static gboolean -start_query_cb (gpointer data) +void +query_notify_objects_removed_1 (Query *query, const char *uid) { - Query *query; QueryPrivate *priv; + GList uids; + + 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_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; + uids.next = uids.prev = NULL; + uids.data = (gpointer)uid; + + query_notify_objects_modified (query, &uids); } -static void -listener_died_cb (EComponentListener *cl, gpointer data) +void +query_notify_query_progress (Query *query, const char *message, int percent) { - QueryPrivate *priv; - Query *query = QUERY (data); - GNOME_Evolution_Calendar_QueryListener ql; + QueryPrivate *priv; 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); + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); + priv = query->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + CORBA_exception_init (&ev); - bonobo_object_release_unref (ql, &ev); + + GNOME_Evolution_Calendar_QueryListener_notifyQueryProgress (priv->listener, message, percent, &ev); if (BONOBO_EX (&ev)) - g_message ("query_destroy(): Could not unref the listener\n"); + g_warning (G_STRLOC ": could not notify the listener of query progress"); 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) +void +query_notify_query_done (Query *query, GNOME_Evolution_Calendar_CallStatus status) { - QueryPrivate *priv; + 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); + g_return_if_fail (query != NULL); + g_return_if_fail (IS_QUERY (query)); priv = query->priv; - + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + 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; + GNOME_Evolution_Calendar_QueryListener_notifyQueryDone (priv->listener, status, &ev); - 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); + if (BONOBO_EX (&ev)) + g_warning (G_STRLOC ": could not notify the listener of query completion"); - return query; + CORBA_exception_free (&ev); } 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 <bonobo/bonobo-object.h> #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 |