/* Evolution calendar client * * Copyright (C) 2001 Ximian, Inc. * * Author: Rodrigo Moya * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include "cal-client-multi.h" /* Private part of the CalClientMulti structure */ struct _CalClientMultiPrivate { GHashTable *calendars; GList *uris; }; static void cal_client_multi_class_init (CalClientMultiClass *klass); static void cal_client_multi_init (CalClientMulti *multi); static void cal_client_multi_destroy (GtkObject *object); /* signal IDs */ enum { CAL_OPENED, OBJ_UPDATED, OBJ_REMOVED, CATEGORIES_CHANGED, FORGET_PASSWORD, LAST_SIGNAL }; static guint cal_multi_signals[LAST_SIGNAL]; static GtkObjectClass *parent_class = NULL; /* * Private functions */ /** * cal_client_multi_get_type * * Registers the #CalClientMulti class if necessary, and returns the type ID * assigned to it. * * Returns: The type ID of the #CalClientMulti class */ GtkType cal_client_multi_get_type (void) { static GtkType type = 0; if (!type) { static const GtkTypeInfo info = { "CalClientMulti", sizeof (CalClientMulti), sizeof (CalClientMultiClass), (GtkClassInitFunc) cal_client_multi_class_init, (GtkObjectInitFunc) cal_client_multi_init, NULL, NULL, (GtkClassInitFunc) NULL }; type = gtk_type_unique (GTK_TYPE_OBJECT, &info); } return type; } /* class initialization function for the multi calendar client */ static void cal_client_multi_class_init (CalClientMultiClass *klass) { GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); parent_class = gtk_type_class (GTK_TYPE_OBJECT); cal_multi_signals[CAL_OPENED] = gtk_signal_new ("cal_opened", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (CalClientMultiClass, cal_opened), gtk_marshal_NONE__POINTER_INT, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_ENUM); cal_multi_signals[OBJ_UPDATED] = gtk_signal_new ("obj_updated", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (CalClientMultiClass, obj_updated), gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_STRING); cal_multi_signals[OBJ_REMOVED] = gtk_signal_new ("obj_removed", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (CalClientMultiClass, obj_removed), gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_STRING); cal_multi_signals[CATEGORIES_CHANGED] = gtk_signal_new ("categories_changed", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (CalClientMultiClass, categories_changed), gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_POINTER); cal_multi_signals[FORGET_PASSWORD] = gtk_signal_new ("forget_password", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (CalClientMultiClass, forget_password), gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_STRING, GTK_TYPE_STRING); object_class->destroy = cal_client_multi_destroy; } /* object initialization function for the multi calendar client */ static void cal_client_multi_init (CalClientMulti *multi) { multi->priv = g_new0 (CalClientMultiPrivate, 1); multi->priv->calendars = g_hash_table_new (g_str_hash, g_str_equal); multi->priv->uris = NULL; } static void free_calendar (gpointer key, gpointer value, gpointer data) { CalClientMulti *multi = (CalClientMulti *) data; g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); multi->priv->uris = g_list_remove (multi->priv->uris, key); g_free (key); gtk_object_unref (GTK_OBJECT (value)); } /* destroy handler for the multi calendar client */ static void cal_client_multi_destroy (GtkObject *object) { CalClientMulti *multi = (CalClientMulti *) object; g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); /* free memory */ g_hash_table_foreach (multi->priv->calendars, free_calendar, multi); g_hash_table_destroy (multi->priv->calendars); g_list_free (multi->priv->uris); g_free (multi->priv); multi->priv = NULL; /* chain to parent class' destroy handler */ if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } /** * cal_client_multi_new * * Creates a new multi-calendar client. This allows you to merge several * #CalClient objects into one entity, making it easier to manage * multiple calendars. * * Returns: A newly-created multi-calendar client. */ CalClientMulti * cal_client_multi_new (void) { CalClientMulti *multi; multi = gtk_type_new (CAL_CLIENT_MULTI_TYPE); return multi; } /* CalClient's signal handlers */ static void client_cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer user_data) { CalClientMulti *multi = (CalClientMulti *) user_data; g_return_if_fail (IS_CAL_CLIENT (client)); g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); gtk_signal_emit (GTK_OBJECT (multi), cal_multi_signals[CAL_OPENED], client, status); } static void client_obj_updated_cb (CalClient *client, const char *uid, gpointer user_data) { CalClientMulti *multi = (CalClientMulti *) user_data; g_return_if_fail (IS_CAL_CLIENT (client)); g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); gtk_signal_emit (GTK_OBJECT (multi), cal_multi_signals[OBJ_UPDATED], client, uid); } static void client_obj_removed_cb (CalClient *client, const char *uid, gpointer user_data) { CalClientMulti *multi = (CalClientMulti *) user_data; g_return_if_fail (IS_CAL_CLIENT (client)); g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); gtk_signal_emit (GTK_OBJECT (multi), cal_multi_signals[OBJ_REMOVED], client, uid); } static void client_categories_changed_cb (CalClient *client, GPtrArray *categories, gpointer user_data) { CalClientMulti *multi = (CalClientMulti *) user_data; g_return_if_fail (IS_CAL_CLIENT (client)); g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); gtk_signal_emit (GTK_OBJECT (multi), cal_multi_signals[CATEGORIES_CHANGED], client, categories); } static void client_forget_password_cb (CalClient *client, const char *key, gpointer user_data) { CalClientMulti *multi = (CalClientMulti *) user_data; g_return_if_fail (IS_CAL_CLIENT (client)); g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); gtk_signal_emit (GTK_OBJECT (multi), cal_multi_signals[FORGET_PASSWORD], client, key); } /** * cal_client_multi_add_client * @multi: A #CalClientMulti object. * @client: The #CalClient object to be added. * * Aggregates the given #CalClient to a #CalClientMulti object, * thus adding it to the list of managed calendars. */ void cal_client_multi_add_client (CalClientMulti *multi, CalClient *client) { char *uri; CalClient *old_client; g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); g_return_if_fail (IS_CAL_CLIENT (client)); uri = g_strdup (cal_client_get_uri (client)); old_client = g_hash_table_lookup (multi->priv->calendars, uri); if (old_client) { g_free (uri); return; } gtk_object_ref (GTK_OBJECT (client)); multi->priv->uris = g_list_append (multi->priv->uris, uri); g_hash_table_insert (multi->priv->calendars, uri, client); /* set up CalClient's signal handlers */ gtk_signal_disconnect_by_data (GTK_OBJECT (client), multi); gtk_signal_connect (GTK_OBJECT (client), "cal_opened", GTK_SIGNAL_FUNC (client_cal_opened_cb), multi); gtk_signal_connect (GTK_OBJECT (client), "obj_updated", GTK_SIGNAL_FUNC (client_obj_updated_cb), multi); gtk_signal_connect (GTK_OBJECT (client), "obj_removed", GTK_SIGNAL_FUNC (client_obj_removed_cb), multi); gtk_signal_connect (GTK_OBJECT (client), "categories_changed", GTK_SIGNAL_FUNC (client_categories_changed_cb), multi); gtk_signal_connect (GTK_OBJECT (client), "forget_password", GTK_SIGNAL_FUNC (client_forget_password_cb), multi); } typedef struct { CalClientAuthFunc func; gpointer user_data; } AuthFuncData; static void set_auth_func (gpointer key, gpointer value, gpointer user_data) { AuthFuncData *cb_data = (AuthFuncData *) user_data; CalClient *client = (CalClient *) value; g_return_if_fail (IS_CAL_CLIENT (client)); g_return_if_fail (cb_data != NULL); cal_client_set_auth_func (client, cb_data->func, cb_data->user_data); } /** * cal_client_multi_set_auth_func * @multi: A #CalClientMulti object. * @func: The authentication function. * @user_data: Data to be passed to the authentication function. * * Sets the authentication function for all the clients in the * given #CalClientMulti. */ void cal_client_multi_set_auth_func (CalClientMulti *multi, CalClientAuthFunc func, gpointer user_data) { AuthFuncData *cb_data; g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); cb_data = g_new0 (AuthFuncData, 1); cb_data->func = func; cb_data->user_data = user_data; g_hash_table_foreach (multi->priv->calendars, set_auth_func, cb_data); g_free (cb_data); } /** * cal_client_multi_open_calendar * @multi: A #CalClientMulti object. * @str_uri: The URI of the calendar to be open * @only_if_exists: * * Open a new calendar in the given #CalClientMulti object. * * Returns: a pointer to the new #CalClient */ CalClient * cal_client_multi_open_calendar (CalClientMulti *multi, const char *str_uri, gboolean only_if_exists) { CalClient *client; gboolean result; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), FALSE); client = cal_client_new (); result = cal_client_open_calendar (client, str_uri, only_if_exists); if (result) { cal_client_multi_add_client (multi, client); gtk_object_unref (GTK_OBJECT (client)); return client; } gtk_object_unref (GTK_OBJECT (client)); return NULL; } /** * cal_client_multi_get_client_for_uri * @multi: A #CalClientMulti object. * @uri: The URI for the client. * * Returns the #CalClient object associated with the given * @uri for the given #CalClientMulti object. * * Returns: a pointer to the client or NULL if no client is * associated with that URI. */ CalClient * cal_client_multi_get_client_for_uri (CalClientMulti *multi, const char *uri) { g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), NULL); g_return_val_if_fail (uri != NULL, NULL); return g_hash_table_lookup (multi->priv->calendars, uri); } /** * cal_client_multi_get_n_objects * @multi: A #CalClientMulti object. * @type: Type for objects * * Get the count of objects of the given type(s) for a #CalClientMulti * object. * * Returns: The count of objects of the given type(s). */ int cal_client_multi_get_n_objects (CalClientMulti *multi, CalObjType type) { CalClient *client; GList *l; int count = 0; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), -1); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) count += cal_client_get_n_objects (client, type); } return count; } /** * cal_client_multi_get_object */ CalClientGetStatus cal_client_multi_get_object (CalClientMulti *multi, const char *uid, CalComponent **comp) { CalClient *client; GList *l; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), CAL_CLIENT_GET_NOT_FOUND); g_return_val_if_fail (uid != NULL, CAL_CLIENT_GET_NOT_FOUND); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) { CalClientGetStatus status; status = cal_client_get_object (client, uid, comp); if (status == CAL_CLIENT_GET_SUCCESS) return status; } } return CAL_CLIENT_GET_NOT_FOUND; } /** * cal_client_multi_get_timezone * @multi: A #CalClientMulti object. * @tzid: ID for the timezone to be retrieved. * @zone: A pointer to where the icaltimezone object will be copied. */ CalClientGetStatus cal_client_multi_get_timezone (CalClientMulti *multi, const char *tzid, icaltimezone **zone) { CalClient *client; GList *l; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), CAL_CLIENT_GET_NOT_FOUND); g_return_val_if_fail (tzid != NULL, CAL_CLIENT_GET_NOT_FOUND); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) { CalClientGetStatus status; status = cal_client_get_timezone (client, tzid, zone); if (status == CAL_CLIENT_GET_SUCCESS) return status; } } return CAL_CLIENT_GET_NOT_FOUND; } /** * cal_client_multi_get_uids * @multi: A #CalClientMulti object. * @type: Type of objects whose IDs will be returned. * * Returns a list of UIDs for all the objects of the given * type(s) that are in the calendars managed by a * #CalClientMulti object * * Returns: a GList of UIDs. */ GList * cal_client_multi_get_uids (CalClientMulti *multi, CalObjType type) { CalClient *client; GList *l; GList *result = NULL; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), NULL); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) { GList *tmp; tmp = cal_client_get_uids (client, type); if (tmp) result = g_list_concat (result, tmp); } } return result; } /** * cal_client_multi_get_changes * @multi: A #CalClientMulti object. * @type: Object type. * @change_id: Change ID. * * Returns a list of changes for the given #CalClientMulti * object. */ GList * cal_client_multi_get_changes (CalClientMulti *multi, CalObjType type, const char *change_id) { CalClient *client; GList *l; GList *result = NULL; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), NULL); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) { GList *tmp; tmp = cal_client_get_changes (client, type, change_id); if (tmp) result = g_list_concat (result, tmp); } } return result; } /** * cal_client_multi_get_objects_in_range * @multi: A #CalClientMulti object. * @type: Type for objects. * @start: Start time. * @end: End time. * * Retrieves a list of all calendar components that are * scheduled within the given time range. The information is * retrieved from all the calendars being managed by the * given #CalClientMulti object. * * Returns: A list of UID strings. This should be freed using the * #cal_obj_uid_list_free() function. **/ GList * cal_client_multi_get_objects_in_range (CalClientMulti *multi, CalObjType type, time_t start, time_t end) { CalClient *client; GList *l; GList *result = NULL; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), NULL); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) { GList *tmp; tmp = cal_client_get_objects_in_range (client, type, start, end); if (tmp) result = g_list_concat (result, tmp); } } return result; } /** * cal_client_multi_get_free_busy * @multi: A #CalClientMulti object. * @users: List of users to retrieve F/B information for. * @start: Start time. * @end: End time. * * Retrieves Free/Busy information for the given users in all * the calendars being managed by the given #CalClient multi * object. * * Returns: A GList of VFREEBUSY CalComponents */ GList * cal_client_multi_get_free_busy (CalClientMulti *multi, GList *users, time_t start, time_t end) { CalClient *client; GList *l; GList *result = NULL; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), NULL); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) { GList *tmp; tmp = cal_client_get_free_busy (client, users, start, end); if (tmp) result = g_list_concat (result, tmp); } } return result; } /** * cal_client_multi_generate_instances */ void cal_client_multi_generate_instances (CalClientMulti *multi, CalObjType type, time_t start, time_t end, CalRecurInstanceFn cb, gpointer cb_data) { CalClient *client; GList *l; g_return_if_fail (IS_CAL_CLIENT_MULTI (multi)); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) { cal_client_generate_instances ( client, type, start, end, cb, cb_data); } } } /** * cal_client_multi_get_alarms_in_range */ GSList * cal_client_multi_get_alarms_in_range (CalClientMulti *multi, time_t start, time_t end) { CalClient *client; GList *l; GSList *result = NULL; g_return_val_if_fail (IS_CAL_CLIENT_MULTI (multi), NULL); for (l = multi->priv->uris; l; l = l->next) { client = cal_client_multi_get_client_for_uri (multi, (const char *) l->data); if (IS_CAL_CLIENT (client)) { GSList *tmp; tmp = cal_client_get_alarms_in_range (client, start, end); if (tmp) result = g_slist_concat (result, tmp); } } return result; }