1
/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
/* Evolution calendar ecal
4
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5
* Copyright (C) 2009 Intel Corporation
7
* Authors: Federico Mena-Quintero <federico@ximian.com>
8
* Rodrigo Moya <rodrigo@novell.com>
9
* Ross Burton <ross@linux.intel.com>
11
* This program is free software; you can redistribute it and/or
12
* modify it under the terms of version 2 of the GNU Lesser General Public
13
* License as published by the Free Software Foundation.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28
* The old signal "cal-opened" is deprecated since 3.0 and is replaced with
29
* its equivalent "cal_opened_ex", which has a detailed #GError structure
30
* as a parameter, instead of a status code only.
39
#include <glib/gi18n-lib.h>
41
#include <libical/ical.h>
42
#include <libedataserver/e-url.h>
43
#include <libedataserver/e-data-server-util.h>
45
#include <glib-object.h>
47
#include "libedata-cal/e-data-cal-types.h"
49
#include "e-cal-check-timezones.h"
50
#include "e-cal-marshal.h"
51
#include "e-cal-time-util.h"
52
#include "e-cal-view-private.h"
55
#include "e-gdbus-egdbuscalfactory.h"
56
#include "e-gdbus-egdbuscal.h"
57
#include "e-gdbus-egdbuscalview.h"
59
static guint active_cals = 0, cal_connection_closed_id = 0;
60
static EGdbusCalFactory *cal_factory_proxy = NULL;
61
static GStaticRecMutex cal_factory_proxy_lock = G_STATIC_REC_MUTEX_INIT;
62
#define LOCK_FACTORY() g_static_rec_mutex_lock (&cal_factory_proxy_lock)
63
#define UNLOCK_FACTORY() g_static_rec_mutex_unlock (&cal_factory_proxy_lock)
65
#define LOCK_CACHE() g_static_rec_mutex_lock (&priv->cache_lock)
66
#define UNLOCK_CACHE() g_static_rec_mutex_unlock (&priv->cache_lock)
68
G_DEFINE_TYPE(ECal, e_cal, G_TYPE_OBJECT)
69
#define E_CAL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_CAL, ECalPrivate))
71
static gboolean open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
72
#ifndef E_CAL_DISABLE_DEPRECATED
73
ECalendarStatus *status,
75
gboolean needs_auth, gboolean async);
76
static void e_cal_dispose (GObject *object);
77
static void e_cal_finalize (GObject *object);
79
/* Private part of the ECal structure */
84
/* Load state to avoid multiple loads */
85
ECalLoadState load_state;
87
/* URI of the calendar that is being loaded or is already loaded, or
88
* NULL if we are not loaded.
94
/* Email address associated with this calendar, or NULL */
96
gchar *alarm_email_address;
97
gchar *ldap_attribute;
106
/* The authentication function */
107
ECalAuthFunc auth_func;
108
gpointer auth_user_data;
110
/* A cache of timezones retrieved from the server, to avoid getting
111
them repeatedly for each get_object() call. */
112
GHashTable *timezones;
114
/* The default timezone to use to resolve DATE and floating DATE-TIME
116
icaltimezone *default_zone;
118
gchar *local_attachment_store;
120
/* For locking the operation while localling cache values like
121
static capabilities, cal address etc. */
122
GStaticRecMutex cache_lock;
129
#ifndef E_CAL_DISABLE_DEPRECATED
139
static guint e_cal_signals[LAST_SIGNAL];
141
static GObjectClass *parent_class;
143
#ifdef __PRETTY_FUNCTION__
144
#define e_return_error_if_fail(expr,error_code) G_STMT_START{ \
145
if G_LIKELY(expr) { } else \
147
g_log (G_LOG_DOMAIN, \
148
G_LOG_LEVEL_CRITICAL, \
149
"file %s: line %d (%s): assertion `%s' failed", \
152
__PRETTY_FUNCTION__, \
154
g_set_error (error, E_CALENDAR_ERROR, (error_code), \
155
"file %s: line %d (%s): assertion `%s' failed", \
158
__PRETTY_FUNCTION__, \
163
#define e_return_error_if_fail(expr,error_code) G_STMT_START{ \
164
if G_LIKELY(expr) { } else \
166
g_log (G_LOG_DOMAIN, \
167
G_LOG_LEVEL_CRITICAL, \
168
"file %s: line %d: assertion `%s' failed", \
172
g_set_error (error, E_CALENDAR_ERROR, (error_code), \
173
"file %s: line %d: assertion `%s' failed", \
181
#define E_CALENDAR_CHECK_STATUS(status,error) \
183
if ((status) == E_CALENDAR_STATUS_OK) \
187
if (error && *error) \
188
return unwrap_gerror (error); \
189
msg = e_cal_get_error_message ((status)); \
190
g_set_error ((error), E_CALENDAR_ERROR, (status), "%s", msg); \
199
e_calendar_error_quark (void)
203
q = g_quark_from_static_string ("e-calendar-error-quark");
209
* If the GError is a remote error, extract the EBookStatus embedded inside.
210
* Otherwise return CORBA_EXCEPTION (I know this is DBus...).
212
static ECalendarStatus
213
get_status_from_error (const GError *error)
215
#define err(a,b) "org.gnome.evolution.dataserver.calendar.Cal." a, b
218
ECalendarStatus err_code;
220
{ err ("Success", E_CALENDAR_STATUS_OK) },
221
{ err ("RepositoryOffline", E_CALENDAR_STATUS_REPOSITORY_OFFLINE) },
222
{ err ("PermissionDenied", E_CALENDAR_STATUS_PERMISSION_DENIED) },
223
{ err ("InvalidRange", E_CALENDAR_STATUS_OTHER_ERROR) },
224
{ err ("ObjectNotFound", E_CALENDAR_STATUS_OBJECT_NOT_FOUND) },
225
{ err ("InvalidObject", E_CALENDAR_STATUS_INVALID_OBJECT) },
226
{ err ("ObjectIdAlreadyExists", E_CALENDAR_STATUS_OBJECT_ID_ALREADY_EXISTS) },
227
{ err ("AuthenticationFailed", E_CALENDAR_STATUS_AUTHENTICATION_FAILED) },
228
{ err ("AuthenticationRequired", E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED) },
229
{ err ("UnsupportedField", E_CALENDAR_STATUS_OTHER_ERROR) },
230
{ err ("UnsupportedMethod", E_CALENDAR_STATUS_OTHER_ERROR) },
231
{ err ("UnsupportedAuthenticationMethod", E_CALENDAR_STATUS_OTHER_ERROR) },
232
{ err ("TLSNotAvailable", E_CALENDAR_STATUS_OTHER_ERROR) },
233
{ err ("NoSuchCal", E_CALENDAR_STATUS_NO_SUCH_CALENDAR) },
234
{ err ("UnknownUser", E_CALENDAR_STATUS_UNKNOWN_USER) },
235
{ err ("OfflineUnavailable", E_CALENDAR_STATUS_OTHER_ERROR) },
236
{ err ("SearchSizeLimitExceeded", E_CALENDAR_STATUS_OTHER_ERROR) },
237
{ err ("SearchTimeLimitExceeded", E_CALENDAR_STATUS_OTHER_ERROR) },
238
{ err ("InvalidQuery", E_CALENDAR_STATUS_OTHER_ERROR) },
239
{ err ("QueryRefused", E_CALENDAR_STATUS_OTHER_ERROR) },
240
{ err ("CouldNotCancel", E_CALENDAR_STATUS_COULD_NOT_CANCEL) },
241
{ err ("OtherError", E_CALENDAR_STATUS_OTHER_ERROR) },
242
{ err ("InvalidServerVersion", E_CALENDAR_STATUS_INVALID_SERVER_VERSION) },
243
{ err ("InvalidArg", E_CALENDAR_STATUS_INVALID_ARG) },
244
{ err ("NotSupported", E_CALENDAR_STATUS_NOT_SUPPORTED) }
248
if G_LIKELY (error == NULL)
251
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
255
name = g_dbus_error_get_remote_error (error);
257
for (i = 0; i < G_N_ELEMENTS (errors); i++) {
258
if (g_ascii_strcasecmp (errors[i].name, name) == 0) {
260
return errors[i].err_code;
264
g_warning ("Unmatched error name %s", name);
267
return E_CALENDAR_STATUS_OTHER_ERROR;
268
} else if (error->domain == E_CALENDAR_ERROR) {
271
/* In this case the error was caused by DBus */
272
return E_CALENDAR_STATUS_DBUS_EXCEPTION;
277
* If the specified GError is a remote error, then create a new error
278
* representing the remote error. If the error is anything else, then leave it
282
unwrap_gerror (GError **error)
287
if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
288
GError *new_error = NULL;
291
code = get_status_from_error (*error);
292
g_dbus_error_strip_remote_error (*error);
294
new_error = g_error_new_literal (E_CALENDAR_ERROR, code, (*error)->message);
296
g_error_free (*error);
304
* e_cal_source_type_enum_get_type:
306
* Registers the #ECalSourceTypeEnum type with glib.
308
* Returns: the ID of the #ECalSourceTypeEnum type.
311
e_cal_source_type_enum_get_type (void)
313
static volatile gsize enum_type__volatile = 0;
315
if (g_once_init_enter (&enum_type__volatile)) {
317
static GEnumValue values[] = {
318
{ E_CAL_SOURCE_TYPE_EVENT, "Event", NULL},
319
{ E_CAL_SOURCE_TYPE_TODO, "ToDo", NULL},
320
{ E_CAL_SOURCE_TYPE_JOURNAL, "Journal", NULL},
321
{ E_CAL_SOURCE_TYPE_LAST, "Invalid", NULL},
325
enum_type = g_enum_register_static ("ECalSourceTypeEnum", values);
326
g_once_init_leave (&enum_type__volatile, enum_type);
329
return enum_type__volatile;
333
* e_cal_set_mode_status_enum_get_type:
335
* Registers the #ECalSetModeStatusEnum type with glib.
337
* Returns: the ID of the #ECalSetModeStatusEnum type.
340
e_cal_set_mode_status_enum_get_type (void)
342
static volatile gsize enum_type__volatile = 0;
344
if (g_once_init_enter (&enum_type__volatile)) {
346
static GEnumValue values[] = {
347
{ E_CAL_SET_MODE_SUCCESS, "ECalSetModeSuccess", "success" },
348
{ E_CAL_SET_MODE_ERROR, "ECalSetModeError", "error" },
349
{ E_CAL_SET_MODE_NOT_SUPPORTED, "ECalSetModeNotSupported", "unsupported" },
353
enum_type = g_enum_register_static ("ECalSetModeStatusEnum", values);
354
g_once_init_leave (&enum_type__volatile, enum_type);
357
return enum_type__volatile;
361
* cal_mode_enum_get_type:
363
* Registers the #CalModeEnum type with glib.
365
* Returns: the ID of the #CalModeEnum type.
368
cal_mode_enum_get_type (void)
370
static volatile gsize enum_type__volatile = 0;
372
if (g_once_init_enter (&enum_type__volatile)) {
374
static GEnumValue values[] = {
375
{ CAL_MODE_INVALID, "CalModeInvalid", "invalid" },
376
{ CAL_MODE_LOCAL, "CalModeLocal", "local" },
377
{ CAL_MODE_REMOTE, "CalModeRemote", "remote" },
378
{ CAL_MODE_ANY, "CalModeAny", "any" },
382
enum_type = g_enum_register_static ("CalModeEnum", values);
383
g_once_init_leave (&enum_type__volatile, enum_type);
386
return enum_type__volatile;
389
static EDataCalObjType
390
convert_type (ECalSourceType type)
393
case E_CAL_SOURCE_TYPE_EVENT:
395
case E_CAL_SOURCE_TYPE_TODO:
397
case E_CAL_SOURCE_TYPE_JOURNAL:
406
e_cal_init (ECal *ecal)
414
ecal->priv = priv = E_CAL_GET_PRIVATE (ecal);
416
priv->load_state = E_CAL_LOAD_NOT_LOADED;
418
priv->local_attachment_store = NULL;
420
priv->cal_address = NULL;
421
priv->alarm_email_address = NULL;
422
priv->ldap_attribute = NULL;
423
priv->capabilities = NULL;
424
priv->gdbus_cal = NULL;
425
priv->timezones = g_hash_table_new (g_str_hash, g_str_equal);
426
priv->default_zone = icaltimezone_get_utc_timezone ();
427
g_static_rec_mutex_init (&priv->cache_lock);
431
gdbus_cal_disconnect (ECal *ecal);
434
* Called when the calendar server dies.
437
gdbus_cal_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, ECal *ecal)
441
g_return_if_fail (E_IS_CAL (ecal));
444
err = g_error_copy (error);
445
unwrap_gerror (&err);
449
g_debug (G_STRLOC ": ECal GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
452
g_debug (G_STRLOC ": ECal GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
455
gdbus_cal_disconnect (ecal);
457
g_signal_emit (G_OBJECT (ecal), e_cal_signals[BACKEND_DIED], 0);
461
gdbus_cal_connection_gone_cb (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
463
/* signal subscription takes care of correct parameters,
464
thus just do what is to be done here */
465
gdbus_cal_closed_cb (connection, TRUE, NULL, user_data);
470
gdbus_cal_disconnect (ECal *ecal)
472
/* Ensure that everything relevant is NULL */
475
if (ecal->priv->gdbus_cal) {
476
GError *error = NULL;
477
GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (ecal->priv->gdbus_cal));
479
g_signal_handlers_disconnect_by_func (connection, gdbus_cal_closed_cb, ecal);
480
g_dbus_connection_signal_unsubscribe (connection, ecal->priv->gone_signal_id);
481
ecal->priv->gone_signal_id = 0;
483
e_gdbus_cal_call_close_sync (ecal->priv->gdbus_cal, NULL, &error);
484
g_object_unref (ecal->priv->gdbus_cal);
485
ecal->priv->gdbus_cal = NULL;
488
unwrap_gerror (&error);
490
g_warning ("%s: Failed to close calendar, %s\n", G_STRFUNC, error->message);
491
g_error_free (error);
497
/* Dispose handler for the calendar ecal */
499
e_cal_dispose (GObject *object)
501
ECal *ecal = E_CAL (object);
503
gdbus_cal_disconnect (ecal);
505
(* G_OBJECT_CLASS (parent_class)->dispose) (object);
509
free_timezone (gpointer key, gpointer value, gpointer data)
511
/* Note that the key comes from within the icaltimezone value, so we
513
icaltimezone_free (value, TRUE);
516
/* Finalize handler for the calendar ecal */
518
e_cal_finalize (GObject *object)
523
g_return_if_fail (object != NULL);
524
g_return_if_fail (E_IS_CAL (object));
526
ecal = E_CAL (object);
529
priv->load_state = E_CAL_LOAD_NOT_LOADED;
532
g_object_unref (priv->source);
541
if (priv->local_attachment_store) {
542
g_free (priv->local_attachment_store);
543
priv->local_attachment_store = NULL;
546
if (priv->cal_address) {
547
g_free (priv->cal_address);
548
priv->cal_address = NULL;
550
if (priv->alarm_email_address) {
551
g_free (priv->alarm_email_address);
552
priv->alarm_email_address = NULL;
554
if (priv->ldap_attribute) {
555
g_free (priv->ldap_attribute);
556
priv->ldap_attribute = NULL;
558
if (priv->capabilities) {
559
g_free (priv->capabilities);
560
priv->capabilities = NULL;
563
g_hash_table_foreach (priv->timezones, free_timezone, NULL);
564
g_hash_table_destroy (priv->timezones);
565
priv->timezones = NULL;
566
g_static_rec_mutex_free (&priv->cache_lock);
568
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
575
/* Class initialization function for the calendar ecal */
577
e_cal_class_init (ECalClass *klass)
579
GObjectClass *object_class;
581
object_class = (GObjectClass *) klass;
583
parent_class = g_type_class_peek_parent (klass);
585
#ifndef E_CAL_DISABLE_DEPRECATED
586
e_cal_signals[CAL_OPENED] =
587
g_signal_new ("cal_opened",
588
G_TYPE_FROM_CLASS (klass),
590
G_STRUCT_OFFSET (ECalClass, cal_opened),
592
g_cclosure_marshal_VOID__INT,
593
G_TYPE_NONE, 1, G_TYPE_INT);
596
e_cal_signals[CAL_OPENED_EX] =
597
g_signal_new ("cal_opened_ex",
598
G_TYPE_FROM_CLASS (klass),
600
G_STRUCT_OFFSET (ECalClass, cal_opened_ex),
602
g_cclosure_marshal_VOID__POINTER,
603
G_TYPE_NONE, 1, G_TYPE_POINTER);
605
e_cal_signals[CAL_SET_MODE] =
606
g_signal_new ("cal_set_mode",
607
G_TYPE_FROM_CLASS (klass),
609
G_STRUCT_OFFSET (ECalClass, cal_set_mode),
611
e_cal_marshal_VOID__ENUM_ENUM,
613
E_CAL_SET_MODE_STATUS_ENUM_TYPE,
615
e_cal_signals[BACKEND_ERROR] =
616
g_signal_new ("backend_error",
617
G_TYPE_FROM_CLASS (klass),
619
G_STRUCT_OFFSET (ECalClass, backend_error),
621
g_cclosure_marshal_VOID__STRING,
624
e_cal_signals[BACKEND_DIED] =
625
g_signal_new ("backend_died",
626
G_TYPE_FROM_CLASS (klass),
628
G_STRUCT_OFFSET (ECalClass, backend_died),
630
g_cclosure_marshal_VOID__VOID,
633
#ifndef E_CAL_DISABLE_DEPRECATED
634
klass->cal_opened = NULL;
636
klass->cal_opened_ex = NULL;
637
klass->backend_died = NULL;
639
object_class->dispose = e_cal_dispose;
640
object_class->finalize = e_cal_finalize;
642
g_type_class_add_private (klass, sizeof (ECalPrivate));
646
cal_factory_proxy_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data)
652
if (cal_connection_closed_id) {
653
g_dbus_connection_signal_unsubscribe (connection, cal_connection_closed_id);
654
cal_connection_closed_id = 0;
655
g_signal_handlers_disconnect_by_func (connection, cal_factory_proxy_closed_cb, NULL);
658
if (cal_factory_proxy) {
659
g_object_unref (cal_factory_proxy);
660
cal_factory_proxy = NULL;
664
err = g_error_copy (error);
665
unwrap_gerror (&err);
669
g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
671
} else if (active_cals) {
672
g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
679
cal_factory_connection_gone_cb (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
681
/* signal subscription takes care of correct parameters,
682
thus just do what is to be done here */
683
cal_factory_proxy_closed_cb (connection, TRUE, NULL, user_data);
686
/* one-time start up for libecal */
688
e_cal_activate (GError **error)
690
GDBusConnection *connection;
693
if (G_LIKELY (cal_factory_proxy)) {
698
cal_factory_proxy = e_gdbus_cal_factory_proxy_new_for_bus_sync (
700
G_DBUS_PROXY_FLAGS_NONE,
701
"org.gnome.evolution.dataserver.Calendar",
702
"/org/gnome/evolution/dataserver/calendar/CalFactory",
706
if (!cal_factory_proxy) {
711
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy));
712
g_dbus_connection_set_exit_on_close (connection, FALSE);
713
cal_connection_closed_id = g_dbus_connection_signal_subscribe (connection,
715
"org.freedesktop.DBus", /* interface */
716
"NameOwnerChanged", /* member */
717
"/org/freedesktop/DBus", /* object_path */
718
"org.gnome.evolution.dataserver.Calendar", /* arg0 */
719
G_DBUS_SIGNAL_FLAGS_NONE,
720
cal_factory_connection_gone_cb, NULL, NULL);
722
g_signal_connect (connection, "closed", G_CALLBACK (cal_factory_proxy_closed_cb), NULL);
730
reopen_with_auth (gpointer data)
732
#ifndef E_CAL_DISABLE_DEPRECATED
733
ECalendarStatus status;
735
GError *error = NULL;
737
open_calendar (E_CAL (data), TRUE, &error,
738
#ifndef E_CAL_DISABLE_DEPRECATED
744
g_error_free (error);
750
auth_required_cb (EGdbusCal *gdbus_cal, ECal *cal)
752
g_return_if_fail (E_IS_CAL (cal));
754
g_idle_add (reopen_with_auth, (gpointer) cal);
764
backend_error_idle_cb (gpointer data)
766
ECalErrorData *error_data = data;
768
g_signal_emit (G_OBJECT (error_data->ecal), e_cal_signals[BACKEND_ERROR], 0, error_data->message);
770
g_object_unref (error_data->ecal);
771
g_free (error_data->message);
777
/* Handle the error_occurred signal from the listener */
779
backend_error_cb (EGdbusCal *gdbus_cal, const gchar *message, ECal *ecal)
781
ECalErrorData *error_data;
783
g_return_if_fail (E_IS_CAL (ecal));
785
error_data = g_new0 (ECalErrorData, 1);
787
error_data->ecal = g_object_ref (ecal);
788
error_data->message = g_strdup (message);
790
g_idle_add (backend_error_idle_cb, error_data);
794
readonly_cb (EGdbusCal *gdbus_cal, gboolean read_only, ECal *cal)
798
g_return_if_fail (cal && E_IS_CAL (cal));
801
priv->read_only = read_only;
805
mode_cb (EGdbusCal *gdbus_cal, EDataCalMode mode, ECal *cal)
807
g_return_if_fail (E_IS_CAL (cal));
808
g_return_if_fail (mode & AnyMode);
810
g_signal_emit (G_OBJECT (cal), e_cal_signals[CAL_SET_MODE],
811
0, E_CALENDAR_STATUS_OK, mode);
816
backend_died_cb (EComponentListener *cl, gpointer user_data)
819
ECal *ecal = (ECal *) user_data;
822
priv->load_state = E_CAL_LOAD_NOT_LOADED;
823
g_signal_emit (G_OBJECT (ecal), e_cal_signals[BACKEND_DIED], 0);
827
set_local_attachment_store (ECal *ecal)
829
gchar *cache_dir = NULL;
830
GError *error = NULL;
832
e_gdbus_cal_call_get_cache_dir_sync (
833
ecal->priv->gdbus_cal, &cache_dir, NULL, &error);
836
ecal->priv->local_attachment_store = cache_dir;
838
unwrap_gerror (&error);
839
g_warning ("%s", error->message);
840
g_error_free (error);
846
* @source: An #ESource to be used for the client.
847
* @type: Type of the client.
849
* Creates a new calendar client. This does not open the calendar itself,
850
* for that, #e_cal_open or #e_cal_open_async needs to be called.
852
* Returns: A newly-created calendar client, or NULL if the client could
853
* not be constructed because it could not contact the calendar server.
856
e_cal_new (ESource *source, ECalSourceType type)
861
GError *error = NULL;
862
GDBusConnection *connection;
864
g_return_val_if_fail (source && E_IS_SOURCE (source), NULL);
865
g_return_val_if_fail (type < E_CAL_SOURCE_TYPE_LAST, NULL);
867
if (!e_cal_activate (&error)) {
868
unwrap_gerror (&error);
869
g_warning("Cannot activate ECal: %s\n", error ? error->message : "Unknown error");
871
g_error_free (error);
875
ecal = g_object_new (E_TYPE_CAL, NULL);
878
priv->source = g_object_ref (source);
879
priv->uri = e_source_get_uri (source);
882
xml = e_source_to_standalone_xml (priv->source);
883
if (!e_gdbus_cal_factory_call_get_cal_sync (cal_factory_proxy, xml, convert_type (priv->type), &path, NULL, &error)) {
885
unwrap_gerror (&error);
886
g_warning ("Cannot get cal from factory: %s", error ? error->message : "Unknown error");
888
g_error_free (error);
889
g_object_unref (ecal);
894
priv->gdbus_cal = e_gdbus_cal_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy)),
895
G_DBUS_PROXY_FLAGS_NONE,
896
"org.gnome.evolution.dataserver.Calendar",
901
if (!priv->gdbus_cal) {
903
unwrap_gerror (&error);
904
g_warning ("Cannot create cal proxy: %s", error ? error->message : "Unknown error");
906
g_error_free (error);
907
g_object_unref (ecal);
911
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (priv->gdbus_cal));
912
priv->gone_signal_id = g_dbus_connection_signal_subscribe (connection,
913
"org.freedesktop.DBus", /* sender */
914
"org.freedesktop.DBus", /* interface */
915
"NameOwnerChanged", /* member */
916
"/org/freedesktop/DBus", /* object_path */
917
"org.gnome.evolution.dataserver.Calendar", /* arg0 */
918
G_DBUS_SIGNAL_FLAGS_NONE,
919
gdbus_cal_connection_gone_cb, ecal, NULL);
920
g_signal_connect (connection, "closed", G_CALLBACK (gdbus_cal_closed_cb), ecal);
922
g_signal_connect (priv->gdbus_cal, "auth-required", G_CALLBACK (auth_required_cb), ecal);
923
g_signal_connect (priv->gdbus_cal, "backend-error", G_CALLBACK (backend_error_cb), ecal);
924
g_signal_connect (priv->gdbus_cal, "readonly", G_CALLBACK (readonly_cb), ecal);
925
g_signal_connect (priv->gdbus_cal, "mode", G_CALLBACK (mode_cb), ecal);
927
/* Set the local attachment store path for the calendar */
928
set_local_attachment_store (ecal);
935
/* for each known source calls check_func, which should return TRUE if the required
936
source have been found. Function returns NULL or the source on which was returned
937
TRUE by the check_func. Non-NULL pointer should be unreffed by g_object_unref.
939
'sources' is an output parameter and cannot be NULL. When returned non-NULL, then
940
should be freed with g_object_unref function. */
942
search_known_sources (ECalSourceType type, gboolean (*check_func)(ESource *source, gpointer user_data), gpointer user_data, ESourceList **sources, GError **error)
948
g_return_val_if_fail (sources != NULL, NULL);
949
g_return_val_if_fail (check_func != NULL, NULL);
953
if (!e_cal_get_sources (sources, type, &err)) {
954
g_propagate_error (error, err);
958
for (g = e_source_list_peek_groups (*sources); g; g = g->next) {
959
ESourceGroup *group = E_SOURCE_GROUP (g->data);
962
for (s = e_source_group_peek_sources (group); s; s = s->next) {
963
ESource *source = E_SOURCE (s->data);
965
if (check_func (source, user_data)) {
966
res = g_object_ref (source);
979
check_uri (ESource *source, gpointer uri)
983
g_return_val_if_fail (source != NULL, FALSE);
984
g_return_val_if_fail (uri != NULL, FALSE);
986
suri = e_source_peek_absolute_uri (source);
988
return suri && g_ascii_strcasecmp (suri, uri) == 0;
992
* e_cal_new_from_uri:
993
* @uri: The URI pointing to the calendar to open.
994
* @type: Type of the client.
996
* Creates a new calendar client. This does not open the calendar itself,
997
* for that, #e_cal_open or #e_cal_open_async needs to be called.
999
* Returns: A newly-created calendar client, or NULL if the client could
1000
* not be constructed because it could not contact the calendar server.
1003
e_cal_new_from_uri (const gchar *uri, ECalSourceType type)
1005
ESourceList *sources = NULL;
1009
source = search_known_sources (type, check_uri, (gpointer) uri, &sources, NULL);
1011
source = e_source_new_with_absolute_uri ("", uri);
1013
cal = e_cal_new (source, type);
1015
g_object_unref (source);
1017
g_object_unref (sources);
1023
* e_cal_new_system_calendar:
1025
* Create a calendar client for the system calendar, which should always be
1026
* present in all Evolution installations. This does not open the calendar
1027
* itself -- for that use e_cal_open() or e_cal_open_async().
1029
* Returns: A newly-created calendar client, or %NULL if the client could
1030
* not be constructed.
1033
e_cal_new_system_calendar (void)
1035
return e_cal_new_from_uri ("local:system", E_CAL_SOURCE_TYPE_EVENT);
1039
* e_cal_new_system_tasks:
1041
* Create a calendar client for the system task list, which should always
1042
* be present in all Evolution installations. This does not open the task
1043
* list itself -- for that use e_cal_open() or e_cal_open_async().
1045
* Returns: A newly-created calendar client, or %NULL if the client could
1046
* not be constructed.
1049
e_cal_new_system_tasks (void)
1051
return e_cal_new_from_uri ("local:system", E_CAL_SOURCE_TYPE_TODO);
1055
* e_cal_new_system_memos:
1057
* Create a calendar client for the system memo list, which should always
1058
* be present in all Evolution installations. This does not open the memo
1059
* list itself -- for that use e_cal_open() or e_cal_open_async().
1061
* Returns: A newly-created calendar client, or %NULL if the client could
1062
* not be constructed.
1065
e_cal_new_system_memos (void)
1067
return e_cal_new_from_uri ("local:system", E_CAL_SOURCE_TYPE_JOURNAL);
1071
* e_cal_set_auth_func
1072
* @ecal: A calendar client.
1073
* @func: The authentication function
1074
* @data: User data to be used when calling the authentication function
1076
* Sets the given authentication function on the calendar client. This
1077
* function will be called any time the calendar server needs a
1078
* password for an operation associated with the calendar and should
1079
* be supplied before any calendar is opened.
1081
* When a calendar is opened asynchronously, the open function is
1082
* processed in a concurrent thread. This means that the
1083
* authentication function will also be called from this thread. As
1084
* such, the authentication callback cannot directly call any
1085
* functions that must be called from the main thread. For example
1086
* any Gtk+ related functions, which must be proxied synchronously to
1087
* the main thread by the callback.
1089
* The authentication function has the following signature
1091
* gchar * auth_func (ECal *ecal,
1092
* const gchar *prompt,
1094
* gpointer user_data)
1097
e_cal_set_auth_func (ECal *ecal, ECalAuthFunc func, gpointer data)
1099
g_return_if_fail (ecal != NULL);
1100
g_return_if_fail (E_IS_CAL (ecal));
1102
ecal->priv->auth_func = func;
1103
ecal->priv->auth_user_data = data;
1107
build_proxy_pass_key (ECal *ecal, const gchar * parent_user)
1113
uri = e_cal_get_uri (ecal);
1115
euri = e_uri_new (uri);
1116
g_free (euri->user);
1117
euri->user = g_strdup(parent_user);
1119
euri_str = e_uri_to_string (euri, FALSE);
1126
build_pass_key (ECal *ecal)
1132
uri = e_cal_get_uri (ecal);
1134
euri = e_uri_new (uri);
1135
euri_str = e_uri_to_string (euri, FALSE);
1142
async_open_report_result (ECal *ecal, const GError *error)
1144
#ifndef E_CAL_DISABLE_DEPRECATED
1145
ECalendarStatus status;
1148
g_return_if_fail (ecal && E_IS_CAL (ecal));
1151
ecal->priv->load_state = E_CAL_LOAD_LOADED;
1154
#ifndef E_CAL_DISABLE_DEPRECATED
1155
status = get_status_from_error (error);
1157
status = E_CALENDAR_STATUS_OK;
1161
e_gdbus_cal_call_is_read_only_sync (ecal->priv->gdbus_cal, NULL, NULL);
1164
#ifndef E_CAL_DISABLE_DEPRECATED
1165
g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, status);
1167
g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, error);
1171
async_open_ready_cb (EGdbusCal *gdbus_cal, GAsyncResult *res, ECal *ecal)
1173
GError *error = NULL;
1175
g_return_if_fail (ecal && E_IS_CAL (ecal));
1177
e_gdbus_cal_call_open_finish (gdbus_cal, res, &error);
1179
unwrap_gerror (&error);
1181
async_open_report_result (ecal, error);
1184
g_error_free (error);
1188
open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
1189
#ifndef E_CAL_DISABLE_DEPRECATED
1190
ECalendarStatus *status,
1192
gboolean needs_auth, gboolean async)
1195
gchar *username = NULL, *auth_type = NULL, *password = NULL;
1197
g_return_val_if_fail (error != NULL, FALSE);
1199
e_return_error_if_fail (ecal != NULL, E_CALENDAR_STATUS_INVALID_ARG);
1200
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1202
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1204
if (!needs_auth && priv->load_state == E_CAL_LOAD_LOADED) {
1208
/* see if the backend needs authentication */
1209
if ( (priv->mode != CAL_MODE_LOCAL) && e_source_get_property (priv->source, "auth")) {
1210
gchar *prompt, *key;
1213
priv->load_state = E_CAL_LOAD_AUTHENTICATING;
1215
if (priv->auth_func == NULL) {
1216
priv->load_state = E_CAL_LOAD_NOT_LOADED;
1217
#ifndef E_CAL_DISABLE_DEPRECATED
1218
*status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1220
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1223
username = e_source_get_duped_property (priv->source, "username");
1225
priv->load_state = E_CAL_LOAD_NOT_LOADED;
1226
#ifndef E_CAL_DISABLE_DEPRECATED
1227
*status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1229
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1232
prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
1233
e_source_peek_name (priv->source), username);
1235
auth_type = e_source_get_duped_property (priv->source, "auth-type");
1237
key = build_pass_key (ecal);
1239
parent_user = e_source_get_duped_property (priv->source, "parent_id_name");
1241
key = build_proxy_pass_key (ecal, parent_user);
1243
This password prompt will be prompted rarely. Since the key that is passed to
1244
the auth_func corresponds to the parent user.
1246
prompt = g_strdup_printf (_("Enter password for %s to enable proxy for user %s"), e_source_peek_name (priv->source), parent_user);
1247
g_free (parent_user);
1249
key = g_strdup (e_cal_get_uri (ecal));
1254
priv->load_state = E_CAL_LOAD_NOT_LOADED;
1255
#ifndef E_CAL_DISABLE_DEPRECATED
1256
*status = E_CALENDAR_STATUS_URI_NOT_LOADED;
1258
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1261
password = priv->auth_func (ecal, prompt, key, priv->auth_user_data);
1264
priv->load_state = E_CAL_LOAD_NOT_LOADED;
1265
#ifndef E_CAL_DISABLE_DEPRECATED
1266
*status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1268
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1275
priv->load_state = E_CAL_LOAD_LOADING;
1277
#ifndef E_CAL_DISABLE_DEPRECATED
1278
*status = E_CALENDAR_STATUS_OK;
1281
if (!e_gdbus_cal_call_open_sync (priv->gdbus_cal, only_if_exists, username ? username : "", password ? password : "", NULL, error)) {
1282
#ifndef E_CAL_DISABLE_DEPRECATED
1283
*status = E_CALENDAR_STATUS_DBUS_EXCEPTION;
1287
priv->load_state = E_CAL_LOAD_LOADED;
1289
e_gdbus_cal_call_open (priv->gdbus_cal, only_if_exists, username ? username : "", password ? password : "", NULL, (GAsyncReadyCallback) async_open_ready_cb, ecal);
1299
e_gdbus_cal_call_is_read_only_sync (ecal->priv->gdbus_cal, NULL, &err);
1305
unwrap_gerror (error);
1306
priv->load_state = E_CAL_LOAD_NOT_LOADED;
1309
return *error == NULL;
1314
* @ecal: A calendar client.
1315
* @only_if_exists: FALSE if the calendar should be opened even if there
1316
* was no storage for it, i.e. to create a new calendar or load an existing
1317
* one if it already exists. TRUE if it should only try to load calendars
1318
* that already exist.
1319
* @error: Placeholder for error information.
1321
* Makes a calendar client initiate a request to open a calendar. The calendar
1322
* client will emit the "cal_opened" signal when the response from the server is
1323
* received. Since 3.0 is emitted also "cal_opened_ex" signal, which contains
1324
* a GError pointer from the open operation (NULL when no error occurred).
1325
* New signal deprecates the old "cal_opened" signal.
1327
* Returns: TRUE on success, FALSE on failure to issue the open request.
1330
e_cal_open (ECal *ecal, gboolean only_if_exists, GError **error)
1332
#ifndef E_CAL_DISABLE_DEPRECATED
1333
ECalendarStatus status;
1338
result = open_calendar (ecal, only_if_exists, &err,
1339
#ifndef E_CAL_DISABLE_DEPRECATED
1343
#ifndef E_CAL_DISABLE_DEPRECATED
1344
g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, status);
1346
g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, err);
1349
g_propagate_error (error, err);
1354
struct idle_async_error_reply_data
1356
ECal *ecal; /* ref-ed */
1357
GError *error; /* cannot be NULL */
1361
idle_async_error_reply_cb (gpointer user_data)
1363
struct idle_async_error_reply_data *data = user_data;
1365
g_return_val_if_fail (data != NULL, FALSE);
1366
g_return_val_if_fail (data->ecal != NULL, FALSE);
1367
g_return_val_if_fail (data->error != NULL, FALSE);
1369
async_open_report_result (data->ecal, data->error);
1371
g_object_unref (data->ecal);
1372
g_error_free (data->error);
1380
* @ecal: A calendar client.
1381
* @only_if_exists: If TRUE, then only open the calendar if it already
1382
* exists. If FALSE, then create a new calendar if it doesn't already
1385
* Open the calendar asynchronously. The calendar will emit the
1386
* "cal_opened" signal when the operation has completed.
1387
* Since 3.0 is emitted also "cal_opened_ex" signal, which contains
1388
* a GError pointer from the open operation (NULL when no error occurred).
1389
* New signal deprecates the old "cal_opened" signal.
1391
* Because this operation runs in another thread, any authentication
1392
* callback set on the calendar will be called from this other thread.
1393
* See #e_cal_set_auth_func() for details.
1396
e_cal_open_async (ECal *ecal, gboolean only_if_exists)
1399
GError *error = NULL;
1400
#ifndef E_CAL_DISABLE_DEPRECATED
1401
ECalendarStatus status;
1404
g_return_if_fail (ecal != NULL);
1405
g_return_if_fail (E_IS_CAL (ecal));
1409
switch (priv->load_state) {
1410
case E_CAL_LOAD_AUTHENTICATING :
1411
case E_CAL_LOAD_LOADING :
1412
#ifndef E_CAL_DISABLE_DEPRECATED
1413
g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, E_CALENDAR_STATUS_BUSY);
1416
error = g_error_new_literal (E_CALENDAR_ERROR, E_CALENDAR_STATUS_BUSY, e_cal_get_error_message (E_CALENDAR_STATUS_BUSY));
1417
g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, error);
1418
g_error_free (error);
1420
case E_CAL_LOAD_LOADED :
1421
#ifndef E_CAL_DISABLE_DEPRECATED
1422
g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, E_CALENDAR_STATUS_OK);
1425
g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, NULL);
1428
/* ignore everything else */
1432
open_calendar (ecal, only_if_exists, &error,
1433
#ifndef E_CAL_DISABLE_DEPRECATED
1438
struct idle_async_error_reply_data *data;
1440
data = g_new0 (struct idle_async_error_reply_data, 1);
1441
data->ecal = g_object_ref (ecal);
1442
data->error = error;
1443
g_idle_add (idle_async_error_reply_cb, data);
1449
* @ecal: A calendar client.
1450
* @error: Placeholder for error information.
1452
* Invokes refresh on a calendar. See @e_cal_get_refresh_supported.
1454
* Returns: TRUE if calendar supports refresh and it was invoked, FALSE otherwise.
1459
e_cal_refresh (ECal *ecal, GError **error)
1463
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1465
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1467
if (!e_gdbus_cal_call_refresh_sync (priv->gdbus_cal, NULL, error)) {
1468
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1476
* @ecal: A calendar client.
1477
* @error: Placeholder for error information.
1479
* Removes a calendar.
1481
* Returns: TRUE if the calendar was removed, FALSE if there was an error.
1484
e_cal_remove (ECal *ecal, GError **error)
1488
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1490
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1492
if (!e_gdbus_cal_call_remove_sync (priv->gdbus_cal, NULL, error)) {
1493
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1500
/* Builds an URI list out of a CORBA string sequence */
1502
build_uri_list (GNOME_Evolution_Calendar_StringSeq *seq)
1507
for (i = 0; i < seq->_length; i++)
1508
uris = g_list_prepend (uris, g_strdup (seq->_buffer[i]));
1516
* @ecal: A calendar client.
1517
* @mode: Mode of the URIs to get.
1519
* Retrieves a list of all calendar clients for the given mode.
1521
* Returns: list of uris.
1524
e_cal_uri_list (ECal *ecal, CalMode mode)
1528
GNOME_Evolution_Calendar_StringSeq *uri_seq;
1530
CORBA_Environment ev;
1533
g_return_val_if_fail (ecal != NULL, NULL);
1534
g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1538
for (f = priv->factories; f; f = f->next) {
1539
CORBA_exception_init (&ev);
1540
uri_seq = GNOME_Evolution_Calendar_CalFactory_uriList (f->data, mode, &ev);
1542
if (BONOBO_EX (&ev)) {
1543
g_message ("e_cal_uri_list(): request failed");
1545
/* free memory and return */
1546
g_list_foreach (uris, (GFunc) g_free, NULL);
1552
uris = g_list_concat (uris, build_uri_list (uri_seq));
1553
CORBA_free (uri_seq);
1556
CORBA_exception_free (&ev);
1566
* e_cal_get_source_type:
1567
* @ecal: A calendar client.
1569
* Gets the type of the calendar client.
1571
* Returns: an #ECalSourceType value corresponding to the type
1572
* of the calendar client.
1575
e_cal_get_source_type (ECal *ecal)
1579
g_return_val_if_fail (ecal != NULL, E_CAL_SOURCE_TYPE_LAST);
1580
g_return_val_if_fail (E_IS_CAL (ecal), E_CAL_SOURCE_TYPE_LAST);
1588
* e_cal_get_load_state:
1589
* @ecal: A calendar client.
1591
* Queries the state of loading of a calendar client.
1593
* Returns: A #ECalLoadState value indicating whether the client has
1594
* not been loaded with #e_cal_open yet, whether it is being
1595
* loaded, or whether it is already loaded.
1598
e_cal_get_load_state (ECal *ecal)
1602
g_return_val_if_fail (ecal != NULL, E_CAL_LOAD_NOT_LOADED);
1603
g_return_val_if_fail (E_IS_CAL (ecal), E_CAL_LOAD_NOT_LOADED);
1606
return priv->load_state;
1611
* @ecal: A calendar client.
1613
* Queries the source that is open in a calendar client.
1615
* Returns: The source of the calendar that is already loaded or is being
1616
* loaded, or NULL if the ecal has not started a load request yet.
1619
e_cal_get_source (ECal *ecal)
1623
g_return_val_if_fail (ecal != NULL, NULL);
1624
g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1627
return priv->source;
1632
* @ecal: A calendar client.
1634
* Queries the URI that is open in a calendar client.
1636
* Returns: The URI of the calendar that is already loaded or is being
1637
* loaded, or NULL if the client has not started a load request yet.
1640
e_cal_get_uri (ECal *ecal)
1644
g_return_val_if_fail (ecal != NULL, NULL);
1645
g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1652
* e_cal_get_local_attachment_store
1653
* @ecal: A calendar client.
1655
* Queries the URL where the calendar attachments are
1656
* serialized in the local filesystem. This enable clients
1657
* to operate with the reference to attachments rather than the data itself
1658
* unless it specifically uses the attachments for open/sending
1661
* Returns: The URL where the attachments are serialized in the
1665
e_cal_get_local_attachment_store (ECal *ecal)
1669
g_return_val_if_fail (ecal != NULL, NULL);
1670
g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1673
return (const gchar *)priv->local_attachment_store;
1677
* e_cal_is_read_only:
1678
* @ecal: A calendar client.
1679
* @read_only: Return value for read only status.
1680
* @error: Placeholder for error information.
1682
* Queries whether the calendar client can perform modifications
1683
* on the calendar or not. Whether the backend is read only or not
1684
* is specified, on exit, in the @read_only argument.
1686
* Returns: TRUE if the call was successful, FALSE if there was an error.
1689
e_cal_is_read_only (ECal *ecal, gboolean *read_only, GError **error)
1693
if (!(ecal && E_IS_CAL (ecal)))
1694
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
1697
*read_only = priv->read_only;
1703
* e_cal_get_cal_address:
1704
* @ecal: A calendar client.
1705
* @cal_address: Return value for address information.
1706
* @error: Placeholder for error information.
1708
* Queries the calendar address associated with a calendar client.
1710
* Returns: TRUE if the operation was successful, FALSE if there
1714
e_cal_get_cal_address (ECal *ecal, gchar **cal_address, GError **error)
1718
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1719
e_return_error_if_fail (cal_address != NULL, E_CALENDAR_STATUS_INVALID_ARG);
1721
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1722
*cal_address = NULL;
1725
if (priv->cal_address == NULL) {
1726
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1727
if (priv->load_state != E_CAL_LOAD_LOADED) {
1729
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
1732
if (!e_gdbus_cal_call_get_cal_address_sync (priv->gdbus_cal, &priv->cal_address, NULL, error)) {
1734
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1738
*cal_address = g_strdup (priv->cal_address);
1745
* e_cal_get_alarm_email_address:
1746
* @ecal: A calendar client.
1747
* @alarm_address: Return value for alarm address.
1748
* @error: Placeholder for error information.
1750
* Queries the address to be used for alarms in a calendar client.
1752
* Returns: TRUE if the operation was successful, FALSE if there was
1753
* an error while contacting the backend.
1756
e_cal_get_alarm_email_address (ECal *ecal, gchar **alarm_address, GError **error)
1760
e_return_error_if_fail (alarm_address != NULL, E_CALENDAR_STATUS_INVALID_ARG);
1761
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1763
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1764
*alarm_address = NULL;
1766
if (priv->load_state != E_CAL_LOAD_LOADED) {
1767
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
1770
if (!e_gdbus_cal_call_get_alarm_email_address_sync (priv->gdbus_cal, alarm_address, NULL, error)) {
1771
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1778
* e_cal_get_ldap_attribute:
1779
* @ecal: A calendar client.
1780
* @ldap_attribute: Return value for the LDAP attribute.
1781
* @error: Placeholder for error information.
1783
* Queries the LDAP attribute for a calendar client.
1785
* Returns: TRUE if the call was successful, FALSE if there was an
1786
* error contacting the backend.
1789
e_cal_get_ldap_attribute (ECal *ecal, gchar **ldap_attribute, GError **error)
1793
e_return_error_if_fail (ldap_attribute != NULL, E_CALENDAR_STATUS_INVALID_ARG);
1794
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1796
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1797
*ldap_attribute = NULL;
1799
if (priv->load_state != E_CAL_LOAD_LOADED) {
1800
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
1803
if (!e_gdbus_cal_call_get_ldap_attribute_sync (priv->gdbus_cal, ldap_attribute, NULL, error)) {
1804
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1811
load_static_capabilities (ECal *ecal, GError **error)
1816
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1818
if (priv->load_state != E_CAL_LOAD_LOADED) {
1819
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
1824
if (priv->capabilities) {
1826
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
1829
if (!e_gdbus_cal_call_get_scheduling_information_sync (priv->gdbus_cal, &priv->capabilities, NULL, error)) {
1831
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1840
check_capability (ECal *ecal, const gchar *cap)
1846
/* FIXME Check result */
1847
load_static_capabilities (ecal, NULL);
1848
if (priv->capabilities && strstr (priv->capabilities, cap))
1855
* e_cal_get_one_alarm_only:
1856
* @ecal: A calendar client.
1858
* Checks if a calendar supports only one alarm per component.
1860
* Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
1863
e_cal_get_one_alarm_only (ECal *ecal)
1865
g_return_val_if_fail (ecal != NULL, FALSE);
1866
g_return_val_if_fail (ecal && E_IS_CAL (ecal), FALSE);
1868
return check_capability (ecal, CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
1872
* e_cal_get_organizer_must_attend:
1873
* @ecal: A calendar client.
1875
* Checks if a calendar forces organizers of meetings to be also attendees.
1877
* Returns: TRUE if the calendar forces organizers to attend meetings,
1881
e_cal_get_organizer_must_attend (ECal *ecal)
1883
g_return_val_if_fail (ecal != NULL, FALSE);
1884
g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1886
return check_capability (ecal, CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
1890
* e_cal_get_recurrences_no_master:
1891
* @ecal: A calendar client.
1893
* Checks if the calendar has a master object for recurrences.
1895
* Returns: TRUE if the calendar has a master object for recurrences,
1899
e_cal_get_recurrences_no_master (ECal *ecal)
1901
g_return_val_if_fail (ecal != NULL, FALSE);
1902
g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1904
return check_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
1908
* e_cal_get_static_capability:
1909
* @ecal: A calendar client.
1910
* @cap: Name of the static capability to check.
1912
* Queries the calendar for static capabilities.
1914
* Returns: TRUE if the capability is supported, FALSE otherwise.
1917
e_cal_get_static_capability (ECal *ecal, const gchar *cap)
1919
g_return_val_if_fail (ecal != NULL, FALSE);
1920
g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1922
return check_capability (ecal, cap);
1926
* e_cal_get_save_schedules:
1927
* @ecal: A calendar client.
1929
* Checks whether the calendar saves schedules.
1931
* Returns: TRUE if it saves schedules, FALSE otherwise.
1934
e_cal_get_save_schedules (ECal *ecal)
1936
g_return_val_if_fail (ecal != NULL, FALSE);
1937
g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1939
return check_capability (ecal, CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
1943
* e_cal_get_organizer_must_accept:
1944
* @ecal: A calendar client.
1946
* Checks whether a calendar requires organizer to accept their attendance to
1949
* Returns: TRUE if the calendar requires organizers to accept, FALSE
1953
e_cal_get_organizer_must_accept (ECal *ecal)
1955
g_return_val_if_fail (ecal != NULL, FALSE);
1956
g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1958
return check_capability (ecal, CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
1962
* e_cal_get_refresh_supported:
1963
* @ecal: A calendar client.
1965
* Checks whether a calendar supports explicit refreshing (see @e_cal_refresh).
1967
* Returns: TRUE if the calendar supports refreshing, FALSE otherwise.
1972
e_cal_get_refresh_supported (ECal *ecal)
1974
g_return_val_if_fail (ecal != NULL, FALSE);
1975
g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1977
return check_capability (ecal, CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
1982
* @ecal: A calendar client.
1983
* @mode: Mode to switch to.
1985
* Switches online/offline mode on the calendar.
1987
* Returns: TRUE if the switch was successful, FALSE if there was an error.
1990
e_cal_set_mode (ECal *ecal, CalMode mode)
1993
GError *error = NULL;
1995
g_return_val_if_fail (ecal != NULL, FALSE);
1996
g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1997
g_return_val_if_fail (mode & CAL_MODE_ANY, FALSE);
2000
g_return_val_if_fail (priv->gdbus_cal, FALSE);
2001
g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, FALSE);
2003
if (!e_gdbus_cal_call_set_mode_sync (priv->gdbus_cal, mode, NULL, &error)) {
2004
unwrap_gerror (&error);
2005
g_printerr ("%s: %s\n", G_STRFUNC, error ? error->message : "Unknown error");
2007
g_error_free (error);
2014
/* This is used in the callback which fetches all the timezones needed for an
2016
typedef struct _ECalGetTimezonesData ECalGetTimezonesData;
2017
struct _ECalGetTimezonesData {
2020
/* This starts out at E_CALENDAR_STATUS_OK. If an error occurs this
2021
contains the last error. */
2022
ECalendarStatus status;
2026
* e_cal_get_default_object:
2027
* @ecal: A calendar client.
2028
* @icalcomp: Return value for the default object.
2029
* @error: Placeholder for error information.
2031
* Retrives an #icalcomponent from the backend that contains the default
2032
* values for properties needed.
2034
* Returns: TRUE if the call was successful, FALSE otherwise.
2037
e_cal_get_default_object (ECal *ecal, icalcomponent **icalcomp, GError **error)
2040
ECalendarStatus status;
2043
e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2044
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2046
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2049
if (priv->load_state != E_CAL_LOAD_LOADED) {
2050
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2053
if (!e_gdbus_cal_call_get_default_object_sync (priv->gdbus_cal, &object, NULL, error)) {
2054
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2058
*icalcomp = icalparser_parse_string (object);
2062
status = E_CALENDAR_STATUS_INVALID_OBJECT;
2064
status = E_CALENDAR_STATUS_OK;
2066
E_CALENDAR_CHECK_STATUS (status, error);
2068
status = E_CALENDAR_STATUS_OTHER_ERROR;
2070
E_CALENDAR_CHECK_STATUS (status, error);
2074
* e_cal_get_attachments_for_comp:
2075
* @ecal: A calendar client.
2076
* @uid: Unique identifier for a calendar component.
2077
* @rid: Recurrence identifier.
2078
* @list: Return the list of attachment uris.
2079
* @error: Placeholder for error information.
2081
* Queries a calendar for a calendar component object based on its unique
2082
* identifier and gets the attachments for the component.
2084
* Returns: TRUE if the call was successful, FALSE otherwise.
2087
e_cal_get_attachments_for_comp (ECal *ecal, const gchar *uid, const gchar *rid, GSList **list, GError **error)
2090
ECalendarStatus status;
2093
e_return_error_if_fail (uid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2094
e_return_error_if_fail (list != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2095
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2097
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2100
if (priv->load_state != E_CAL_LOAD_LOADED) {
2101
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2104
if (!e_gdbus_cal_call_get_attachment_list_sync (priv->gdbus_cal, uid, rid ? rid: "", &list_array, NULL, error)) {
2105
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2110
for (string = list_array; *string; string++) {
2111
*list = g_slist_append (*list, g_strdup (*string));
2113
g_strfreev (list_array);
2114
status = E_CALENDAR_STATUS_OK;
2116
status = E_CALENDAR_STATUS_OTHER_ERROR;
2118
E_CALENDAR_CHECK_STATUS (status, error);
2123
* @ecal: A calendar client.
2124
* @uid: Unique identifier for a calendar component.
2125
* @rid: Recurrence identifier.
2126
* @icalcomp: Return value for the calendar component object.
2127
* @error: Placeholder for error information.
2129
* Queries a calendar for a calendar component object based on its unique
2132
* Returns: TRUE if the call was successful, FALSE otherwise.
2135
e_cal_get_object (ECal *ecal, const gchar *uid, const gchar *rid, icalcomponent **icalcomp, GError **error)
2138
ECalendarStatus status;
2140
icalcomponent *tmp_icalcomp;
2141
icalcomponent_kind kind;
2143
e_return_error_if_fail (uid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2144
e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2145
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2147
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2150
if (priv->load_state != E_CAL_LOAD_LOADED) {
2151
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2154
if (!e_gdbus_cal_call_get_object_sync (priv->gdbus_cal, uid, rid ? rid : "", &object, NULL, error)) {
2155
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2158
status = E_CALENDAR_STATUS_OK;
2159
tmp_icalcomp = icalparser_parse_string (object);
2160
if (!tmp_icalcomp) {
2161
status = E_CALENDAR_STATUS_INVALID_OBJECT;
2164
kind = icalcomponent_isa (tmp_icalcomp);
2165
if ((kind == ICAL_VEVENT_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_EVENT) ||
2166
(kind == ICAL_VTODO_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_TODO) ||
2167
(kind == ICAL_VJOURNAL_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_JOURNAL)) {
2168
*icalcomp = icalcomponent_new_clone (tmp_icalcomp);
2169
} else if (kind == ICAL_VCALENDAR_COMPONENT) {
2170
icalcomponent *subcomp = NULL;
2172
switch (priv->type) {
2173
case E_CAL_SOURCE_TYPE_EVENT :
2174
subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VEVENT_COMPONENT);
2176
case E_CAL_SOURCE_TYPE_TODO :
2177
subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VTODO_COMPONENT);
2179
case E_CAL_SOURCE_TYPE_JOURNAL :
2180
subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VJOURNAL_COMPONENT);
2183
/* ignore everything else */
2187
/* we are only interested in the first component */
2189
*icalcomp = icalcomponent_new_clone (subcomp);
2192
icalcomponent_free (tmp_icalcomp);
2197
E_CALENDAR_CHECK_STATUS (status, error);
2201
* e_cal_get_objects_for_uid:
2202
* @ecal: A calendar client.
2203
* @uid: Unique identifier for a calendar component.
2204
* @objects: Return value for the list of objects obtained from the backend.
2205
* @error: Placeholder for error information.
2207
* Queries a calendar for all calendar components with the given unique
2208
* ID. This will return any recurring event and all its detached recurrences.
2209
* For non-recurring events, it will just return the object with that ID.
2211
* Returns: TRUE if the call was successful, FALSE otherwise.
2214
e_cal_get_objects_for_uid (ECal *ecal, const gchar *uid, GList **objects, GError **error)
2217
ECalendarStatus status;
2220
e_return_error_if_fail (uid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2221
e_return_error_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2222
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2224
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2227
if (priv->load_state != E_CAL_LOAD_LOADED) {
2228
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2231
if (!e_gdbus_cal_call_get_object_sync (priv->gdbus_cal, uid, "", &object, NULL, error)) {
2232
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2235
status = E_CALENDAR_STATUS_OK;
2237
icalcomponent *icalcomp;
2238
icalcomponent_kind kind;
2240
icalcomp = icalparser_parse_string (object);
2242
status = E_CALENDAR_STATUS_INVALID_OBJECT;
2245
ECalComponent *comp;
2247
kind = icalcomponent_isa (icalcomp);
2248
if ((kind == ICAL_VEVENT_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_EVENT) ||
2249
(kind == ICAL_VTODO_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_TODO) ||
2250
(kind == ICAL_VJOURNAL_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_JOURNAL)) {
2251
comp = e_cal_component_new ();
2252
e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2253
*objects = g_list_append (NULL, comp);
2254
} else if (kind == ICAL_VCALENDAR_COMPONENT) {
2255
icalcomponent *subcomp;
2256
icalcomponent_kind kind_to_find;
2258
switch (priv->type) {
2259
case E_CAL_SOURCE_TYPE_TODO :
2260
kind_to_find = ICAL_VTODO_COMPONENT;
2262
case E_CAL_SOURCE_TYPE_JOURNAL :
2263
kind_to_find = ICAL_VJOURNAL_COMPONENT;
2265
case E_CAL_SOURCE_TYPE_EVENT :
2267
kind_to_find = ICAL_VEVENT_COMPONENT;
2272
subcomp = icalcomponent_get_first_component (icalcomp, kind_to_find);
2274
comp = e_cal_component_new ();
2275
e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
2276
*objects = g_list_append (*objects, comp);
2277
subcomp = icalcomponent_get_next_component (icalcomp, kind_to_find);
2281
icalcomponent_free (icalcomp);
2286
E_CALENDAR_CHECK_STATUS (status, error);
2290
* e_cal_resolve_tzid_cb:
2291
* @tzid: ID of the timezone to resolve.
2292
* @data: Closure data for the callback.
2294
* Resolves TZIDs for the recurrence generator.
2296
* Returns: The timezone identified by the @tzid argument, or %NULL if
2297
* it could not be found.
2300
e_cal_resolve_tzid_cb (const gchar *tzid, gpointer data)
2303
icaltimezone *zone = NULL;
2305
g_return_val_if_fail (data != NULL, NULL);
2306
g_return_val_if_fail (E_IS_CAL (data), NULL);
2308
ecal = E_CAL (data);
2310
/* FIXME: Handle errors. */
2311
e_cal_get_timezone (ecal, tzid, &zone, NULL);
2317
* e_cal_get_changes:
2318
* @ecal: A calendar client.
2319
* @change_id: ID to use for comparing changes.
2320
* @changes: Return value for the list of changes.
2321
* @error: Placeholder for error information.
2323
* Returns a list of changes made to the calendar since a specific time. That time
2324
* is identified by the @change_id argument, which is used by the backend to
2325
* compute the changes done.
2327
* Returns: TRUE if the call was successful, FALSE otherwise.
2330
e_cal_get_changes (ECal *ecal, const gchar *change_id, GList **changes, GError **error)
2333
gchar **additions = NULL, **modifications = NULL, **removals = NULL;
2335
e_return_error_if_fail (changes != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2336
e_return_error_if_fail (change_id != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2337
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2339
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2342
if (priv->load_state != E_CAL_LOAD_LOADED) {
2343
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2346
if (!e_gdbus_cal_call_get_changes_sync (priv->gdbus_cal, change_id, &additions, &modifications, &removals, NULL, error)) {
2347
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2350
/* TODO: Be more elegant and split this into a function */
2351
/* Mostly copied from the old e-cal-listener.c */
2352
if ((additions)&&(modifications)&&(removals)) {
2354
gchar **list = NULL, **l;
2355
ECalChangeType change_type = E_CAL_CHANGE_ADDED;
2356
icalcomponent *icalcomp;
2359
for (i = 0; i < 3; i++) {
2362
change_type = E_CAL_CHANGE_ADDED;
2366
change_type = E_CAL_CHANGE_MODIFIED;
2367
list = modifications;
2370
change_type = E_CAL_CHANGE_DELETED;
2374
for (l = list; *l; l++) {
2375
icalcomp = icalparser_parse_string (*l);
2378
change = g_new (ECalChange, 1);
2379
change->comp = e_cal_component_new ();
2380
if (!e_cal_component_set_icalcomponent (change->comp, icalcomp)) {
2381
icalcomponent_free (icalcomp);
2382
g_object_unref (G_OBJECT (change->comp));
2386
change->type = change_type;
2387
*changes = g_list_append (*changes, change);
2391
g_strfreev (additions);
2392
g_strfreev (modifications);
2393
g_strfreev (removals);
2395
g_strfreev (additions);
2396
g_strfreev (modifications);
2397
g_strfreev (removals);
2399
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
2402
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2406
* e_cal_free_change_list:
2407
* @list: List of changes to be freed.
2409
* Free a list of changes as returned by #e_cal_get_changes.
2412
e_cal_free_change_list (GList *list)
2417
for (l = list; l; l = l->next) {
2420
if (c != NULL && c->comp != NULL) {
2421
g_object_unref (G_OBJECT (c->comp));
2424
g_warn_if_reached ();
2431
* e_cal_get_object_list:
2432
* @ecal: A calendar client.
2433
* @query: Query string.
2434
* @objects: Return value for list of objects.
2435
* @error: Placeholder for error information.
2437
* Gets a list of objects from the calendar that match the query specified
2438
* by the @query argument. The objects will be returned in the @objects
2439
* argument, which is a list of #icalcomponent. When done, this list
2440
* should be freed by using the #e_cal_free_object_list function.
2442
* Returns: TRUE if the operation was successful, FALSE otherwise.
2445
e_cal_get_object_list (ECal *ecal, const gchar *query, GList **objects, GError **error)
2448
gchar **object_array;
2450
e_return_error_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2451
e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
2452
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2454
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2457
if (priv->load_state != E_CAL_LOAD_LOADED) {
2458
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2461
if (!e_gdbus_cal_call_get_object_list_sync (priv->gdbus_cal, query, &object_array, NULL, error)) {
2462
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2466
icalcomponent *comp;
2468
for (object = object_array; *object; object++) {
2469
comp = icalcomponent_new_from_string (*object);
2470
if (!comp) continue;
2471
*objects = g_list_prepend (*objects, comp);
2474
g_strfreev (object_array);
2476
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2479
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
2483
* e_cal_get_object_list_as_comp:
2484
* @ecal: A calendar client.
2485
* @query: Query string.
2486
* @objects: Return value for list of objects.
2487
* @error: Placeholder for error information.
2489
* Gets a list of objects from the calendar that match the query specified
2490
* by the @query argument. The objects will be returned in the @objects
2491
* argument, which is a list of #ECalComponent.
2493
* Returns: TRUE if the operation was successful, FALSE otherwise.
2496
e_cal_get_object_list_as_comp (ECal *ecal, const gchar *query, GList **objects, GError **error)
2498
GList *ical_objects = NULL;
2501
e_return_error_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2504
e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2505
e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
2507
if (!e_cal_get_object_list (ecal, query, &ical_objects, error))
2510
for (l = ical_objects; l; l = l->next) {
2511
ECalComponent *comp;
2513
comp = e_cal_component_new ();
2514
e_cal_component_set_icalcomponent (comp, l->data);
2515
*objects = g_list_prepend (*objects, comp);
2518
g_list_free (ical_objects);
2524
* e_cal_free_object_list:
2525
* @objects: List of objects to be freed.
2527
* Frees a list of objects as returned by #e_cal_get_object_list.
2530
e_cal_free_object_list (GList *objects)
2534
for (l = objects; l; l = l->next)
2535
icalcomponent_free (l->data);
2537
g_list_free (objects);
2541
build_free_busy_list (const gchar **seq)
2546
/* Create the list in reverse order */
2547
for (i = 0; seq[i]; i++) {
2548
ECalComponent *comp;
2549
icalcomponent *icalcomp;
2550
icalcomponent_kind kind;
2552
icalcomp = icalcomponent_new_from_string ((gchar *)seq[i]);
2556
kind = icalcomponent_isa (icalcomp);
2557
if (kind == ICAL_VFREEBUSY_COMPONENT) {
2558
comp = e_cal_component_new ();
2559
if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
2560
icalcomponent_free (icalcomp);
2561
g_object_unref (G_OBJECT (comp));
2565
list = g_list_append (list, comp);
2567
icalcomponent_free (icalcomp);
2575
* e_cal_get_free_busy
2576
* @ecal: A calendar client.
2577
* @users: List of users to retrieve free/busy information for.
2578
* @start: Start time for query.
2579
* @end: End time for query.
2580
* @freebusy: Return value for VFREEBUSY objects.
2581
* @error: Placeholder for error information.
2583
* Gets free/busy information from the calendar server.
2585
* Returns: TRUE if the operation was successful, FALSE otherwise.
2588
e_cal_get_free_busy (ECal *ecal, GList *users, time_t start, time_t end,
2589
GList **freebusy, GError **error)
2593
gchar **freebusy_array;
2597
e_return_error_if_fail (users != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2598
e_return_error_if_fail (freebusy != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2599
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2601
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2604
if (priv->load_state != E_CAL_LOAD_LOADED) {
2605
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2608
users_list = g_new0 (gchar *, g_list_length (users) + 1);
2609
for (l = users, i = 0; l; l = l->next, i++)
2610
users_list[i] = g_strdup (l->data);
2612
if (!e_gdbus_cal_call_get_free_busy_sync (priv->gdbus_cal, (const gchar * const *) users_list, start, end, &freebusy_array, NULL, error)) {
2613
g_strfreev (users_list);
2614
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2616
g_strfreev (users_list);
2618
if (freebusy_array) {
2619
*freebusy = build_free_busy_list ((const gchar **) freebusy_array);
2620
g_strfreev (freebusy_array);
2621
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2623
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
2626
struct comp_instance {
2627
ECalComponent *comp;
2632
struct instances_info {
2634
icaltimezone *start_zone;
2637
/* Called from cal_recur_generate_instances(); adds an instance to the list */
2639
add_instance (ECalComponent *comp, time_t start, time_t end, gpointer data)
2642
struct comp_instance *ci;
2643
struct icaltimetype itt;
2644
icalcomponent *icalcomp;
2645
struct instances_info *instances_hold;
2647
instances_hold = data;
2648
list = instances_hold->instances;
2650
ci = g_new (struct comp_instance, 1);
2652
icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
2654
/* add the instance to the list */
2655
ci->comp = e_cal_component_new ();
2656
e_cal_component_set_icalcomponent (ci->comp, icalcomp);
2658
/* set the RECUR-ID for the instance */
2659
if (e_cal_util_component_has_recurrences (icalcomp)) {
2660
if (!(icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY))) {
2661
ECalComponentRange *range;
2662
ECalComponentDateTime datetime;
2664
e_cal_component_get_dtstart (comp, &datetime);
2666
if (instances_hold->start_zone)
2667
itt = icaltime_from_timet_with_zone (start, datetime.value->is_date, instances_hold->start_zone);
2669
itt = icaltime_from_timet (start, datetime.value->is_date);
2671
if (datetime.tzid) {
2672
g_free ((gchar *) datetime.tzid);
2673
datetime.tzid = NULL;
2677
g_free (datetime.value);
2678
datetime.value = &itt;
2680
range = g_new0 (ECalComponentRange, 1);
2681
range->type = E_CAL_COMPONENT_RANGE_SINGLE;
2682
range->datetime = datetime;
2684
e_cal_component_set_recurid (ci->comp, range);
2687
g_free ((gchar *) datetime.tzid);
2695
*list = g_list_prepend (*list, ci);
2700
/* Used from g_list_sort(); compares two struct comp_instance structures */
2702
compare_comp_instance (gconstpointer a, gconstpointer b)
2704
const struct comp_instance *cia, *cib;
2710
diff = cia->start - cib->start;
2711
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
2715
process_detached_instances (GList *instances, GList *detached_instances)
2717
struct comp_instance *ci, *cid;
2718
GList *dl, *unprocessed_instances = NULL;
2720
for (dl = detached_instances; dl != NULL; dl = dl->next) {
2724
ECalComponentRange recur_id, instance_recur_id;
2729
e_cal_component_get_uid (cid->comp, &uid);
2730
e_cal_component_get_recurid (cid->comp, &recur_id);
2732
/* search for coincident instances already expanded */
2733
for (il = instances; il != NULL; il = il->next) {
2734
const gchar *instance_uid;
2738
e_cal_component_get_uid (ci->comp, &instance_uid);
2739
e_cal_component_get_recurid (ci->comp, &instance_recur_id);
2740
if (strcmp (uid, instance_uid) == 0) {
2741
gchar *i_rid = NULL, *d_rid = NULL;
2743
i_rid = e_cal_component_get_recurid_as_string (ci->comp);
2744
d_rid = e_cal_component_get_recurid_as_string (cid->comp);
2746
if (i_rid && d_rid && strcmp (i_rid, d_rid) == 0) {
2747
g_object_unref (ci->comp);
2748
ci->comp = g_object_ref (cid->comp);
2749
ci->start = cid->start;
2754
if (!instance_recur_id.datetime.value ||
2755
!recur_id.datetime.value) {
2757
* Prevent obvious segfault by ignoring missing
2758
* recurrency ids. Real problem might be elsewhere,
2759
* but anything is better than crashing...
2761
g_log (G_LOG_DOMAIN,
2762
G_LOG_LEVEL_CRITICAL,
2763
"UID %s: instance RECURRENCE-ID %s + detached instance RECURRENCE-ID %s: cannot compare",
2768
e_cal_component_free_datetime (&instance_recur_id.datetime);
2773
cmp = icaltime_compare (*instance_recur_id.datetime.value,
2774
*recur_id.datetime.value);
2775
if ((recur_id.type == E_CAL_COMPONENT_RANGE_THISPRIOR && cmp <= 0) ||
2776
(recur_id.type == E_CAL_COMPONENT_RANGE_THISFUTURE && cmp >= 0)) {
2777
ECalComponent *comp;
2779
comp = e_cal_component_new ();
2780
e_cal_component_set_icalcomponent (
2782
icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
2783
e_cal_component_set_recurid (comp, &instance_recur_id);
2785
/* replace the generated instances */
2786
g_object_unref (ci->comp);
2793
e_cal_component_free_datetime (&instance_recur_id.datetime);
2796
e_cal_component_free_datetime (&recur_id.datetime);
2799
unprocessed_instances = g_list_prepend (unprocessed_instances, cid);
2802
/* add the unprocessed instances (ie, detached instances with no master object */
2803
while (unprocessed_instances != NULL) {
2804
cid = unprocessed_instances->data;
2805
ci = g_new0 (struct comp_instance, 1);
2806
ci->comp = g_object_ref (cid->comp);
2807
ci->start = cid->start;
2809
instances = g_list_append (instances, ci);
2811
unprocessed_instances = g_list_remove (unprocessed_instances, cid);
2818
generate_instances (ECal *ecal, time_t start, time_t end, const gchar *uid,
2819
ECalRecurInstanceFn cb, gpointer cb_data)
2821
GList *objects = NULL;
2822
GList *instances, *detached_instances = NULL;
2825
gchar *iso_start, *iso_end;
2830
/* Generate objects */
2832
GError *error = NULL;
2836
if (!e_cal_get_objects_for_uid (ecal, uid, &objects, &error)) {
2837
if (error->code == E_CALENDAR_STATUS_BUSY && tries >= 10) {
2840
g_clear_error (&error);
2845
unwrap_gerror (&error);
2846
g_message ("Failed to get recurrence objects for uid %s \n", error ? error->message : "Unknown error");
2847
g_clear_error (&error);
2852
iso_start = isodate_from_time_t (start);
2856
iso_end = isodate_from_time_t (end);
2862
query = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))",
2863
iso_start, iso_end);
2866
if (!e_cal_get_object_list_as_comp (ecal, query, &objects, NULL)) {
2875
for (l = objects; l; l = l->next) {
2876
ECalComponent *comp;
2877
icaltimezone *default_zone;
2879
if (priv->default_zone)
2880
default_zone = priv->default_zone;
2882
default_zone = icaltimezone_get_utc_timezone ();
2885
if (e_cal_component_is_instance (comp)) {
2886
struct comp_instance *ci;
2887
ECalComponentDateTime dtstart, dtend;
2888
icaltimezone *start_zone = NULL, *end_zone = NULL;
2890
/* keep the detached instances apart */
2891
ci = g_new0 (struct comp_instance, 1);
2894
e_cal_component_get_dtstart (comp, &dtstart);
2895
e_cal_component_get_dtend (comp, &dtend);
2897
/* For DATE-TIME values with a TZID, we use
2898
e_cal_resolve_tzid_cb to resolve the TZID.
2899
For DATE values and DATE-TIME values without a
2900
TZID (i.e. floating times) we use the default
2902
if (dtstart.tzid && !dtstart.value->is_date) {
2903
start_zone = e_cal_resolve_tzid_cb (dtstart.tzid, ecal);
2905
start_zone = default_zone;
2907
start_zone = default_zone;
2910
if (dtend.tzid && !dtend.value->is_date) {
2911
end_zone = e_cal_resolve_tzid_cb (dtend.tzid, ecal);
2913
end_zone = default_zone;
2915
end_zone = default_zone;
2918
ci->start = icaltime_as_timet_with_zone (*dtstart.value, start_zone);
2921
ci->end = icaltime_as_timet_with_zone (*dtend.value, end_zone);
2922
else if (icaltime_is_date (*dtstart.value))
2923
ci->end = time_day_end (ci->start);
2925
ci->end = ci->start;
2927
e_cal_component_free_datetime (&dtstart);
2928
e_cal_component_free_datetime (&dtend);
2930
if (ci->start <= end && ci->end >= start) {
2931
detached_instances = g_list_prepend (detached_instances, ci);
2933
/* it doesn't fit to our time range, thus skip it */
2934
g_object_unref (G_OBJECT (ci->comp));
2938
ECalComponentDateTime datetime;
2939
icaltimezone *start_zone;
2940
struct instances_info *instances_hold;
2942
/* Get the start timezone */
2943
e_cal_component_get_dtstart (comp, &datetime);
2944
e_cal_get_timezone (ecal, datetime.tzid, &start_zone, NULL);
2945
e_cal_component_free_datetime (&datetime);
2947
instances_hold = g_new0 (struct instances_info, 1);
2948
instances_hold->instances = &instances;
2949
instances_hold->start_zone = start_zone;
2951
e_cal_recur_generate_instances (comp, start, end, add_instance, instances_hold,
2952
e_cal_resolve_tzid_cb, ecal,
2955
g_free (instances_hold);
2956
g_object_unref (comp);
2960
g_list_free (objects);
2962
/* Generate instances and spew them out */
2964
instances = g_list_sort (instances, compare_comp_instance);
2965
instances = process_detached_instances (instances, detached_instances);
2967
for (l = instances; l; l = l->next) {
2968
struct comp_instance *ci;
2973
result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2981
for (l = instances; l; l = l->next) {
2982
struct comp_instance *ci;
2985
g_object_unref (G_OBJECT (ci->comp));
2989
g_list_free (instances);
2991
for (l = detached_instances; l; l = l->next) {
2992
struct comp_instance *ci;
2995
g_object_unref (G_OBJECT (ci->comp));
2999
g_list_free (detached_instances);
3004
* e_cal_generate_instances:
3005
* @ecal: A calendar client.
3006
* @start: Start time for query.
3007
* @end: End time for query.
3008
* @cb: Callback for each generated instance.
3009
* @cb_data: Closure data for the callback.
3011
* Does a combination of #e_cal_get_object_list () and
3012
* #e_cal_recur_generate_instances().
3014
* The callback function should do a g_object_ref() of the calendar component
3015
* it gets passed if it intends to keep it around, since it will be unref'ed
3016
* as soon as the callback returns.
3019
e_cal_generate_instances (ECal *ecal, time_t start, time_t end,
3020
ECalRecurInstanceFn cb, gpointer cb_data)
3024
g_return_if_fail (ecal != NULL);
3025
g_return_if_fail (E_IS_CAL (ecal));
3028
g_return_if_fail (priv->load_state == E_CAL_LOAD_LOADED);
3030
g_return_if_fail (start >= 0);
3031
g_return_if_fail (end >= 0);
3032
g_return_if_fail (cb != NULL);
3034
generate_instances (ecal, start, end, NULL, cb, cb_data);
3038
* e_cal_generate_instances_for_object:
3039
* @ecal: A calendar client.
3040
* @icalcomp: Object to generate instances from.
3041
* @start: Start time for query.
3042
* @end: End time for query.
3043
* @cb: Callback for each generated instance.
3044
* @cb_data: Closure data for the callback.
3046
* Does a combination of #e_cal_get_object_list () and
3047
* #e_cal_recur_generate_instances(), like #e_cal_generate_instances(), but
3048
* for a single object.
3050
* The callback function should do a g_object_ref() of the calendar component
3051
* it gets passed if it intends to keep it around, since it will be unref'ed
3052
* as soon as the callback returns.
3055
e_cal_generate_instances_for_object (ECal *ecal, icalcomponent *icalcomp,
3056
time_t start, time_t end,
3057
ECalRecurInstanceFn cb, gpointer cb_data)
3060
ECalComponent *comp;
3064
GList *instances = NULL;
3065
ECalComponentDateTime datetime;
3066
icaltimezone *start_zone;
3067
struct instances_info *instances_hold;
3068
gboolean is_single_instance = FALSE;
3070
g_return_if_fail (E_IS_CAL (ecal));
3071
g_return_if_fail (start >= 0);
3072
g_return_if_fail (end >= 0);
3073
g_return_if_fail (cb != NULL);
3077
comp = e_cal_component_new ();
3078
e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
3080
if (!e_cal_component_has_recurrences (comp))
3081
is_single_instance = TRUE;
3083
/*If the backend stores it as individual instances and does not
3084
* have a master object - do not expand*/
3085
if (is_single_instance || e_cal_get_static_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
3087
/*return the same instance */
3088
result = (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), ecal->priv->default_zone),
3089
icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), ecal->priv->default_zone), cb_data);
3090
g_object_unref (comp);
3094
e_cal_component_get_uid (comp, &uid);
3095
rid = e_cal_component_get_recurid_as_string (comp);
3097
/* Get the start timezone */
3098
e_cal_component_get_dtstart (comp, &datetime);
3099
e_cal_get_timezone (ecal, datetime.tzid, &start_zone, NULL);
3100
e_cal_component_free_datetime (&datetime);
3102
instances_hold = g_new0 (struct instances_info, 1);
3103
instances_hold->instances = &instances;
3104
instances_hold->start_zone = start_zone;
3106
/* generate all instances in the given time range */
3107
generate_instances (ecal, start, end, uid, add_instance, instances_hold);
3109
instances = *(instances_hold->instances);
3110
/* now only return back the instances for the given object */
3112
while (instances != NULL) {
3113
struct comp_instance *ci;
3114
gchar *instance_rid = NULL;
3116
ci = instances->data;
3119
instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
3122
if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
3123
result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3125
result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3128
/* remove instance from list */
3129
instances = g_list_remove (instances, ci);
3130
g_object_unref (ci->comp);
3132
g_free (instance_rid);
3136
g_object_unref (comp);
3137
g_free (instances_hold);
3141
/* Builds a list of ECalComponentAlarms structures */
3143
build_component_alarms_list (ECal *ecal, GList *object_list, time_t start, time_t end)
3145
GSList *comp_alarms;
3150
for (l = object_list; l != NULL; l = l->next) {
3151
ECalComponent *comp;
3152
ECalComponentAlarms *alarms;
3153
ECalComponentAlarmAction omit[] = {-1};
3155
comp = e_cal_component_new ();
3156
if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) {
3157
g_object_unref (G_OBJECT (comp));
3161
alarms = e_cal_util_generate_alarms_for_comp (comp, start, end, omit, e_cal_resolve_tzid_cb,
3162
ecal, ecal->priv->default_zone);
3164
comp_alarms = g_slist_prepend (comp_alarms, alarms);
3171
* e_cal_get_alarms_in_range:
3172
* @ecal: A calendar client.
3173
* @start: Start time for query.
3174
* @end: End time for query.
3176
* Queries a calendar for the alarms that trigger in the specified range of
3179
* Returns: A list of #ECalComponentAlarms structures. This should be freed
3180
* using the #e_cal_free_alarms() function, or by freeing each element
3181
* separately with #e_cal_component_alarms_free() and then freeing the list with
3185
e_cal_get_alarms_in_range (ECal *ecal, time_t start, time_t end)
3189
gchar *sexp, *iso_start, *iso_end;
3190
GList *object_list = NULL;
3192
g_return_val_if_fail (ecal != NULL, NULL);
3193
g_return_val_if_fail (E_IS_CAL (ecal), NULL);
3196
g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, NULL);
3198
g_return_val_if_fail (start >= 0 && end >= 0, NULL);
3199
g_return_val_if_fail (start <= end, NULL);
3201
iso_start = isodate_from_time_t (start);
3205
iso_end = isodate_from_time_t (end);
3211
/* build the query string */
3212
sexp = g_strdup_printf ("(has-alarms-in-range? (make-time \"%s\") (make-time \"%s\"))",
3213
iso_start, iso_end);
3217
/* execute the query on the server */
3218
if (!e_cal_get_object_list (ecal, sexp, &object_list, NULL)) {
3223
alarms = build_component_alarms_list (ecal, object_list, start, end);
3225
g_list_foreach (object_list, (GFunc) icalcomponent_free, NULL);
3226
g_list_free (object_list);
3233
* e_cal_free_alarms:
3234
* @comp_alarms: A list of #ECalComponentAlarms structures.
3236
* Frees a list of #ECalComponentAlarms structures as returned by
3237
* e_cal_get_alarms_in_range().
3240
e_cal_free_alarms (GSList *comp_alarms)
3244
for (l = comp_alarms; l; l = l->next) {
3245
ECalComponentAlarms *alarms;
3249
e_cal_component_alarms_free (alarms);
3251
g_warn_if_reached ();
3254
g_slist_free (comp_alarms);
3258
* e_cal_get_alarms_for_object:
3259
* @ecal: A calendar client.
3260
* @id: Unique identifier for a calendar component.
3261
* @start: Start time for query.
3262
* @end: End time for query.
3263
* @alarms: Return value for the component's alarm instances. Will return NULL
3264
* if no instances occur within the specified time range. This should be freed
3265
* using the e_cal_component_alarms_free() function.
3267
* Queries a calendar for the alarms of a particular object that trigger in the
3268
* specified range of time.
3270
* Returns: TRUE on success, FALSE if the object was not found.
3273
e_cal_get_alarms_for_object (ECal *ecal, const ECalComponentId *id,
3274
time_t start, time_t end,
3275
ECalComponentAlarms **alarms)
3278
icalcomponent *icalcomp;
3279
ECalComponent *comp;
3280
ECalComponentAlarmAction omit[] = {-1};
3282
g_return_val_if_fail (alarms != NULL, FALSE);
3285
g_return_val_if_fail (ecal != NULL, FALSE);
3286
g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
3289
g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, FALSE);
3291
g_return_val_if_fail (id != NULL, FALSE);
3292
g_return_val_if_fail (start >= 0 && end >= 0, FALSE);
3293
g_return_val_if_fail (start <= end, FALSE);
3295
if (!e_cal_get_object (ecal, id->uid, id->rid, &icalcomp, NULL))
3300
comp = e_cal_component_new ();
3301
if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
3302
icalcomponent_free (icalcomp);
3303
g_object_unref (G_OBJECT (comp));
3307
*alarms = e_cal_util_generate_alarms_for_comp (comp, start, end, omit, e_cal_resolve_tzid_cb,
3308
ecal, priv->default_zone);
3314
* e_cal_discard_alarm
3315
* @ecal: A calendar ecal.
3316
* @comp: The component to discard the alarm from.
3317
* @auid: Unique identifier of the alarm to be discarded.
3318
* @error: Placeholder for error information.
3320
* Tells the calendar backend to get rid of the alarm identified by the
3321
* @auid argument in @comp. Some backends might remove the alarm or
3322
* update internal information about the alarm be discarded, or, like
3323
* the file backend does, ignore the operation.
3325
* Returns: TRUE if the operation was successful, FALSE otherwise.
3328
e_cal_discard_alarm (ECal *ecal, ECalComponent *comp, const gchar *auid, GError **error)
3333
e_return_error_if_fail (ecal != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3334
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3335
e_return_error_if_fail (comp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3336
e_return_error_if_fail (E_IS_CAL_COMPONENT (comp), E_CALENDAR_STATUS_INVALID_ARG);
3337
e_return_error_if_fail (auid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3339
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3341
if (priv->load_state != E_CAL_LOAD_LOADED) {
3342
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3345
e_cal_component_get_uid (comp, &uid);
3347
if (!e_gdbus_cal_call_discard_alarm_sync (priv->gdbus_cal, uid ? uid : "", auid, NULL, error)) {
3348
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3351
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3354
typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
3355
struct _ForeachTZIDCallbackData {
3357
GHashTable *timezone_hash;
3358
gboolean include_all_timezones;
3362
/* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
3365
foreach_tzid_callback (icalparameter *param, gpointer cbdata)
3367
ForeachTZIDCallbackData *data = cbdata;
3371
icalcomponent *vtimezone_comp;
3372
gchar *vtimezone_as_string;
3374
priv = data->ecal->priv;
3376
/* Get the TZID string from the parameter. */
3377
tzid = icalparameter_get_tzid (param);
3381
/* Check if we've already added it to the GHashTable. */
3382
if (g_hash_table_lookup (data->timezone_hash, tzid))
3385
if (data->include_all_timezones) {
3386
if (!e_cal_get_timezone (data->ecal, tzid, &zone, NULL)) {
3387
data->success = FALSE;
3391
/* Check if it is in our cache. If it is, it must already be
3392
on the server so return. */
3393
if (g_hash_table_lookup (priv->timezones, tzid))
3396
/* Check if it is a builtin timezone. If it isn't, return. */
3397
zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
3402
/* Convert it to a string and add it to the hash. */
3403
vtimezone_comp = icaltimezone_get_component (zone);
3404
if (!vtimezone_comp)
3407
vtimezone_as_string = icalcomponent_as_ical_string_r (vtimezone_comp);
3409
g_hash_table_insert (data->timezone_hash, (gchar *) tzid,
3410
vtimezone_as_string);
3413
/* This appends the value string to the GString given in data. */
3415
append_timezone_string (gpointer key, gpointer value, gpointer data)
3417
GString *vcal_string = data;
3419
g_string_append (vcal_string, value);
3423
/* This simply frees the hash values. */
3425
free_timezone_string (gpointer key, gpointer value, gpointer data)
3430
/* This converts the VEVENT/VTODO to a string. If include_all_timezones is
3431
TRUE, it includes all the VTIMEZONE components needed for the VEVENT/VTODO.
3432
If not, it only includes builtin timezones that may not be on the server.
3434
To do that we check every TZID in the component to see if it is a builtin
3435
timezone. If it is, we see if it it in our cache. If it is in our cache,
3436
then we know the server already has it and we don't need to send it.
3437
If it isn't in our cache, then we need to send it to the server.
3438
If we need to send any timezones to the server, then we have to create a
3439
complete VCALENDAR object, otherwise we can just send a single VEVENT/VTODO
3442
e_cal_get_component_as_string_internal (ECal *ecal,
3443
icalcomponent *icalcomp,
3444
gboolean include_all_timezones)
3446
GHashTable *timezone_hash;
3447
GString *vcal_string;
3448
gint initial_vcal_string_len;
3449
ForeachTZIDCallbackData cbdata;
3452
timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
3454
/* Add any timezones needed to the hash. We use a hash since we only
3455
want to add each timezone once at most. */
3457
cbdata.timezone_hash = timezone_hash;
3458
cbdata.include_all_timezones = include_all_timezones;
3459
cbdata.success = TRUE;
3460
icalcomponent_foreach_tzid (icalcomp, foreach_tzid_callback, &cbdata);
3461
if (!cbdata.success) {
3462
g_hash_table_foreach (timezone_hash, free_timezone_string,
3467
/* Create the start of a VCALENDAR, to add the VTIMEZONES to,
3468
and remember its length so we know if any VTIMEZONEs get added. */
3469
vcal_string = g_string_new (NULL);
3470
g_string_append (vcal_string,
3472
"PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
3474
"METHOD:PUBLISH\n");
3475
initial_vcal_string_len = vcal_string->len;
3477
/* Now concatenate all the timezone strings. This also frees the
3478
timezone strings as it goes. */
3479
g_hash_table_foreach (timezone_hash, append_timezone_string,
3482
/* Get the string for the VEVENT/VTODO. */
3483
obj_string = icalcomponent_as_ical_string_r (icalcomp);
3485
/* If there were any timezones to send, create a complete VCALENDAR,
3486
else just send the VEVENT/VTODO string. */
3487
if (!include_all_timezones
3488
&& vcal_string->len == initial_vcal_string_len) {
3489
g_string_free (vcal_string, TRUE);
3491
g_string_append (vcal_string, obj_string);
3492
g_string_append (vcal_string, "END:VCALENDAR\n");
3493
g_free (obj_string);
3494
obj_string = vcal_string->str;
3495
g_string_free (vcal_string, FALSE);
3498
g_hash_table_destroy (timezone_hash);
3504
* e_cal_get_component_as_string:
3505
* @ecal: A calendar client.
3506
* @icalcomp: A calendar component object.
3508
* Gets a calendar component as an iCalendar string, with a toplevel
3509
* VCALENDAR component and all VTIMEZONEs needed for the component.
3511
* Returns: the component as a complete iCalendar string, or NULL on
3512
* failure. The string should be freed after use.
3515
e_cal_get_component_as_string (ECal *ecal, icalcomponent *icalcomp)
3517
return e_cal_get_component_as_string_internal (ecal, icalcomp, TRUE);
3521
* e_cal_create_object:
3522
* @ecal: A calendar client.
3523
* @icalcomp: The component to create.
3524
* @uid: Return value for the UID assigned to the new component by the calendar backend.
3525
* @error: Placeholder for error information.
3527
* Requests the calendar backend to create the object specified by the @icalcomp
3528
* argument. Some backends would assign a specific UID to the newly created object,
3529
* in those cases that UID would be returned in the @uid argument.
3531
* Returns: TRUE if the operation was successful, FALSE otherwise.
3534
e_cal_create_object (ECal *ecal, icalcomponent *icalcomp, gchar **uid, GError **error)
3537
gchar *obj, *muid = NULL;
3539
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3540
e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3541
e_return_error_if_fail (icalcomponent_is_valid (icalcomp), E_CALENDAR_STATUS_INVALID_ARG);
3543
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3545
if (priv->load_state != E_CAL_LOAD_LOADED) {
3546
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3549
obj = icalcomponent_as_ical_string_r (icalcomp);
3550
if (!e_gdbus_cal_call_create_object_sync (priv->gdbus_cal, obj, &muid, NULL, error)) {
3552
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3558
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
3560
icalcomponent_set_uid (icalcomp, muid);
3567
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3572
* e_cal_modify_object:
3573
* @ecal: A calendar client.
3574
* @icalcomp: Component to modify.
3575
* @mod: Type of modification.
3576
* @error: Placeholder for error information.
3578
* Requests the calendar backend to modify an existing object. If the object
3579
* does not exist on the calendar, an error will be returned.
3581
* For recurrent appointments, the @mod argument specifies what to modify,
3582
* if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
3583
* or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
3584
* CALOBJ_MOD_THISANDFUTURE).
3586
* Returns: TRUE if the operation was successful, FALSE otherwise.
3589
e_cal_modify_object (ECal *ecal, icalcomponent *icalcomp, CalObjModType mod, GError **error)
3594
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3595
e_return_error_if_fail (icalcomp, E_CALENDAR_STATUS_INVALID_ARG);
3596
e_return_error_if_fail (icalcomponent_is_valid (icalcomp), E_CALENDAR_STATUS_INVALID_ARG);
3597
e_return_error_if_fail (mod & CALOBJ_MOD_ALL, E_CALENDAR_STATUS_INVALID_ARG);
3599
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3601
if (priv->load_state != E_CAL_LOAD_LOADED) {
3602
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3605
obj = icalcomponent_as_ical_string_r (icalcomp);
3606
if (!e_gdbus_cal_call_modify_object_sync (priv->gdbus_cal, obj, mod, NULL, error)) {
3608
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3612
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3616
* e_cal_remove_object_with_mod:
3617
* @ecal: A calendar client.
3618
* @uid: UID og the object to remove.
3619
* @rid: Recurrence ID of the specific recurrence to remove.
3620
* @mod: Type of removal.
3621
* @error: Placeholder for error information.
3623
* This function allows the removal of instances of a recurrent
3624
* appointment. By using a combination of the @uid, @rid and @mod
3625
* arguments, you can remove specific instances. If what you want
3626
* is to remove all instances, use e_cal_remove_object instead.
3628
* If not all instances are removed, the client will get a "obj_modified"
3629
* signal, while it will get a "obj_removed" signal when all instances
3632
* Returns: TRUE if the operation was successful, FALSE otherwise.
3635
e_cal_remove_object_with_mod (ECal *ecal, const gchar *uid,
3636
const gchar *rid, CalObjModType mod, GError **error)
3640
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3641
e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
3642
e_return_error_if_fail (mod & CALOBJ_MOD_ALL, E_CALENDAR_STATUS_INVALID_ARG);
3644
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3646
if (priv->load_state != E_CAL_LOAD_LOADED) {
3647
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3650
if (!e_gdbus_cal_call_remove_object_sync (priv->gdbus_cal, uid, rid ? rid : "", mod, NULL, error)) {
3651
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3654
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3658
* e_cal_remove_object:
3659
* @ecal: A calendar client.
3660
* @uid: Unique identifier of the calendar component to remove.
3661
* @error: Placeholder for error information.
3663
* Asks a calendar to remove a component. If the server is able to remove the
3664
* component, all clients will be notified and they will emit the "obj_removed"
3667
* Returns: %TRUE if successful, %FALSE otherwise.
3670
e_cal_remove_object (ECal *ecal, const gchar *uid, GError **error)
3672
e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3673
e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
3675
return e_cal_remove_object_with_mod (ecal, uid, NULL, CALOBJ_MOD_THIS, error);
3679
* e_cal_receive_objects:
3680
* @ecal: A calendar client.
3681
* @icalcomp: An icalcomponent.
3682
* @error: Placeholder for error information.
3684
* Makes the backend receive the set of iCalendar objects specified in the
3685
* @icalcomp argument. This is used for iTIP confirmation/cancellation
3686
* messages for scheduled meetings.
3688
* Returns: %TRUE if successful, %FALSE otherwise.
3691
e_cal_receive_objects (ECal *ecal, icalcomponent *icalcomp, GError **error)
3695
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3696
e_return_error_if_fail (icalcomp, E_CALENDAR_STATUS_INVALID_ARG);
3697
e_return_error_if_fail (icalcomponent_is_valid (icalcomp), E_CALENDAR_STATUS_INVALID_ARG);
3699
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3701
if (priv->load_state != E_CAL_LOAD_LOADED) {
3702
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3705
if (!e_gdbus_cal_call_receive_objects_sync (priv->gdbus_cal, icalcomponent_as_ical_string (icalcomp), NULL, error)) {
3706
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3709
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3713
* e_cal_send_objects:
3714
* @ecal: A calendar client.
3715
* @icalcomp: An icalcomponent.
3716
* @users: List of users to send the objects to.
3717
* @modified_icalcomp: Return value for the icalcomponent after all the operations
3719
* @error: Placeholder for error information.
3721
* Requests a calendar backend to send meeting information to the specified list
3724
* Returns: TRUE if the operation was successful, FALSE otherwise.
3727
e_cal_send_objects (ECal *ecal, icalcomponent *icalcomp, GList **users, icalcomponent **modified_icalcomp, GError **error)
3730
ECalendarStatus status;
3731
gchar **users_array;
3734
e_return_error_if_fail (users != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3735
e_return_error_if_fail (modified_icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3736
e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3737
e_return_error_if_fail (icalcomponent_is_valid (icalcomp), E_CALENDAR_STATUS_INVALID_ARG);
3738
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3740
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3742
*modified_icalcomp = NULL;
3744
if (priv->load_state != E_CAL_LOAD_LOADED) {
3745
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3748
if (!e_gdbus_cal_call_send_objects_sync (priv->gdbus_cal, icalcomponent_as_ical_string (icalcomp), &users_array, &object, NULL, error)) {
3749
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3752
status = E_CALENDAR_STATUS_OK;
3755
*modified_icalcomp = icalparser_parse_string (object);
3756
if (!(*modified_icalcomp))
3757
status = E_CALENDAR_STATUS_INVALID_OBJECT;
3759
for (user = users_array; *user; user++)
3760
*users = g_list_append (*users, g_strdup (*user));
3761
g_strfreev (users_array);
3763
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
3765
E_CALENDAR_CHECK_STATUS (status, error);
3769
* e_cal_get_timezone:
3770
* @ecal: A calendar client.
3771
* @tzid: ID of the timezone to retrieve.
3772
* @zone: Return value for the timezone.
3773
* @error: Placeholder for error information.
3775
* Retrieves a timezone object from the calendar backend.
3777
* Returns: TRUE if the operation was successful, FALSE otherwise.
3780
e_cal_get_timezone (ECal *ecal, const gchar *tzid, icaltimezone **zone, GError **error)
3783
ECalendarStatus status = E_CALENDAR_STATUS_OK;
3784
icalcomponent *icalcomp = NULL;
3786
const gchar *systzid = NULL;
3788
e_return_error_if_fail (zone, E_CALENDAR_STATUS_INVALID_ARG);
3789
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3791
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3794
if (priv->load_state != E_CAL_LOAD_LOADED) {
3795
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3798
/* Check for well known zones and in the cache */
3799
/* If tzid is NULL or "" we return NULL, since it is a 'local time'. */
3800
if (!tzid || !tzid[0]) {
3801
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3805
/* If it is UTC, we return the special UTC timezone. */
3806
if (!strcmp (tzid, "UTC")) {
3807
*zone = icaltimezone_get_utc_timezone ();
3809
/* See if we already have it in the cache. */
3810
*zone = g_hash_table_lookup (priv->timezones, tzid);
3815
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3819
* Try to replace the original time zone with a more complete
3820
* and/or potentially updated system time zone. Note that this
3821
* also applies to TZIDs which match system time zones exactly:
3822
* they are extracted via icaltimezone_get_builtin_timezone_from_tzid()
3823
* below without a roundtrip to the backend.
3825
systzid = e_cal_match_tzid (tzid);
3827
/* call the backend */
3828
if (!e_gdbus_cal_call_get_timezone_sync (priv->gdbus_cal, tzid, &object, NULL, error)) {
3830
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3833
icalcomp = icalparser_parse_string (object);
3835
status = E_CALENDAR_STATUS_INVALID_OBJECT;
3839
* Use built-in time zone *and* rename it:
3840
* if the caller is asking for a TZID=FOO,
3841
* then likely because it has an event with
3842
* such a TZID. Returning a different TZID
3843
* would lead to broken VCALENDARs in the
3846
icaltimezone *syszone = icaltimezone_get_builtin_timezone_from_tzid (systzid);
3848
gboolean found = FALSE;
3851
icalcomp = icalcomponent_new_clone (icaltimezone_get_component (syszone));
3852
prop = icalcomponent_get_first_property(icalcomp,
3854
while (!found && prop) {
3855
if (icalproperty_isa(prop) == ICAL_TZID_PROPERTY) {
3856
icalproperty_set_value_from_string(prop, tzid, "NO");
3859
prop = icalcomponent_get_next_property(icalcomp,
3863
status = E_CALENDAR_STATUS_INVALID_OBJECT;
3869
E_CALENDAR_CHECK_STATUS (status, error);
3872
*zone = icaltimezone_new ();
3873
if (!icaltimezone_set_component (*zone, icalcomp)) {
3874
icaltimezone_free (*zone, 1);
3876
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OBJECT_NOT_FOUND, error);
3879
/* Now add it to the cache, to avoid the server call in future. */
3880
g_hash_table_insert (priv->timezones, (gpointer) icaltimezone_get_tzid (*zone), *zone);
3883
E_CALENDAR_CHECK_STATUS (status, error);
3887
* e_cal_add_timezone
3888
* @ecal: A calendar client.
3889
* @izone: The timezone to add.
3890
* @error: Placeholder for error information.
3892
* Add a VTIMEZONE object to the given calendar.
3894
* Returns: TRUE if successful, FALSE otherwise.
3897
e_cal_add_timezone (ECal *ecal, icaltimezone *izone, GError **error)
3901
icalcomponent *icalcomp;
3903
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3904
e_return_error_if_fail (izone, E_CALENDAR_STATUS_INVALID_ARG);
3906
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3908
if (priv->load_state != E_CAL_LOAD_LOADED) {
3909
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3912
/* Make sure we have a valid component - UTC doesn't, nor do
3913
* we really have to add it */
3914
if (izone == icaltimezone_get_utc_timezone ()) {
3915
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3918
icalcomp = icaltimezone_get_component (izone);
3920
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
3923
/* convert icaltimezone into a string */
3924
tzobj = icalcomponent_as_ical_string_r (icalcomp);
3926
/* call the backend */
3927
if (!e_gdbus_cal_call_add_timezone_sync (priv->gdbus_cal, tzobj, NULL, error)) {
3929
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3933
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3938
* @ecal: A calendar client.
3939
* @sexp: S-expression representing the query.
3940
* @query: Return value for the new query.
3941
* @error: Placeholder for error information.
3943
* Creates a live query object from a loaded calendar.
3945
* Returns: A query object that will emit notification signals as calendar
3946
* components are added and removed from the query in the server.
3949
e_cal_get_query (ECal *ecal, const gchar *sexp, ECalView **query, GError **error)
3952
ECalendarStatus status;
3954
EGdbusCalView *gdbus_calview;
3956
e_return_error_if_fail (sexp, E_CALENDAR_STATUS_INVALID_ARG);
3957
e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
3958
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3960
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3963
if (priv->load_state != E_CAL_LOAD_LOADED) {
3964
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3967
if (!e_gdbus_cal_call_get_query_sync (priv->gdbus_cal, sexp, &query_path, NULL, error)) {
3968
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3971
status = E_CALENDAR_STATUS_OK;
3973
gdbus_calview = e_gdbus_cal_view_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy)),
3974
G_DBUS_PROXY_FLAGS_NONE,
3975
"org.gnome.evolution.dataserver.Calendar",
3980
g_free (query_path);
3982
if (!gdbus_calview) {
3984
status = E_CALENDAR_STATUS_OTHER_ERROR;
3986
*query = _e_cal_view_new (ecal, gdbus_calview);
3987
g_object_unref (gdbus_calview);
3990
E_CALENDAR_CHECK_STATUS (status, error);
3994
* e_cal_set_default_timezone:
3995
* @ecal: A calendar client.
3996
* @zone: A timezone object.
3997
* @error: Placeholder for error information.
3999
* Sets the default timezone on the calendar. This should be called before opening
4002
* Returns: TRUE if the operation was successful, FALSE otherwise.
4005
e_cal_set_default_timezone (ECal *ecal, icaltimezone *zone, GError **error)
4008
icalcomponent *icalcomp = NULL;
4011
e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4012
e_return_error_if_fail (zone, E_CALENDAR_STATUS_INVALID_ARG);
4014
e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4016
/* If the same timezone is already set, we don't have to do anything. */
4017
if (priv->default_zone == zone)
4020
/* FIXME Adding it to the server to change the tzid */
4021
icalcomp = icaltimezone_get_component (zone);
4023
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
4026
/* convert icaltimezone into a string */
4027
tzobj = icalcomponent_as_ical_string_r (icalcomp);
4029
/* call the backend */
4030
if (!e_gdbus_cal_call_set_default_timezone_sync (priv->gdbus_cal, tzobj, NULL, error)) {
4032
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4036
priv->default_zone = zone;
4038
E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4042
* e_cal_get_error_message
4043
* @status: A status code.
4045
* Gets an error message for the given status code.
4047
* Returns: the error message.
4050
e_cal_get_error_message (ECalendarStatus status)
4053
case E_CALENDAR_STATUS_INVALID_ARG :
4054
return _("Invalid argument");
4055
case E_CALENDAR_STATUS_BUSY :
4056
return _("Backend is busy");
4057
case E_CALENDAR_STATUS_REPOSITORY_OFFLINE :
4058
return _("Repository is offline");
4059
case E_CALENDAR_STATUS_NO_SUCH_CALENDAR :
4060
return _("No such calendar");
4061
case E_CALENDAR_STATUS_OBJECT_NOT_FOUND :
4062
return _("Object not found");
4063
case E_CALENDAR_STATUS_INVALID_OBJECT :
4064
return _("Invalid object");
4065
case E_CALENDAR_STATUS_URI_NOT_LOADED :
4066
return _("URI not loaded");
4067
case E_CALENDAR_STATUS_URI_ALREADY_LOADED :
4068
return _("URI already loaded");
4069
case E_CALENDAR_STATUS_PERMISSION_DENIED :
4070
return _("Permission denied");
4071
case E_CALENDAR_STATUS_UNKNOWN_USER :
4072
return _("Unknown User");
4073
case E_CALENDAR_STATUS_OBJECT_ID_ALREADY_EXISTS :
4074
return _("Object ID already exists");
4075
case E_CALENDAR_STATUS_PROTOCOL_NOT_SUPPORTED :
4076
return _("Protocol not supported");
4077
case E_CALENDAR_STATUS_CANCELLED :
4078
return _("Operation has been canceled");
4079
case E_CALENDAR_STATUS_COULD_NOT_CANCEL :
4080
return _("Could not cancel operation");
4081
case E_CALENDAR_STATUS_AUTHENTICATION_FAILED :
4082
return _("Authentication failed");
4083
case E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED :
4084
return _("Authentication required");
4085
case E_CALENDAR_STATUS_DBUS_EXCEPTION :
4086
return _("A D-Bus exception has occurred");
4087
case E_CALENDAR_STATUS_OTHER_ERROR :
4088
return _("Unknown error");
4089
case E_CALENDAR_STATUS_OK :
4090
return _("No error");
4091
case E_CALENDAR_STATUS_NOT_SUPPORTED :
4092
return _("Not supported");
4094
/* ignore everything else */
4102
* e_cal_open_default:
4103
* @ecal: A calendar client.
4104
* @type: Type of the calendar.
4105
* @func: Authentication function.
4106
* @data: Closure data for the authentication function.
4107
* @error: Placeholder for error information.
4109
* Opens the default calendar.
4111
* Returns: TRUE if it opened correctly, FALSE otherwise.
4114
e_cal_open_default (ECal **ecal,
4115
ECalSourceType type,
4120
ESourceList *source_list;
4124
g_return_val_if_fail (ecal != NULL, FALSE);
4126
/* In case something goes wrong... */
4129
if (!e_cal_get_sources (&source_list, type, error))
4132
source = e_source_list_peek_default_source (source_list);
4134
g_set_error_literal (error, E_CALENDAR_ERROR,
4135
E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4136
e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));
4137
g_object_unref (source_list);
4141
/* XXX This can fail but doesn't take a GError!? */
4142
client = e_cal_new (source, type);
4144
g_set_error_literal (error, E_CALENDAR_ERROR,
4145
E_CALENDAR_STATUS_OTHER_ERROR,
4146
e_cal_get_error_message (E_CALENDAR_STATUS_OTHER_ERROR));
4147
g_object_unref (source_list);
4151
e_cal_set_auth_func (client, func, data);
4152
if (!e_cal_open (client, TRUE, error)) {
4153
g_object_unref (client);
4154
g_object_unref (source_list);
4160
g_object_unref (source_list);
4166
* e_cal_set_default:
4167
* @ecal: A calendar client.
4168
* @error: Placeholder for error information.
4170
* Sets a calendar as the default one.
4172
* Returns: TRUE if the operation was successful, FALSE otherwise.
4175
e_cal_set_default (ECal *ecal, GError **error)
4179
e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4181
source = e_cal_get_source (ecal);
4183
g_set_error_literal (error, E_CALENDAR_ERROR,
4184
E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4185
e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));
4189
return e_cal_set_default_source (source, ecal->priv->type, error);
4193
set_default_source (ESourceList *sources, ESource *source, GError **error)
4199
uid = e_source_peek_uid (source);
4201
/* make sure the source is actually in the ESourceList. if
4202
it's not we don't bother adding it, just return an error */
4203
source = e_source_list_peek_source_by_uid (sources, uid);
4205
g_set_error_literal (error, E_CALENDAR_ERROR,
4206
E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4207
e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));
4208
g_object_unref (sources);
4212
/* loop over all the sources clearing out any "default"
4213
properties we find */
4214
for (g = e_source_list_peek_groups (sources); g; g = g->next) {
4216
for (s = e_source_group_peek_sources (E_SOURCE_GROUP (g->data));
4218
e_source_set_property (E_SOURCE (s->data), "default", NULL);
4222
/* set the "default" property on the source */
4223
e_source_set_property (source, "default", "true");
4225
if (!e_source_list_sync (sources, &err)) {
4226
g_propagate_error (error, err);
4234
* e_cal_set_default_source:
4235
* @source: An #ESource.
4236
* @type: Type of the source.
4237
* @error: Placeholder for error information.
4239
* Sets the default source for the specified @type.
4241
* Returns: TRUE if the operation was successful, FALSE otherwise.
4244
e_cal_set_default_source (ESource *source, ECalSourceType type, GError **error)
4246
ESourceList *sources;
4249
if (!e_cal_get_sources (&sources, type, &err)) {
4250
g_propagate_error (error, err);
4254
return set_default_source (sources, source, error);
4258
get_sources (ESourceList **sources, const gchar *key, GError **error)
4260
GConfClient *gconf = gconf_client_get_default();
4262
*sources = e_source_list_new_for_gconf (gconf, key);
4263
g_object_unref (gconf);
4269
* e_cal_get_sources:
4270
* @sources: Return value for list of sources.
4271
* @type: Type of the sources to get.
4272
* @error: Placeholder for error information.
4274
* Gets the list of sources defined in the configuration for the given @type.
4276
* Returns: TRUE if the operation was successful, FALSE otherwise.
4279
e_cal_get_sources (ESourceList **sources, ECalSourceType type, GError **error)
4281
e_return_error_if_fail (sources != NULL, E_CALENDAR_STATUS_INVALID_ARG);
4285
case E_CAL_SOURCE_TYPE_EVENT:
4286
return get_sources (sources, "/apps/evolution/calendar/sources", error);
4288
case E_CAL_SOURCE_TYPE_TODO:
4289
return get_sources (sources, "/apps/evolution/tasks/sources", error);
4291
case E_CAL_SOURCE_TYPE_JOURNAL:
4292
return get_sources (sources, "/apps/evolution/memos/sources", error);
4295
g_set_error_literal (error, E_CALENDAR_ERROR,
4296
E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4297
e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));
4301
g_set_error_literal (error, E_CALENDAR_ERROR,
4302
E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4303
e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));