~ubuntu-branches/ubuntu/natty/evolution-data-server/natty

« back to all changes in this revision

Viewing changes to .pc/199-git-backport-2.32.1-to-b08a6a1.patch/calendar/libecal/e-cal.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2011-02-07 14:11:56 UTC
  • mfrom: (1.1.84 upstream)
  • Revision ID: james.westby@ubuntu.com-20110207141156-jakojbbkzee62447
Tags: 2.32.2-0ubuntu1
* New upstream release
* debian/patches/01_various_linking_issues.patch:
* debian/patches/02_fix_sources_migration.patch:
* debian/patches/199-git-backport-2.32.1-b08a6a1_to_2d0f4a3.patch:
* debian/patches/199-git-backport-2.32.1-to-b08a6a1.patch:
* debian/patches/199-git-skip-empty-cache-files-ee21a86.patch:
  - Fixed upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
 
/* Evolution calendar ecal
3
 
 *
4
 
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5
 
 * Copyright (C) 2009 Intel Corporation
6
 
 *
7
 
 * Authors: Federico Mena-Quintero <federico@ximian.com>
8
 
 *          Rodrigo Moya <rodrigo@novell.com>
9
 
 *          Ross Burton <ross@linux.intel.com>
10
 
 *
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.
14
 
 *
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.
19
 
 *
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.
23
 
 */
24
 
 
25
 
/**
26
 
 * SECTION:e-cal
27
 
 *
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.
31
 
 */
32
 
 
33
 
#ifdef HAVE_CONFIG_H
34
 
#include <config.h>
35
 
#endif
36
 
 
37
 
#include <unistd.h>
38
 
#include <string.h>
39
 
#include <glib/gi18n-lib.h>
40
 
 
41
 
#include <libical/ical.h>
42
 
#include <libedataserver/e-url.h>
43
 
#include <libedataserver/e-data-server-util.h>
44
 
 
45
 
#include <glib-object.h>
46
 
 
47
 
#include "libedata-cal/e-data-cal-types.h"
48
 
 
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"
53
 
#include "e-cal.h"
54
 
 
55
 
#include "e-gdbus-egdbuscalfactory.h"
56
 
#include "e-gdbus-egdbuscal.h"
57
 
#include "e-gdbus-egdbuscalview.h"
58
 
 
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)
64
 
 
65
 
#define LOCK_CACHE()   g_static_rec_mutex_lock   (&priv->cache_lock)
66
 
#define UNLOCK_CACHE() g_static_rec_mutex_unlock (&priv->cache_lock)
67
 
 
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))
70
 
 
71
 
static gboolean open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
72
 
        #ifndef E_CAL_DISABLE_DEPRECATED
73
 
        ECalendarStatus *status,
74
 
        #endif
75
 
        gboolean needs_auth, gboolean async);
76
 
static void e_cal_dispose (GObject *object);
77
 
static void e_cal_finalize (GObject *object);
78
 
 
79
 
/* Private part of the ECal structure */
80
 
struct _ECalPrivate {
81
 
        EGdbusCal *gdbus_cal;
82
 
        guint gone_signal_id;
83
 
 
84
 
        /* Load state to avoid multiple loads */
85
 
        ECalLoadState load_state;
86
 
 
87
 
        /* URI of the calendar that is being loaded or is already loaded, or
88
 
         * NULL if we are not loaded.
89
 
         */
90
 
        ESource *source;
91
 
        gchar *uri;
92
 
        ECalSourceType type;
93
 
 
94
 
        /* Email address associated with this calendar, or NULL */
95
 
        gchar *cal_address;
96
 
        gchar *alarm_email_address;
97
 
        gchar *ldap_attribute;
98
 
 
99
 
        /* Scheduling info */
100
 
        gchar *capabilities;
101
 
 
102
 
        gint mode;
103
 
 
104
 
        gboolean read_only;
105
 
 
106
 
        /* The authentication function */
107
 
        ECalAuthFunc auth_func;
108
 
        gpointer auth_user_data;
109
 
 
110
 
        /* A cache of timezones retrieved from the server, to avoid getting
111
 
           them repeatedly for each get_object() call. */
112
 
        GHashTable *timezones;
113
 
 
114
 
        /* The default timezone to use to resolve DATE and floating DATE-TIME
115
 
           values. */
116
 
        icaltimezone *default_zone;
117
 
 
118
 
        gchar *local_attachment_store;
119
 
 
120
 
        /* For locking the operation while localling cache values like 
121
 
           static capabilities, cal address etc. */
122
 
        GStaticRecMutex cache_lock;
123
 
};
124
 
 
125
 
 
126
 
 
127
 
/* Signal IDs */
128
 
enum {
129
 
        #ifndef E_CAL_DISABLE_DEPRECATED
130
 
        CAL_OPENED,
131
 
        #endif
132
 
        CAL_OPENED_EX,
133
 
        CAL_SET_MODE,
134
 
        BACKEND_ERROR,
135
 
        BACKEND_DIED,
136
 
        LAST_SIGNAL
137
 
};
138
 
 
139
 
static guint e_cal_signals[LAST_SIGNAL];
140
 
 
141
 
static GObjectClass *parent_class;
142
 
 
143
 
#ifdef __PRETTY_FUNCTION__
144
 
#define e_return_error_if_fail(expr,error_code) G_STMT_START{           \
145
 
     if G_LIKELY(expr) { } else                                         \
146
 
       {                                                                \
147
 
         g_log (G_LOG_DOMAIN,                                           \
148
 
                G_LOG_LEVEL_CRITICAL,                                   \
149
 
                "file %s: line %d (%s): assertion `%s' failed",         \
150
 
                __FILE__,                                               \
151
 
                __LINE__,                                               \
152
 
                __PRETTY_FUNCTION__,                                    \
153
 
                #expr);                                                 \
154
 
         g_set_error (error, E_CALENDAR_ERROR, (error_code),                \
155
 
                "file %s: line %d (%s): assertion `%s' failed",         \
156
 
                __FILE__,                                               \
157
 
                __LINE__,                                               \
158
 
                __PRETTY_FUNCTION__,                                    \
159
 
                #expr);                                                 \
160
 
         return FALSE;                                                  \
161
 
       };                               }G_STMT_END
162
 
#else
163
 
#define e_return_error_if_fail(expr,error_code) G_STMT_START{           \
164
 
     if G_LIKELY(expr) { } else                                         \
165
 
       {                                                                \
166
 
         g_log (G_LOG_DOMAIN,                                           \
167
 
                G_LOG_LEVEL_CRITICAL,                                   \
168
 
                "file %s: line %d: assertion `%s' failed",              \
169
 
                __FILE__,                                               \
170
 
                __LINE__,                                               \
171
 
                #expr);                                                 \
172
 
         g_set_error (error, E_CALENDAR_ERROR, (error_code),                \
173
 
                "file %s: line %d: assertion `%s' failed",              \
174
 
                __FILE__,                                               \
175
 
                __LINE__,                                               \
176
 
                #expr);                                                 \
177
 
         return FALSE;                                                  \
178
 
       };                               }G_STMT_END
179
 
#endif
180
 
 
181
 
#define E_CALENDAR_CHECK_STATUS(status,error)                           \
182
 
G_STMT_START{                                                           \
183
 
        if ((status) == E_CALENDAR_STATUS_OK)                           \
184
 
                return TRUE;                                            \
185
 
        else {                                                          \
186
 
                const gchar *msg;                                       \
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);   \
191
 
                return FALSE;                                           \
192
 
        }                                                               \
193
 
} G_STMT_END
194
 
 
195
 
 
196
 
 
197
 
/* Error quark */
198
 
GQuark
199
 
e_calendar_error_quark (void)
200
 
{
201
 
        static GQuark q = 0;
202
 
        if (q == 0)
203
 
                q = g_quark_from_static_string ("e-calendar-error-quark");
204
 
 
205
 
        return q;
206
 
}
207
 
 
208
 
/**
209
 
 * If the GError is a remote error, extract the EBookStatus embedded inside.
210
 
 * Otherwise return CORBA_EXCEPTION (I know this is DBus...).
211
 
 */
212
 
static ECalendarStatus
213
 
get_status_from_error (const GError *error)
214
 
{
215
 
        #define err(a,b) "org.gnome.evolution.dataserver.calendar.Cal." a, b
216
 
        static struct {
217
 
                const gchar *name;
218
 
                ECalendarStatus err_code;
219
 
        } errors[] = {
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) }
245
 
        };
246
 
        #undef err
247
 
 
248
 
        if G_LIKELY (error == NULL)
249
 
                return Success;
250
 
 
251
 
        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
252
 
                gchar *name;
253
 
                gint i;
254
 
 
255
 
                name = g_dbus_error_get_remote_error (error);
256
 
 
257
 
                for (i = 0; i < G_N_ELEMENTS (errors); i++) {
258
 
                        if (g_ascii_strcasecmp (errors[i].name, name) == 0) {
259
 
                                g_free (name);
260
 
                                return errors[i].err_code;
261
 
                        }
262
 
                }
263
 
 
264
 
                g_warning ("Unmatched error name %s", name);
265
 
                g_free (name);
266
 
 
267
 
                return E_CALENDAR_STATUS_OTHER_ERROR;
268
 
        } else if (error->domain == E_CALENDAR_ERROR) {
269
 
                return error->code;
270
 
        } else {
271
 
                /* In this case the error was caused by DBus */
272
 
                return E_CALENDAR_STATUS_DBUS_EXCEPTION;
273
 
        }
274
 
}
275
 
 
276
 
/**
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
279
 
 * alone.
280
 
 */
281
 
static gboolean
282
 
unwrap_gerror (GError **error)
283
 
{
284
 
        if (*error == NULL)
285
 
                return TRUE;
286
 
 
287
 
        if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
288
 
                GError *new_error = NULL;
289
 
                gint code;
290
 
 
291
 
                code = get_status_from_error (*error);
292
 
                g_dbus_error_strip_remote_error (*error);
293
 
 
294
 
                new_error = g_error_new_literal (E_CALENDAR_ERROR, code, (*error)->message);
295
 
 
296
 
                g_error_free (*error);
297
 
                *error = new_error;
298
 
        }
299
 
 
300
 
        return FALSE;
301
 
}
302
 
 
303
 
/**
304
 
 * e_cal_source_type_enum_get_type:
305
 
 *
306
 
 * Registers the #ECalSourceTypeEnum type with glib.
307
 
 *
308
 
 * Returns: the ID of the #ECalSourceTypeEnum type.
309
 
 */
310
 
GType
311
 
e_cal_source_type_enum_get_type (void)
312
 
{
313
 
        static volatile gsize enum_type__volatile = 0;
314
 
 
315
 
        if (g_once_init_enter (&enum_type__volatile)) {
316
 
                GType enum_type;
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},
322
 
                        { -1, NULL, NULL}
323
 
                };
324
 
 
325
 
                enum_type = g_enum_register_static ("ECalSourceTypeEnum", values);
326
 
                g_once_init_leave (&enum_type__volatile, enum_type);
327
 
        }
328
 
 
329
 
        return enum_type__volatile;
330
 
}
331
 
 
332
 
/**
333
 
 * e_cal_set_mode_status_enum_get_type:
334
 
 *
335
 
 * Registers the #ECalSetModeStatusEnum type with glib.
336
 
 *
337
 
 * Returns: the ID of the #ECalSetModeStatusEnum type.
338
 
 */
339
 
GType
340
 
e_cal_set_mode_status_enum_get_type (void)
341
 
{
342
 
        static volatile gsize enum_type__volatile = 0;
343
 
 
344
 
        if (g_once_init_enter (&enum_type__volatile)) {
345
 
                GType enum_type;
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" },
350
 
                        { -1,                                   NULL,                              NULL}
351
 
                };
352
 
 
353
 
                enum_type = g_enum_register_static ("ECalSetModeStatusEnum", values);
354
 
                g_once_init_leave (&enum_type__volatile, enum_type);
355
 
        }
356
 
 
357
 
        return enum_type__volatile;
358
 
}
359
 
 
360
 
/**
361
 
 * cal_mode_enum_get_type:
362
 
 *
363
 
 * Registers the #CalModeEnum type with glib.
364
 
 *
365
 
 * Returns: the ID of the #CalModeEnum type.
366
 
 */
367
 
GType
368
 
cal_mode_enum_get_type (void)
369
 
{
370
 
        static volatile gsize enum_type__volatile = 0;
371
 
 
372
 
        if (g_once_init_enter (&enum_type__volatile)) {
373
 
                GType enum_type;
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"     },
379
 
                        { -1,                                   NULL,                              NULL      }
380
 
                };
381
 
 
382
 
                enum_type = g_enum_register_static ("CalModeEnum", values);
383
 
                g_once_init_leave (&enum_type__volatile, enum_type);
384
 
        }
385
 
 
386
 
        return enum_type__volatile;
387
 
}
388
 
 
389
 
static EDataCalObjType
390
 
convert_type (ECalSourceType type)
391
 
{
392
 
        switch (type) {
393
 
        case E_CAL_SOURCE_TYPE_EVENT:
394
 
                return Event;
395
 
        case E_CAL_SOURCE_TYPE_TODO:
396
 
                return Todo;
397
 
        case E_CAL_SOURCE_TYPE_JOURNAL:
398
 
                return Journal;
399
 
        default:
400
 
                return AnyType;
401
 
        }
402
 
 
403
 
        return AnyType;
404
 
}
405
 
static void
406
 
e_cal_init (ECal *ecal)
407
 
{
408
 
        ECalPrivate *priv;
409
 
 
410
 
        LOCK_FACTORY ();
411
 
        active_cals++;
412
 
        UNLOCK_FACTORY ();
413
 
 
414
 
        ecal->priv = priv = E_CAL_GET_PRIVATE (ecal);
415
 
 
416
 
        priv->load_state = E_CAL_LOAD_NOT_LOADED;
417
 
        priv->uri = NULL;
418
 
        priv->local_attachment_store = NULL;
419
 
 
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);
428
 
}
429
 
 
430
 
static void
431
 
gdbus_cal_disconnect (ECal *ecal);
432
 
 
433
 
/*
434
 
 * Called when the calendar server dies.
435
 
 */
436
 
static void
437
 
gdbus_cal_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, ECal *ecal)
438
 
{
439
 
        GError *err = NULL;
440
 
 
441
 
        g_return_if_fail (E_IS_CAL (ecal));
442
 
 
443
 
        if (error) {
444
 
                err = g_error_copy (error);
445
 
                unwrap_gerror (&err);
446
 
        }
447
 
 
448
 
        if (err) {
449
 
                g_debug (G_STRLOC ": ECal GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
450
 
                g_error_free (err);
451
 
        } else {
452
 
                g_debug (G_STRLOC ": ECal GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
453
 
        }
454
 
 
455
 
        gdbus_cal_disconnect (ecal);
456
 
 
457
 
        g_signal_emit (G_OBJECT (ecal), e_cal_signals[BACKEND_DIED], 0);
458
 
}
459
 
 
460
 
static void
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)
462
 
{
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);
466
 
}
467
 
 
468
 
 
469
 
static void
470
 
gdbus_cal_disconnect (ECal *ecal)
471
 
{
472
 
        /* Ensure that everything relevant is NULL */
473
 
        LOCK_FACTORY ();
474
 
 
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));
478
 
 
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;
482
 
 
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;
486
 
 
487
 
                if (error) {
488
 
                        unwrap_gerror (&error);
489
 
 
490
 
                        g_warning ("%s: Failed to close calendar, %s\n", G_STRFUNC, error->message);
491
 
                        g_error_free (error);
492
 
                }
493
 
        }
494
 
        UNLOCK_FACTORY ();
495
 
}
496
 
 
497
 
/* Dispose handler for the calendar ecal */
498
 
static void
499
 
e_cal_dispose (GObject *object)
500
 
{
501
 
        ECal *ecal = E_CAL (object);
502
 
 
503
 
        gdbus_cal_disconnect (ecal);
504
 
 
505
 
        (* G_OBJECT_CLASS (parent_class)->dispose) (object);
506
 
}
507
 
 
508
 
static void
509
 
free_timezone (gpointer key, gpointer value, gpointer data)
510
 
{
511
 
        /* Note that the key comes from within the icaltimezone value, so we
512
 
           don't free that. */
513
 
        icaltimezone_free (value, TRUE);
514
 
}
515
 
 
516
 
/* Finalize handler for the calendar ecal */
517
 
static void
518
 
e_cal_finalize (GObject *object)
519
 
{
520
 
        ECal *ecal;
521
 
        ECalPrivate *priv;
522
 
 
523
 
        g_return_if_fail (object != NULL);
524
 
        g_return_if_fail (E_IS_CAL (object));
525
 
 
526
 
        ecal = E_CAL (object);
527
 
        priv = ecal->priv;
528
 
 
529
 
        priv->load_state = E_CAL_LOAD_NOT_LOADED;
530
 
 
531
 
        if (priv->source) {
532
 
                g_object_unref (priv->source);
533
 
                priv->source = NULL;
534
 
        }
535
 
 
536
 
        if (priv->uri) {
537
 
                g_free (priv->uri);
538
 
                priv->uri = NULL;
539
 
        }
540
 
 
541
 
        if (priv->local_attachment_store) {
542
 
                g_free (priv->local_attachment_store);
543
 
                priv->local_attachment_store = NULL;
544
 
        }
545
 
 
546
 
        if (priv->cal_address) {
547
 
                g_free (priv->cal_address);
548
 
                priv->cal_address = NULL;
549
 
        }
550
 
        if (priv->alarm_email_address) {
551
 
                g_free (priv->alarm_email_address);
552
 
                priv->alarm_email_address = NULL;
553
 
        }
554
 
        if (priv->ldap_attribute) {
555
 
                g_free (priv->ldap_attribute);
556
 
                priv->ldap_attribute = NULL;
557
 
        }
558
 
        if (priv->capabilities) {
559
 
                g_free (priv->capabilities);
560
 
                priv->capabilities = NULL;
561
 
        }
562
 
 
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);
567
 
 
568
 
        (* G_OBJECT_CLASS (parent_class)->finalize) (object);
569
 
 
570
 
        LOCK_FACTORY ();
571
 
        active_cals--;
572
 
        UNLOCK_FACTORY ();
573
 
}
574
 
 
575
 
/* Class initialization function for the calendar ecal */
576
 
static void
577
 
e_cal_class_init (ECalClass *klass)
578
 
{
579
 
        GObjectClass *object_class;
580
 
 
581
 
        object_class = (GObjectClass *) klass;
582
 
 
583
 
        parent_class = g_type_class_peek_parent (klass);
584
 
 
585
 
        #ifndef E_CAL_DISABLE_DEPRECATED
586
 
        e_cal_signals[CAL_OPENED] =
587
 
                g_signal_new ("cal_opened",
588
 
                              G_TYPE_FROM_CLASS (klass),
589
 
                              G_SIGNAL_RUN_FIRST,
590
 
                              G_STRUCT_OFFSET (ECalClass, cal_opened),
591
 
                              NULL, NULL,
592
 
                              g_cclosure_marshal_VOID__INT,
593
 
                              G_TYPE_NONE, 1, G_TYPE_INT);
594
 
        #endif
595
 
 
596
 
        e_cal_signals[CAL_OPENED_EX] =
597
 
                g_signal_new ("cal_opened_ex",
598
 
                              G_TYPE_FROM_CLASS (klass),
599
 
                              G_SIGNAL_RUN_FIRST,
600
 
                              G_STRUCT_OFFSET (ECalClass, cal_opened_ex),
601
 
                              NULL, NULL,
602
 
                              g_cclosure_marshal_VOID__POINTER,
603
 
                              G_TYPE_NONE, 1, G_TYPE_POINTER);
604
 
 
605
 
        e_cal_signals[CAL_SET_MODE] =
606
 
                g_signal_new ("cal_set_mode",
607
 
                              G_TYPE_FROM_CLASS (klass),
608
 
                              G_SIGNAL_RUN_FIRST,
609
 
                              G_STRUCT_OFFSET (ECalClass, cal_set_mode),
610
 
                              NULL, NULL,
611
 
                              e_cal_marshal_VOID__ENUM_ENUM,
612
 
                              G_TYPE_NONE, 2,
613
 
                              E_CAL_SET_MODE_STATUS_ENUM_TYPE,
614
 
                              CAL_MODE_ENUM_TYPE);
615
 
        e_cal_signals[BACKEND_ERROR] =
616
 
                g_signal_new ("backend_error",
617
 
                              G_TYPE_FROM_CLASS (klass),
618
 
                              G_SIGNAL_RUN_FIRST,
619
 
                              G_STRUCT_OFFSET (ECalClass, backend_error),
620
 
                              NULL, NULL,
621
 
                              g_cclosure_marshal_VOID__STRING,
622
 
                              G_TYPE_NONE, 1,
623
 
                              G_TYPE_STRING);
624
 
        e_cal_signals[BACKEND_DIED] =
625
 
                g_signal_new ("backend_died",
626
 
                              G_TYPE_FROM_CLASS (klass),
627
 
                              G_SIGNAL_RUN_FIRST,
628
 
                              G_STRUCT_OFFSET (ECalClass, backend_died),
629
 
                              NULL, NULL,
630
 
                              g_cclosure_marshal_VOID__VOID,
631
 
                              G_TYPE_NONE, 0);
632
 
 
633
 
        #ifndef E_CAL_DISABLE_DEPRECATED
634
 
        klass->cal_opened = NULL;
635
 
        #endif
636
 
        klass->cal_opened_ex = NULL;
637
 
        klass->backend_died = NULL;
638
 
 
639
 
        object_class->dispose = e_cal_dispose;
640
 
        object_class->finalize = e_cal_finalize;
641
 
 
642
 
        g_type_class_add_private (klass, sizeof (ECalPrivate));
643
 
}
644
 
 
645
 
static void
646
 
cal_factory_proxy_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data)
647
 
{
648
 
        GError *err = NULL;
649
 
 
650
 
        LOCK_FACTORY ();
651
 
 
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);
656
 
        }
657
 
 
658
 
        if (cal_factory_proxy) {
659
 
                g_object_unref (cal_factory_proxy);
660
 
                cal_factory_proxy = NULL;
661
 
        }
662
 
 
663
 
        if (error) {
664
 
                err = g_error_copy (error);
665
 
                unwrap_gerror (&err);
666
 
        }
667
 
 
668
 
        if (err) {
669
 
                g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
670
 
                g_error_free (err);
671
 
        } else if (active_cals) {
672
 
                g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
673
 
        }
674
 
 
675
 
        UNLOCK_FACTORY ();
676
 
}
677
 
 
678
 
static void
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)
680
 
{
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);
684
 
}
685
 
 
686
 
/* one-time start up for libecal */
687
 
static gboolean
688
 
e_cal_activate (GError **error)
689
 
{
690
 
        GDBusConnection *connection;
691
 
 
692
 
        LOCK_FACTORY ();
693
 
        if (G_LIKELY (cal_factory_proxy)) {
694
 
                UNLOCK_FACTORY ();
695
 
                return TRUE;
696
 
        }
697
 
 
698
 
        cal_factory_proxy = e_gdbus_cal_factory_proxy_new_for_bus_sync (
699
 
                G_BUS_TYPE_SESSION,
700
 
                G_DBUS_PROXY_FLAGS_NONE,
701
 
                "org.gnome.evolution.dataserver.Calendar",
702
 
                "/org/gnome/evolution/dataserver/calendar/CalFactory",
703
 
                NULL,
704
 
                error);
705
 
 
706
 
        if (!cal_factory_proxy) {
707
 
                UNLOCK_FACTORY ();
708
 
                return FALSE;
709
 
        }
710
 
 
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,
714
 
                NULL,                                           /* sender */
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);
721
 
 
722
 
        g_signal_connect (connection, "closed", G_CALLBACK (cal_factory_proxy_closed_cb), NULL);
723
 
 
724
 
        UNLOCK_FACTORY ();
725
 
 
726
 
        return TRUE;
727
 
}
728
 
 
729
 
static gboolean
730
 
reopen_with_auth (gpointer data)
731
 
{
732
 
        #ifndef E_CAL_DISABLE_DEPRECATED
733
 
        ECalendarStatus status;
734
 
        #endif
735
 
        GError *error = NULL;
736
 
 
737
 
        open_calendar (E_CAL (data), TRUE, &error,
738
 
                #ifndef E_CAL_DISABLE_DEPRECATED
739
 
                &status,
740
 
                #endif
741
 
                TRUE, FALSE);
742
 
 
743
 
        if (error)
744
 
                g_error_free (error);
745
 
 
746
 
        return FALSE;
747
 
}
748
 
 
749
 
static void
750
 
auth_required_cb (EGdbusCal *gdbus_cal, ECal *cal)
751
 
{
752
 
        g_return_if_fail (E_IS_CAL (cal));
753
 
 
754
 
        g_idle_add (reopen_with_auth, (gpointer) cal);
755
 
}
756
 
 
757
 
typedef struct
758
 
{
759
 
        ECal *ecal;
760
 
        gchar *message;
761
 
}  ECalErrorData;
762
 
 
763
 
static gboolean
764
 
backend_error_idle_cb (gpointer data)
765
 
{
766
 
        ECalErrorData *error_data = data;
767
 
 
768
 
        g_signal_emit (G_OBJECT (error_data->ecal), e_cal_signals[BACKEND_ERROR], 0, error_data->message);
769
 
 
770
 
        g_object_unref (error_data->ecal);
771
 
        g_free (error_data->message);
772
 
        g_free (error_data);
773
 
 
774
 
        return FALSE;
775
 
}
776
 
 
777
 
/* Handle the error_occurred signal from the listener */
778
 
static void
779
 
backend_error_cb (EGdbusCal *gdbus_cal, const gchar *message, ECal *ecal)
780
 
{
781
 
        ECalErrorData *error_data;
782
 
 
783
 
        g_return_if_fail (E_IS_CAL (ecal));
784
 
 
785
 
        error_data = g_new0 (ECalErrorData, 1);
786
 
 
787
 
        error_data->ecal = g_object_ref (ecal);
788
 
        error_data->message = g_strdup (message);
789
 
 
790
 
        g_idle_add (backend_error_idle_cb, error_data);
791
 
}
792
 
 
793
 
static void
794
 
readonly_cb (EGdbusCal *gdbus_cal, gboolean read_only, ECal *cal)
795
 
{
796
 
        ECalPrivate *priv;
797
 
 
798
 
        g_return_if_fail (cal && E_IS_CAL (cal));
799
 
 
800
 
        priv = cal->priv;
801
 
        priv->read_only = read_only;
802
 
}
803
 
 
804
 
static void
805
 
mode_cb (EGdbusCal *gdbus_cal, EDataCalMode mode, ECal *cal)
806
 
{
807
 
        g_return_if_fail (E_IS_CAL (cal));
808
 
        g_return_if_fail (mode & AnyMode);
809
 
 
810
 
        g_signal_emit (G_OBJECT (cal), e_cal_signals[CAL_SET_MODE],
811
 
                       0, E_CALENDAR_STATUS_OK, mode);
812
 
}
813
 
 
814
 
/*
815
 
static void
816
 
backend_died_cb (EComponentListener *cl, gpointer user_data)
817
 
{
818
 
        ECalPrivate *priv;
819
 
        ECal *ecal = (ECal *) user_data;
820
 
 
821
 
        priv = ecal->priv;
822
 
        priv->load_state = E_CAL_LOAD_NOT_LOADED;
823
 
        g_signal_emit (G_OBJECT (ecal), e_cal_signals[BACKEND_DIED], 0);
824
 
}*/
825
 
 
826
 
static void
827
 
set_local_attachment_store (ECal *ecal)
828
 
{
829
 
        gchar *cache_dir = NULL;
830
 
        GError *error = NULL;
831
 
 
832
 
        e_gdbus_cal_call_get_cache_dir_sync (
833
 
                ecal->priv->gdbus_cal, &cache_dir, NULL, &error);
834
 
 
835
 
        if (error == NULL)
836
 
                ecal->priv->local_attachment_store = cache_dir;
837
 
        else {
838
 
                unwrap_gerror (&error);
839
 
                g_warning ("%s", error->message);
840
 
                g_error_free (error);
841
 
        }
842
 
}
843
 
 
844
 
/**
845
 
 * e_cal_new:
846
 
 * @source: An #ESource to be used for the client.
847
 
 * @type: Type of the client.
848
 
 *
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.
851
 
 *
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.
854
 
 **/
855
 
ECal *
856
 
e_cal_new (ESource *source, ECalSourceType type)
857
 
{
858
 
        ECal *ecal;
859
 
        ECalPrivate *priv;
860
 
        gchar *path, *xml;
861
 
        GError *error = NULL;
862
 
        GDBusConnection *connection;
863
 
 
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);
866
 
 
867
 
        if (!e_cal_activate (&error)) {
868
 
                unwrap_gerror (&error);
869
 
                g_warning("Cannot activate ECal: %s\n", error ? error->message : "Unknown error");
870
 
                if (error)
871
 
                        g_error_free (error);
872
 
                return NULL;
873
 
        }
874
 
 
875
 
        ecal = g_object_new (E_TYPE_CAL, NULL);
876
 
        priv = ecal->priv;
877
 
 
878
 
        priv->source = g_object_ref (source);
879
 
        priv->uri = e_source_get_uri (source);
880
 
        priv->type = type;
881
 
 
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)) {
884
 
                g_free (xml);
885
 
                unwrap_gerror (&error);
886
 
                g_warning ("Cannot get cal from factory: %s", error ? error->message : "Unknown error");
887
 
                if (error)
888
 
                        g_error_free (error);
889
 
                g_object_unref (ecal);
890
 
                return NULL;
891
 
        }
892
 
        g_free (xml);
893
 
 
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",
897
 
                                                      path,
898
 
                                                      NULL,
899
 
                                                      &error);
900
 
 
901
 
        if (!priv->gdbus_cal) {
902
 
                g_free (path);
903
 
                unwrap_gerror (&error);
904
 
                g_warning ("Cannot create cal proxy: %s", error ? error->message : "Unknown error");
905
 
                if (error)
906
 
                        g_error_free (error);
907
 
                g_object_unref (ecal);
908
 
                return NULL;
909
 
        }
910
 
 
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);
921
 
 
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);
926
 
 
927
 
        /* Set the local attachment store path for the calendar */
928
 
        set_local_attachment_store (ecal);
929
 
 
930
 
        g_free (path);
931
 
 
932
 
        return ecal;
933
 
}
934
 
 
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.
938
 
 
939
 
   'sources' is an output parameter and cannot be NULL. When returned non-NULL, then
940
 
   should be freed with g_object_unref function. */
941
 
static ESource *
942
 
search_known_sources (ECalSourceType type, gboolean (*check_func)(ESource *source, gpointer user_data), gpointer user_data, ESourceList **sources, GError **error)
943
 
{
944
 
        ESource *res = NULL;
945
 
        GSList *g;
946
 
        GError *err = NULL;
947
 
 
948
 
        g_return_val_if_fail (sources != NULL, NULL);
949
 
        g_return_val_if_fail (check_func != NULL, NULL);
950
 
 
951
 
        *sources = NULL;
952
 
 
953
 
        if (!e_cal_get_sources (sources, type, &err)) {
954
 
                g_propagate_error (error, err);
955
 
                return NULL;
956
 
        }
957
 
 
958
 
        for (g = e_source_list_peek_groups (*sources); g; g = g->next) {
959
 
                ESourceGroup *group = E_SOURCE_GROUP (g->data);
960
 
                GSList *s;
961
 
 
962
 
                for (s = e_source_group_peek_sources (group); s; s = s->next) {
963
 
                        ESource *source = E_SOURCE (s->data);
964
 
 
965
 
                        if (check_func (source, user_data)) {
966
 
                                res = g_object_ref (source);
967
 
                                break;
968
 
                        }
969
 
                }
970
 
 
971
 
                if (res)
972
 
                        break;
973
 
        }
974
 
 
975
 
        return res;
976
 
}
977
 
 
978
 
static gboolean
979
 
check_uri (ESource *source, gpointer uri)
980
 
{
981
 
        const gchar *suri;
982
 
 
983
 
        g_return_val_if_fail (source != NULL, FALSE);
984
 
        g_return_val_if_fail (uri != NULL, FALSE);
985
 
 
986
 
        suri = e_source_peek_absolute_uri (source);
987
 
 
988
 
        return suri && g_ascii_strcasecmp (suri, uri) == 0;
989
 
}
990
 
 
991
 
/**
992
 
 * e_cal_new_from_uri:
993
 
 * @uri: The URI pointing to the calendar to open.
994
 
 * @type: Type of the client.
995
 
 *
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.
998
 
 *
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.
1001
 
 **/
1002
 
ECal *
1003
 
e_cal_new_from_uri (const gchar *uri, ECalSourceType type)
1004
 
{
1005
 
        ESourceList *sources = NULL;
1006
 
        ESource *source;
1007
 
        ECal *cal;
1008
 
 
1009
 
        source = search_known_sources (type, check_uri, (gpointer) uri, &sources, NULL);
1010
 
        if (!source)
1011
 
                source = e_source_new_with_absolute_uri ("", uri);
1012
 
 
1013
 
        cal = e_cal_new (source, type);
1014
 
 
1015
 
        g_object_unref (source);
1016
 
        if (sources)
1017
 
                g_object_unref (sources);
1018
 
 
1019
 
        return cal;
1020
 
}
1021
 
 
1022
 
/**
1023
 
 * e_cal_new_system_calendar:
1024
 
 *
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().
1028
 
 *
1029
 
 * Returns: A newly-created calendar client, or %NULL if the client could
1030
 
 * not be constructed.
1031
 
 */
1032
 
ECal *
1033
 
e_cal_new_system_calendar (void)
1034
 
{
1035
 
        return e_cal_new_from_uri ("local:system", E_CAL_SOURCE_TYPE_EVENT);
1036
 
}
1037
 
 
1038
 
/**
1039
 
 * e_cal_new_system_tasks:
1040
 
 *
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().
1044
 
 *
1045
 
 * Returns: A newly-created calendar client, or %NULL if the client could
1046
 
 * not be constructed.
1047
 
 */
1048
 
ECal *
1049
 
e_cal_new_system_tasks (void)
1050
 
{
1051
 
        return e_cal_new_from_uri ("local:system", E_CAL_SOURCE_TYPE_TODO);
1052
 
}
1053
 
 
1054
 
/**
1055
 
 * e_cal_new_system_memos:
1056
 
 *
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().
1060
 
 *
1061
 
 * Returns: A newly-created calendar client, or %NULL if the client could
1062
 
 * not be constructed.
1063
 
 */
1064
 
ECal *
1065
 
e_cal_new_system_memos (void)
1066
 
{
1067
 
        return e_cal_new_from_uri ("local:system", E_CAL_SOURCE_TYPE_JOURNAL);
1068
 
}
1069
 
 
1070
 
/**
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
1075
 
 *
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.
1080
 
 *
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.
1088
 
 *
1089
 
 * The authentication function has the following signature
1090
 
 * (ECalAuthFunc):
1091
 
 *      gchar * auth_func (ECal *ecal,
1092
 
 *                        const gchar *prompt,
1093
 
 *                        const gchar *key,
1094
 
 *                        gpointer user_data)
1095
 
 */
1096
 
void
1097
 
e_cal_set_auth_func (ECal *ecal, ECalAuthFunc func, gpointer data)
1098
 
{
1099
 
        g_return_if_fail (ecal != NULL);
1100
 
        g_return_if_fail (E_IS_CAL (ecal));
1101
 
 
1102
 
        ecal->priv->auth_func = func;
1103
 
        ecal->priv->auth_user_data = data;
1104
 
}
1105
 
 
1106
 
static gchar *
1107
 
build_proxy_pass_key (ECal *ecal, const gchar * parent_user)
1108
 
{
1109
 
        gchar *euri_str;
1110
 
        const gchar *uri;
1111
 
        EUri *euri;
1112
 
 
1113
 
        uri = e_cal_get_uri (ecal);
1114
 
 
1115
 
        euri = e_uri_new (uri);
1116
 
        g_free (euri->user);
1117
 
        euri->user = g_strdup(parent_user);
1118
 
 
1119
 
        euri_str = e_uri_to_string (euri, FALSE);
1120
 
 
1121
 
        e_uri_free (euri);
1122
 
        return euri_str;
1123
 
}
1124
 
 
1125
 
static gchar *
1126
 
build_pass_key (ECal *ecal)
1127
 
{
1128
 
        gchar *euri_str;
1129
 
        const gchar *uri;
1130
 
        EUri *euri;
1131
 
 
1132
 
        uri = e_cal_get_uri (ecal);
1133
 
 
1134
 
        euri = e_uri_new (uri);
1135
 
        euri_str = e_uri_to_string (euri, FALSE);
1136
 
 
1137
 
        e_uri_free (euri);
1138
 
        return euri_str;
1139
 
}
1140
 
 
1141
 
static void
1142
 
async_open_report_result (ECal *ecal, const GError *error)
1143
 
{
1144
 
        #ifndef E_CAL_DISABLE_DEPRECATED
1145
 
        ECalendarStatus status;
1146
 
        #endif
1147
 
 
1148
 
        g_return_if_fail (ecal && E_IS_CAL (ecal));
1149
 
 
1150
 
        if (!error)
1151
 
                ecal->priv->load_state = E_CAL_LOAD_LOADED;
1152
 
 
1153
 
        if (error) {
1154
 
        #ifndef E_CAL_DISABLE_DEPRECATED
1155
 
                status = get_status_from_error (error);
1156
 
        } else {
1157
 
                status = E_CALENDAR_STATUS_OK;
1158
 
        #else
1159
 
        } else {
1160
 
        #endif
1161
 
                e_gdbus_cal_call_is_read_only_sync (ecal->priv->gdbus_cal, NULL, NULL);
1162
 
        }
1163
 
 
1164
 
        #ifndef E_CAL_DISABLE_DEPRECATED
1165
 
        g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, status);
1166
 
        #endif
1167
 
        g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, error);
1168
 
}
1169
 
 
1170
 
static void
1171
 
async_open_ready_cb (EGdbusCal *gdbus_cal, GAsyncResult *res, ECal *ecal)
1172
 
{
1173
 
        GError *error = NULL;
1174
 
 
1175
 
        g_return_if_fail (ecal && E_IS_CAL (ecal));
1176
 
 
1177
 
        e_gdbus_cal_call_open_finish (gdbus_cal, res, &error);
1178
 
 
1179
 
        unwrap_gerror (&error);
1180
 
 
1181
 
        async_open_report_result (ecal, error);
1182
 
 
1183
 
        if (error)
1184
 
                g_error_free (error);
1185
 
}
1186
 
 
1187
 
static gboolean
1188
 
open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
1189
 
        #ifndef E_CAL_DISABLE_DEPRECATED
1190
 
        ECalendarStatus *status,
1191
 
        #endif
1192
 
        gboolean needs_auth, gboolean async)
1193
 
{
1194
 
        ECalPrivate *priv;
1195
 
        gchar *username = NULL, *auth_type = NULL, *password = NULL;
1196
 
 
1197
 
        g_return_val_if_fail (error != NULL, FALSE);
1198
 
 
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);
1201
 
        priv = ecal->priv;
1202
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1203
 
 
1204
 
        if (!needs_auth && priv->load_state == E_CAL_LOAD_LOADED) {
1205
 
                return TRUE;
1206
 
        }
1207
 
 
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;
1211
 
                gchar *parent_user;
1212
 
 
1213
 
                priv->load_state = E_CAL_LOAD_AUTHENTICATING;
1214
 
 
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;
1219
 
                        #endif
1220
 
                        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1221
 
                }
1222
 
 
1223
 
                username = e_source_get_duped_property (priv->source, "username");
1224
 
                if (!username) {
1225
 
                        priv->load_state = E_CAL_LOAD_NOT_LOADED;
1226
 
                        #ifndef E_CAL_DISABLE_DEPRECATED
1227
 
                        *status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1228
 
                        #endif
1229
 
                        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1230
 
                }
1231
 
 
1232
 
                prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
1233
 
                                e_source_peek_name (priv->source), username);
1234
 
 
1235
 
                auth_type = e_source_get_duped_property (priv->source, "auth-type");
1236
 
                if (auth_type)
1237
 
                        key = build_pass_key (ecal);
1238
 
                else {
1239
 
                        parent_user = e_source_get_duped_property (priv->source, "parent_id_name");
1240
 
                        if (parent_user) {
1241
 
                                key = build_proxy_pass_key (ecal, parent_user);
1242
 
                                /*
1243
 
                                   This password prompt will be prompted rarely. Since the key that is passed to
1244
 
                                   the auth_func corresponds to the parent user.
1245
 
                                 */
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);
1248
 
                        } else
1249
 
                                key = g_strdup (e_cal_get_uri (ecal));
1250
 
                }
1251
 
                g_free (auth_type);
1252
 
 
1253
 
                if (!key) {
1254
 
                        priv->load_state = E_CAL_LOAD_NOT_LOADED;
1255
 
                        #ifndef E_CAL_DISABLE_DEPRECATED
1256
 
                        *status = E_CALENDAR_STATUS_URI_NOT_LOADED;
1257
 
                        #endif
1258
 
                        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1259
 
                }
1260
 
 
1261
 
                password = priv->auth_func (ecal, prompt, key, priv->auth_user_data);
1262
 
 
1263
 
                if (!password) {
1264
 
                        priv->load_state = E_CAL_LOAD_NOT_LOADED;
1265
 
                        #ifndef E_CAL_DISABLE_DEPRECATED
1266
 
                        *status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1267
 
                        #endif
1268
 
                        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1269
 
                }
1270
 
 
1271
 
                g_free (prompt);
1272
 
                g_free (key);
1273
 
        }
1274
 
 
1275
 
        priv->load_state = E_CAL_LOAD_LOADING;
1276
 
 
1277
 
        #ifndef E_CAL_DISABLE_DEPRECATED
1278
 
        *status = E_CALENDAR_STATUS_OK;
1279
 
        #endif
1280
 
        if (!async) {
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;
1284
 
                        #endif
1285
 
                }
1286
 
                if (!*error)
1287
 
                        priv->load_state = E_CAL_LOAD_LOADED;
1288
 
        } else {
1289
 
                e_gdbus_cal_call_open (priv->gdbus_cal, only_if_exists, username ? username : "", password ? password : "", NULL, (GAsyncReadyCallback) async_open_ready_cb, ecal);
1290
 
        }
1291
 
 
1292
 
        g_free (password);
1293
 
        g_free (username);
1294
 
 
1295
 
        if (!*error) {
1296
 
                if (!async) {
1297
 
                        GError *err = NULL;
1298
 
 
1299
 
                        e_gdbus_cal_call_is_read_only_sync (ecal->priv->gdbus_cal, NULL, &err);
1300
 
 
1301
 
                        if (err)
1302
 
                                g_error_free (err);
1303
 
                }
1304
 
        } else {
1305
 
                unwrap_gerror (error);
1306
 
                priv->load_state = E_CAL_LOAD_NOT_LOADED;
1307
 
        }
1308
 
 
1309
 
        return *error == NULL;
1310
 
}
1311
 
 
1312
 
/**
1313
 
 * e_cal_open
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.
1320
 
 *
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.
1326
 
 *
1327
 
 * Returns: TRUE on success, FALSE on failure to issue the open request.
1328
 
 **/
1329
 
gboolean
1330
 
e_cal_open (ECal *ecal, gboolean only_if_exists, GError **error)
1331
 
{
1332
 
        #ifndef E_CAL_DISABLE_DEPRECATED
1333
 
        ECalendarStatus status;
1334
 
        #endif
1335
 
        GError *err = NULL;
1336
 
        gboolean result;
1337
 
 
1338
 
        result = open_calendar (ecal, only_if_exists, &err,
1339
 
                #ifndef E_CAL_DISABLE_DEPRECATED
1340
 
                &status,
1341
 
                #endif
1342
 
                FALSE, FALSE);
1343
 
        #ifndef E_CAL_DISABLE_DEPRECATED
1344
 
        g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, status);
1345
 
        #endif
1346
 
        g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, err);
1347
 
 
1348
 
        if (err)
1349
 
                g_propagate_error (error, err);
1350
 
 
1351
 
        return result;
1352
 
}
1353
 
 
1354
 
struct idle_async_error_reply_data
1355
 
{
1356
 
        ECal *ecal; /* ref-ed */
1357
 
        GError *error; /* cannot be NULL */
1358
 
};
1359
 
 
1360
 
static gboolean
1361
 
idle_async_error_reply_cb (gpointer user_data)
1362
 
{
1363
 
        struct idle_async_error_reply_data *data = user_data;
1364
 
 
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);
1368
 
 
1369
 
        async_open_report_result (data->ecal, data->error);
1370
 
 
1371
 
        g_object_unref (data->ecal);
1372
 
        g_error_free (data->error);
1373
 
        g_free (data);
1374
 
 
1375
 
        return FALSE;
1376
 
}
1377
 
 
1378
 
/**
1379
 
 * e_cal_open_async:
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
1383
 
 * exist.
1384
 
 *
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.
1390
 
 *
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.
1394
 
 **/
1395
 
void
1396
 
e_cal_open_async (ECal *ecal, gboolean only_if_exists)
1397
 
{
1398
 
        ECalPrivate *priv;
1399
 
        GError *error = NULL;
1400
 
        #ifndef E_CAL_DISABLE_DEPRECATED
1401
 
        ECalendarStatus status;
1402
 
        #endif
1403
 
 
1404
 
        g_return_if_fail (ecal != NULL);
1405
 
        g_return_if_fail (E_IS_CAL (ecal));
1406
 
 
1407
 
        priv = ecal->priv;
1408
 
 
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);
1414
 
                #endif
1415
 
 
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);
1419
 
                return;
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);
1423
 
                #endif
1424
 
 
1425
 
                g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, NULL);
1426
 
                return;
1427
 
        default:
1428
 
                /* ignore everything else */
1429
 
                break;
1430
 
        }
1431
 
 
1432
 
        open_calendar (ecal, only_if_exists, &error,
1433
 
                #ifndef E_CAL_DISABLE_DEPRECATED
1434
 
                &status,
1435
 
                #endif
1436
 
                FALSE, TRUE);
1437
 
        if (error) {
1438
 
                struct idle_async_error_reply_data *data;
1439
 
 
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);
1444
 
        }
1445
 
}
1446
 
 
1447
 
/**
1448
 
 * e_cal_refresh:
1449
 
 * @ecal: A calendar client.
1450
 
 * @error: Placeholder for error information.
1451
 
 *
1452
 
 * Invokes refresh on a calendar. See @e_cal_get_refresh_supported.
1453
 
 *
1454
 
 * Returns: TRUE if calendar supports refresh and it was invoked, FALSE otherwise.
1455
 
 *
1456
 
 * Since: 2.30
1457
 
 **/
1458
 
gboolean
1459
 
e_cal_refresh (ECal *ecal, GError **error)
1460
 
{
1461
 
        ECalPrivate *priv;
1462
 
 
1463
 
        e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1464
 
        priv = ecal->priv;
1465
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1466
 
 
1467
 
        if (!e_gdbus_cal_call_refresh_sync (priv->gdbus_cal, NULL, error)) {
1468
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1469
 
        }
1470
 
 
1471
 
        return TRUE;
1472
 
}
1473
 
 
1474
 
/**
1475
 
 * e_cal_remove:
1476
 
 * @ecal: A calendar client.
1477
 
 * @error: Placeholder for error information.
1478
 
 *
1479
 
 * Removes a calendar.
1480
 
 *
1481
 
 * Returns: TRUE if the calendar was removed, FALSE if there was an error.
1482
 
 */
1483
 
gboolean
1484
 
e_cal_remove (ECal *ecal, GError **error)
1485
 
{
1486
 
        ECalPrivate *priv;
1487
 
 
1488
 
        e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1489
 
        priv = ecal->priv;
1490
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1491
 
 
1492
 
        if (!e_gdbus_cal_call_remove_sync (priv->gdbus_cal, NULL, error)) {
1493
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1494
 
        }
1495
 
 
1496
 
        return TRUE;
1497
 
}
1498
 
 
1499
 
#if 0
1500
 
/* Builds an URI list out of a CORBA string sequence */
1501
 
static GList *
1502
 
build_uri_list (GNOME_Evolution_Calendar_StringSeq *seq)
1503
 
{
1504
 
        GList *uris = NULL;
1505
 
        gint i;
1506
 
 
1507
 
        for (i = 0; i < seq->_length; i++)
1508
 
                uris = g_list_prepend (uris, g_strdup (seq->_buffer[i]));
1509
 
 
1510
 
        return uris;
1511
 
}
1512
 
#endif
1513
 
 
1514
 
/**
1515
 
 * e_cal_uri_list:
1516
 
 * @ecal: A calendar client.
1517
 
 * @mode: Mode of the URIs to get.
1518
 
 *
1519
 
 * Retrieves a list of all calendar clients for the given mode.
1520
 
 *
1521
 
 * Returns: list of uris.
1522
 
 */
1523
 
GList *
1524
 
e_cal_uri_list (ECal *ecal, CalMode mode)
1525
 
{
1526
 
#if 0
1527
 
        ECalPrivate *priv;
1528
 
        GNOME_Evolution_Calendar_StringSeq *uri_seq;
1529
 
        GList *uris = NULL;
1530
 
        CORBA_Environment ev;
1531
 
        GList *f;
1532
 
 
1533
 
        g_return_val_if_fail (ecal != NULL, NULL);
1534
 
        g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1535
 
 
1536
 
        priv = ecal->priv;
1537
 
 
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);
1541
 
 
1542
 
                if (BONOBO_EX (&ev)) {
1543
 
                        g_message ("e_cal_uri_list(): request failed");
1544
 
 
1545
 
                        /* free memory and return */
1546
 
                        g_list_foreach (uris, (GFunc) g_free, NULL);
1547
 
                        g_list_free (uris);
1548
 
                        uris = NULL;
1549
 
                        break;
1550
 
                }
1551
 
                else {
1552
 
                        uris = g_list_concat (uris, build_uri_list (uri_seq));
1553
 
                        CORBA_free (uri_seq);
1554
 
                }
1555
 
 
1556
 
                CORBA_exception_free (&ev);
1557
 
        }
1558
 
 
1559
 
        return uris;
1560
 
#endif
1561
 
 
1562
 
        return NULL;
1563
 
}
1564
 
 
1565
 
/**
1566
 
 * e_cal_get_source_type:
1567
 
 * @ecal: A calendar client.
1568
 
 *
1569
 
 * Gets the type of the calendar client.
1570
 
 *
1571
 
 * Returns: an #ECalSourceType value corresponding to the type
1572
 
 * of the calendar client.
1573
 
 */
1574
 
ECalSourceType
1575
 
e_cal_get_source_type (ECal *ecal)
1576
 
{
1577
 
        ECalPrivate *priv;
1578
 
 
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);
1581
 
 
1582
 
        priv = ecal->priv;
1583
 
 
1584
 
        return priv->type;
1585
 
}
1586
 
 
1587
 
/**
1588
 
 * e_cal_get_load_state:
1589
 
 * @ecal: A calendar client.
1590
 
 *
1591
 
 * Queries the state of loading of a calendar client.
1592
 
 *
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.
1596
 
 **/
1597
 
ECalLoadState
1598
 
e_cal_get_load_state (ECal *ecal)
1599
 
{
1600
 
        ECalPrivate *priv;
1601
 
 
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);
1604
 
 
1605
 
        priv = ecal->priv;
1606
 
        return priv->load_state;
1607
 
}
1608
 
 
1609
 
/**
1610
 
 * e_cal_get_source:
1611
 
 * @ecal: A calendar client.
1612
 
 *
1613
 
 * Queries the source that is open in a calendar client.
1614
 
 *
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.
1617
 
 **/
1618
 
ESource *
1619
 
e_cal_get_source (ECal *ecal)
1620
 
{
1621
 
        ECalPrivate *priv;
1622
 
 
1623
 
        g_return_val_if_fail (ecal != NULL, NULL);
1624
 
        g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1625
 
 
1626
 
        priv = ecal->priv;
1627
 
        return priv->source;
1628
 
}
1629
 
 
1630
 
/**
1631
 
 * e_cal_get_uri:
1632
 
 * @ecal: A calendar client.
1633
 
 *
1634
 
 * Queries the URI that is open in a calendar client.
1635
 
 *
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.
1638
 
 **/
1639
 
const gchar *
1640
 
e_cal_get_uri (ECal *ecal)
1641
 
{
1642
 
        ECalPrivate *priv;
1643
 
 
1644
 
        g_return_val_if_fail (ecal != NULL, NULL);
1645
 
        g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1646
 
 
1647
 
        priv = ecal->priv;
1648
 
        return priv->uri;
1649
 
}
1650
 
 
1651
 
/**
1652
 
 * e_cal_get_local_attachment_store
1653
 
 * @ecal: A calendar client.
1654
 
 *
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
1659
 
 * operations.
1660
 
 *
1661
 
 * Returns: The URL where the attachments are serialized in the
1662
 
 * local filesystem.
1663
 
 **/
1664
 
const gchar *
1665
 
e_cal_get_local_attachment_store (ECal *ecal)
1666
 
{
1667
 
        ECalPrivate *priv;
1668
 
 
1669
 
        g_return_val_if_fail (ecal != NULL, NULL);
1670
 
        g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1671
 
 
1672
 
        priv = ecal->priv;
1673
 
        return (const gchar *)priv->local_attachment_store;
1674
 
}
1675
 
 
1676
 
/**
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.
1681
 
 *
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.
1685
 
 *
1686
 
 * Returns: TRUE if the call was successful, FALSE if there was an error.
1687
 
 */
1688
 
gboolean
1689
 
e_cal_is_read_only (ECal *ecal, gboolean *read_only, GError **error)
1690
 
{
1691
 
        ECalPrivate *priv;
1692
 
 
1693
 
        if (!(ecal && E_IS_CAL (ecal)))
1694
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
1695
 
 
1696
 
        priv = ecal->priv;
1697
 
        *read_only = priv->read_only;
1698
 
 
1699
 
        return TRUE;
1700
 
}
1701
 
 
1702
 
/**
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.
1707
 
 *
1708
 
 * Queries the calendar address associated with a calendar client.
1709
 
 *
1710
 
 * Returns: TRUE if the operation was successful, FALSE if there
1711
 
 * was an error.
1712
 
 **/
1713
 
gboolean
1714
 
e_cal_get_cal_address (ECal *ecal, gchar **cal_address, GError **error)
1715
 
{
1716
 
        ECalPrivate *priv;
1717
 
 
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);
1720
 
        priv = ecal->priv;
1721
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1722
 
        *cal_address = NULL;
1723
 
 
1724
 
        LOCK_CACHE();
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) {
1728
 
                        UNLOCK_CACHE();
1729
 
                        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
1730
 
                }
1731
 
 
1732
 
                if (!e_gdbus_cal_call_get_cal_address_sync (priv->gdbus_cal, &priv->cal_address, NULL, error)) {
1733
 
                        UNLOCK_CACHE();
1734
 
                        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1735
 
                }
1736
 
        }
1737
 
 
1738
 
        *cal_address = g_strdup (priv->cal_address);
1739
 
        UNLOCK_CACHE();
1740
 
 
1741
 
        return TRUE;
1742
 
}
1743
 
 
1744
 
/**
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.
1749
 
 *
1750
 
 * Queries the address to be used for alarms in a calendar client.
1751
 
 *
1752
 
 * Returns: TRUE if the operation was successful, FALSE if there was
1753
 
 * an error while contacting the backend.
1754
 
 */
1755
 
gboolean
1756
 
e_cal_get_alarm_email_address (ECal *ecal, gchar **alarm_address, GError **error)
1757
 
{
1758
 
        ECalPrivate *priv;
1759
 
 
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);
1762
 
        priv = ecal->priv;
1763
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1764
 
        *alarm_address = NULL;
1765
 
 
1766
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
1767
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
1768
 
        }
1769
 
 
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);
1772
 
        }
1773
 
 
1774
 
        return TRUE;
1775
 
}
1776
 
 
1777
 
/**
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.
1782
 
 *
1783
 
 * Queries the LDAP attribute for a calendar client.
1784
 
 *
1785
 
 * Returns: TRUE if the call was successful, FALSE if there was an
1786
 
 * error contacting the backend.
1787
 
 */
1788
 
gboolean
1789
 
e_cal_get_ldap_attribute (ECal *ecal, gchar **ldap_attribute, GError **error)
1790
 
{
1791
 
        ECalPrivate *priv;
1792
 
 
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);
1795
 
        priv = ecal->priv;
1796
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1797
 
        *ldap_attribute = NULL;
1798
 
 
1799
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
1800
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
1801
 
        }
1802
 
 
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);
1805
 
        }
1806
 
 
1807
 
        return TRUE;
1808
 
}
1809
 
 
1810
 
static gboolean
1811
 
load_static_capabilities (ECal *ecal, GError **error)
1812
 
{
1813
 
        ECalPrivate *priv;
1814
 
 
1815
 
        priv = ecal->priv;
1816
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1817
 
 
1818
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
1819
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
1820
 
        }
1821
 
 
1822
 
        LOCK_CACHE();
1823
 
 
1824
 
        if (priv->capabilities) {
1825
 
                UNLOCK_CACHE();
1826
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
1827
 
        }
1828
 
 
1829
 
        if (!e_gdbus_cal_call_get_scheduling_information_sync (priv->gdbus_cal, &priv->capabilities, NULL, error)) {
1830
 
                UNLOCK_CACHE();
1831
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1832
 
        }
1833
 
 
1834
 
        UNLOCK_CACHE();
1835
 
 
1836
 
        return TRUE;
1837
 
}
1838
 
 
1839
 
static gboolean
1840
 
check_capability (ECal *ecal, const gchar *cap)
1841
 
{
1842
 
        ECalPrivate *priv;
1843
 
 
1844
 
        priv = ecal->priv;
1845
 
 
1846
 
        /* FIXME Check result */
1847
 
        load_static_capabilities (ecal, NULL);
1848
 
        if (priv->capabilities && strstr (priv->capabilities, cap))
1849
 
                return TRUE;
1850
 
 
1851
 
        return FALSE;
1852
 
}
1853
 
 
1854
 
/**
1855
 
 * e_cal_get_one_alarm_only:
1856
 
 * @ecal: A calendar client.
1857
 
 *
1858
 
 * Checks if a calendar supports only one alarm per component.
1859
 
 *
1860
 
 * Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
1861
 
 */
1862
 
gboolean
1863
 
e_cal_get_one_alarm_only (ECal *ecal)
1864
 
{
1865
 
        g_return_val_if_fail (ecal != NULL, FALSE);
1866
 
        g_return_val_if_fail (ecal && E_IS_CAL (ecal), FALSE);
1867
 
 
1868
 
        return check_capability (ecal, CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
1869
 
}
1870
 
 
1871
 
/**
1872
 
 * e_cal_get_organizer_must_attend:
1873
 
 * @ecal: A calendar client.
1874
 
 *
1875
 
 * Checks if a calendar forces organizers of meetings to be also attendees.
1876
 
 *
1877
 
 * Returns: TRUE if the calendar forces organizers to attend meetings,
1878
 
 * FALSE otherwise.
1879
 
 */
1880
 
gboolean
1881
 
e_cal_get_organizer_must_attend (ECal *ecal)
1882
 
{
1883
 
        g_return_val_if_fail (ecal != NULL, FALSE);
1884
 
        g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1885
 
 
1886
 
        return check_capability (ecal, CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
1887
 
}
1888
 
 
1889
 
/**
1890
 
 * e_cal_get_recurrences_no_master:
1891
 
 * @ecal: A calendar client.
1892
 
 *
1893
 
 * Checks if the calendar has a master object for recurrences.
1894
 
 *
1895
 
 * Returns: TRUE if the calendar has a master object for recurrences,
1896
 
 * FALSE otherwise.
1897
 
 */
1898
 
gboolean
1899
 
e_cal_get_recurrences_no_master (ECal *ecal)
1900
 
{
1901
 
        g_return_val_if_fail (ecal != NULL, FALSE);
1902
 
        g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1903
 
 
1904
 
        return check_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
1905
 
}
1906
 
 
1907
 
/**
1908
 
 * e_cal_get_static_capability:
1909
 
 * @ecal: A calendar client.
1910
 
 * @cap: Name of the static capability to check.
1911
 
 *
1912
 
 * Queries the calendar for static capabilities.
1913
 
 *
1914
 
 * Returns: TRUE if the capability is supported, FALSE otherwise.
1915
 
 */
1916
 
gboolean
1917
 
e_cal_get_static_capability (ECal *ecal, const gchar *cap)
1918
 
{
1919
 
        g_return_val_if_fail (ecal != NULL, FALSE);
1920
 
        g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1921
 
 
1922
 
        return check_capability (ecal, cap);
1923
 
}
1924
 
 
1925
 
/**
1926
 
 * e_cal_get_save_schedules:
1927
 
 * @ecal: A calendar client.
1928
 
 *
1929
 
 * Checks whether the calendar saves schedules.
1930
 
 *
1931
 
 * Returns: TRUE if it saves schedules, FALSE otherwise.
1932
 
 */
1933
 
gboolean
1934
 
e_cal_get_save_schedules (ECal *ecal)
1935
 
{
1936
 
        g_return_val_if_fail (ecal != NULL, FALSE);
1937
 
        g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1938
 
 
1939
 
        return check_capability (ecal, CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
1940
 
}
1941
 
 
1942
 
/**
1943
 
 * e_cal_get_organizer_must_accept:
1944
 
 * @ecal: A calendar client.
1945
 
 *
1946
 
 * Checks whether a calendar requires organizer to accept their attendance to
1947
 
 * meetings.
1948
 
 *
1949
 
 * Returns: TRUE if the calendar requires organizers to accept, FALSE
1950
 
 * otherwise.
1951
 
 */
1952
 
gboolean
1953
 
e_cal_get_organizer_must_accept (ECal *ecal)
1954
 
{
1955
 
        g_return_val_if_fail (ecal != NULL, FALSE);
1956
 
        g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1957
 
 
1958
 
        return check_capability (ecal, CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
1959
 
}
1960
 
 
1961
 
/**
1962
 
 * e_cal_get_refresh_supported:
1963
 
 * @ecal: A calendar client.
1964
 
 *
1965
 
 * Checks whether a calendar supports explicit refreshing (see @e_cal_refresh).
1966
 
 *
1967
 
 * Returns: TRUE if the calendar supports refreshing, FALSE otherwise.
1968
 
 *
1969
 
 * Since: 2.30
1970
 
 */
1971
 
gboolean
1972
 
e_cal_get_refresh_supported (ECal *ecal)
1973
 
{
1974
 
        g_return_val_if_fail (ecal != NULL, FALSE);
1975
 
        g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1976
 
 
1977
 
        return check_capability (ecal, CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
1978
 
}
1979
 
 
1980
 
/**
1981
 
 * e_cal_set_mode:
1982
 
 * @ecal: A calendar client.
1983
 
 * @mode: Mode to switch to.
1984
 
 *
1985
 
 * Switches online/offline mode on the calendar.
1986
 
 *
1987
 
 * Returns: TRUE if the switch was successful, FALSE if there was an error.
1988
 
 */
1989
 
gboolean
1990
 
e_cal_set_mode (ECal *ecal, CalMode mode)
1991
 
{
1992
 
        ECalPrivate *priv;
1993
 
        GError *error = NULL;
1994
 
 
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);
1998
 
 
1999
 
        priv = ecal->priv;
2000
 
        g_return_val_if_fail (priv->gdbus_cal, FALSE);
2001
 
        g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, FALSE);
2002
 
 
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");
2006
 
                if (error)
2007
 
                        g_error_free (error);
2008
 
                return FALSE;
2009
 
        }
2010
 
 
2011
 
        return TRUE;
2012
 
}
2013
 
 
2014
 
/* This is used in the callback which fetches all the timezones needed for an
2015
 
   object. */
2016
 
typedef struct _ECalGetTimezonesData ECalGetTimezonesData;
2017
 
struct _ECalGetTimezonesData {
2018
 
        ECal *ecal;
2019
 
 
2020
 
        /* This starts out at E_CALENDAR_STATUS_OK. If an error occurs this
2021
 
           contains the last error. */
2022
 
        ECalendarStatus status;
2023
 
};
2024
 
 
2025
 
/**
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.
2030
 
 *
2031
 
 * Retrives an #icalcomponent from the backend that contains the default
2032
 
 * values for properties needed.
2033
 
 *
2034
 
 * Returns: TRUE if the call was successful, FALSE otherwise.
2035
 
 */
2036
 
gboolean
2037
 
e_cal_get_default_object (ECal *ecal, icalcomponent **icalcomp, GError **error)
2038
 
{
2039
 
        ECalPrivate *priv;
2040
 
        ECalendarStatus status;
2041
 
        gchar *object;
2042
 
 
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);
2045
 
        priv = ecal->priv;
2046
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2047
 
        *icalcomp = NULL;
2048
 
 
2049
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
2050
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2051
 
        }
2052
 
 
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);
2055
 
        }
2056
 
 
2057
 
        if (object) {
2058
 
                *icalcomp = icalparser_parse_string (object);
2059
 
                g_free (object);
2060
 
 
2061
 
                if (!(*icalcomp))
2062
 
                        status = E_CALENDAR_STATUS_INVALID_OBJECT;
2063
 
                else
2064
 
                        status = E_CALENDAR_STATUS_OK;
2065
 
 
2066
 
                E_CALENDAR_CHECK_STATUS (status, error);
2067
 
        } else
2068
 
                status = E_CALENDAR_STATUS_OTHER_ERROR;
2069
 
 
2070
 
        E_CALENDAR_CHECK_STATUS (status, error);
2071
 
}
2072
 
 
2073
 
/**
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.
2080
 
 *
2081
 
 * Queries a calendar for a calendar component object based on its unique
2082
 
 * identifier and gets the attachments for the component.
2083
 
 *
2084
 
 * Returns: TRUE if the call was successful, FALSE otherwise.
2085
 
 **/
2086
 
gboolean
2087
 
e_cal_get_attachments_for_comp (ECal *ecal, const gchar *uid, const gchar *rid, GSList **list, GError **error)
2088
 
{
2089
 
        ECalPrivate *priv;
2090
 
        ECalendarStatus status;
2091
 
        gchar **list_array;
2092
 
 
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);
2096
 
        priv = ecal->priv;
2097
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2098
 
        *list = NULL;
2099
 
 
2100
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
2101
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2102
 
        }
2103
 
 
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);
2106
 
        }
2107
 
 
2108
 
        if (list_array) {
2109
 
                gchar **string;
2110
 
                for (string = list_array; *string; string++) {
2111
 
                        *list = g_slist_append (*list, g_strdup (*string));
2112
 
                }
2113
 
                g_strfreev (list_array);
2114
 
                status = E_CALENDAR_STATUS_OK;
2115
 
        } else
2116
 
                status = E_CALENDAR_STATUS_OTHER_ERROR;
2117
 
 
2118
 
        E_CALENDAR_CHECK_STATUS (status, error);
2119
 
}
2120
 
 
2121
 
/**
2122
 
 * e_cal_get_object:
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.
2128
 
 *
2129
 
 * Queries a calendar for a calendar component object based on its unique
2130
 
 * identifier.
2131
 
 *
2132
 
 * Returns: TRUE if the call was successful, FALSE otherwise.
2133
 
 **/
2134
 
gboolean
2135
 
e_cal_get_object (ECal *ecal, const gchar *uid, const gchar *rid, icalcomponent **icalcomp, GError **error)
2136
 
{
2137
 
        ECalPrivate *priv;
2138
 
        ECalendarStatus status;
2139
 
        gchar *object;
2140
 
        icalcomponent *tmp_icalcomp;
2141
 
        icalcomponent_kind kind;
2142
 
 
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);
2146
 
        priv = ecal->priv;
2147
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2148
 
        *icalcomp = NULL;
2149
 
 
2150
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
2151
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2152
 
        }
2153
 
 
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);
2156
 
        }
2157
 
 
2158
 
        status = E_CALENDAR_STATUS_OK;
2159
 
        tmp_icalcomp = icalparser_parse_string (object);
2160
 
        if (!tmp_icalcomp) {
2161
 
                status = E_CALENDAR_STATUS_INVALID_OBJECT;
2162
 
                *icalcomp = NULL;
2163
 
        } else {
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;
2171
 
 
2172
 
                        switch (priv->type) {
2173
 
                        case E_CAL_SOURCE_TYPE_EVENT :
2174
 
                                subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VEVENT_COMPONENT);
2175
 
                                break;
2176
 
                        case E_CAL_SOURCE_TYPE_TODO :
2177
 
                                subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VTODO_COMPONENT);
2178
 
                                break;
2179
 
                        case E_CAL_SOURCE_TYPE_JOURNAL :
2180
 
                                subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VJOURNAL_COMPONENT);
2181
 
                                break;
2182
 
                        default:
2183
 
                                /* ignore everything else */
2184
 
                                break;
2185
 
                        }
2186
 
 
2187
 
                        /* we are only interested in the first component */
2188
 
                        if (subcomp)
2189
 
                                *icalcomp = icalcomponent_new_clone (subcomp);
2190
 
                }
2191
 
 
2192
 
                icalcomponent_free (tmp_icalcomp);
2193
 
        }
2194
 
 
2195
 
        g_free (object);
2196
 
 
2197
 
        E_CALENDAR_CHECK_STATUS (status, error);
2198
 
}
2199
 
 
2200
 
/**
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.
2206
 
 *
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.
2210
 
 *
2211
 
 * Returns: TRUE if the call was successful, FALSE otherwise.
2212
 
 **/
2213
 
gboolean
2214
 
e_cal_get_objects_for_uid (ECal *ecal, const gchar *uid, GList **objects, GError **error)
2215
 
{
2216
 
        ECalPrivate *priv;
2217
 
        ECalendarStatus status;
2218
 
        gchar *object;
2219
 
 
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);
2223
 
        priv = ecal->priv;
2224
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2225
 
        *objects = NULL;
2226
 
 
2227
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
2228
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2229
 
        }
2230
 
 
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);
2233
 
        }
2234
 
 
2235
 
        status = E_CALENDAR_STATUS_OK;
2236
 
        {
2237
 
                icalcomponent *icalcomp;
2238
 
                icalcomponent_kind kind;
2239
 
 
2240
 
                icalcomp = icalparser_parse_string (object);
2241
 
                if (!icalcomp) {
2242
 
                        status = E_CALENDAR_STATUS_INVALID_OBJECT;
2243
 
                        *objects = NULL;
2244
 
                } else {
2245
 
                        ECalComponent *comp;
2246
 
 
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;
2257
 
 
2258
 
                                switch (priv->type) {
2259
 
                                case E_CAL_SOURCE_TYPE_TODO :
2260
 
                                        kind_to_find = ICAL_VTODO_COMPONENT;
2261
 
                                        break;
2262
 
                                case E_CAL_SOURCE_TYPE_JOURNAL :
2263
 
                                        kind_to_find = ICAL_VJOURNAL_COMPONENT;
2264
 
                                        break;
2265
 
                                case E_CAL_SOURCE_TYPE_EVENT :
2266
 
                                default:
2267
 
                                        kind_to_find = ICAL_VEVENT_COMPONENT;
2268
 
                                        break;
2269
 
                                }
2270
 
 
2271
 
                                *objects = NULL;
2272
 
                                subcomp = icalcomponent_get_first_component (icalcomp, kind_to_find);
2273
 
                                while (subcomp) {
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);
2278
 
                                }
2279
 
                        }
2280
 
 
2281
 
                        icalcomponent_free (icalcomp);
2282
 
                }
2283
 
        }
2284
 
        g_free (object);
2285
 
 
2286
 
        E_CALENDAR_CHECK_STATUS (status, error);
2287
 
}
2288
 
 
2289
 
/**
2290
 
 * e_cal_resolve_tzid_cb:
2291
 
 * @tzid: ID of the timezone to resolve.
2292
 
 * @data: Closure data for the callback.
2293
 
 *
2294
 
 * Resolves TZIDs for the recurrence generator.
2295
 
 *
2296
 
 * Returns: The timezone identified by the @tzid argument, or %NULL if
2297
 
 * it could not be found.
2298
 
 */
2299
 
icaltimezone*
2300
 
e_cal_resolve_tzid_cb (const gchar *tzid, gpointer data)
2301
 
{
2302
 
        ECal *ecal;
2303
 
        icaltimezone *zone = NULL;
2304
 
 
2305
 
        g_return_val_if_fail (data != NULL, NULL);
2306
 
        g_return_val_if_fail (E_IS_CAL (data), NULL);
2307
 
 
2308
 
        ecal = E_CAL (data);
2309
 
 
2310
 
        /* FIXME: Handle errors. */
2311
 
        e_cal_get_timezone (ecal, tzid, &zone, NULL);
2312
 
 
2313
 
        return zone;
2314
 
}
2315
 
 
2316
 
/**
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.
2322
 
 *
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.
2326
 
 *
2327
 
 * Returns: TRUE if the call was successful, FALSE otherwise.
2328
 
 */
2329
 
gboolean
2330
 
e_cal_get_changes (ECal *ecal, const gchar *change_id, GList **changes, GError **error)
2331
 
{
2332
 
        ECalPrivate *priv;
2333
 
        gchar **additions = NULL, **modifications = NULL, **removals = NULL;
2334
 
 
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);
2338
 
        priv = ecal->priv;
2339
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2340
 
        *changes = NULL;
2341
 
 
2342
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
2343
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2344
 
        }
2345
 
 
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);
2348
 
        }
2349
 
 
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)) {
2353
 
                gint i;
2354
 
                gchar **list = NULL, **l;
2355
 
                ECalChangeType change_type = E_CAL_CHANGE_ADDED;
2356
 
                icalcomponent *icalcomp;
2357
 
                ECalChange *change;
2358
 
 
2359
 
                for (i = 0; i < 3; i++) {
2360
 
                        switch (i) {
2361
 
                        case 0:
2362
 
                                change_type = E_CAL_CHANGE_ADDED;
2363
 
                                list = additions;
2364
 
                                break;
2365
 
                        case 1:
2366
 
                                change_type = E_CAL_CHANGE_MODIFIED;
2367
 
                                list = modifications;
2368
 
                                break;
2369
 
                        case 2:
2370
 
                                change_type = E_CAL_CHANGE_DELETED;
2371
 
                                list = removals;
2372
 
                        }
2373
 
 
2374
 
                        for (l = list; *l; l++) {
2375
 
                                icalcomp = icalparser_parse_string (*l);
2376
 
                                if (!icalcomp)
2377
 
                                        continue;
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));
2383
 
                                        g_free (change);
2384
 
                                        continue;
2385
 
                                }
2386
 
                                change->type = change_type;
2387
 
                                *changes = g_list_append (*changes, change);
2388
 
                        }
2389
 
                }
2390
 
 
2391
 
                g_strfreev (additions);
2392
 
                g_strfreev (modifications);
2393
 
                g_strfreev (removals);
2394
 
        } else {
2395
 
                g_strfreev (additions);
2396
 
                g_strfreev (modifications);
2397
 
                g_strfreev (removals);
2398
 
 
2399
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
2400
 
        }
2401
 
 
2402
 
        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2403
 
}
2404
 
 
2405
 
/**
2406
 
 * e_cal_free_change_list:
2407
 
 * @list: List of changes to be freed.
2408
 
 *
2409
 
 * Free a list of changes as returned by #e_cal_get_changes.
2410
 
 */
2411
 
void
2412
 
e_cal_free_change_list (GList *list)
2413
 
{
2414
 
        ECalChange *c;
2415
 
        GList *l;
2416
 
 
2417
 
        for (l = list; l; l = l->next) {
2418
 
                c = l->data;
2419
 
 
2420
 
                if (c != NULL && c->comp != NULL) {
2421
 
                        g_object_unref (G_OBJECT (c->comp));
2422
 
                        g_free (c);
2423
 
                } else
2424
 
                        g_warn_if_reached ();
2425
 
        }
2426
 
 
2427
 
        g_list_free (list);
2428
 
}
2429
 
 
2430
 
/**
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.
2436
 
 *
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.
2441
 
 *
2442
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
2443
 
 **/
2444
 
gboolean
2445
 
e_cal_get_object_list (ECal *ecal, const gchar *query, GList **objects, GError **error)
2446
 
{
2447
 
        ECalPrivate *priv;
2448
 
        gchar **object_array;
2449
 
 
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);
2453
 
        priv = ecal->priv;
2454
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2455
 
        *objects = NULL;
2456
 
 
2457
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
2458
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2459
 
        }
2460
 
 
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);
2463
 
        }
2464
 
 
2465
 
        if (object_array) {
2466
 
                icalcomponent *comp;
2467
 
                gchar **object;
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);
2472
 
                }
2473
 
 
2474
 
                g_strfreev (object_array);
2475
 
 
2476
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2477
 
        }
2478
 
        else
2479
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
2480
 
}
2481
 
 
2482
 
/**
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.
2488
 
 *
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.
2492
 
 *
2493
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
2494
 
 */
2495
 
gboolean
2496
 
e_cal_get_object_list_as_comp (ECal *ecal, const gchar *query, GList **objects, GError **error)
2497
 
{
2498
 
        GList *ical_objects = NULL;
2499
 
        GList *l;
2500
 
 
2501
 
        e_return_error_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2502
 
        *objects = NULL;
2503
 
 
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);
2506
 
 
2507
 
        if (!e_cal_get_object_list (ecal, query, &ical_objects, error))
2508
 
                return FALSE;
2509
 
 
2510
 
        for (l = ical_objects; l; l = l->next) {
2511
 
                ECalComponent *comp;
2512
 
 
2513
 
                comp = e_cal_component_new ();
2514
 
                e_cal_component_set_icalcomponent (comp, l->data);
2515
 
                *objects = g_list_prepend (*objects, comp);
2516
 
        }
2517
 
 
2518
 
        g_list_free (ical_objects);
2519
 
 
2520
 
        return TRUE;
2521
 
}
2522
 
 
2523
 
/**
2524
 
 * e_cal_free_object_list:
2525
 
 * @objects: List of objects to be freed.
2526
 
 *
2527
 
 * Frees a list of objects as returned by #e_cal_get_object_list.
2528
 
 */
2529
 
void
2530
 
e_cal_free_object_list (GList *objects)
2531
 
{
2532
 
        GList *l;
2533
 
 
2534
 
        for (l = objects; l; l = l->next)
2535
 
                icalcomponent_free (l->data);
2536
 
 
2537
 
        g_list_free (objects);
2538
 
}
2539
 
 
2540
 
static GList *
2541
 
build_free_busy_list (const gchar **seq)
2542
 
{
2543
 
        GList *list = NULL;
2544
 
        gint i;
2545
 
 
2546
 
        /* Create the list in reverse order */
2547
 
        for (i = 0; seq[i]; i++) {
2548
 
                ECalComponent *comp;
2549
 
                icalcomponent *icalcomp;
2550
 
                icalcomponent_kind kind;
2551
 
 
2552
 
                icalcomp = icalcomponent_new_from_string ((gchar *)seq[i]);
2553
 
                if (!icalcomp)
2554
 
                        continue;
2555
 
 
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));
2562
 
                                continue;
2563
 
                        }
2564
 
 
2565
 
                        list = g_list_append (list, comp);
2566
 
                } else {
2567
 
                        icalcomponent_free (icalcomp);
2568
 
                }
2569
 
        }
2570
 
 
2571
 
        return list;
2572
 
}
2573
 
 
2574
 
/**
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.
2582
 
 *
2583
 
 * Gets free/busy information from the calendar server.
2584
 
 *
2585
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
2586
 
 */
2587
 
gboolean
2588
 
e_cal_get_free_busy (ECal *ecal, GList *users, time_t start, time_t end,
2589
 
                     GList **freebusy, GError **error)
2590
 
{
2591
 
        ECalPrivate *priv;
2592
 
        gchar **users_list;
2593
 
        gchar **freebusy_array;
2594
 
        GList *l;
2595
 
        gint i;
2596
 
 
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);
2600
 
        priv = ecal->priv;
2601
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2602
 
        *freebusy = NULL;
2603
 
 
2604
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
2605
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2606
 
        }
2607
 
 
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);
2611
 
 
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);
2615
 
        }
2616
 
        g_strfreev (users_list);
2617
 
 
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);
2622
 
        } else
2623
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
2624
 
}
2625
 
 
2626
 
struct comp_instance {
2627
 
        ECalComponent *comp;
2628
 
        time_t start;
2629
 
        time_t end;
2630
 
};
2631
 
 
2632
 
struct instances_info {
2633
 
        GList **instances;
2634
 
        icaltimezone *start_zone;
2635
 
};
2636
 
 
2637
 
/* Called from cal_recur_generate_instances(); adds an instance to the list */
2638
 
static gboolean
2639
 
add_instance (ECalComponent *comp, time_t start, time_t end, gpointer data)
2640
 
{
2641
 
        GList **list;
2642
 
        struct comp_instance *ci;
2643
 
        struct icaltimetype itt;
2644
 
        icalcomponent *icalcomp;
2645
 
        struct instances_info *instances_hold;
2646
 
 
2647
 
        instances_hold = data;
2648
 
        list = instances_hold->instances;
2649
 
 
2650
 
        ci = g_new (struct comp_instance, 1);
2651
 
 
2652
 
        icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
2653
 
 
2654
 
        /* add the instance to the list */
2655
 
        ci->comp = e_cal_component_new ();
2656
 
        e_cal_component_set_icalcomponent (ci->comp, icalcomp);
2657
 
 
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;
2663
 
 
2664
 
                        e_cal_component_get_dtstart (comp, &datetime);
2665
 
 
2666
 
                        if (instances_hold->start_zone)
2667
 
                                itt = icaltime_from_timet_with_zone (start, datetime.value->is_date, instances_hold->start_zone);
2668
 
                        else {
2669
 
                                itt = icaltime_from_timet (start, datetime.value->is_date);
2670
 
 
2671
 
                                if (datetime.tzid) {
2672
 
                                        g_free ((gchar *) datetime.tzid);
2673
 
                                        datetime.tzid = NULL;
2674
 
                                }
2675
 
                        }
2676
 
 
2677
 
                        g_free (datetime.value);
2678
 
                        datetime.value = &itt;
2679
 
 
2680
 
                        range = g_new0 (ECalComponentRange, 1);
2681
 
                        range->type = E_CAL_COMPONENT_RANGE_SINGLE;
2682
 
                        range->datetime = datetime;
2683
 
 
2684
 
                        e_cal_component_set_recurid (ci->comp, range);
2685
 
 
2686
 
                        if (datetime.tzid)
2687
 
                                g_free ((gchar *) datetime.tzid);
2688
 
                        g_free (range);
2689
 
                }
2690
 
        }
2691
 
 
2692
 
        ci->start = start;
2693
 
        ci->end = end;
2694
 
 
2695
 
        *list = g_list_prepend (*list, ci);
2696
 
 
2697
 
        return TRUE;
2698
 
}
2699
 
 
2700
 
/* Used from g_list_sort(); compares two struct comp_instance structures */
2701
 
static gint
2702
 
compare_comp_instance (gconstpointer a, gconstpointer b)
2703
 
{
2704
 
        const struct comp_instance *cia, *cib;
2705
 
        time_t diff;
2706
 
 
2707
 
        cia = a;
2708
 
        cib = b;
2709
 
 
2710
 
        diff = cia->start - cib->start;
2711
 
        return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
2712
 
}
2713
 
 
2714
 
static GList *
2715
 
process_detached_instances (GList *instances, GList *detached_instances)
2716
 
{
2717
 
        struct comp_instance *ci, *cid;
2718
 
        GList *dl, *unprocessed_instances = NULL;
2719
 
 
2720
 
        for (dl = detached_instances; dl != NULL; dl = dl->next) {
2721
 
                GList *il;
2722
 
                const gchar *uid;
2723
 
                gboolean processed;
2724
 
                ECalComponentRange recur_id, instance_recur_id;
2725
 
 
2726
 
                processed = FALSE;
2727
 
 
2728
 
                cid = dl->data;
2729
 
                e_cal_component_get_uid (cid->comp, &uid);
2730
 
                e_cal_component_get_recurid (cid->comp, &recur_id);
2731
 
 
2732
 
                /* search for coincident instances already expanded */
2733
 
                for (il = instances; il != NULL; il = il->next) {
2734
 
                        const gchar *instance_uid;
2735
 
                        gint cmp;
2736
 
 
2737
 
                        ci = il->data;
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;
2742
 
 
2743
 
                                i_rid = e_cal_component_get_recurid_as_string (ci->comp);
2744
 
                                d_rid = e_cal_component_get_recurid_as_string (cid->comp);
2745
 
 
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;
2750
 
                                        ci->end = cid->end;
2751
 
 
2752
 
                                        processed = TRUE;
2753
 
                                } else {
2754
 
                                        if (!instance_recur_id.datetime.value ||
2755
 
                                            !recur_id.datetime.value) {
2756
 
                                                /*
2757
 
                                                 * Prevent obvious segfault by ignoring missing
2758
 
                                                 * recurrency ids. Real problem might be elsewhere,
2759
 
                                                 * but anything is better than crashing...
2760
 
                                                 */
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",
2764
 
                                                       uid,
2765
 
                                                       i_rid,
2766
 
                                                       d_rid);
2767
 
 
2768
 
                                                e_cal_component_free_datetime (&instance_recur_id.datetime);
2769
 
                                                g_free (i_rid);
2770
 
                                                g_free (d_rid);
2771
 
                                                continue;
2772
 
                                        }
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;
2778
 
 
2779
 
                                                comp = e_cal_component_new ();
2780
 
                                                e_cal_component_set_icalcomponent (
2781
 
                                                        comp,
2782
 
                                                        icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
2783
 
                                                e_cal_component_set_recurid (comp, &instance_recur_id);
2784
 
 
2785
 
                                                /* replace the generated instances */
2786
 
                                                g_object_unref (ci->comp);
2787
 
                                                ci->comp = comp;
2788
 
                                        }
2789
 
                                }
2790
 
                                g_free (i_rid);
2791
 
                                g_free (d_rid);
2792
 
                        }
2793
 
                        e_cal_component_free_datetime (&instance_recur_id.datetime);
2794
 
                }
2795
 
 
2796
 
                e_cal_component_free_datetime (&recur_id.datetime);
2797
 
 
2798
 
                if (!processed)
2799
 
                        unprocessed_instances = g_list_prepend (unprocessed_instances, cid);
2800
 
        }
2801
 
 
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;
2808
 
                ci->end = cid->end;
2809
 
                instances = g_list_append (instances, ci);
2810
 
 
2811
 
                unprocessed_instances = g_list_remove (unprocessed_instances, cid);
2812
 
        }
2813
 
 
2814
 
        return instances;
2815
 
}
2816
 
 
2817
 
static void
2818
 
generate_instances (ECal *ecal, time_t start, time_t end, const gchar *uid,
2819
 
                    ECalRecurInstanceFn cb, gpointer cb_data)
2820
 
{
2821
 
        GList *objects = NULL;
2822
 
        GList *instances, *detached_instances = NULL;
2823
 
        GList *l;
2824
 
        gchar *query;
2825
 
        gchar *iso_start, *iso_end;
2826
 
        ECalPrivate *priv;
2827
 
 
2828
 
        priv = ecal->priv;
2829
 
 
2830
 
        /* Generate objects */
2831
 
        if (uid && *uid) {
2832
 
                GError *error = NULL;
2833
 
                gint tries = 0;
2834
 
 
2835
 
try_again:
2836
 
                if (!e_cal_get_objects_for_uid (ecal, uid, &objects, &error)) {
2837
 
                        if (error->code == E_CALENDAR_STATUS_BUSY && tries >= 10) {
2838
 
                                tries++;
2839
 
                                g_usleep (500);
2840
 
                                g_clear_error (&error);
2841
 
 
2842
 
                                goto try_again;
2843
 
                        }
2844
 
 
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);
2848
 
                        return;
2849
 
                }
2850
 
        }
2851
 
        else {
2852
 
                iso_start = isodate_from_time_t (start);
2853
 
                if (!iso_start)
2854
 
                        return;
2855
 
 
2856
 
                iso_end = isodate_from_time_t (end);
2857
 
                if (!iso_end) {
2858
 
                        g_free (iso_start);
2859
 
                        return;
2860
 
                }
2861
 
 
2862
 
                query = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))",
2863
 
                                         iso_start, iso_end);
2864
 
                g_free (iso_start);
2865
 
                g_free (iso_end);
2866
 
                if (!e_cal_get_object_list_as_comp (ecal, query, &objects, NULL)) {
2867
 
                        g_free (query);
2868
 
                        return;
2869
 
                }
2870
 
                g_free (query);
2871
 
        }
2872
 
 
2873
 
        instances = NULL;
2874
 
 
2875
 
        for (l = objects; l; l = l->next) {
2876
 
                ECalComponent *comp;
2877
 
                icaltimezone *default_zone;
2878
 
 
2879
 
                if (priv->default_zone)
2880
 
                        default_zone = priv->default_zone;
2881
 
                else
2882
 
                        default_zone = icaltimezone_get_utc_timezone ();
2883
 
 
2884
 
                comp = l->data;
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;
2889
 
 
2890
 
                        /* keep the detached instances apart */
2891
 
                        ci = g_new0 (struct comp_instance, 1);
2892
 
                        ci->comp = comp;
2893
 
 
2894
 
                        e_cal_component_get_dtstart (comp, &dtstart);
2895
 
                        e_cal_component_get_dtend (comp, &dtend);
2896
 
 
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
2901
 
                        timezone. */
2902
 
                        if (dtstart.tzid && !dtstart.value->is_date) {
2903
 
                                start_zone = e_cal_resolve_tzid_cb (dtstart.tzid, ecal);
2904
 
                                if (!start_zone)
2905
 
                                        start_zone = default_zone;
2906
 
                        } else {
2907
 
                                start_zone = default_zone;
2908
 
                        }
2909
 
 
2910
 
                        if (dtend.tzid && !dtend.value->is_date) {
2911
 
                                end_zone = e_cal_resolve_tzid_cb (dtend.tzid, ecal);
2912
 
                                if (!end_zone)
2913
 
                                        end_zone = default_zone;
2914
 
                        } else {
2915
 
                                end_zone = default_zone;
2916
 
                        }
2917
 
 
2918
 
                        ci->start = icaltime_as_timet_with_zone (*dtstart.value, start_zone);
2919
 
 
2920
 
                        if (dtend.value)
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);
2924
 
                        else
2925
 
                                ci->end = ci->start;
2926
 
 
2927
 
                        e_cal_component_free_datetime (&dtstart);
2928
 
                        e_cal_component_free_datetime (&dtend);
2929
 
 
2930
 
                        if (ci->start <= end && ci->end >= start) {
2931
 
                                detached_instances = g_list_prepend (detached_instances, ci);
2932
 
                        } else {
2933
 
                                /* it doesn't fit to our time range, thus skip it */
2934
 
                                g_object_unref (G_OBJECT (ci->comp));
2935
 
                                g_free (ci);
2936
 
                        }
2937
 
                } else {
2938
 
                        ECalComponentDateTime datetime;
2939
 
                        icaltimezone *start_zone;
2940
 
                        struct instances_info *instances_hold;
2941
 
 
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);
2946
 
 
2947
 
                        instances_hold = g_new0 (struct instances_info, 1);
2948
 
                        instances_hold->instances = &instances;
2949
 
                        instances_hold->start_zone = start_zone;
2950
 
 
2951
 
                        e_cal_recur_generate_instances (comp, start, end, add_instance, instances_hold,
2952
 
                                                        e_cal_resolve_tzid_cb, ecal,
2953
 
                                                        default_zone);
2954
 
 
2955
 
                        g_free (instances_hold);
2956
 
                        g_object_unref (comp);
2957
 
                }
2958
 
        }
2959
 
 
2960
 
        g_list_free (objects);
2961
 
 
2962
 
        /* Generate instances and spew them out */
2963
 
 
2964
 
        instances = g_list_sort (instances, compare_comp_instance);
2965
 
        instances = process_detached_instances (instances, detached_instances);
2966
 
 
2967
 
        for (l = instances; l; l = l->next) {
2968
 
                struct comp_instance *ci;
2969
 
                gboolean result;
2970
 
 
2971
 
                ci = l->data;
2972
 
 
2973
 
                result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2974
 
 
2975
 
                if (!result)
2976
 
                        break;
2977
 
        }
2978
 
 
2979
 
        /* Clean up */
2980
 
 
2981
 
        for (l = instances; l; l = l->next) {
2982
 
                struct comp_instance *ci;
2983
 
 
2984
 
                ci = l->data;
2985
 
                g_object_unref (G_OBJECT (ci->comp));
2986
 
                g_free (ci);
2987
 
        }
2988
 
 
2989
 
        g_list_free (instances);
2990
 
 
2991
 
        for (l = detached_instances; l; l = l->next) {
2992
 
                struct comp_instance *ci;
2993
 
 
2994
 
                ci = l->data;
2995
 
                g_object_unref (G_OBJECT (ci->comp));
2996
 
                g_free (ci);
2997
 
        }
2998
 
 
2999
 
        g_list_free (detached_instances);
3000
 
 
3001
 
}
3002
 
 
3003
 
/**
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.
3010
 
 *
3011
 
 * Does a combination of #e_cal_get_object_list () and
3012
 
 * #e_cal_recur_generate_instances().
3013
 
 *
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.
3017
 
 **/
3018
 
void
3019
 
e_cal_generate_instances (ECal *ecal, time_t start, time_t end,
3020
 
                          ECalRecurInstanceFn cb, gpointer cb_data)
3021
 
{
3022
 
        ECalPrivate *priv;
3023
 
 
3024
 
        g_return_if_fail (ecal != NULL);
3025
 
        g_return_if_fail (E_IS_CAL (ecal));
3026
 
 
3027
 
        priv = ecal->priv;
3028
 
        g_return_if_fail (priv->load_state == E_CAL_LOAD_LOADED);
3029
 
 
3030
 
        g_return_if_fail (start >= 0);
3031
 
        g_return_if_fail (end >= 0);
3032
 
        g_return_if_fail (cb != NULL);
3033
 
 
3034
 
        generate_instances (ecal, start, end, NULL, cb, cb_data);
3035
 
}
3036
 
 
3037
 
/**
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.
3045
 
 *
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.
3049
 
 *
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.
3053
 
 **/
3054
 
void
3055
 
e_cal_generate_instances_for_object (ECal *ecal, icalcomponent *icalcomp,
3056
 
                                     time_t start, time_t end,
3057
 
                                     ECalRecurInstanceFn cb, gpointer cb_data)
3058
 
{
3059
 
        ECalPrivate *priv;
3060
 
        ECalComponent *comp;
3061
 
        const gchar *uid;
3062
 
        gchar *rid;
3063
 
        gboolean result;
3064
 
        GList *instances = NULL;
3065
 
        ECalComponentDateTime datetime;
3066
 
        icaltimezone *start_zone;
3067
 
        struct instances_info *instances_hold;
3068
 
        gboolean is_single_instance = FALSE;
3069
 
 
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);
3074
 
 
3075
 
        priv = ecal->priv;
3076
 
 
3077
 
        comp = e_cal_component_new ();
3078
 
        e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
3079
 
 
3080
 
        if (!e_cal_component_has_recurrences (comp))
3081
 
                is_single_instance = TRUE;
3082
 
 
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)) {
3086
 
 
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);
3091
 
                return;
3092
 
        }
3093
 
 
3094
 
        e_cal_component_get_uid (comp, &uid);
3095
 
        rid = e_cal_component_get_recurid_as_string (comp);
3096
 
 
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);
3101
 
 
3102
 
        instances_hold = g_new0 (struct instances_info, 1);
3103
 
        instances_hold->instances = &instances;
3104
 
        instances_hold->start_zone = start_zone;
3105
 
 
3106
 
        /* generate all instances in the given time range */
3107
 
        generate_instances (ecal, start, end, uid, add_instance, instances_hold);
3108
 
 
3109
 
        instances = *(instances_hold->instances);
3110
 
        /* now only return back the instances for the given object */
3111
 
        result = TRUE;
3112
 
        while (instances != NULL) {
3113
 
                struct comp_instance *ci;
3114
 
                gchar *instance_rid = NULL;
3115
 
 
3116
 
                ci = instances->data;
3117
 
 
3118
 
                if (result) {
3119
 
                        instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
3120
 
 
3121
 
                        if (rid && *rid) {
3122
 
                                if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
3123
 
                                        result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3124
 
                        } else
3125
 
                                result = (* cb)  (ci->comp, ci->start, ci->end, cb_data);
3126
 
                }
3127
 
 
3128
 
                /* remove instance from list */
3129
 
                instances = g_list_remove (instances, ci);
3130
 
                g_object_unref (ci->comp);
3131
 
                g_free (ci);
3132
 
                g_free (instance_rid);
3133
 
        }
3134
 
 
3135
 
        /* clean up */
3136
 
        g_object_unref (comp);
3137
 
        g_free (instances_hold);
3138
 
        g_free (rid);
3139
 
}
3140
 
 
3141
 
/* Builds a list of ECalComponentAlarms structures */
3142
 
static GSList *
3143
 
build_component_alarms_list (ECal *ecal, GList *object_list, time_t start, time_t end)
3144
 
{
3145
 
        GSList *comp_alarms;
3146
 
        GList *l;
3147
 
 
3148
 
        comp_alarms = NULL;
3149
 
 
3150
 
        for (l = object_list; l != NULL; l = l->next) {
3151
 
                ECalComponent *comp;
3152
 
                ECalComponentAlarms *alarms;
3153
 
                ECalComponentAlarmAction omit[] = {-1};
3154
 
 
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));
3158
 
                        continue;
3159
 
                }
3160
 
 
3161
 
                alarms = e_cal_util_generate_alarms_for_comp (comp, start, end, omit, e_cal_resolve_tzid_cb,
3162
 
                                                              ecal, ecal->priv->default_zone);
3163
 
                if (alarms)
3164
 
                        comp_alarms = g_slist_prepend (comp_alarms, alarms);
3165
 
        }
3166
 
 
3167
 
        return comp_alarms;
3168
 
}
3169
 
 
3170
 
/**
3171
 
 * e_cal_get_alarms_in_range:
3172
 
 * @ecal: A calendar client.
3173
 
 * @start: Start time for query.
3174
 
 * @end: End time for query.
3175
 
 *
3176
 
 * Queries a calendar for the alarms that trigger in the specified range of
3177
 
 * time.
3178
 
 *
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
3182
 
 * #g_slist_free().
3183
 
 **/
3184
 
GSList *
3185
 
e_cal_get_alarms_in_range (ECal *ecal, time_t start, time_t end)
3186
 
{
3187
 
        ECalPrivate *priv;
3188
 
        GSList *alarms;
3189
 
        gchar *sexp, *iso_start, *iso_end;
3190
 
        GList *object_list = NULL;
3191
 
 
3192
 
        g_return_val_if_fail (ecal != NULL, NULL);
3193
 
        g_return_val_if_fail (E_IS_CAL (ecal), NULL);
3194
 
 
3195
 
        priv = ecal->priv;
3196
 
        g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, NULL);
3197
 
 
3198
 
        g_return_val_if_fail (start >= 0 && end >= 0, NULL);
3199
 
        g_return_val_if_fail (start <= end, NULL);
3200
 
 
3201
 
        iso_start = isodate_from_time_t (start);
3202
 
        if (!iso_start)
3203
 
                return NULL;
3204
 
 
3205
 
        iso_end = isodate_from_time_t (end);
3206
 
        if (!iso_end) {
3207
 
                g_free (iso_start);
3208
 
                return NULL;
3209
 
        }
3210
 
 
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);
3214
 
        g_free (iso_start);
3215
 
        g_free (iso_end);
3216
 
 
3217
 
        /* execute the query on the server */
3218
 
        if (!e_cal_get_object_list (ecal, sexp, &object_list, NULL)) {
3219
 
                g_free (sexp);
3220
 
                return NULL;
3221
 
        }
3222
 
 
3223
 
        alarms = build_component_alarms_list (ecal, object_list, start, end);
3224
 
 
3225
 
        g_list_foreach (object_list, (GFunc) icalcomponent_free, NULL);
3226
 
        g_list_free (object_list);
3227
 
        g_free (sexp);
3228
 
 
3229
 
        return alarms;
3230
 
}
3231
 
 
3232
 
/**
3233
 
 * e_cal_free_alarms:
3234
 
 * @comp_alarms: A list of #ECalComponentAlarms structures.
3235
 
 *
3236
 
 * Frees a list of #ECalComponentAlarms structures as returned by
3237
 
 * e_cal_get_alarms_in_range().
3238
 
 **/
3239
 
void
3240
 
e_cal_free_alarms (GSList *comp_alarms)
3241
 
{
3242
 
        GSList *l;
3243
 
 
3244
 
        for (l = comp_alarms; l; l = l->next) {
3245
 
                ECalComponentAlarms *alarms;
3246
 
 
3247
 
                alarms = l->data;
3248
 
                if (alarms != NULL)
3249
 
                        e_cal_component_alarms_free (alarms);
3250
 
                else
3251
 
                        g_warn_if_reached ();
3252
 
        }
3253
 
 
3254
 
        g_slist_free (comp_alarms);
3255
 
}
3256
 
 
3257
 
/**
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.
3266
 
 *
3267
 
 * Queries a calendar for the alarms of a particular object that trigger in the
3268
 
 * specified range of time.
3269
 
 *
3270
 
 * Returns: TRUE on success, FALSE if the object was not found.
3271
 
 **/
3272
 
gboolean
3273
 
e_cal_get_alarms_for_object (ECal *ecal, const ECalComponentId *id,
3274
 
                             time_t start, time_t end,
3275
 
                             ECalComponentAlarms **alarms)
3276
 
{
3277
 
        ECalPrivate *priv;
3278
 
        icalcomponent *icalcomp;
3279
 
        ECalComponent *comp;
3280
 
        ECalComponentAlarmAction omit[] = {-1};
3281
 
 
3282
 
        g_return_val_if_fail (alarms != NULL, FALSE);
3283
 
        *alarms = NULL;
3284
 
 
3285
 
        g_return_val_if_fail (ecal != NULL, FALSE);
3286
 
        g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
3287
 
 
3288
 
        priv = ecal->priv;
3289
 
        g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, FALSE);
3290
 
 
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);
3294
 
 
3295
 
        if (!e_cal_get_object (ecal, id->uid, id->rid, &icalcomp, NULL))
3296
 
                return FALSE;
3297
 
        if (!icalcomp)
3298
 
                return FALSE;
3299
 
 
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));
3304
 
                return FALSE;
3305
 
        }
3306
 
 
3307
 
        *alarms = e_cal_util_generate_alarms_for_comp (comp, start, end, omit, e_cal_resolve_tzid_cb,
3308
 
                                                       ecal, priv->default_zone);
3309
 
 
3310
 
        return TRUE;
3311
 
}
3312
 
 
3313
 
/**
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.
3319
 
 *
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.
3324
 
 *
3325
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
3326
 
 */
3327
 
gboolean
3328
 
e_cal_discard_alarm (ECal *ecal, ECalComponent *comp, const gchar *auid, GError **error)
3329
 
{
3330
 
        ECalPrivate *priv;
3331
 
        const gchar *uid;
3332
 
 
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);
3338
 
        priv = ecal->priv;
3339
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3340
 
 
3341
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3342
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3343
 
        }
3344
 
 
3345
 
        e_cal_component_get_uid (comp, &uid);
3346
 
 
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);
3349
 
        }
3350
 
 
3351
 
        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3352
 
}
3353
 
 
3354
 
typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
3355
 
struct _ForeachTZIDCallbackData {
3356
 
        ECal *ecal;
3357
 
        GHashTable *timezone_hash;
3358
 
        gboolean include_all_timezones;
3359
 
        gboolean success;
3360
 
};
3361
 
 
3362
 
/* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
3363
 
   data. */
3364
 
static void
3365
 
foreach_tzid_callback (icalparameter *param, gpointer cbdata)
3366
 
{
3367
 
        ForeachTZIDCallbackData *data = cbdata;
3368
 
        ECalPrivate *priv;
3369
 
        const gchar *tzid;
3370
 
        icaltimezone *zone;
3371
 
        icalcomponent *vtimezone_comp;
3372
 
        gchar *vtimezone_as_string;
3373
 
 
3374
 
        priv = data->ecal->priv;
3375
 
 
3376
 
        /* Get the TZID string from the parameter. */
3377
 
        tzid = icalparameter_get_tzid (param);
3378
 
        if (!tzid)
3379
 
                return;
3380
 
 
3381
 
        /* Check if we've already added it to the GHashTable. */
3382
 
        if (g_hash_table_lookup (data->timezone_hash, tzid))
3383
 
                return;
3384
 
 
3385
 
        if (data->include_all_timezones) {
3386
 
                if (!e_cal_get_timezone (data->ecal, tzid, &zone, NULL)) {
3387
 
                        data->success = FALSE;
3388
 
                        return;
3389
 
                }
3390
 
        } else {
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))
3394
 
                        return;
3395
 
 
3396
 
                /* Check if it is a builtin timezone. If it isn't, return. */
3397
 
                zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
3398
 
                if (!zone)
3399
 
                        return;
3400
 
        }
3401
 
 
3402
 
        /* Convert it to a string and add it to the hash. */
3403
 
        vtimezone_comp = icaltimezone_get_component (zone);
3404
 
        if (!vtimezone_comp)
3405
 
                return;
3406
 
 
3407
 
        vtimezone_as_string = icalcomponent_as_ical_string_r (vtimezone_comp);
3408
 
 
3409
 
        g_hash_table_insert (data->timezone_hash, (gchar *) tzid,
3410
 
                             vtimezone_as_string);
3411
 
}
3412
 
 
3413
 
/* This appends the value string to the GString given in data. */
3414
 
static void
3415
 
append_timezone_string (gpointer key, gpointer value, gpointer data)
3416
 
{
3417
 
        GString *vcal_string = data;
3418
 
 
3419
 
        g_string_append (vcal_string, value);
3420
 
        g_free (value);
3421
 
}
3422
 
 
3423
 
/* This simply frees the hash values. */
3424
 
static void
3425
 
free_timezone_string (gpointer key, gpointer value, gpointer data)
3426
 
{
3427
 
        g_free (value);
3428
 
}
3429
 
 
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.
3433
 
 
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
3440
 
   as before. */
3441
 
static gchar *
3442
 
e_cal_get_component_as_string_internal (ECal *ecal,
3443
 
                                        icalcomponent *icalcomp,
3444
 
                                        gboolean include_all_timezones)
3445
 
{
3446
 
        GHashTable *timezone_hash;
3447
 
        GString *vcal_string;
3448
 
        gint initial_vcal_string_len;
3449
 
        ForeachTZIDCallbackData cbdata;
3450
 
        gchar *obj_string;
3451
 
 
3452
 
        timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
3453
 
 
3454
 
        /* Add any timezones needed to the hash. We use a hash since we only
3455
 
           want to add each timezone once at most. */
3456
 
        cbdata.ecal = ecal;
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,
3463
 
                                      NULL);
3464
 
                return NULL;
3465
 
        }
3466
 
 
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,
3471
 
                         "BEGIN:VCALENDAR\n"
3472
 
                         "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
3473
 
                         "VERSION:2.0\n"
3474
 
                         "METHOD:PUBLISH\n");
3475
 
        initial_vcal_string_len = vcal_string->len;
3476
 
 
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,
3480
 
                              vcal_string);
3481
 
 
3482
 
        /* Get the string for the VEVENT/VTODO. */
3483
 
        obj_string = icalcomponent_as_ical_string_r (icalcomp);
3484
 
 
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);
3490
 
        } else {
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);
3496
 
        }
3497
 
 
3498
 
        g_hash_table_destroy (timezone_hash);
3499
 
 
3500
 
        return obj_string;
3501
 
}
3502
 
 
3503
 
/**
3504
 
 * e_cal_get_component_as_string:
3505
 
 * @ecal: A calendar client.
3506
 
 * @icalcomp: A calendar component object.
3507
 
 *
3508
 
 * Gets a calendar component as an iCalendar string, with a toplevel
3509
 
 * VCALENDAR component and all VTIMEZONEs needed for the component.
3510
 
 *
3511
 
 * Returns: the component as a complete iCalendar string, or NULL on
3512
 
 * failure. The string should be freed after use.
3513
 
 **/
3514
 
gchar *
3515
 
e_cal_get_component_as_string (ECal *ecal, icalcomponent *icalcomp)
3516
 
{
3517
 
        return e_cal_get_component_as_string_internal (ecal, icalcomp, TRUE);
3518
 
}
3519
 
 
3520
 
/**
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.
3526
 
 *
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.
3530
 
 *
3531
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
3532
 
 */
3533
 
gboolean
3534
 
e_cal_create_object (ECal *ecal, icalcomponent *icalcomp, gchar **uid, GError **error)
3535
 
{
3536
 
        ECalPrivate *priv;
3537
 
        gchar *obj, *muid = NULL;
3538
 
 
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);
3542
 
        priv = ecal->priv;
3543
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3544
 
 
3545
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3546
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3547
 
        }
3548
 
 
3549
 
        obj = icalcomponent_as_ical_string_r (icalcomp);
3550
 
        if (!e_gdbus_cal_call_create_object_sync (priv->gdbus_cal, obj, &muid, NULL, error)) {
3551
 
                g_free (obj);
3552
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3553
 
        }
3554
 
 
3555
 
        g_free (obj);
3556
 
 
3557
 
        if (!muid) {
3558
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
3559
 
        } else {
3560
 
                icalcomponent_set_uid (icalcomp, muid);
3561
 
 
3562
 
                if (uid)
3563
 
                        *uid = muid;
3564
 
                else
3565
 
                        g_free (muid);
3566
 
 
3567
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3568
 
        }
3569
 
}
3570
 
 
3571
 
/**
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.
3577
 
 *
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.
3580
 
 *
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).
3585
 
 *
3586
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
3587
 
 */
3588
 
gboolean
3589
 
e_cal_modify_object (ECal *ecal, icalcomponent *icalcomp, CalObjModType mod, GError **error)
3590
 
{
3591
 
        ECalPrivate *priv;
3592
 
        gchar *obj;
3593
 
 
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);
3598
 
        priv = ecal->priv;
3599
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3600
 
 
3601
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3602
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3603
 
        }
3604
 
 
3605
 
        obj = icalcomponent_as_ical_string_r (icalcomp);
3606
 
        if (!e_gdbus_cal_call_modify_object_sync (priv->gdbus_cal, obj, mod, NULL, error)) {
3607
 
                g_free (obj);
3608
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3609
 
        }
3610
 
 
3611
 
        g_free (obj);
3612
 
        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3613
 
}
3614
 
 
3615
 
/**
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.
3622
 
 *
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.
3627
 
 *
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
3630
 
 * are removed.
3631
 
 *
3632
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
3633
 
 */
3634
 
gboolean
3635
 
e_cal_remove_object_with_mod (ECal *ecal, const gchar *uid,
3636
 
                              const gchar *rid, CalObjModType mod, GError **error)
3637
 
{
3638
 
        ECalPrivate *priv;
3639
 
 
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);
3643
 
        priv = ecal->priv;
3644
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3645
 
 
3646
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3647
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3648
 
        }
3649
 
 
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);
3652
 
        }
3653
 
 
3654
 
        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3655
 
}
3656
 
 
3657
 
/**
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.
3662
 
 *
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"
3665
 
 * signal.
3666
 
 *
3667
 
 * Returns: %TRUE if successful, %FALSE otherwise.
3668
 
 **/
3669
 
gboolean
3670
 
e_cal_remove_object (ECal *ecal, const gchar *uid, GError **error)
3671
 
{
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);
3674
 
 
3675
 
        return e_cal_remove_object_with_mod (ecal, uid, NULL, CALOBJ_MOD_THIS, error);
3676
 
}
3677
 
 
3678
 
/**
3679
 
 * e_cal_receive_objects:
3680
 
 * @ecal:  A calendar client.
3681
 
 * @icalcomp: An icalcomponent.
3682
 
 * @error: Placeholder for error information.
3683
 
 *
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.
3687
 
 *
3688
 
 * Returns: %TRUE if successful, %FALSE otherwise.
3689
 
 */
3690
 
gboolean
3691
 
e_cal_receive_objects (ECal *ecal, icalcomponent *icalcomp, GError **error)
3692
 
{
3693
 
        ECalPrivate *priv;
3694
 
 
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);
3698
 
        priv = ecal->priv;
3699
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3700
 
 
3701
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3702
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3703
 
        }
3704
 
 
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);
3707
 
        }
3708
 
 
3709
 
        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3710
 
}
3711
 
 
3712
 
/**
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
3718
 
 * performed.
3719
 
 * @error: Placeholder for error information.
3720
 
 *
3721
 
 * Requests a calendar backend to send meeting information to the specified list
3722
 
 * of users.
3723
 
 *
3724
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
3725
 
 */
3726
 
gboolean
3727
 
e_cal_send_objects (ECal *ecal, icalcomponent *icalcomp, GList **users, icalcomponent **modified_icalcomp, GError **error)
3728
 
{
3729
 
        ECalPrivate *priv;
3730
 
        ECalendarStatus status;
3731
 
        gchar **users_array;
3732
 
        gchar *object;
3733
 
 
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);
3739
 
        priv = ecal->priv;
3740
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3741
 
        *users = NULL;
3742
 
        *modified_icalcomp = NULL;
3743
 
 
3744
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3745
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3746
 
        }
3747
 
 
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);
3750
 
        }
3751
 
 
3752
 
        status = E_CALENDAR_STATUS_OK;
3753
 
        if (users_array) {
3754
 
                gchar **user;
3755
 
                *modified_icalcomp = icalparser_parse_string (object);
3756
 
                if (!(*modified_icalcomp))
3757
 
                        status = E_CALENDAR_STATUS_INVALID_OBJECT;
3758
 
 
3759
 
                for (user = users_array; *user; user++)
3760
 
                        *users = g_list_append (*users, g_strdup (*user));
3761
 
                g_strfreev (users_array);
3762
 
        } else
3763
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
3764
 
 
3765
 
        E_CALENDAR_CHECK_STATUS (status, error);
3766
 
}
3767
 
 
3768
 
/**
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.
3774
 
 *
3775
 
 * Retrieves a timezone object from the calendar backend.
3776
 
 *
3777
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
3778
 
 */
3779
 
gboolean
3780
 
e_cal_get_timezone (ECal *ecal, const gchar *tzid, icaltimezone **zone, GError **error)
3781
 
{
3782
 
        ECalPrivate *priv;
3783
 
        ECalendarStatus status = E_CALENDAR_STATUS_OK;
3784
 
        icalcomponent *icalcomp = NULL;
3785
 
        gchar *object;
3786
 
        const gchar *systzid = NULL;
3787
 
 
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);
3790
 
        priv = ecal->priv;
3791
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3792
 
        *zone = NULL;
3793
 
 
3794
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3795
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3796
 
        }
3797
 
 
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);
3802
 
        }
3803
 
 
3804
 
        LOCK_CACHE ();
3805
 
        /* If it is UTC, we return the special UTC timezone. */
3806
 
        if (!strcmp (tzid, "UTC")) {
3807
 
                *zone = icaltimezone_get_utc_timezone ();
3808
 
        } else {
3809
 
                /* See if we already have it in the cache. */
3810
 
                *zone = g_hash_table_lookup (priv->timezones, tzid);
3811
 
        }
3812
 
 
3813
 
        if (*zone) {
3814
 
                UNLOCK_CACHE ();
3815
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3816
 
        }
3817
 
 
3818
 
        /*
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.
3824
 
         */
3825
 
        systzid = e_cal_match_tzid (tzid);
3826
 
        if (!systzid) {
3827
 
                /* call the backend */
3828
 
                if (!e_gdbus_cal_call_get_timezone_sync (priv->gdbus_cal, tzid, &object, NULL, error)) {
3829
 
                        UNLOCK_CACHE ();
3830
 
                        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3831
 
                }
3832
 
 
3833
 
                icalcomp = icalparser_parse_string (object);
3834
 
                if (!icalcomp)
3835
 
                        status = E_CALENDAR_STATUS_INVALID_OBJECT;
3836
 
                g_free (object);
3837
 
        } else {
3838
 
                /*
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
3844
 
                 * caller.
3845
 
                 */
3846
 
                icaltimezone *syszone = icaltimezone_get_builtin_timezone_from_tzid (systzid);
3847
 
                if (syszone) {
3848
 
                        gboolean found = FALSE;
3849
 
                        icalproperty *prop;
3850
 
 
3851
 
                        icalcomp = icalcomponent_new_clone (icaltimezone_get_component (syszone));
3852
 
                        prop = icalcomponent_get_first_property(icalcomp,
3853
 
                                                                ICAL_ANY_PROPERTY);
3854
 
                        while (!found && prop) {
3855
 
                                if (icalproperty_isa(prop) == ICAL_TZID_PROPERTY) {
3856
 
                                        icalproperty_set_value_from_string(prop, tzid, "NO");
3857
 
                                        found = TRUE;
3858
 
                                }
3859
 
                                prop = icalcomponent_get_next_property(icalcomp,
3860
 
                                                                       ICAL_ANY_PROPERTY);
3861
 
                        }
3862
 
                } else {
3863
 
                        status = E_CALENDAR_STATUS_INVALID_OBJECT;
3864
 
                }
3865
 
        }
3866
 
 
3867
 
        if (!icalcomp) {
3868
 
                UNLOCK_CACHE ();
3869
 
                E_CALENDAR_CHECK_STATUS (status, error);
3870
 
        }
3871
 
 
3872
 
        *zone = icaltimezone_new ();
3873
 
        if (!icaltimezone_set_component (*zone, icalcomp)) {
3874
 
                icaltimezone_free (*zone, 1);
3875
 
                UNLOCK_CACHE ();
3876
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OBJECT_NOT_FOUND, error);
3877
 
        }
3878
 
 
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);
3881
 
 
3882
 
        UNLOCK_CACHE ();
3883
 
        E_CALENDAR_CHECK_STATUS (status, error);
3884
 
}
3885
 
 
3886
 
/**
3887
 
 * e_cal_add_timezone
3888
 
 * @ecal: A calendar client.
3889
 
 * @izone: The timezone to add.
3890
 
 * @error: Placeholder for error information.
3891
 
 *
3892
 
 * Add a VTIMEZONE object to the given calendar.
3893
 
 *
3894
 
 * Returns: TRUE if successful, FALSE otherwise.
3895
 
 */
3896
 
gboolean
3897
 
e_cal_add_timezone (ECal *ecal, icaltimezone *izone, GError **error)
3898
 
{
3899
 
        ECalPrivate *priv;
3900
 
        gchar *tzobj;
3901
 
        icalcomponent *icalcomp;
3902
 
 
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);
3905
 
        priv = ecal->priv;
3906
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3907
 
 
3908
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3909
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3910
 
        }
3911
 
 
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);
3916
 
        }
3917
 
 
3918
 
        icalcomp = icaltimezone_get_component (izone);
3919
 
        if (!icalcomp) {
3920
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
3921
 
        }
3922
 
 
3923
 
        /* convert icaltimezone into a string */
3924
 
        tzobj = icalcomponent_as_ical_string_r (icalcomp);
3925
 
 
3926
 
        /* call the backend */
3927
 
        if (!e_gdbus_cal_call_add_timezone_sync (priv->gdbus_cal, tzobj, NULL, error)) {
3928
 
                g_free (tzobj);
3929
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3930
 
        }
3931
 
 
3932
 
        g_free (tzobj);
3933
 
        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3934
 
}
3935
 
 
3936
 
/**
3937
 
 * e_cal_get_query:
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.
3942
 
 *
3943
 
 * Creates a live query object from a loaded calendar.
3944
 
 *
3945
 
 * Returns: A query object that will emit notification signals as calendar
3946
 
 * components are added and removed from the query in the server.
3947
 
 **/
3948
 
gboolean
3949
 
e_cal_get_query (ECal *ecal, const gchar *sexp, ECalView **query, GError **error)
3950
 
{
3951
 
        ECalPrivate *priv;
3952
 
        ECalendarStatus status;
3953
 
        gchar *query_path;
3954
 
        EGdbusCalView *gdbus_calview;
3955
 
 
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);
3959
 
        priv = ecal->priv;
3960
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3961
 
        *query = NULL;
3962
 
 
3963
 
        if (priv->load_state != E_CAL_LOAD_LOADED) {
3964
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3965
 
        }
3966
 
 
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);
3969
 
        }
3970
 
 
3971
 
        status = E_CALENDAR_STATUS_OK;
3972
 
 
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",
3976
 
                                                        query_path,
3977
 
                                                        NULL,
3978
 
                                                        error);
3979
 
 
3980
 
        g_free (query_path);
3981
 
 
3982
 
        if (!gdbus_calview) {
3983
 
                *query = NULL;
3984
 
                status = E_CALENDAR_STATUS_OTHER_ERROR;
3985
 
        } else {
3986
 
                *query = _e_cal_view_new (ecal, gdbus_calview);
3987
 
                g_object_unref (gdbus_calview);
3988
 
        }
3989
 
 
3990
 
        E_CALENDAR_CHECK_STATUS (status, error);
3991
 
}
3992
 
 
3993
 
/**
3994
 
 * e_cal_set_default_timezone:
3995
 
 * @ecal: A calendar client.
3996
 
 * @zone: A timezone object.
3997
 
 * @error: Placeholder for error information.
3998
 
 *
3999
 
 * Sets the default timezone on the calendar. This should be called before opening
4000
 
 * the calendar.
4001
 
 *
4002
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
4003
 
 */
4004
 
gboolean
4005
 
e_cal_set_default_timezone (ECal *ecal, icaltimezone *zone, GError **error)
4006
 
{
4007
 
        ECalPrivate *priv;
4008
 
        icalcomponent *icalcomp = NULL;
4009
 
        gchar *tzobj;
4010
 
 
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);
4013
 
        priv = ecal->priv;
4014
 
        e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4015
 
 
4016
 
        /* If the same timezone is already set, we don't have to do anything. */
4017
 
        if (priv->default_zone == zone)
4018
 
                return TRUE;
4019
 
 
4020
 
        /* FIXME Adding it to the server to change the tzid */
4021
 
        icalcomp = icaltimezone_get_component (zone);
4022
 
        if (!icalcomp) {
4023
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
4024
 
        }
4025
 
 
4026
 
        /* convert icaltimezone into a string */
4027
 
        tzobj = icalcomponent_as_ical_string_r (icalcomp);
4028
 
 
4029
 
        /* call the backend */
4030
 
        if (!e_gdbus_cal_call_set_default_timezone_sync (priv->gdbus_cal, tzobj, NULL, error)) {
4031
 
                g_free (tzobj);
4032
 
                E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4033
 
        }
4034
 
 
4035
 
        g_free (tzobj);
4036
 
        priv->default_zone = zone;
4037
 
 
4038
 
        E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4039
 
}
4040
 
 
4041
 
/**
4042
 
 * e_cal_get_error_message
4043
 
 * @status: A status code.
4044
 
 *
4045
 
 * Gets an error message for the given status code.
4046
 
 *
4047
 
 * Returns: the error message.
4048
 
 */
4049
 
const gchar *
4050
 
e_cal_get_error_message (ECalendarStatus status)
4051
 
{
4052
 
        switch (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");
4093
 
        default:
4094
 
                /* ignore everything else */
4095
 
                break;
4096
 
        }
4097
 
 
4098
 
        return NULL;
4099
 
}
4100
 
 
4101
 
/**
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.
4108
 
 *
4109
 
 * Opens the default calendar.
4110
 
 *
4111
 
 * Returns: TRUE if it opened correctly, FALSE otherwise.
4112
 
 */
4113
 
gboolean
4114
 
e_cal_open_default (ECal **ecal,
4115
 
                    ECalSourceType type,
4116
 
                    ECalAuthFunc func,
4117
 
                    gpointer data,
4118
 
                    GError **error)
4119
 
{
4120
 
        ESourceList *source_list;
4121
 
        ESource *source;
4122
 
        ECal *client;
4123
 
 
4124
 
        g_return_val_if_fail (ecal != NULL, FALSE);
4125
 
 
4126
 
        /* In case something goes wrong... */
4127
 
        *ecal = NULL;
4128
 
 
4129
 
        if (!e_cal_get_sources (&source_list, type, error))
4130
 
                return FALSE;
4131
 
 
4132
 
        source = e_source_list_peek_default_source (source_list);
4133
 
        if (!source) {
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);
4138
 
                return FALSE;
4139
 
        }
4140
 
 
4141
 
        /* XXX This can fail but doesn't take a GError!? */
4142
 
        client = e_cal_new (source, type);
4143
 
        if (!client) {
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);
4148
 
                return FALSE;
4149
 
        }
4150
 
 
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);
4155
 
                return FALSE;
4156
 
        }
4157
 
 
4158
 
        *ecal = client;
4159
 
 
4160
 
        g_object_unref (source_list);
4161
 
 
4162
 
        return TRUE;
4163
 
}
4164
 
 
4165
 
/**
4166
 
 * e_cal_set_default:
4167
 
 * @ecal: A calendar client.
4168
 
 * @error: Placeholder for error information.
4169
 
 *
4170
 
 * Sets a calendar as the default one.
4171
 
 *
4172
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
4173
 
 */
4174
 
gboolean
4175
 
e_cal_set_default (ECal *ecal, GError **error)
4176
 
{
4177
 
        ESource *source;
4178
 
 
4179
 
        e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4180
 
 
4181
 
        source = e_cal_get_source (ecal);
4182
 
        if (!source) {
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));
4186
 
                return FALSE;
4187
 
        }
4188
 
 
4189
 
        return e_cal_set_default_source (source, ecal->priv->type, error);
4190
 
}
4191
 
 
4192
 
static gboolean
4193
 
set_default_source (ESourceList *sources, ESource *source, GError **error)
4194
 
{
4195
 
        const gchar *uid;
4196
 
        GError *err = NULL;
4197
 
        GSList *g;
4198
 
 
4199
 
        uid = e_source_peek_uid (source);
4200
 
 
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);
4204
 
        if (!source) {
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);
4209
 
                return FALSE;
4210
 
        }
4211
 
 
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) {
4215
 
                GSList *s;
4216
 
                for (s = e_source_group_peek_sources (E_SOURCE_GROUP (g->data));
4217
 
                     s; s = s->next) {
4218
 
                        e_source_set_property (E_SOURCE (s->data), "default", NULL);
4219
 
                }
4220
 
        }
4221
 
 
4222
 
        /* set the "default" property on the source */
4223
 
        e_source_set_property (source, "default", "true");
4224
 
 
4225
 
        if (!e_source_list_sync (sources, &err)) {
4226
 
                g_propagate_error (error, err);
4227
 
                return FALSE;
4228
 
        }
4229
 
 
4230
 
        return TRUE;
4231
 
}
4232
 
 
4233
 
/**
4234
 
 * e_cal_set_default_source:
4235
 
 * @source: An #ESource.
4236
 
 * @type: Type of the source.
4237
 
 * @error: Placeholder for error information.
4238
 
 *
4239
 
 * Sets the default source for the specified @type.
4240
 
 *
4241
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
4242
 
 */
4243
 
gboolean
4244
 
e_cal_set_default_source (ESource *source, ECalSourceType type, GError **error)
4245
 
{
4246
 
        ESourceList *sources;
4247
 
        GError *err = NULL;
4248
 
 
4249
 
        if (!e_cal_get_sources (&sources, type, &err)) {
4250
 
                g_propagate_error (error, err);
4251
 
                return FALSE;
4252
 
        }
4253
 
 
4254
 
        return set_default_source (sources, source, error);
4255
 
}
4256
 
 
4257
 
static gboolean
4258
 
get_sources (ESourceList **sources, const gchar *key, GError **error)
4259
 
{
4260
 
        GConfClient *gconf = gconf_client_get_default();
4261
 
 
4262
 
        *sources = e_source_list_new_for_gconf (gconf, key);
4263
 
        g_object_unref (gconf);
4264
 
 
4265
 
        return TRUE;
4266
 
}
4267
 
 
4268
 
/**
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.
4273
 
 *
4274
 
 * Gets the list of sources defined in the configuration for the given @type.
4275
 
 *
4276
 
 * Returns: TRUE if the operation was successful, FALSE otherwise.
4277
 
 */
4278
 
gboolean
4279
 
e_cal_get_sources (ESourceList **sources, ECalSourceType type, GError **error)
4280
 
{
4281
 
        e_return_error_if_fail (sources != NULL, E_CALENDAR_STATUS_INVALID_ARG);
4282
 
        *sources = NULL;
4283
 
 
4284
 
        switch (type) {
4285
 
        case E_CAL_SOURCE_TYPE_EVENT:
4286
 
                return get_sources (sources, "/apps/evolution/calendar/sources", error);
4287
 
                break;
4288
 
        case E_CAL_SOURCE_TYPE_TODO:
4289
 
                return get_sources (sources, "/apps/evolution/tasks/sources", error);
4290
 
                break;
4291
 
        case E_CAL_SOURCE_TYPE_JOURNAL:
4292
 
                return get_sources (sources, "/apps/evolution/memos/sources", error);
4293
 
                break;
4294
 
        default:
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));
4298
 
                return FALSE;
4299
 
        }
4300
 
 
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));
4304
 
        return FALSE;
4305
 
}