~ubuntu-branches/ubuntu/natty/lunar-applet/natty

« back to all changes in this revision

Viewing changes to .pc/e-source-get-color-replacement.patch/src/calendar-client.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2011-01-29 03:13:30 UTC
  • Revision ID: james.westby@ubuntu.com-20110129031330-30i7ef8ltnabi25o
Tags: 2.0-2ubuntu1
debian/patches/e-source-get-color-replacement.patch: fix FTBFS against new
evolution library API: replace the call to e_source_get_color() with a
simpler e_source_peek_color_spec() which does the same thing.
(LP: #708721, Closes: #611327)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2004 Free Software Foundation, Inc.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License as
 
6
 * published by the Free Software Foundation; either version 2 of the
 
7
 * License, or (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful, but
 
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
17
 * 02111-1307, USA.
 
18
 *
 
19
 * Authors:
 
20
 *     Mark McLoughlin  <mark@skynet.ie>
 
21
 *     William Jon McCann  <mccann@jhu.edu>
 
22
 *     Martin Grimme  <martin@pycage.de>
 
23
 *     Christian Kellner  <gicmo@xatom.net>
 
24
 */
 
25
 
 
26
#include <config.h>
 
27
 
 
28
#include "calendar-client.h"
 
29
 
 
30
#include <libintl.h>
 
31
#include <string.h>
 
32
#include <libecal/e-cal.h>
 
33
#include <libecal/e-cal-time-util.h>
 
34
#include <libecal/e-cal-recur.h>
 
35
 
 
36
#include "calendar-sources.h"
 
37
 
 
38
#undef CALENDAR_ENABLE_DEBUG
 
39
#include "calendar-debug.h"
 
40
 
 
41
#define CALENDAR_CONFIG_PREFIX   "/apps/evolution/calendar"
 
42
#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
 
43
 
 
44
#ifndef _
 
45
#define _(x) gettext(x)
 
46
#endif
 
47
 
 
48
#ifndef N_
 
49
#define N_(x) x
 
50
#endif
 
51
 
 
52
#define CALENDAR_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_CLIENT, CalendarClientPrivate))
 
53
 
 
54
typedef struct _CalendarClientQuery  CalendarClientQuery;
 
55
typedef struct _CalendarClientSource CalendarClientSource;
 
56
 
 
57
struct _CalendarClientQuery
 
58
{
 
59
  ECalView   *view;
 
60
  GHashTable *events;
 
61
};
 
62
 
 
63
struct _CalendarClientSource
 
64
{
 
65
  CalendarClient      *client;
 
66
  ECal                *source;
 
67
 
 
68
  CalendarClientQuery  completed_query;
 
69
  CalendarClientQuery  in_progress_query;
 
70
 
 
71
  guint                changed_signal_id;
 
72
 
 
73
  guint                query_completed : 1;
 
74
  guint                query_in_progress : 1;
 
75
};
 
76
 
 
77
struct _CalendarClientPrivate
 
78
{
 
79
  CalendarSources     *calendar_sources;
 
80
 
 
81
  GSList              *appointment_sources;
 
82
  GSList              *task_sources;
 
83
 
 
84
  icaltimezone        *zone;
 
85
 
 
86
  guint                zone_listener;
 
87
  GConfClient         *gconf_client;
 
88
 
 
89
  guint                day;
 
90
  guint                month;
 
91
  guint                year;
 
92
};
 
93
 
 
94
static void calendar_client_class_init   (CalendarClientClass *klass);
 
95
static void calendar_client_init         (CalendarClient      *client);
 
96
static void calendar_client_finalize     (GObject             *object);
 
97
static void calendar_client_set_property (GObject             *object,
 
98
                                          guint                prop_id,
 
99
                                          const GValue        *value,
 
100
                                          GParamSpec          *pspec);
 
101
static void calendar_client_get_property (GObject             *object,
 
102
                                          guint                prop_id,
 
103
                                          GValue              *value,
 
104
                                          GParamSpec          *pspec);
 
105
 
 
106
static GSList *calendar_client_update_sources_list         (CalendarClient       *client,
 
107
                                                            GSList               *sources,
 
108
                                                            GSList               *esources,
 
109
                                                            guint                 changed_signal_id);
 
110
static void    calendar_client_appointment_sources_changed (CalendarClient       *client);
 
111
static void    calendar_client_task_sources_changed        (CalendarClient       *client);
 
112
 
 
113
static void calendar_client_stop_query  (CalendarClient       *client,
 
114
                                         CalendarClientSource *source,
 
115
                                         CalendarClientQuery  *query);
 
116
static void calendar_client_start_query (CalendarClient       *client,
 
117
                                         CalendarClientSource *source,
 
118
                                         const char           *query);
 
119
 
 
120
static void calendar_client_source_finalize (CalendarClientSource *source);
 
121
static void calendar_client_query_finalize  (CalendarClientQuery  *query);
 
122
 
 
123
enum
 
124
{
 
125
  PROP_O,
 
126
  PROP_DAY,
 
127
  PROP_MONTH,
 
128
  PROP_YEAR
 
129
};
 
130
 
 
131
enum
 
132
{
 
133
  APPOINTMENTS_CHANGED,
 
134
  TASKS_CHANGED,
 
135
  LAST_SIGNAL
 
136
};
 
137
 
 
138
static GObjectClass *parent_class = NULL;
 
139
static guint         signals [LAST_SIGNAL] = { 0, };
 
140
 
 
141
GType
 
142
calendar_client_get_type (void)
 
143
{
 
144
  static GType client_type = 0;
 
145
  
 
146
  if (!client_type)
 
147
    {
 
148
      static const GTypeInfo client_info =
 
149
      {
 
150
        sizeof (CalendarClientClass),
 
151
        NULL,           /* base_init */
 
152
        NULL,           /* base_finalize */
 
153
        (GClassInitFunc) calendar_client_class_init,
 
154
        NULL,           /* class_finalize */
 
155
        NULL,           /* class_data */
 
156
        sizeof (CalendarClient),
 
157
        0,              /* n_preallocs */
 
158
        (GInstanceInitFunc) calendar_client_init,
 
159
      };
 
160
      
 
161
      client_type = g_type_register_static (G_TYPE_OBJECT,
 
162
                                            "CalendarClient",
 
163
                                            &client_info, 0);
 
164
    }
 
165
  
 
166
  return client_type;
 
167
}
 
168
 
 
169
static void
 
170
calendar_client_class_init (CalendarClientClass *klass)
 
171
{
 
172
  GObjectClass *gobject_class = (GObjectClass *) klass;
 
173
 
 
174
  parent_class = g_type_class_peek_parent (klass);
 
175
 
 
176
  gobject_class->finalize     = calendar_client_finalize;
 
177
  gobject_class->set_property = calendar_client_set_property;
 
178
  gobject_class->get_property = calendar_client_get_property;
 
179
 
 
180
  g_type_class_add_private (klass, sizeof (CalendarClientPrivate));
 
181
 
 
182
  g_object_class_install_property (gobject_class,
 
183
                                   PROP_DAY,
 
184
                                   g_param_spec_uint ("day",
 
185
                                                      "Day",
 
186
                                                      "The currently monitored day between 1 and 31 (0 denotes unset)",
 
187
                                                      0, G_MAXUINT, 0,
 
188
                                                      G_PARAM_READWRITE));
 
189
 
 
190
  g_object_class_install_property (gobject_class,
 
191
                                   PROP_MONTH,
 
192
                                   g_param_spec_uint ("month",
 
193
                                                      "Month",
 
194
                                                      "The currently monitored month between 0 and 11",
 
195
                                                      0, G_MAXUINT, 0,
 
196
                                                      G_PARAM_READWRITE));
 
197
 
 
198
  g_object_class_install_property (gobject_class,
 
199
                                   PROP_YEAR,
 
200
                                   g_param_spec_uint ("year",
 
201
                                                      "Year",
 
202
                                                      "The currently monitored year",
 
203
                                                      0, G_MAXUINT, 0,
 
204
                                                      G_PARAM_READWRITE));
 
205
 
 
206
  signals [APPOINTMENTS_CHANGED] =
 
207
    g_signal_new ("appointments-changed",
 
208
                  G_TYPE_FROM_CLASS (gobject_class),
 
209
                  G_SIGNAL_RUN_LAST,
 
210
                  G_STRUCT_OFFSET (CalendarClientClass, tasks_changed),
 
211
                  NULL,
 
212
                  NULL,
 
213
                  g_cclosure_marshal_VOID__VOID,
 
214
                  G_TYPE_NONE,
 
215
                  0);
 
216
 
 
217
  signals [TASKS_CHANGED] =
 
218
    g_signal_new ("tasks-changed",
 
219
                  G_TYPE_FROM_CLASS (gobject_class),
 
220
                  G_SIGNAL_RUN_LAST,
 
221
                  G_STRUCT_OFFSET (CalendarClientClass, tasks_changed),
 
222
                  NULL,
 
223
                  NULL,
 
224
                  g_cclosure_marshal_VOID__VOID,
 
225
                  G_TYPE_NONE,
 
226
                  0);
 
227
}
 
228
 
 
229
/* Timezone code adapted from evolution/calendar/gui/calendar-config.c */
 
230
/* The current timezone, e.g. "Europe/London". It may be NULL, in which case
 
231
   you should assume UTC. */
 
232
static gchar *
 
233
calendar_client_config_get_timezone (GConfClient *gconf_client)
 
234
{
 
235
  char *location;
 
236
 
 
237
  location = gconf_client_get_string (gconf_client,
 
238
                                      CALENDAR_CONFIG_TIMEZONE,
 
239
                                      NULL);
 
240
 
 
241
  return location;
 
242
}
 
243
 
 
244
static icaltimezone *
 
245
calendar_client_config_get_icaltimezone (GConfClient *gconf_client)
 
246
{
 
247
  char         *location;
 
248
  icaltimezone *zone = NULL;
 
249
        
 
250
  location = calendar_client_config_get_timezone (gconf_client);
 
251
  if (!location)
 
252
    return icaltimezone_get_utc_timezone ();
 
253
 
 
254
  zone = icaltimezone_get_builtin_timezone (location);
 
255
  g_free (location);
 
256
        
 
257
  return zone;
 
258
}
 
259
 
 
260
static void
 
261
calendar_client_set_timezone (CalendarClient *client) 
 
262
{
 
263
  GSList *l;
 
264
  GSList *esources;
 
265
 
 
266
  client->priv->zone = calendar_client_config_get_icaltimezone (client->priv->gconf_client);
 
267
 
 
268
  esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
 
269
  for (l = esources; l; l = l->next) {
 
270
    ECal *source = l->data;
 
271
                        
 
272
    if (e_cal_get_load_state (source) != E_CAL_LOAD_LOADED)
 
273
      continue;
 
274
 
 
275
    e_cal_set_default_timezone (source, client->priv->zone, NULL);
 
276
  }
 
277
}
 
278
 
 
279
static void
 
280
calendar_client_timezone_changed_cb (GConfClient    *gconf_client,
 
281
                                     guint           id,
 
282
                                     GConfEntry     *entry,
 
283
                                     CalendarClient *client)
 
284
{
 
285
  calendar_client_set_timezone (client);
 
286
}
 
287
 
 
288
 
 
289
static void
 
290
calendar_client_init (CalendarClient *client)
 
291
{
 
292
  GSList *esources;
 
293
 
 
294
  client->priv = CALENDAR_CLIENT_GET_PRIVATE (client);
 
295
 
 
296
  client->priv->calendar_sources = calendar_sources_get ();
 
297
 
 
298
  esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
 
299
  client->priv->appointment_sources =
 
300
    calendar_client_update_sources_list (client, NULL, esources, signals [APPOINTMENTS_CHANGED]);
 
301
 
 
302
  esources = calendar_sources_get_task_sources (client->priv->calendar_sources);
 
303
  client->priv->task_sources =
 
304
    calendar_client_update_sources_list (client, NULL, esources, signals [TASKS_CHANGED]);
 
305
 
 
306
  g_signal_connect_swapped (client->priv->calendar_sources,
 
307
                            "appointment-sources-changed",
 
308
                            G_CALLBACK (calendar_client_appointment_sources_changed),
 
309
                            client);
 
310
  g_signal_connect_swapped (client->priv->calendar_sources,
 
311
                            "task-sources-changed",
 
312
                            G_CALLBACK (calendar_client_task_sources_changed),
 
313
                            client);
 
314
 
 
315
  client->priv->gconf_client = gconf_client_get_default ();
 
316
 
 
317
  gconf_client_add_dir (client->priv->gconf_client,
 
318
                        CALENDAR_CONFIG_PREFIX,
 
319
                        GCONF_CLIENT_PRELOAD_NONE,
 
320
                        NULL);
 
321
 
 
322
  calendar_client_set_timezone (client);
 
323
  client->priv->zone_listener = gconf_client_notify_add (client->priv->gconf_client,
 
324
                                                         CALENDAR_CONFIG_TIMEZONE,
 
325
                                                         (GConfClientNotifyFunc) calendar_client_timezone_changed_cb,
 
326
                                                         client, NULL, NULL);
 
327
 
 
328
  client->priv->day   = -1;
 
329
  client->priv->month = -1;
 
330
  client->priv->year  = -1;
 
331
}
 
332
 
 
333
static void
 
334
calendar_client_finalize (GObject *object)
 
335
{
 
336
  CalendarClient *client = CALENDAR_CLIENT (object);
 
337
  GSList         *l;
 
338
 
 
339
  if (client->priv->zone_listener)
 
340
    {
 
341
      gconf_client_notify_remove (client->priv->gconf_client,
 
342
                                  client->priv->zone_listener);
 
343
      client->priv->zone_listener = 0;
 
344
    }
 
345
 
 
346
  gconf_client_remove_dir (client->priv->gconf_client,
 
347
                           CALENDAR_CONFIG_PREFIX,
 
348
                           NULL);
 
349
 
 
350
  if (client->priv->gconf_client)
 
351
    g_object_unref (client->priv->gconf_client);
 
352
  client->priv->gconf_client = NULL;
 
353
 
 
354
  for (l = client->priv->appointment_sources; l; l = l->next)
 
355
    {
 
356
      calendar_client_source_finalize (l->data);
 
357
      g_free (l->data);
 
358
    }
 
359
  g_slist_free (client->priv->appointment_sources);
 
360
  client->priv->appointment_sources = NULL;
 
361
 
 
362
  for (l = client->priv->task_sources; l; l = l->next)
 
363
    {
 
364
      calendar_client_source_finalize (l->data);
 
365
      g_free (l->data);
 
366
    }
 
367
  g_slist_free (client->priv->task_sources);
 
368
  client->priv->task_sources = NULL;
 
369
 
 
370
  if (client->priv->calendar_sources)
 
371
    g_object_unref (client->priv->calendar_sources);
 
372
  client->priv->calendar_sources = NULL;
 
373
 
 
374
  if (G_OBJECT_CLASS (parent_class)->finalize)
 
375
    G_OBJECT_CLASS (parent_class)->finalize (object);
 
376
}
 
377
 
 
378
static void
 
379
calendar_client_set_property (GObject      *object,
 
380
                              guint         prop_id,
 
381
                              const GValue *value,
 
382
                              GParamSpec   *pspec)
 
383
{
 
384
  CalendarClient *client = CALENDAR_CLIENT (object);
 
385
 
 
386
  switch (prop_id)
 
387
    {
 
388
    case PROP_DAY:
 
389
      calendar_client_select_day (client, g_value_get_uint (value));
 
390
      break;
 
391
    case PROP_MONTH:
 
392
      calendar_client_select_month (client,
 
393
                                    g_value_get_uint (value),
 
394
                                    client->priv->year);
 
395
      break;
 
396
    case PROP_YEAR:
 
397
      calendar_client_select_month (client,
 
398
                                    client->priv->month,
 
399
                                    g_value_get_uint (value));
 
400
      break;
 
401
    default:
 
402
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
403
      break;
 
404
    }
 
405
}
 
406
 
 
407
static void
 
408
calendar_client_get_property (GObject    *object,
 
409
                              guint       prop_id,
 
410
                              GValue     *value,
 
411
                              GParamSpec *pspec)
 
412
{
 
413
  CalendarClient *client = CALENDAR_CLIENT (object);
 
414
 
 
415
  switch (prop_id)
 
416
    {
 
417
    case PROP_DAY:
 
418
      g_value_set_uint (value, client->priv->day);
 
419
      break;
 
420
    case PROP_MONTH:
 
421
      g_value_set_uint (value, client->priv->month);
 
422
      break;
 
423
    case PROP_YEAR:
 
424
      g_value_set_uint (value, client->priv->year);
 
425
      break;
 
426
    default:
 
427
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
428
      break;
 
429
    }
 
430
}
 
431
 
 
432
CalendarClient *
 
433
calendar_client_new (void)
 
434
{
 
435
  return g_object_new (CALENDAR_TYPE_CLIENT, NULL);
 
436
}
 
437
 
 
438
/* @day and @month can happily be out of range as
 
439
 * mktime() will normalize them correctly. From mktime(3):
 
440
 *
 
441
 * "If structure members are outside their legal interval,
 
442
 *  they will be normalized (so that, e.g., 40 October is
 
443
 *  changed into 9 November)."
 
444
 *
 
445
 * "What?", you say, "Something useful in libc?"
 
446
 */
 
447
static inline GTime
 
448
make_time_for_day_begin (int day,
 
449
                         int month,
 
450
                         int year)
 
451
{
 
452
  struct tm localtime_tm = { 0, };
 
453
 
 
454
  localtime_tm.tm_mday  = day;
 
455
  localtime_tm.tm_mon   = month;
 
456
  localtime_tm.tm_year  = year - 1900;
 
457
  localtime_tm.tm_isdst = -1;
 
458
 
 
459
  return mktime (&localtime_tm);
 
460
}
 
461
 
 
462
static inline char *
 
463
make_isodate_for_day_begin (int day,
 
464
                            int month,
 
465
                            int year)
 
466
{
 
467
  GTime utctime;
 
468
 
 
469
  utctime = make_time_for_day_begin (day, month, year);
 
470
 
 
471
  return utctime != -1 ? isodate_from_time_t (utctime) : NULL;
 
472
}
 
473
 
 
474
static GTime
 
475
get_time_from_property (icalcomponent         *ical,
 
476
                        icalproperty_kind      prop_kind,
 
477
                        struct icaltimetype (* get_prop_func) (const icalproperty *prop),
 
478
                        icaltimezone          *default_zone)
 
479
{
 
480
  icalproperty        *prop;
 
481
  struct icaltimetype  ical_time;
 
482
  icalparameter       *param;
 
483
  icaltimezone        *timezone = NULL;
 
484
  
 
485
  prop = icalcomponent_get_first_property (ical, prop_kind);
 
486
  if (!prop)
 
487
    return 0;
 
488
 
 
489
  ical_time = get_prop_func (prop);
 
490
 
 
491
  param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
 
492
  if (param)
 
493
    timezone = icaltimezone_get_builtin_timezone_from_tzid (icalparameter_get_tzid (param));
 
494
  else if (icaltime_is_utc (ical_time))
 
495
    timezone = icaltimezone_get_utc_timezone ();
 
496
  else 
 
497
    timezone = default_zone;
 
498
 
 
499
  return icaltime_as_timet_with_zone (ical_time, timezone);
 
500
}
 
501
 
 
502
static char *
 
503
get_ical_uid (icalcomponent *ical)
 
504
{
 
505
  return g_strdup (icalcomponent_get_uid (ical));
 
506
}
 
507
 
 
508
static char *
 
509
get_ical_rid (icalcomponent *ical)
 
510
{
 
511
  icalproperty        *prop;
 
512
  struct icaltimetype  ical_time;
 
513
  
 
514
  prop = icalcomponent_get_first_property (ical, ICAL_RECURRENCEID_PROPERTY);
 
515
  if (!prop)
 
516
    return NULL;
 
517
 
 
518
  ical_time = icalproperty_get_recurrenceid (prop);
 
519
 
 
520
  return icaltime_is_valid_time (ical_time) && !icaltime_is_null_time (ical_time) ? 
 
521
    g_strdup (icaltime_as_ical_string (ical_time)) : NULL;
 
522
}
 
523
 
 
524
static char *
 
525
get_ical_summary (icalcomponent *ical)
 
526
{
 
527
  icalproperty *prop;
 
528
 
 
529
  prop = icalcomponent_get_first_property (ical, ICAL_SUMMARY_PROPERTY);
 
530
  if (!prop)
 
531
    return NULL;
 
532
 
 
533
  return g_strdup (icalproperty_get_summary (prop));
 
534
}
 
535
 
 
536
static char *
 
537
get_ical_description (icalcomponent *ical)
 
538
{
 
539
  icalproperty *prop;
 
540
 
 
541
  prop = icalcomponent_get_first_property (ical, ICAL_DESCRIPTION_PROPERTY);
 
542
  if (!prop)
 
543
    return NULL;
 
544
 
 
545
  return g_strdup (icalproperty_get_description (prop));
 
546
}
 
547
 
 
548
static char *
 
549
get_ical_url (icalcomponent *ical)
 
550
{
 
551
  icalproperty *prop;
 
552
 
 
553
  prop = icalcomponent_get_first_property (ical, ICAL_URL_PROPERTY);
 
554
  if (!prop)
 
555
    return NULL;
 
556
 
 
557
  return g_strdup (icalproperty_get_url (prop));
 
558
}
 
559
 
 
560
static inline GTime
 
561
get_ical_start_time (icalcomponent *ical,
 
562
                     icaltimezone  *default_zone)
 
563
{
 
564
  return get_time_from_property (ical,
 
565
                                 ICAL_DTSTART_PROPERTY,
 
566
                                 icalproperty_get_dtstart,
 
567
                                 default_zone);
 
568
}
 
569
 
 
570
static inline GTime
 
571
get_ical_end_time (icalcomponent *ical,
 
572
                   icaltimezone  *default_zone)
 
573
{
 
574
  return get_time_from_property (ical,
 
575
                                 ICAL_DTEND_PROPERTY,
 
576
                                 icalproperty_get_dtend,
 
577
                                 default_zone);
 
578
}
 
579
 
 
580
static gboolean
 
581
get_ical_is_all_day (icalcomponent *ical,
 
582
                     GTime          start_gtime,
 
583
                     icaltimezone  *default_zone)
 
584
{
 
585
  icalproperty            *prop;
 
586
  time_t                   start_time;
 
587
  struct tm               *start_tm;
 
588
  GTime                    end_time;
 
589
  struct icaldurationtype  duration;
 
590
  struct icaltimetype      start_icaltime;
 
591
 
 
592
  start_icaltime = icalcomponent_get_dtstart (ical);
 
593
  if (start_icaltime.is_date)
 
594
    return TRUE;
 
595
 
 
596
  start_time = (time_t) start_gtime;
 
597
  start_tm = gmtime (&start_time);
 
598
  if (start_tm->tm_sec  != 0 ||
 
599
      start_tm->tm_min  != 0 ||
 
600
      start_tm->tm_hour != 0)
 
601
    return FALSE;
 
602
 
 
603
  if ((end_time = get_ical_end_time (ical, default_zone)))
 
604
    return (end_time - start_time) % 86400 == 0;
 
605
 
 
606
  prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY);
 
607
  if (!prop)
 
608
    return FALSE;
 
609
 
 
610
  duration = icalproperty_get_duration (prop);
 
611
 
 
612
  return icaldurationtype_as_int (duration) % 86400 == 0;
 
613
}
 
614
 
 
615
static inline GTime
 
616
get_ical_due_time (icalcomponent *ical,
 
617
                   icaltimezone  *default_zone)
 
618
{
 
619
  return get_time_from_property (ical,
 
620
                                 ICAL_DUE_PROPERTY,
 
621
                                 icalproperty_get_due,
 
622
                                 default_zone);
 
623
}
 
624
 
 
625
static guint
 
626
get_ical_percent_complete (icalcomponent *ical)
 
627
{
 
628
  icalproperty *prop;
 
629
  int           percent_complete;
 
630
 
 
631
  prop = icalcomponent_get_first_property (ical, ICAL_COMPLETED_PROPERTY);
 
632
  if (prop)
 
633
    return 100;
 
634
 
 
635
  prop = icalcomponent_get_first_property (ical, ICAL_PERCENTCOMPLETE_PROPERTY);
 
636
  if (!prop)
 
637
    return 0;
 
638
 
 
639
  percent_complete = icalproperty_get_percentcomplete (prop);
 
640
 
 
641
  return CLAMP (percent_complete, 0, 100);
 
642
}
 
643
 
 
644
static inline GTime
 
645
get_ical_completed_time (icalcomponent *ical,
 
646
                         icaltimezone  *default_zone)
 
647
{
 
648
  return get_time_from_property (ical,
 
649
                                 ICAL_COMPLETED_PROPERTY,
 
650
                                 icalproperty_get_completed,
 
651
                                 default_zone);
 
652
}
 
653
 
 
654
static int
 
655
get_ical_priority (icalcomponent *ical)
 
656
{
 
657
  icalproperty *prop;
 
658
 
 
659
  prop = icalcomponent_get_first_property (ical, ICAL_PRIORITY_PROPERTY);
 
660
  if (!prop)
 
661
    return -1;
 
662
 
 
663
  return icalproperty_get_priority (prop);
 
664
}
 
665
 
 
666
static char *
 
667
get_source_color (ECal *esource)
 
668
{
 
669
  ESource *source;
 
670
  guint32  color;
 
671
 
 
672
  g_return_val_if_fail (E_IS_CAL (esource), NULL);
 
673
 
 
674
  source = e_cal_get_source (esource);
 
675
  if (e_source_get_color (source, &color)) {
 
676
    return g_strdup_printf ("%06x", color);
 
677
  }
 
678
  
 
679
  return NULL;
 
680
}
 
681
 
 
682
static inline int
 
683
null_safe_strcmp (const char *a,
 
684
                  const char *b)
 
685
{
 
686
  return (!a && !b) ? 0 : (a && !b) || (!a && b) ? 1 : strcmp (a, b);
 
687
}
 
688
 
 
689
static inline gboolean
 
690
calendar_appointment_equal (CalendarAppointment *a,
 
691
                            CalendarAppointment *b)
 
692
{
 
693
  GSList *la, *lb;
 
694
 
 
695
  if (g_slist_length (a->occurrences) != g_slist_length (b->occurrences))
 
696
      return FALSE;
 
697
 
 
698
  for (la = a->occurrences, lb = b->occurrences; la && lb; la = la->next, lb = lb->next)
 
699
    {
 
700
      CalendarOccurrence *oa = la->data;
 
701
      CalendarOccurrence *ob = lb->data;
 
702
 
 
703
      if (oa->start_time != ob->start_time ||
 
704
          oa->end_time   != ob->end_time)
 
705
        return FALSE;
 
706
    }
 
707
 
 
708
  return
 
709
    null_safe_strcmp (a->uid,          b->uid)          == 0 &&
 
710
    null_safe_strcmp (a->summary,      b->summary)      == 0 &&
 
711
    null_safe_strcmp (a->description,  b->description)  == 0 &&
 
712
    null_safe_strcmp (a->color_string, b->color_string) == 0 &&
 
713
    a->start_time == b->start_time                         &&
 
714
    a->end_time   == b->end_time                           &&
 
715
    a->is_all_day == b->is_all_day;
 
716
}
 
717
 
 
718
static void
 
719
calendar_appointment_copy (CalendarAppointment *appointment,
 
720
                           CalendarAppointment *appointment_copy)
 
721
{
 
722
  GSList *l;
 
723
 
 
724
  g_assert (appointment != NULL);
 
725
  g_assert (appointment_copy != NULL);
 
726
 
 
727
  appointment_copy->occurrences = g_slist_copy (appointment->occurrences);
 
728
  for (l = appointment_copy->occurrences; l; l = l->next)
 
729
    {
 
730
      CalendarOccurrence *occurrence = l->data;
 
731
      CalendarOccurrence *occurrence_copy;
 
732
 
 
733
      occurrence_copy             = g_new0 (CalendarOccurrence, 1);
 
734
      occurrence_copy->start_time = occurrence->start_time;
 
735
      occurrence_copy->end_time   = occurrence->end_time;
 
736
 
 
737
      l->data = occurrence_copy;
 
738
    }
 
739
 
 
740
  appointment_copy->uid          = g_strdup (appointment->uid);
 
741
  appointment_copy->summary      = g_strdup (appointment->summary);
 
742
  appointment_copy->description  = g_strdup (appointment->description);
 
743
  appointment_copy->color_string = g_strdup (appointment->color_string);
 
744
  appointment_copy->start_time   = appointment->start_time;
 
745
  appointment_copy->end_time     = appointment->end_time;
 
746
  appointment_copy->is_all_day   = appointment->is_all_day;
 
747
}
 
748
 
 
749
static void
 
750
calendar_appointment_finalize (CalendarAppointment *appointment)
 
751
{
 
752
  GSList *l;
 
753
 
 
754
  for (l = appointment->occurrences; l; l = l->next)
 
755
    g_free (l->data);
 
756
  g_slist_free (appointment->occurrences);
 
757
  appointment->occurrences = NULL;
 
758
 
 
759
  g_free (appointment->uid);
 
760
  appointment->uid = NULL;
 
761
 
 
762
  g_free (appointment->summary);
 
763
  appointment->summary = NULL;
 
764
 
 
765
  g_free (appointment->description);
 
766
  appointment->description = NULL;
 
767
 
 
768
  g_free (appointment->color_string);
 
769
  appointment->color_string = NULL;
 
770
 
 
771
  appointment->start_time = 0;
 
772
  appointment->is_all_day = FALSE;
 
773
}
 
774
 
 
775
static void
 
776
calendar_appointment_init (CalendarAppointment  *appointment,
 
777
                           icalcomponent        *ical,
 
778
                           CalendarClientSource *source,
 
779
                           icaltimezone         *default_zone)
 
780
{
 
781
  appointment->uid          = get_ical_uid (ical);
 
782
  appointment->rid          = get_ical_rid (ical);
 
783
  appointment->summary      = get_ical_summary (ical);
 
784
  appointment->description  = get_ical_description (ical);
 
785
  appointment->color_string = get_source_color (source->source);
 
786
  appointment->start_time   = get_ical_start_time (ical, default_zone);
 
787
  appointment->end_time     = get_ical_end_time (ical, default_zone);
 
788
  appointment->is_all_day   = get_ical_is_all_day (ical,
 
789
                                                   appointment->start_time,
 
790
                                                   default_zone);
 
791
}
 
792
 
 
793
static icaltimezone *
 
794
resolve_timezone_id (const char *tzid,
 
795
                     ECal       *source)
 
796
{
 
797
  icaltimezone *retval;
 
798
 
 
799
  retval = icaltimezone_get_builtin_timezone_from_tzid (tzid);
 
800
  if (!retval)
 
801
    {
 
802
      e_cal_get_timezone (source, tzid, &retval, NULL);
 
803
    }
 
804
 
 
805
  return retval;
 
806
}
 
807
 
 
808
static gboolean
 
809
calendar_appointment_collect_occurrence (ECalComponent  *component,
 
810
                                         GTime           occurrence_start,
 
811
                                         GTime           occurrence_end,
 
812
                                         GSList        **collect_loc)
 
813
{
 
814
  CalendarOccurrence *occurrence;
 
815
 
 
816
  occurrence             = g_new0 (CalendarOccurrence, 1);
 
817
  occurrence->start_time = occurrence_start;
 
818
  occurrence->end_time   = occurrence_end;
 
819
 
 
820
  *collect_loc = g_slist_prepend (*collect_loc, occurrence);
 
821
 
 
822
  return TRUE;
 
823
}
 
824
 
 
825
static void
 
826
calendar_appointment_generate_ocurrences (CalendarAppointment *appointment,
 
827
                                          icalcomponent       *ical,
 
828
                                          ECal                *source,
 
829
                                          GTime                start,
 
830
                                          GTime                end,
 
831
                                          icaltimezone        *default_zone)
 
832
{
 
833
  ECalComponent *ecal;
 
834
 
 
835
  g_assert (appointment->occurrences == NULL);
 
836
 
 
837
  ecal = e_cal_component_new ();
 
838
  e_cal_component_set_icalcomponent (ecal,
 
839
                                     icalcomponent_new_clone (ical));
 
840
 
 
841
  e_cal_recur_generate_instances (ecal,
 
842
                                  start,
 
843
                                  end,
 
844
                                  (ECalRecurInstanceFn) calendar_appointment_collect_occurrence,
 
845
                                  &appointment->occurrences,
 
846
                                  (ECalRecurResolveTimezoneFn) resolve_timezone_id,
 
847
                                  source,
 
848
                                  default_zone);
 
849
 
 
850
  g_object_unref (ecal);
 
851
 
 
852
  appointment->occurrences = g_slist_reverse (appointment->occurrences);
 
853
}
 
854
 
 
855
static inline gboolean
 
856
calendar_task_equal (CalendarTask *a,
 
857
                     CalendarTask *b)
 
858
{
 
859
  return
 
860
    null_safe_strcmp (a->uid,          b->uid)          == 0 &&
 
861
    null_safe_strcmp (a->summary,      b->summary)      == 0 &&
 
862
    null_safe_strcmp (a->description,  b->description)  == 0 &&
 
863
    null_safe_strcmp (a->color_string, b->color_string) == 0 &&
 
864
    null_safe_strcmp (a->url,          b->url)          == 0 &&
 
865
    a->start_time       == b->start_time                   &&
 
866
    a->due_time         == b->due_time                     &&
 
867
    a->percent_complete == b->percent_complete             &&
 
868
    a->completed_time   == b->completed_time               &&
 
869
    a->priority         == b->priority;
 
870
}
 
871
 
 
872
static void
 
873
calendar_task_copy (CalendarTask *task,
 
874
                    CalendarTask *task_copy)
 
875
{
 
876
  g_assert (task != NULL);
 
877
  g_assert (task_copy != NULL);
 
878
 
 
879
  task_copy->uid              = g_strdup (task->uid);
 
880
  task_copy->summary          = g_strdup (task->summary);
 
881
  task_copy->description      = g_strdup (task->description);
 
882
  task_copy->color_string     = g_strdup (task->color_string);
 
883
  task_copy->url              = g_strdup (task->url);
 
884
  task_copy->start_time       = task->start_time;
 
885
  task_copy->due_time         = task->due_time;
 
886
  task_copy->percent_complete = task->percent_complete;
 
887
  task_copy->completed_time   = task->completed_time;
 
888
  task_copy->priority         = task->priority;
 
889
}
 
890
 
 
891
static void
 
892
calendar_task_finalize (CalendarTask *task)
 
893
{
 
894
  g_free (task->uid);
 
895
  task->uid = NULL;
 
896
 
 
897
  g_free (task->summary);
 
898
  task->summary = NULL;
 
899
 
 
900
  g_free (task->description);
 
901
  task->description = NULL;
 
902
 
 
903
  g_free (task->color_string);
 
904
  task->color_string = NULL;
 
905
 
 
906
  g_free (task->url);
 
907
  task->url = NULL;
 
908
 
 
909
  task->percent_complete = 0;
 
910
}
 
911
 
 
912
static void
 
913
calendar_task_init (CalendarTask         *task,
 
914
                    icalcomponent        *ical,
 
915
                    CalendarClientSource *source,
 
916
                    icaltimezone         *default_zone)
 
917
{
 
918
  task->uid              = get_ical_uid (ical);
 
919
  task->summary          = get_ical_summary (ical);
 
920
  task->description      = get_ical_description (ical);
 
921
  task->color_string     = get_source_color (source->source);
 
922
  task->url              = get_ical_url (ical);
 
923
  task->start_time       = get_ical_start_time (ical, default_zone);
 
924
  task->due_time         = get_ical_due_time (ical, default_zone);
 
925
  task->percent_complete = get_ical_percent_complete (ical);
 
926
  task->completed_time   = get_ical_completed_time (ical, default_zone);
 
927
  task->priority         = get_ical_priority (ical);
 
928
}
 
929
 
 
930
void
 
931
calendar_event_free (CalendarEvent *event)
 
932
{
 
933
  switch (event->type)
 
934
    {
 
935
    case CALENDAR_EVENT_APPOINTMENT:
 
936
      calendar_appointment_finalize (CALENDAR_APPOINTMENT (event));
 
937
      break;
 
938
    case CALENDAR_EVENT_TASK:
 
939
      calendar_task_finalize (CALENDAR_TASK (event));
 
940
      break;
 
941
    default:
 
942
      g_assert_not_reached ();
 
943
      break;
 
944
    }
 
945
 
 
946
  g_free (event);
 
947
}
 
948
 
 
949
static CalendarEvent *
 
950
calendar_event_new (icalcomponent        *ical,
 
951
                    CalendarClientSource *source,
 
952
                    icaltimezone         *default_zone)
 
953
{
 
954
  CalendarEvent *event;
 
955
 
 
956
  event = g_new0 (CalendarEvent, 1);
 
957
 
 
958
  switch (icalcomponent_isa (ical))
 
959
    {
 
960
    case ICAL_VEVENT_COMPONENT:
 
961
      event->type = CALENDAR_EVENT_APPOINTMENT;
 
962
      calendar_appointment_init (CALENDAR_APPOINTMENT (event),
 
963
                                 ical,
 
964
                                 source,
 
965
                                 default_zone);
 
966
      break;
 
967
    case ICAL_VTODO_COMPONENT:
 
968
      event->type = CALENDAR_EVENT_TASK;
 
969
      calendar_task_init (CALENDAR_TASK (event),
 
970
                          ical,
 
971
                          source,
 
972
                          default_zone);
 
973
      break;
 
974
    default:
 
975
      g_warning ("Unknown calendar component type: %d\n",
 
976
                 icalcomponent_isa (ical));
 
977
      g_free (event);
 
978
      return NULL;
 
979
    }
 
980
 
 
981
  return event;
 
982
}
 
983
 
 
984
static CalendarEvent *
 
985
calendar_event_copy (CalendarEvent *event)
 
986
{
 
987
  CalendarEvent *retval;
 
988
 
 
989
  if (!event)
 
990
    return NULL;
 
991
 
 
992
  retval = g_new0 (CalendarEvent, 1);
 
993
 
 
994
  retval->type = event->type;
 
995
 
 
996
  switch (event->type)
 
997
    {
 
998
    case CALENDAR_EVENT_APPOINTMENT:
 
999
      calendar_appointment_copy (CALENDAR_APPOINTMENT (event),
 
1000
                                 CALENDAR_APPOINTMENT (retval));
 
1001
      break;
 
1002
    case CALENDAR_EVENT_TASK:
 
1003
      calendar_task_copy (CALENDAR_TASK (event),
 
1004
                          CALENDAR_TASK (retval));
 
1005
      break;
 
1006
    default:
 
1007
      g_assert_not_reached ();
 
1008
      break;
 
1009
    }
 
1010
 
 
1011
  return retval;
 
1012
}
 
1013
 
 
1014
static char *
 
1015
calendar_event_get_uid (CalendarEvent *event)
 
1016
{
 
1017
  switch (event->type)
 
1018
    {
 
1019
    case CALENDAR_EVENT_APPOINTMENT:
 
1020
      return g_strdup_printf ("%s%s", CALENDAR_APPOINTMENT (event)->uid, CALENDAR_APPOINTMENT (event)->rid ? CALENDAR_APPOINTMENT (event)->rid : ""); 
 
1021
      break;
 
1022
    case CALENDAR_EVENT_TASK:
 
1023
      return g_strdup (CALENDAR_TASK (event)->uid);
 
1024
      break;
 
1025
    default:
 
1026
      g_assert_not_reached ();
 
1027
      break;
 
1028
    }
 
1029
 
 
1030
  return NULL;
 
1031
}
 
1032
 
 
1033
static gboolean
 
1034
calendar_event_equal (CalendarEvent *a,
 
1035
                      CalendarEvent *b)
 
1036
{
 
1037
  if (!a && !b)
 
1038
    return TRUE;
 
1039
 
 
1040
  if ((a && !b) || (!a && b))
 
1041
    return FALSE;
 
1042
 
 
1043
  if (a->type != b->type)
 
1044
    return FALSE;
 
1045
 
 
1046
  switch (a->type)
 
1047
    {
 
1048
    case CALENDAR_EVENT_APPOINTMENT:
 
1049
      return calendar_appointment_equal (CALENDAR_APPOINTMENT (a),
 
1050
                                         CALENDAR_APPOINTMENT (b));
 
1051
    case CALENDAR_EVENT_TASK:
 
1052
      return calendar_task_equal (CALENDAR_TASK (a),
 
1053
                                  CALENDAR_TASK (b));
 
1054
    default:
 
1055
      break;
 
1056
    }
 
1057
 
 
1058
  g_assert_not_reached ();
 
1059
 
 
1060
  return FALSE;
 
1061
}
 
1062
 
 
1063
static void
 
1064
calendar_event_generate_ocurrences (CalendarEvent *event,
 
1065
                                    icalcomponent *ical,
 
1066
                                    ECal          *source,
 
1067
                                    GTime          start,
 
1068
                                    GTime          end,
 
1069
                                    icaltimezone  *default_zone)
 
1070
{
 
1071
  if (event->type != CALENDAR_EVENT_APPOINTMENT)
 
1072
    return;
 
1073
 
 
1074
  calendar_appointment_generate_ocurrences (CALENDAR_APPOINTMENT (event),
 
1075
                                            ical,
 
1076
                                            source,
 
1077
                                            start,
 
1078
                                            end,
 
1079
                                            default_zone);
 
1080
}
 
1081
 
 
1082
static inline void
 
1083
calendar_event_debug_dump (CalendarEvent *event)
 
1084
{
 
1085
#ifdef CALENDAR_ENABLE_DEBUG
 
1086
  switch (event->type)
 
1087
    {
 
1088
    case CALENDAR_EVENT_APPOINTMENT:
 
1089
      {
 
1090
        char   *start_str;
 
1091
        char   *end_str;
 
1092
        GSList *l;
 
1093
 
 
1094
        start_str = CALENDAR_APPOINTMENT (event)->start_time ?
 
1095
                            isodate_from_time_t (CALENDAR_APPOINTMENT (event)->start_time) :
 
1096
                            g_strdup ("(undefined)");
 
1097
        end_str = CALENDAR_APPOINTMENT (event)->end_time ?
 
1098
                            isodate_from_time_t (CALENDAR_APPOINTMENT (event)->end_time) :
 
1099
                            g_strdup ("(undefined)");
 
1100
          
 
1101
        dprintf ("Appointment: uid '%s', summary '%s', description '%s', "
 
1102
                 "start_time '%s', end_time '%s', is_all_day %s\n",
 
1103
                 CALENDAR_APPOINTMENT (event)->uid,
 
1104
                 CALENDAR_APPOINTMENT (event)->summary,
 
1105
                 CALENDAR_APPOINTMENT (event)->description,
 
1106
                 start_str,
 
1107
                 end_str,
 
1108
                 CALENDAR_APPOINTMENT (event)->is_all_day ? "(true)" : "(false)");
 
1109
 
 
1110
        g_free (start_str);
 
1111
        g_free (end_str);
 
1112
 
 
1113
        dprintf ("  Occurrences:\n");
 
1114
        for (l = CALENDAR_APPOINTMENT (event)->occurrences; l; l = l->next)
 
1115
          {
 
1116
            CalendarOccurrence *occurrence = l->data;
 
1117
 
 
1118
            start_str = occurrence->start_time ?
 
1119
              isodate_from_time_t (occurrence->start_time) :
 
1120
              g_strdup ("(undefined)");
 
1121
            
 
1122
            end_str = occurrence->end_time ?
 
1123
              isodate_from_time_t (occurrence->end_time) :
 
1124
              g_strdup ("(undefined)");
 
1125
 
 
1126
            dprintf ("    start_time '%s', end_time '%s'\n",
 
1127
                     start_str, end_str);
 
1128
 
 
1129
            g_free (start_str);
 
1130
            g_free (end_str);
 
1131
          }
 
1132
      }
 
1133
      break;
 
1134
    case CALENDAR_EVENT_TASK:
 
1135
      {
 
1136
        char *start_str;
 
1137
        char *due_str;
 
1138
        char *completed_str;
 
1139
 
 
1140
        start_str = CALENDAR_TASK (event)->start_time ?
 
1141
                            isodate_from_time_t (CALENDAR_TASK (event)->start_time) :
 
1142
                            g_strdup ("(undefined)");
 
1143
        due_str = CALENDAR_TASK (event)->due_time ?
 
1144
                            isodate_from_time_t (CALENDAR_TASK (event)->due_time) :
 
1145
                            g_strdup ("(undefined)");
 
1146
        completed_str = CALENDAR_TASK (event)->completed_time ?
 
1147
                            isodate_from_time_t (CALENDAR_TASK (event)->completed_time) :
 
1148
                            g_strdup ("(undefined)");
 
1149
 
 
1150
        dprintf ("Task: uid '%s', summary '%s', description '%s', "
 
1151
                 "start_time '%s', due_time '%s', percent_complete %d, completed_time '%s'\n",
 
1152
                 CALENDAR_TASK (event)->uid,
 
1153
                 CALENDAR_TASK (event)->summary,
 
1154
                 CALENDAR_TASK (event)->description,
 
1155
                 start_str,
 
1156
                 due_str,
 
1157
                 CALENDAR_TASK (event)->percent_complete,
 
1158
                 completed_str);
 
1159
 
 
1160
        g_free (completed_str);
 
1161
      }
 
1162
      break;
 
1163
    default:
 
1164
      g_assert_not_reached ();
 
1165
      break;
 
1166
    }
 
1167
#endif
 
1168
}
 
1169
 
 
1170
static inline CalendarClientQuery *
 
1171
goddamn_this_is_crack (CalendarClientSource *source,
 
1172
                       ECalView             *view,
 
1173
                       gboolean             *emit_signal)
 
1174
{
 
1175
  g_assert (view != NULL);
 
1176
 
 
1177
  if (source->completed_query.view == view)
 
1178
    {
 
1179
      if (emit_signal)
 
1180
        *emit_signal = TRUE;
 
1181
      return &source->completed_query;
 
1182
    }
 
1183
  else if (source->in_progress_query.view == view)
 
1184
    {
 
1185
      if (emit_signal)
 
1186
        *emit_signal = FALSE;
 
1187
      return &source->in_progress_query;
 
1188
    }
 
1189
 
 
1190
  g_assert_not_reached ();
 
1191
 
 
1192
  return NULL;
 
1193
}
 
1194
 
 
1195
static void
 
1196
calendar_client_handle_query_completed (CalendarClientSource *source,
 
1197
                                        ECalendarStatus       status,
 
1198
                                        ECalView             *view)
 
1199
{
 
1200
  CalendarClientQuery *query;
 
1201
 
 
1202
  query = goddamn_this_is_crack (source, view, NULL);
 
1203
  
 
1204
  dprintf ("Query %p completed: %s\n", query, e_cal_get_error_message (status));
 
1205
 
 
1206
  if (status != E_CALENDAR_STATUS_OK)
 
1207
    {
 
1208
      g_warning ("Calendar query failed: %s\n",
 
1209
                 e_cal_get_error_message (status));
 
1210
      calendar_client_stop_query (source->client, source, query);
 
1211
      return;
 
1212
    }
 
1213
 
 
1214
  g_assert (source->query_in_progress != FALSE);
 
1215
  g_assert (query == &source->in_progress_query);
 
1216
 
 
1217
  calendar_client_query_finalize (&source->completed_query);
 
1218
 
 
1219
  source->completed_query = source->in_progress_query;
 
1220
  source->query_completed = TRUE;
 
1221
 
 
1222
  source->query_in_progress        = FALSE;
 
1223
  source->in_progress_query.view   = NULL;
 
1224
  source->in_progress_query.events = NULL;
 
1225
 
 
1226
  g_signal_emit (source->client, source->changed_signal_id, 0);
 
1227
}
 
1228
 
 
1229
static void
 
1230
calendar_client_handle_query_result (CalendarClientSource *source,
 
1231
                                     GList                *objects,
 
1232
                                     ECalView             *view)
 
1233
{
 
1234
  CalendarClientQuery *query;
 
1235
  CalendarClient      *client;
 
1236
  gboolean             emit_signal;
 
1237
  gboolean             events_changed;
 
1238
  GList               *l;
 
1239
  GTime                month_begin;
 
1240
  GTime                month_end;
 
1241
 
 
1242
  client = source->client;
 
1243
 
 
1244
  query = goddamn_this_is_crack (source, view, &emit_signal);
 
1245
 
 
1246
  dprintf ("Query %p result: %d objects:\n",
 
1247
           query, g_list_length (objects));
 
1248
 
 
1249
  month_begin = make_time_for_day_begin (1,
 
1250
                                         client->priv->month,
 
1251
                                         client->priv->year);
 
1252
 
 
1253
  month_end = make_time_for_day_begin (1,
 
1254
                                       client->priv->month + 1,
 
1255
                                       client->priv->year);
 
1256
 
 
1257
  events_changed = FALSE;
 
1258
  for (l = objects; l; l = l->next)
 
1259
    {
 
1260
      CalendarEvent *event;
 
1261
      CalendarEvent *old_event;
 
1262
      icalcomponent *ical = l->data;
 
1263
      char          *uid;
 
1264
      
 
1265
      event = calendar_event_new (ical, source, client->priv->zone);
 
1266
      if (!event)
 
1267
              continue;
 
1268
 
 
1269
      calendar_event_generate_ocurrences (event,
 
1270
                                          ical,
 
1271
                                          source->source,
 
1272
                                          month_begin,
 
1273
                                          month_end,
 
1274
                                          client->priv->zone);
 
1275
 
 
1276
      uid = calendar_event_get_uid (event);
 
1277
      
 
1278
      old_event = g_hash_table_lookup (query->events, uid);
 
1279
 
 
1280
      if (!calendar_event_equal (event, old_event))
 
1281
        {
 
1282
          dprintf ("Event %s: ", old_event ? "modified" : "added");
 
1283
 
 
1284
          calendar_event_debug_dump (event);
 
1285
 
 
1286
          g_hash_table_replace (query->events, uid, event);
 
1287
 
 
1288
          events_changed = TRUE;
 
1289
        }
 
1290
      else
 
1291
        {
 
1292
          g_free (uid);
 
1293
        }               
 
1294
    }
 
1295
 
 
1296
  if (emit_signal && events_changed)
 
1297
    {
 
1298
      g_signal_emit (source->client, source->changed_signal_id, 0);
 
1299
    }
 
1300
}
 
1301
 
 
1302
static gboolean
 
1303
check_object_remove (gpointer key,
 
1304
                     gpointer value,
 
1305
                     gpointer data)
 
1306
{
 
1307
  char             *uid = data;
 
1308
  ssize_t           len;
 
1309
 
 
1310
  len = strlen (uid);
 
1311
  
 
1312
  if (len <= strlen (key) && strncmp (uid, key, len) == 0)
 
1313
    {
 
1314
      dprintf ("Event removed: ");
 
1315
 
 
1316
      calendar_event_debug_dump (value);
 
1317
 
 
1318
      return TRUE;
 
1319
    }
 
1320
 
 
1321
  return FALSE;
 
1322
}
 
1323
 
 
1324
static void
 
1325
calendar_client_handle_objects_removed (CalendarClientSource *source,
 
1326
                                        GList                *ids,
 
1327
                                        ECalView             *view)
 
1328
{
 
1329
  CalendarClientQuery *query;
 
1330
  gboolean             emit_signal;
 
1331
  gboolean             events_changed;
 
1332
  GList               *l;
 
1333
 
 
1334
  query = goddamn_this_is_crack (source, view, &emit_signal);
 
1335
 
 
1336
  events_changed = FALSE;
 
1337
  for (l = ids; l; l = l->next)
 
1338
    {
 
1339
      CalendarEvent   *event;
 
1340
      ECalComponentId *id = l->data;
 
1341
      char            *uid = g_strdup_printf ("%s%s", id->uid, id->rid ? id->rid : "");
 
1342
 
 
1343
      if (!id->rid || !(*id->rid))
 
1344
        {
 
1345
          int size = g_hash_table_size (query->events);
 
1346
 
 
1347
          g_hash_table_foreach_remove (query->events, check_object_remove, id->uid);
 
1348
 
 
1349
                if (size != g_hash_table_size (query->events))
 
1350
                        events_changed = TRUE;          
 
1351
        }
 
1352
      else if ((event = g_hash_table_lookup (query->events, uid)))
 
1353
        {
 
1354
          dprintf ("Event removed: ");
 
1355
 
 
1356
          calendar_event_debug_dump (event);
 
1357
 
 
1358
          g_assert (g_hash_table_remove (query->events, uid));
 
1359
 
 
1360
          events_changed = TRUE;
 
1361
        }
 
1362
      g_free (uid);
 
1363
    }
 
1364
 
 
1365
  if (emit_signal && events_changed)
 
1366
    {
 
1367
      g_signal_emit (source->client, source->changed_signal_id, 0);
 
1368
    }
 
1369
}
 
1370
 
 
1371
static void
 
1372
calendar_client_query_finalize (CalendarClientQuery *query)
 
1373
{
 
1374
  if (query->view)
 
1375
    g_object_unref (query->view);
 
1376
  query->view = NULL;
 
1377
 
 
1378
  if (query->events)
 
1379
    g_hash_table_destroy (query->events);
 
1380
  query->events = NULL;
 
1381
}
 
1382
 
 
1383
static void
 
1384
calendar_client_stop_query (CalendarClient       *client,
 
1385
                            CalendarClientSource *source,
 
1386
                            CalendarClientQuery  *query)
 
1387
{
 
1388
  if (query == &source->in_progress_query)
 
1389
    {
 
1390
      dprintf ("Stopping in progress query %p\n", query);
 
1391
 
 
1392
      g_assert (source->query_in_progress != FALSE);
 
1393
 
 
1394
      source->query_in_progress = FALSE;
 
1395
    }
 
1396
  else if (query == &source->completed_query)
 
1397
    {
 
1398
      dprintf ("Stopping completed query %p\n", query);
 
1399
 
 
1400
      g_assert (source->query_completed != FALSE);
 
1401
 
 
1402
      source->query_completed = FALSE;
 
1403
    }
 
1404
  else
 
1405
    g_assert_not_reached ();
 
1406
  
 
1407
  calendar_client_query_finalize (query);
 
1408
}
 
1409
 
 
1410
static void
 
1411
calendar_client_start_query (CalendarClient       *client,
 
1412
                             CalendarClientSource *source,
 
1413
                             const char           *query)
 
1414
{
 
1415
  ECalView *view = NULL;
 
1416
  GError   *error = NULL;
 
1417
 
 
1418
  if (!e_cal_get_query (source->source, query, &view, &error))
 
1419
    {
 
1420
      g_warning ("Error preparing the query: '%s': %s\n",
 
1421
                 query, error->message);
 
1422
      g_error_free (error);
 
1423
      return;
 
1424
    }
 
1425
 
 
1426
  g_assert (view != NULL);
 
1427
 
 
1428
  if (source->query_in_progress)
 
1429
    calendar_client_stop_query (client, source, &source->in_progress_query);
 
1430
  
 
1431
  dprintf ("Starting query %p: '%s'\n", &source->in_progress_query, query);
 
1432
 
 
1433
  source->query_in_progress        = TRUE;
 
1434
  source->in_progress_query.view   = view;
 
1435
  source->in_progress_query.events =
 
1436
    g_hash_table_new_full (g_str_hash,
 
1437
                           g_str_equal,
 
1438
                           g_free,
 
1439
                           (GDestroyNotify) calendar_event_free);
 
1440
 
 
1441
  g_signal_connect_swapped (view, "objects-added",
 
1442
                            G_CALLBACK (calendar_client_handle_query_result),
 
1443
                            source);
 
1444
  g_signal_connect_swapped (view, "objects-modified",
 
1445
                            G_CALLBACK (calendar_client_handle_query_result),
 
1446
                            source);
 
1447
  g_signal_connect_swapped (view, "objects-removed",
 
1448
                            G_CALLBACK (calendar_client_handle_objects_removed),
 
1449
                            source);
 
1450
  g_signal_connect_swapped (view, "view-done",
 
1451
                            G_CALLBACK (calendar_client_handle_query_completed),
 
1452
                            source);
 
1453
 
 
1454
  e_cal_view_start (view);
 
1455
}
 
1456
 
 
1457
static void
 
1458
calendar_client_update_appointments (CalendarClient *client)
 
1459
{
 
1460
  GSList *l;
 
1461
  char   *query;
 
1462
  char   *month_begin;
 
1463
  char   *month_end;
 
1464
 
 
1465
  if (client->priv->month == -1 ||
 
1466
      client->priv->year  == -1)
 
1467
    return;
 
1468
 
 
1469
  month_begin = make_isodate_for_day_begin (1,
 
1470
                                            client->priv->month,
 
1471
                                            client->priv->year);
 
1472
 
 
1473
  month_end = make_isodate_for_day_begin (1,
 
1474
                                          client->priv->month + 1,
 
1475
                                          client->priv->year);
 
1476
 
 
1477
  query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") "
 
1478
                                                "(make-time \"%s\")",
 
1479
                           month_begin, month_end);
 
1480
 
 
1481
  for (l = client->priv->appointment_sources; l; l = l->next)
 
1482
    calendar_client_start_query (client, l->data, query);
 
1483
 
 
1484
  g_free (month_begin);
 
1485
  g_free (month_end);
 
1486
  g_free (query);
 
1487
}
 
1488
 
 
1489
/* FIXME:
 
1490
 * perhaps we should use evo's "hide_completed_tasks" pref?
 
1491
 */
 
1492
static void
 
1493
calendar_client_update_tasks (CalendarClient *client)
 
1494
{
 
1495
  GSList *l;
 
1496
  char   *query;
 
1497
 
 
1498
#ifdef FIX_BROKEN_TASKS_QUERY
 
1499
  /* FIXME: this doesn't work for tasks without a start or
 
1500
   *        due date
 
1501
   *        Look at filter_task() to see the behaviour we
 
1502
   *        want.
 
1503
   */
 
1504
  
 
1505
  char   *day_begin;
 
1506
  char   *day_end;
 
1507
 
 
1508
  if (client->priv->day   == -1 ||
 
1509
      client->priv->month == -1 ||
 
1510
      client->priv->year  == -1)
 
1511
    return;
 
1512
 
 
1513
  day_begin = make_isodate_for_day_begin (client->priv->day,
 
1514
                                          client->priv->month,
 
1515
                                          client->priv->year);
 
1516
 
 
1517
  day_end = make_isodate_for_day_begin (client->priv->day + 1,
 
1518
                                        client->priv->month,
 
1519
                                        client->priv->year);
 
1520
  if (!day_begin || !day_end)
 
1521
    {
 
1522
      g_warning ("Cannot run query with invalid date: %dd %dy %dm\n",
 
1523
                 client->priv->day,
 
1524
                 client->priv->month,
 
1525
                 client->priv->year);
 
1526
      g_free (day_begin);
 
1527
      g_free (day_end);
 
1528
      return;
 
1529
    }
 
1530
  
 
1531
  query = g_strdup_printf ("(and (occur-in-time-range? (make-time \"%s\") "
 
1532
                                                      "(make-time \"%s\")) "
 
1533
                             "(or (not is-completed?) "
 
1534
                               "(and (is-completed?) "
 
1535
                                    "(not (completed-before? (make-time \"%s\"))))))",
 
1536
                           day_begin, day_end, day_begin);
 
1537
#else
 
1538
  query = g_strdup ("#t");
 
1539
#endif /* FIX_BROKEN_TASKS_QUERY */
 
1540
 
 
1541
  for (l = client->priv->task_sources; l; l = l->next)
 
1542
    calendar_client_start_query (client, l->data, query);
 
1543
 
 
1544
#ifdef FIX_BROKEN_TASKS_QUERY
 
1545
  g_free (day_begin);
 
1546
  g_free (day_end);
 
1547
#endif
 
1548
  g_free (query);
 
1549
}
 
1550
 
 
1551
static void
 
1552
calendar_client_source_finalize (CalendarClientSource *source)
 
1553
{
 
1554
  source->client = NULL;
 
1555
 
 
1556
  if (source->source)
 
1557
    g_object_unref (source->source);
 
1558
  source->source = NULL;
 
1559
 
 
1560
  calendar_client_query_finalize (&source->completed_query);
 
1561
  calendar_client_query_finalize (&source->in_progress_query);
 
1562
  
 
1563
  source->query_completed   = FALSE;
 
1564
  source->query_in_progress = FALSE;
 
1565
}
 
1566
 
 
1567
static int
 
1568
compare_calendar_sources (CalendarClientSource *s1,
 
1569
                          CalendarClientSource *s2)
 
1570
{
 
1571
  return (s1->source == s2->source) ? 0 : 1;
 
1572
}
 
1573
 
 
1574
static GSList *
 
1575
calendar_client_update_sources_list (CalendarClient *client,
 
1576
                                     GSList         *sources,
 
1577
                                     GSList         *esources,
 
1578
                                     guint           changed_signal_id)
 
1579
{
 
1580
  GSList *retval, *l;
 
1581
 
 
1582
  retval = NULL;
 
1583
 
 
1584
  for (l = esources; l; l = l->next)
 
1585
    {
 
1586
      CalendarClientSource  dummy_source;
 
1587
      CalendarClientSource *new_source;
 
1588
      GSList               *s;
 
1589
      ECal                 *esource = l->data;
 
1590
 
 
1591
      dummy_source.source = esource;
 
1592
 
 
1593
      dprintf ("update_sources_list: adding client %s: ",
 
1594
               e_source_peek_uid (e_cal_get_source (esource)));
 
1595
 
 
1596
      if ((s = g_slist_find_custom (sources,
 
1597
                                    &dummy_source,
 
1598
                                    (GCompareFunc) compare_calendar_sources)))
 
1599
        {
 
1600
          dprintf ("already on list\n");
 
1601
          new_source = s->data;
 
1602
          sources = g_slist_delete_link (sources, s);
 
1603
        }
 
1604
      else
 
1605
        {
 
1606
          dprintf ("added\n");
 
1607
          new_source                    = g_new0 (CalendarClientSource, 1);
 
1608
          new_source->client            = client;
 
1609
          new_source->source            = g_object_ref (esource);
 
1610
          new_source->changed_signal_id = changed_signal_id;
 
1611
        }
 
1612
 
 
1613
      retval = g_slist_prepend (retval, new_source);
 
1614
    }
 
1615
 
 
1616
  for (l = sources; l; l = l->next)
 
1617
    {
 
1618
      CalendarClientSource *source = l->data;
 
1619
 
 
1620
      dprintf ("Removing client %s from list\n",
 
1621
               e_source_peek_uid (e_cal_get_source (source->source)));
 
1622
 
 
1623
      calendar_client_source_finalize (source);
 
1624
      g_free (source);
 
1625
    }
 
1626
  g_slist_free (sources);
 
1627
 
 
1628
  return retval;
 
1629
}
 
1630
 
 
1631
static void
 
1632
calendar_client_appointment_sources_changed (CalendarClient  *client)
 
1633
{
 
1634
  GSList *esources;
 
1635
 
 
1636
  dprintf ("appointment_sources_changed: updating ...\n");
 
1637
 
 
1638
  esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
 
1639
 
 
1640
  client->priv->appointment_sources = 
 
1641
    calendar_client_update_sources_list (client,
 
1642
                                         client->priv->appointment_sources,
 
1643
                                         esources,
 
1644
                                         signals [APPOINTMENTS_CHANGED]);
 
1645
 
 
1646
  calendar_client_update_appointments (client);
 
1647
}
 
1648
 
 
1649
static void
 
1650
calendar_client_task_sources_changed (CalendarClient  *client)
 
1651
{
 
1652
  GSList *esources;
 
1653
 
 
1654
  dprintf ("task_sources_changed: updating ...\n");
 
1655
 
 
1656
  esources = calendar_sources_get_task_sources (client->priv->calendar_sources);
 
1657
 
 
1658
  client->priv->task_sources = 
 
1659
    calendar_client_update_sources_list (client,
 
1660
                                         client->priv->task_sources,
 
1661
                                         esources,
 
1662
                                         signals [TASKS_CHANGED]);
 
1663
 
 
1664
  calendar_client_update_tasks (client);
 
1665
}
 
1666
 
 
1667
void
 
1668
calendar_client_get_date (CalendarClient *client,
 
1669
                          guint          *year,
 
1670
                          guint          *month,
 
1671
                          guint          *day)
 
1672
{
 
1673
  g_return_if_fail (CALENDAR_IS_CLIENT (client));
 
1674
 
 
1675
  if (year)
 
1676
    *year = client->priv->year;
 
1677
 
 
1678
  if (month)
 
1679
    *month = client->priv->month;
 
1680
 
 
1681
  if (day)
 
1682
    *day = client->priv->day;
 
1683
}
 
1684
 
 
1685
void
 
1686
calendar_client_select_month (CalendarClient *client,
 
1687
                              guint           month,
 
1688
                              guint           year)
 
1689
{
 
1690
  g_return_if_fail (CALENDAR_IS_CLIENT (client));
 
1691
  g_return_if_fail (month >= 0 && month <= 11);
 
1692
 
 
1693
  if (client->priv->year != year || client->priv->month != month)
 
1694
    {
 
1695
      client->priv->month = month;
 
1696
      client->priv->year  = year;
 
1697
 
 
1698
      calendar_client_update_appointments (client);
 
1699
      calendar_client_update_tasks (client);
 
1700
 
 
1701
      g_object_freeze_notify (G_OBJECT (client));
 
1702
      g_object_notify (G_OBJECT (client), "month");
 
1703
      g_object_notify (G_OBJECT (client), "year");
 
1704
      g_object_thaw_notify (G_OBJECT (client));
 
1705
    }
 
1706
}
 
1707
 
 
1708
void
 
1709
calendar_client_select_day (CalendarClient *client,
 
1710
                            guint           day)
 
1711
{
 
1712
  g_return_if_fail (CALENDAR_IS_CLIENT (client));
 
1713
  g_return_if_fail (day <= 31);
 
1714
 
 
1715
  if (client->priv->day != day)
 
1716
    {
 
1717
      client->priv->day = day;
 
1718
 
 
1719
      /* don't need to update appointments unless
 
1720
       * the selected month changes
 
1721
       */
 
1722
#ifdef FIX_BROKEN_TASKS_QUERY
 
1723
      calendar_client_update_tasks (client);
 
1724
#endif
 
1725
 
 
1726
      g_object_notify (G_OBJECT (client), "day");
 
1727
    }
 
1728
}
 
1729
 
 
1730
typedef struct
 
1731
{
 
1732
  CalendarClient *client;
 
1733
  GSList         *events;
 
1734
  GTime           start_time;
 
1735
  GTime           end_time;
 
1736
} FilterData;
 
1737
 
 
1738
typedef void (* CalendarEventFilterFunc) (const char    *uid,
 
1739
                                          CalendarEvent *event,
 
1740
                                          FilterData    *filter_data);
 
1741
 
 
1742
static void
 
1743
filter_appointment (const char    *uid,
 
1744
                    CalendarEvent *event,
 
1745
                    FilterData    *filter_data)
 
1746
{
 
1747
  GSList *occurrences, *l;
 
1748
 
 
1749
  if (event->type != CALENDAR_EVENT_APPOINTMENT)
 
1750
    return;
 
1751
 
 
1752
  occurrences = CALENDAR_APPOINTMENT (event)->occurrences;
 
1753
  CALENDAR_APPOINTMENT (event)->occurrences = NULL;
 
1754
 
 
1755
  for (l = occurrences; l; l = l->next)
 
1756
    {
 
1757
      CalendarOccurrence *occurrence = l->data;
 
1758
      GTime start_time = occurrence->start_time;
 
1759
      GTime end_time   = occurrence->end_time;
 
1760
 
 
1761
      if ((start_time >= filter_data->start_time &&
 
1762
           start_time < filter_data->end_time) ||
 
1763
          (start_time <= filter_data->start_time &&
 
1764
           (end_time - 1) > filter_data->start_time))
 
1765
        {
 
1766
          CalendarEvent *new_event;
 
1767
 
 
1768
          new_event = calendar_event_copy (event);
 
1769
              
 
1770
          CALENDAR_APPOINTMENT (new_event)->start_time = occurrence->start_time;
 
1771
          CALENDAR_APPOINTMENT (new_event)->end_time   = occurrence->end_time;
 
1772
              
 
1773
          filter_data->events = g_slist_prepend (filter_data->events, new_event);
 
1774
        }
 
1775
    }
 
1776
 
 
1777
  CALENDAR_APPOINTMENT (event)->occurrences = occurrences;
 
1778
}
 
1779
 
 
1780
static void
 
1781
filter_task (const char    *uid,
 
1782
             CalendarEvent *event,
 
1783
             FilterData    *filter_data)
 
1784
{
 
1785
  CalendarTask *task;
 
1786
 
 
1787
  if (event->type != CALENDAR_EVENT_TASK)
 
1788
    return;
 
1789
 
 
1790
  task = CALENDAR_TASK (event);
 
1791
 
 
1792
#ifdef FIX_BROKEN_TASKS_QUERY
 
1793
  if (task->start_time && task->start_time > filter_data->start_time)
 
1794
    return;
 
1795
 
 
1796
  if (task->completed_time && 
 
1797
      (task->completed_time < filter_data->start_time ||
 
1798
       task->completed_time > filter_data->end_time))
 
1799
    return;
 
1800
#endif /* FIX_BROKEN_TASKS_QUERY */
 
1801
 
 
1802
  filter_data->events = g_slist_prepend (filter_data->events,
 
1803
                                         calendar_event_copy (event));
 
1804
}
 
1805
 
 
1806
static GSList *
 
1807
calendar_client_filter_events (CalendarClient          *client,
 
1808
                               GSList                  *sources,
 
1809
                               CalendarEventFilterFunc  filter_func,
 
1810
                               GTime                    start_time,
 
1811
                               GTime                    end_time)
 
1812
{
 
1813
  FilterData  filter_data;
 
1814
  GSList     *l;
 
1815
  GSList     *retval;
 
1816
 
 
1817
  if (!sources)
 
1818
    return NULL;
 
1819
 
 
1820
  filter_data.client     = client;
 
1821
  filter_data.events     = NULL;
 
1822
  filter_data.start_time = start_time;
 
1823
  filter_data.end_time   = end_time;
 
1824
 
 
1825
  retval = NULL;
 
1826
  for (l = sources; l; l = l->next)
 
1827
    {
 
1828
      CalendarClientSource *source = l->data;
 
1829
 
 
1830
      if (source->query_completed)
 
1831
        {
 
1832
          filter_data.events = NULL;
 
1833
          g_hash_table_foreach (source->completed_query.events,
 
1834
                                (GHFunc) filter_func,
 
1835
                                &filter_data);
 
1836
 
 
1837
          filter_data.events = g_slist_reverse (filter_data.events);
 
1838
 
 
1839
          retval = g_slist_concat (retval, filter_data.events);
 
1840
        }
 
1841
    }
 
1842
 
 
1843
  return retval;
 
1844
}
 
1845
 
 
1846
GSList *
 
1847
calendar_client_get_events (CalendarClient    *client,
 
1848
                            CalendarEventType  event_mask)
 
1849
{
 
1850
  GSList *appointments;
 
1851
  GSList *tasks;
 
1852
  GTime   day_begin;
 
1853
  GTime   day_end;
 
1854
 
 
1855
  g_return_val_if_fail (CALENDAR_IS_CLIENT (client), NULL);
 
1856
  g_return_val_if_fail (client->priv->day   != -1 &&
 
1857
                        client->priv->month != -1 &&
 
1858
                        client->priv->year  != -1, NULL);
 
1859
 
 
1860
  day_begin = make_time_for_day_begin (client->priv->day,
 
1861
                                       client->priv->month,
 
1862
                                       client->priv->year);
 
1863
  day_end   = make_time_for_day_begin (client->priv->day + 1,
 
1864
                                       client->priv->month,
 
1865
                                       client->priv->year);
 
1866
 
 
1867
  appointments = NULL;
 
1868
  if (event_mask & CALENDAR_EVENT_APPOINTMENT)
 
1869
    {
 
1870
      appointments = calendar_client_filter_events (client,
 
1871
                                                    client->priv->appointment_sources,
 
1872
                                                    filter_appointment,
 
1873
                                                    day_begin,
 
1874
                                                    day_end);
 
1875
    }
 
1876
 
 
1877
  tasks = NULL;
 
1878
  if (event_mask & CALENDAR_EVENT_TASK)
 
1879
    {
 
1880
      tasks = calendar_client_filter_events (client,
 
1881
                                             client->priv->task_sources,
 
1882
                                             filter_task,
 
1883
                                             day_begin,
 
1884
                                             day_end);
 
1885
    }
 
1886
 
 
1887
  return g_slist_concat (appointments, tasks);
 
1888
}
 
1889
 
 
1890
static inline int
 
1891
day_from_time_t (time_t t)
 
1892
{
 
1893
  struct tm *tm = localtime (&t);
 
1894
 
 
1895
  g_assert (tm == NULL || (tm->tm_mday >=1 && tm->tm_mday <= 31));
 
1896
 
 
1897
  return tm ? tm->tm_mday : 0;
 
1898
}
 
1899
 
 
1900
void
 
1901
calendar_client_foreach_appointment_day (CalendarClient  *client,
 
1902
                                         CalendarDayIter  iter_func,
 
1903
                                         gpointer         user_data)
 
1904
{
 
1905
  GSList   *appointments, *l;
 
1906
  gboolean  marked_days [32] = { FALSE, };
 
1907
  GTime     month_begin;
 
1908
  GTime     month_end;
 
1909
  int       i;
 
1910
 
 
1911
  g_return_if_fail (CALENDAR_IS_CLIENT (client));
 
1912
  g_return_if_fail (iter_func != NULL);
 
1913
  g_return_if_fail (client->priv->month != -1 &&
 
1914
                    client->priv->year  != -1);
 
1915
 
 
1916
  month_begin = make_time_for_day_begin (1,
 
1917
                                         client->priv->month,
 
1918
                                         client->priv->year);
 
1919
  month_end   = make_time_for_day_begin (1,
 
1920
                                         client->priv->month + 1,
 
1921
                                         client->priv->year);
 
1922
  
 
1923
  appointments = calendar_client_filter_events (client,
 
1924
                                                client->priv->appointment_sources,
 
1925
                                                filter_appointment,
 
1926
                                                month_begin,
 
1927
                                                month_end);
 
1928
  for (l = appointments; l; l = l->next)
 
1929
    {
 
1930
      CalendarAppointment *appointment = l->data;
 
1931
 
 
1932
      if (appointment->start_time)
 
1933
        {
 
1934
          GTime day_time = appointment->start_time;
 
1935
 
 
1936
          if (day_time >= month_begin)
 
1937
            marked_days [day_from_time_t (day_time)] = TRUE;
 
1938
      
 
1939
          if (appointment->end_time)
 
1940
            {
 
1941
              int day_offset;
 
1942
              int duration = appointment->end_time - appointment->start_time;
 
1943
              for (day_offset = 1; day_offset < duration / 86400; day_offset++)
 
1944
                {
 
1945
                  GTime day_time = appointment->start_time + day_offset * 86400;
 
1946
 
 
1947
                  if (day_time > month_end)
 
1948
                    break;
 
1949
                  if (day_time >= month_begin)
 
1950
                    marked_days [day_from_time_t (day_time)] = TRUE;
 
1951
                }
 
1952
            }
 
1953
        }
 
1954
      calendar_event_free (CALENDAR_EVENT (appointment));
 
1955
    }
 
1956
 
 
1957
  g_slist_free (appointments);
 
1958
 
 
1959
  for (i = 1; i < 32; i++)
 
1960
    {
 
1961
      if (marked_days [i])
 
1962
        iter_func (client, i, user_data);
 
1963
    }
 
1964
}
 
1965
 
 
1966
void
 
1967
calendar_client_set_task_completed (CalendarClient *client,
 
1968
                                    char           *task_uid,
 
1969
                                    gboolean        task_completed,
 
1970
                                    guint           percent_complete)
 
1971
{
 
1972
  GSList              *l;
 
1973
  ECal                *esource;
 
1974
  icalcomponent       *ical;
 
1975
  icalproperty        *prop;
 
1976
  icalproperty_status  status;
 
1977
 
 
1978
  g_return_if_fail (CALENDAR_IS_CLIENT (client));
 
1979
  g_return_if_fail (task_uid != NULL);
 
1980
  g_return_if_fail (task_completed == FALSE || percent_complete == 100);
 
1981
 
 
1982
  ical = NULL;
 
1983
  esource = NULL;
 
1984
  for (l = client->priv->task_sources; l; l = l->next)
 
1985
    {
 
1986
      CalendarClientSource *source = l->data;
 
1987
 
 
1988
      esource = source->source;
 
1989
      e_cal_get_object (esource, task_uid, NULL, &ical, NULL);
 
1990
      if (ical)
 
1991
        break;
 
1992
    }
 
1993
 
 
1994
  if (!ical)
 
1995
    {
 
1996
      g_warning ("Cannot locate task with uid = '%s'\n", task_uid);
 
1997
      return;
 
1998
    }
 
1999
 
 
2000
  g_assert (esource != NULL);
 
2001
 
 
2002
  /* Completed time */
 
2003
  prop = icalcomponent_get_first_property (ical,
 
2004
                                           ICAL_COMPLETED_PROPERTY);
 
2005
  if (task_completed)
 
2006
    {
 
2007
      struct icaltimetype  completed_time;
 
2008
 
 
2009
      completed_time = icaltime_current_time_with_zone (client->priv->zone);
 
2010
      if (!prop)
 
2011
        {
 
2012
          icalcomponent_add_property (ical,
 
2013
                                      icalproperty_new_completed (completed_time));
 
2014
        }
 
2015
      else
 
2016
        {
 
2017
          icalproperty_set_completed (prop, completed_time);
 
2018
        }
 
2019
    }
 
2020
  else if (prop)
 
2021
    {
 
2022
      icalcomponent_remove_property (ical, prop);
 
2023
    }
 
2024
 
 
2025
  /* Percent complete */
 
2026
  prop = icalcomponent_get_first_property (ical,
 
2027
                                           ICAL_PERCENTCOMPLETE_PROPERTY);
 
2028
  if (!prop)
 
2029
    {
 
2030
      icalcomponent_add_property (ical,
 
2031
                                  icalproperty_new_percentcomplete (percent_complete));
 
2032
    }
 
2033
  else
 
2034
    {
 
2035
      icalproperty_set_percentcomplete (prop, percent_complete);
 
2036
    }
 
2037
 
 
2038
  /* Status */
 
2039
  status = task_completed ? ICAL_STATUS_COMPLETED : ICAL_STATUS_NEEDSACTION;
 
2040
  prop = icalcomponent_get_first_property (ical, ICAL_STATUS_PROPERTY);
 
2041
  if (prop)
 
2042
    {
 
2043
      icalproperty_set_status (prop, status);
 
2044
    }
 
2045
  else
 
2046
    {
 
2047
      icalcomponent_add_property (ical,
 
2048
                                  icalproperty_new_status (status));
 
2049
    }
 
2050
 
 
2051
  e_cal_modify_object (esource, ical, CALOBJ_MOD_ALL, NULL);
 
2052
}