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

« back to all changes in this revision

Viewing changes to .pc/gweather_3.6.patch/calendar/backends/weather/e-cal-backend-weather.c

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-10-08 12:58:16 UTC
  • mfrom: (181.1.7 quantal)
  • Revision ID: package-import@ubuntu.com-20121008125816-i3n76e8c0m64e7xp
Tags: 3.6.0-0ubuntu2
* Fix LP: #1038047 part 1 - Don't abort in e_source_registry_new* when a
  problem occurs connecting to the Dbus service
  - add debian/patches/dont-abort-in-e_source_registry_new.patch
  - update debian/patches/series
* Fix LP: #1038047 part 2 - libedataserver depends on
  evolution-data-server-common to ensure that the GSettings schemas are
  present
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Evolution calendar - weather backend
2
 
 *
3
 
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4
 
 *
5
 
 * Authors: David Trowbridge <trowbrds@cs.colorado.edu>
6
 
 *
7
 
 * This program is free software; you can redistribute it and/or
8
 
 * modify it under the terms of version 2 of the GNU Lesser General Public
9
 
 * License as published by the Free Software Foundation.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU Lesser General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU Lesser General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 
 */
20
 
 
21
 
#include <config.h>
22
 
#include <glib/gi18n-lib.h>
23
 
#include <string.h>
24
 
 
25
 
#include "e-cal-backend-weather.h"
26
 
#include "e-source-weather.h"
27
 
#include "e-weather-source.h"
28
 
 
29
 
#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
30
 
#include <libgweather/weather.h>
31
 
#undef GWEATHER_I_KNOW_THIS_IS_UNSTABLE
32
 
 
33
 
#define WEATHER_UID_EXT "-weather"
34
 
 
35
 
#define E_CAL_BACKEND_WEATHER_GET_PRIVATE(obj) \
36
 
        (G_TYPE_INSTANCE_GET_PRIVATE \
37
 
        ((obj), E_TYPE_CAL_BACKEND_WEATHER, ECalBackendWeatherPrivate))
38
 
 
39
 
#define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
40
 
#define EDC_ERROR_EX(_code, _msg) e_data_cal_create_error (_code, _msg)
41
 
 
42
 
G_DEFINE_TYPE (ECalBackendWeather, e_cal_backend_weather, E_TYPE_CAL_BACKEND_SYNC)
43
 
 
44
 
static gboolean reload_cb (ECalBackendWeather *cbw);
45
 
static gboolean begin_retrieval_cb (ECalBackendWeather *cbw);
46
 
static ECalComponent * create_weather (ECalBackendWeather *cbw, WeatherInfo *report, gboolean is_forecast);
47
 
static void e_cal_backend_weather_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **perror);
48
 
 
49
 
/* Private part of the ECalBackendWeather structure */
50
 
struct _ECalBackendWeatherPrivate {
51
 
        /* URI to get remote weather data from */
52
 
        gchar *uri;
53
 
 
54
 
        /* The file cache */
55
 
        ECalBackendStore *store;
56
 
 
57
 
        GHashTable *zones;
58
 
 
59
 
        /* Reload */
60
 
        guint reload_timeout_id;
61
 
        guint is_loading : 1;
62
 
 
63
 
        /* Flags */
64
 
        gboolean opened;
65
 
 
66
 
        /* City (for summary) */
67
 
        gchar *city;
68
 
 
69
 
        /* Weather source */
70
 
        EWeatherSource *source;
71
 
 
72
 
        guint begin_retrival_id;
73
 
};
74
 
 
75
 
static gboolean
76
 
reload_cb (ECalBackendWeather *cbw)
77
 
{
78
 
        ECalBackendWeatherPrivate *priv;
79
 
 
80
 
        priv = cbw->priv;
81
 
 
82
 
        if (priv->is_loading)
83
 
                return TRUE;
84
 
 
85
 
        priv->reload_timeout_id = 0;
86
 
        priv->opened = TRUE;
87
 
        begin_retrieval_cb (cbw);
88
 
        return FALSE;
89
 
}
90
 
 
91
 
static void
92
 
maybe_start_reload_timeout (ECalBackendWeather *cbw)
93
 
{
94
 
        ECalBackendWeatherPrivate *priv;
95
 
        ESource *source;
96
 
        ESourceRefresh *extension;
97
 
        const gchar *extension_name;
98
 
        guint interval_in_minutes = 0;
99
 
 
100
 
        priv = cbw->priv;
101
 
 
102
 
        if (priv->reload_timeout_id)
103
 
                return;
104
 
 
105
 
        source = e_backend_get_source (E_BACKEND (cbw));
106
 
 
107
 
        extension_name = E_SOURCE_EXTENSION_REFRESH;
108
 
        extension = e_source_get_extension (source, extension_name);
109
 
 
110
 
        /* By default, reload every 4 hours. At least for CCF, the forecasts
111
 
         * only come out twice a day, and chances are while the NWS and similar
112
 
         * organizations have some serious bandwidth, they would appreciate it
113
 
         * if we didn't hammer their servers. */
114
 
        if (e_source_refresh_get_enabled (extension)) {
115
 
                interval_in_minutes =
116
 
                        e_source_refresh_get_interval_minutes (extension);
117
 
                if (interval_in_minutes == 0)
118
 
                        interval_in_minutes = 240;
119
 
        }
120
 
 
121
 
        if (interval_in_minutes > 0)
122
 
                priv->reload_timeout_id = g_timeout_add_seconds (
123
 
                        interval_in_minutes * 60,
124
 
                        (GSourceFunc) reload_cb, cbw);
125
 
}
126
 
 
127
 
/* TODO Do not replicate this in every backend */
128
 
static icaltimezone *
129
 
resolve_tzid (const gchar *tzid,
130
 
              gpointer user_data)
131
 
{
132
 
        icaltimezone *zone;
133
 
 
134
 
        zone = (!strcmp (tzid, "UTC"))
135
 
                ? icaltimezone_get_utc_timezone ()
136
 
                : icaltimezone_get_builtin_timezone_from_tzid (tzid);
137
 
 
138
 
        if (!zone)
139
 
                zone = e_cal_backend_internal_get_timezone (E_CAL_BACKEND (user_data), tzid);
140
 
 
141
 
        return zone;
142
 
}
143
 
 
144
 
static void
145
 
put_component_to_store (ECalBackendWeather *cb,
146
 
                        ECalComponent *comp)
147
 
{
148
 
        time_t time_start, time_end;
149
 
        ECalBackendWeatherPrivate *priv;
150
 
 
151
 
        priv = cb->priv;
152
 
 
153
 
        e_cal_util_get_component_occur_times (comp, &time_start, &time_end,
154
 
                                   resolve_tzid, cb, icaltimezone_get_utc_timezone (),
155
 
                                   e_cal_backend_get_kind (E_CAL_BACKEND (cb)));
156
 
 
157
 
        e_cal_backend_store_put_component_with_time_range (priv->store, comp, time_start, time_end);
158
 
}
159
 
 
160
 
static void
161
 
finished_retrieval_cb (WeatherInfo *info,
162
 
                       ECalBackendWeather *cbw)
163
 
{
164
 
        ECalBackendWeatherPrivate *priv;
165
 
        ECalComponent *comp;
166
 
        GSList *comps, *l;
167
 
 
168
 
        priv = cbw->priv;
169
 
 
170
 
        if (info == NULL) {
171
 
                e_cal_backend_notify_error (E_CAL_BACKEND (cbw), _("Could not retrieve weather data"));
172
 
                return;
173
 
        }
174
 
 
175
 
        /* update cache */
176
 
        comps = e_cal_backend_store_get_components (priv->store);
177
 
 
178
 
        for (l = comps; l != NULL; l = g_slist_next (l)) {
179
 
                ECalComponentId *id;
180
 
 
181
 
                comp = E_CAL_COMPONENT (l->data);
182
 
                id = e_cal_component_get_id (comp);
183
 
 
184
 
                e_cal_backend_notify_component_removed (E_CAL_BACKEND (cbw), id, comp, NULL);
185
 
 
186
 
                e_cal_component_free_id (id);
187
 
                g_object_unref (comp);
188
 
        }
189
 
        g_slist_free (comps);
190
 
        e_cal_backend_store_clean (priv->store);
191
 
 
192
 
        comp = create_weather (cbw, info, FALSE);
193
 
        if (comp) {
194
 
                GSList *forecasts;
195
 
 
196
 
                put_component_to_store (cbw, comp);
197
 
                e_cal_backend_notify_component_created (E_CAL_BACKEND (cbw), comp);
198
 
                g_object_unref (comp);
199
 
 
200
 
                forecasts = weather_info_get_forecast_list (info);
201
 
                if (forecasts) {
202
 
                        GSList *f;
203
 
 
204
 
                        /* skip the first one, it's for today, which has been added above */
205
 
                        for (f = forecasts->next; f; f = f->next) {
206
 
                                WeatherInfo *nfo = f->data;
207
 
 
208
 
                                if (nfo) {
209
 
                                        comp = create_weather (cbw, nfo, TRUE);
210
 
                                        if (comp) {
211
 
                                                put_component_to_store (cbw, comp);
212
 
                                                e_cal_backend_notify_component_created (E_CAL_BACKEND (cbw), comp);
213
 
                                                g_object_unref (comp);
214
 
                                        }
215
 
                                }
216
 
                        }
217
 
                }
218
 
        }
219
 
 
220
 
        priv->is_loading = FALSE;
221
 
}
222
 
 
223
 
static gboolean
224
 
begin_retrieval_cb (ECalBackendWeather *cbw)
225
 
{
226
 
        ECalBackendWeatherPrivate *priv = cbw->priv;
227
 
        ESource *e_source;
228
 
        GSource *source;
229
 
 
230
 
        /* XXX Too much overloading of the word 'source' here! */
231
 
 
232
 
        if (!e_backend_get_online (E_BACKEND (cbw)))
233
 
                return TRUE;
234
 
 
235
 
        maybe_start_reload_timeout (cbw);
236
 
 
237
 
        e_source = e_backend_get_source (E_BACKEND (cbw));
238
 
 
239
 
        if (priv->source == NULL) {
240
 
                ESourceWeather *extension;
241
 
                const gchar *extension_name;
242
 
                gchar *location;
243
 
 
244
 
                extension_name = E_SOURCE_EXTENSION_WEATHER_BACKEND;
245
 
                extension = e_source_get_extension (e_source, extension_name);
246
 
 
247
 
                location = e_source_weather_dup_location (extension);
248
 
                priv->source = e_weather_source_new (location);
249
 
                g_free (location);
250
 
        }
251
 
 
252
 
        source = g_main_current_source ();
253
 
 
254
 
        if (priv->begin_retrival_id == g_source_get_id (source))
255
 
                priv->begin_retrival_id = 0;
256
 
 
257
 
        if (priv->is_loading)
258
 
                return FALSE;
259
 
 
260
 
        priv->is_loading = TRUE;
261
 
 
262
 
        e_weather_source_parse (
263
 
                priv->source, (EWeatherSourceFinished)
264
 
                finished_retrieval_cb, cbw);
265
 
 
266
 
        return FALSE;
267
 
}
268
 
 
269
 
static const gchar *
270
 
getCategory (WeatherInfo *report)
271
 
{
272
 
        struct {
273
 
                const gchar *description;
274
 
                const gchar *icon_name;
275
 
        } categories[] = {
276
 
                { N_("Weather: Fog"),           "weather-fog" },
277
 
                { N_("Weather: Cloudy Night"),  "weather-few-clouds-night" },
278
 
                { N_("Weather: Cloudy"),        "weather-few-clouds" },
279
 
                { N_("Weather: Overcast"),      "weather-overcast" },
280
 
                { N_("Weather: Showers"),       "weather-showers" },
281
 
                { N_("Weather: Snow"),          "weather-snow" },
282
 
                { N_("Weather: Clear Night"),   "weather-clear-night" },
283
 
                { N_("Weather: Sunny"),         "weather-clear" },
284
 
                { N_("Weather: Thunderstorms"), "weather-storm" },
285
 
                { NULL,                         NULL }
286
 
        };
287
 
 
288
 
        gint i;
289
 
        const gchar *icon_name = weather_info_get_icon_name (report);
290
 
 
291
 
        if (!icon_name)
292
 
                return NULL;
293
 
 
294
 
        for (i = 0; categories[i].description; i++) {
295
 
                if (!g_ascii_strncasecmp (categories[i].icon_name,
296
 
                                              icon_name, strlen (icon_name)))
297
 
                        return _(categories[i].description);
298
 
        }
299
 
 
300
 
        return NULL;
301
 
}
302
 
 
303
 
static ECalComponent *
304
 
create_weather (ECalBackendWeather *cbw,
305
 
                WeatherInfo *report,
306
 
                gboolean is_forecast)
307
 
{
308
 
        ECalBackendWeatherPrivate *priv;
309
 
        ECalComponent             *cal_comp;
310
 
        ECalComponentText          comp_summary;
311
 
        icalcomponent             *ical_comp;
312
 
        struct icaltimetype        itt;
313
 
        ECalComponentDateTime      dt;
314
 
        gchar                     *uid;
315
 
        GSList                    *text_list = NULL;
316
 
        ECalComponentText         *description;
317
 
        ESource                   *source;
318
 
        const gchar               *tmp;
319
 
        time_t                     update_time;
320
 
        icaltimezone              *update_zone = NULL;
321
 
        ESourceWeather            *extension;
322
 
        const gchar               *extension_name;
323
 
        const WeatherLocation     *location;
324
 
        ESourceWeatherUnits        units;
325
 
 
326
 
        g_return_val_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), NULL);
327
 
 
328
 
        if (!weather_info_get_value_update (report, &update_time))
329
 
                return NULL;
330
 
 
331
 
        priv = cbw->priv;
332
 
 
333
 
        source = e_backend_get_source (E_BACKEND (cbw));
334
 
 
335
 
        extension_name = E_SOURCE_EXTENSION_WEATHER_BACKEND;
336
 
        extension = e_source_get_extension (source, extension_name);
337
 
        units = e_source_weather_get_units (extension);
338
 
 
339
 
        /* Prefer metric if units is invalid. */
340
 
        if (units == E_SOURCE_WEATHER_UNITS_IMPERIAL)
341
 
                weather_info_to_imperial (report);
342
 
        else
343
 
                weather_info_to_metric (report);
344
 
 
345
 
        /* create the component and event object */
346
 
        ical_comp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
347
 
        cal_comp = e_cal_component_new ();
348
 
        e_cal_component_set_icalcomponent (cal_comp, ical_comp);
349
 
 
350
 
        /* set uid */
351
 
        uid = e_cal_component_gen_uid ();
352
 
        e_cal_component_set_uid (cal_comp, uid);
353
 
        g_free (uid);
354
 
 
355
 
        /* use timezone of the location to determine date for which this is set */
356
 
        location = weather_info_get_location (report);
357
 
        if (location && location->tz_hint && *location->tz_hint)
358
 
                update_zone = icaltimezone_get_builtin_timezone (location->tz_hint);
359
 
 
360
 
        if (!update_zone)
361
 
                update_zone = icaltimezone_get_utc_timezone ();
362
 
 
363
 
        /* Set all-day event's date from forecast data - cannot set is_date,
364
 
         * because in that case no timezone conversion is done */
365
 
        itt = icaltime_from_timet_with_zone (update_time, 0, update_zone);
366
 
        itt.hour = 0;
367
 
        itt.minute = 0;
368
 
        itt.second = 0;
369
 
        itt.is_date = 1;
370
 
 
371
 
        dt.value = &itt;
372
 
        if (update_zone)
373
 
                dt.tzid = icaltimezone_get_tzid (update_zone);
374
 
        else
375
 
                dt.tzid = NULL;
376
 
 
377
 
        e_cal_component_set_dtstart (cal_comp, &dt);
378
 
 
379
 
        icaltime_adjust (&itt, 1, 0, 0, 0);
380
 
        /* We have to add 1 day to DTEND, as it is not inclusive. */
381
 
        e_cal_component_set_dtend (cal_comp, &dt);
382
 
 
383
 
        if (is_forecast) {
384
 
                gdouble tmin = 0.0, tmax = 0.0;
385
 
 
386
 
                if (weather_info_get_value_temp_min (report, TEMP_UNIT_DEFAULT, &tmin) &&
387
 
                    weather_info_get_value_temp_max (report, TEMP_UNIT_DEFAULT, &tmax) &&
388
 
                    tmin != tmax) {
389
 
                        /* because weather_info_get_temp* uses one internal buffer, thus finally
390
 
                         * the last value is shown for both, which is obviously wrong */
391
 
                        GString *str = g_string_new (priv->city);
392
 
 
393
 
                        g_string_append (str, " : ");
394
 
                        g_string_append (str, weather_info_get_temp_min (report));
395
 
                        g_string_append (str, "/");
396
 
                        g_string_append (str, weather_info_get_temp_max (report));
397
 
 
398
 
                        comp_summary.value = g_string_free (str, FALSE);
399
 
                } else {
400
 
                        comp_summary.value = g_strdup_printf ("%s : %s", priv->city, weather_info_get_temp (report));
401
 
                }
402
 
        } else {
403
 
                gdouble tmin = 0.0, tmax = 0.0;
404
 
                /* because weather_info_get_temp* uses one internal buffer, thus finally
405
 
                 * the last value is shown for both, which is obviously wrong */
406
 
                GString *str = g_string_new (priv->city);
407
 
 
408
 
                g_string_append (str, " : ");
409
 
                if (weather_info_get_value_temp_min (report, TEMP_UNIT_DEFAULT, &tmin) &&
410
 
                    weather_info_get_value_temp_max (report, TEMP_UNIT_DEFAULT, &tmax) &&
411
 
                    tmin != tmax) {
412
 
                        g_string_append (str, weather_info_get_temp_min (report));
413
 
                        g_string_append (str, "/");
414
 
                        g_string_append (str, weather_info_get_temp_max (report));
415
 
                } else {
416
 
                        g_string_append (str, weather_info_get_temp (report));
417
 
                }
418
 
 
419
 
                comp_summary.value = g_string_free (str, FALSE);
420
 
        }
421
 
        comp_summary.altrep = NULL;
422
 
        e_cal_component_set_summary (cal_comp, &comp_summary);
423
 
        g_free ((gchar *) comp_summary.value);
424
 
 
425
 
        tmp = weather_info_get_forecast (report);
426
 
        comp_summary.value = weather_info_get_weather_summary (report);
427
 
 
428
 
        description = g_new0 (ECalComponentText, 1);
429
 
        description->value = g_strconcat (is_forecast ? "" : comp_summary.value, is_forecast ? "" : "\n", tmp ? _("Forecast") : "", tmp ? ":" : "", tmp && !is_forecast ? "\n" : "", tmp ? tmp : "", NULL);
430
 
        description->altrep = "";
431
 
        text_list = g_slist_append (text_list, description);
432
 
        e_cal_component_set_description_list (cal_comp, text_list);
433
 
        g_free ((gchar *) comp_summary.value);
434
 
 
435
 
        /* Set category and visibility */
436
 
        e_cal_component_set_categories (cal_comp, getCategory (report));
437
 
        e_cal_component_set_classification (cal_comp, E_CAL_COMPONENT_CLASS_PUBLIC);
438
 
 
439
 
        /* Weather is shown as free time */
440
 
        e_cal_component_set_transparency (cal_comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT);
441
 
 
442
 
        e_cal_component_commit_sequence (cal_comp);
443
 
 
444
 
        return cal_comp;
445
 
}
446
 
 
447
 
static gboolean
448
 
e_cal_backend_weather_get_backend_property (ECalBackendSync *backend,
449
 
                                            EDataCal *cal,
450
 
                                            GCancellable *cancellable,
451
 
                                            const gchar *prop_name,
452
 
                                            gchar **prop_value,
453
 
                                            GError **perror)
454
 
{
455
 
        gboolean processed = TRUE;
456
 
 
457
 
        g_return_val_if_fail (prop_name != NULL, FALSE);
458
 
        g_return_val_if_fail (prop_value != NULL, FALSE);
459
 
 
460
 
        if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
461
 
                *prop_value = g_strdup (CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT ","
462
 
                                        CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS ","
463
 
                                        CAL_STATIC_CAPABILITY_NO_DISPLAY_ALARMS ","
464
 
                                        CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS ","
465
 
                                        CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT ","
466
 
                                        CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
467
 
                                        CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
468
 
                                        CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
469
 
        } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
470
 
                   g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
471
 
                /* Weather has no particular email addresses associated with it */
472
 
                *prop_value = NULL;
473
 
        } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
474
 
                g_propagate_error (perror, EDC_ERROR (UnsupportedMethod));
475
 
        } else {
476
 
                processed = FALSE;
477
 
        }
478
 
 
479
 
        return processed;
480
 
}
481
 
 
482
 
static void
483
 
e_cal_backend_weather_open (ECalBackendSync *backend,
484
 
                            EDataCal *cal,
485
 
                            GCancellable *cancellable,
486
 
                            gboolean only_if_exists,
487
 
                            GError **perror)
488
 
{
489
 
        ECalBackendWeather *cbw;
490
 
        ECalBackendWeatherPrivate *priv;
491
 
        ESource *source;
492
 
        ESourceWeather *extension;
493
 
        const gchar *extension_name;
494
 
        const gchar *cache_dir;
495
 
        gchar *location;
496
 
        gboolean online;
497
 
 
498
 
        cbw = E_CAL_BACKEND_WEATHER (backend);
499
 
        priv = cbw->priv;
500
 
 
501
 
        source = e_backend_get_source (E_BACKEND (backend));
502
 
        cache_dir = e_cal_backend_get_cache_dir (E_CAL_BACKEND (backend));
503
 
 
504
 
        extension_name = E_SOURCE_EXTENSION_WEATHER_BACKEND;
505
 
        extension = e_source_get_extension (source, extension_name);
506
 
 
507
 
        g_free (priv->city);
508
 
 
509
 
        location = e_source_weather_dup_location (extension);
510
 
        priv->city = g_strdup (strrchr (location, '/') + 1);
511
 
        g_free (location);
512
 
 
513
 
        e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), TRUE);
514
 
 
515
 
        online = e_backend_get_online (E_BACKEND (backend));
516
 
        e_cal_backend_notify_online (E_CAL_BACKEND (backend), online);
517
 
 
518
 
        if (!priv->store) {
519
 
                e_cal_backend_cache_remove (cache_dir, "cache.xml");
520
 
                priv->store = e_cal_backend_file_store_new (cache_dir);
521
 
 
522
 
                if (!priv->store) {
523
 
                        g_propagate_error (perror, EDC_ERROR_EX (OtherError, _("Could not create cache file")));
524
 
                        return;
525
 
                }
526
 
 
527
 
                /* do we require to load this new store */
528
 
                e_cal_backend_store_load (priv->store);
529
 
                e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
530
 
 
531
 
                if (!e_backend_get_online (E_BACKEND (backend)))
532
 
                        return;
533
 
 
534
 
                if (!priv->begin_retrival_id)
535
 
                        priv->begin_retrival_id = g_idle_add ((GSourceFunc) begin_retrieval_cb, cbw);
536
 
        }
537
 
 
538
 
        e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
539
 
}
540
 
 
541
 
static void
542
 
e_cal_backend_weather_refresh (ECalBackendSync *backend,
543
 
                               EDataCal *cal,
544
 
                               GCancellable *cancellable,
545
 
                               GError **perror)
546
 
{
547
 
        ECalBackendWeather *cbw;
548
 
        ECalBackendWeatherPrivate *priv;
549
 
 
550
 
        cbw = E_CAL_BACKEND_WEATHER (backend);
551
 
        priv = cbw->priv;
552
 
 
553
 
        if (!priv->opened ||
554
 
            priv->is_loading)
555
 
                return;
556
 
 
557
 
        if (priv->reload_timeout_id)
558
 
                g_source_remove (priv->reload_timeout_id);
559
 
        priv->reload_timeout_id = 0;
560
 
 
561
 
        /* wait a second, then start reloading */
562
 
        priv->reload_timeout_id = g_timeout_add (1000, (GSourceFunc) reload_cb, cbw);
563
 
}
564
 
 
565
 
static void
566
 
e_cal_backend_weather_remove (ECalBackendSync *backend,
567
 
                              EDataCal *cal,
568
 
                              GCancellable *cancellable,
569
 
                              GError **perror)
570
 
{
571
 
        ECalBackendWeather *cbw;
572
 
        ECalBackendWeatherPrivate *priv;
573
 
 
574
 
        cbw = E_CAL_BACKEND_WEATHER (backend);
575
 
        priv = cbw->priv;
576
 
 
577
 
        if (!priv->store) {
578
 
                /* lie here a bit, but otherwise the calendar will not be removed, even it should */
579
 
                g_print (G_STRLOC ": Doesn't have a cache?!?");
580
 
                return;
581
 
        }
582
 
 
583
 
        e_cal_backend_store_remove (priv->store);
584
 
}
585
 
 
586
 
static void
587
 
e_cal_backend_weather_receive_objects (ECalBackendSync *backend,
588
 
                                       EDataCal *cal,
589
 
                                       GCancellable *cancellable,
590
 
                                       const gchar *calobj,
591
 
                                       GError **perror)
592
 
{
593
 
        g_propagate_error (perror, EDC_ERROR (PermissionDenied));
594
 
}
595
 
 
596
 
static void
597
 
e_cal_backend_weather_get_object (ECalBackendSync *backend,
598
 
                                  EDataCal *cal,
599
 
                                  GCancellable *cancellable,
600
 
                                  const gchar *uid,
601
 
                                  const gchar *rid,
602
 
                                  gchar **object,
603
 
                                  GError **error)
604
 
{
605
 
        ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend);
606
 
        ECalBackendWeatherPrivate *priv = cbw->priv;
607
 
        ECalComponent *comp;
608
 
 
609
 
        e_return_data_cal_error_if_fail (uid != NULL, InvalidArg);
610
 
        e_return_data_cal_error_if_fail (priv->store != NULL, InvalidArg);
611
 
 
612
 
        comp = e_cal_backend_store_get_component (priv->store, uid, rid);
613
 
        if (!comp) {
614
 
                g_propagate_error (error, EDC_ERROR (ObjectNotFound));
615
 
                return;
616
 
        }
617
 
 
618
 
        *object = e_cal_component_get_as_string (comp);
619
 
        g_object_unref (comp);
620
 
}
621
 
 
622
 
static void
623
 
e_cal_backend_weather_get_object_list (ECalBackendSync *backend,
624
 
                                       EDataCal *cal,
625
 
                                       GCancellable *cancellable,
626
 
                                       const gchar *sexp_string,
627
 
                                       GSList **objects,
628
 
                                       GError **perror)
629
 
{
630
 
        ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend);
631
 
        ECalBackendWeatherPrivate *priv = cbw->priv;
632
 
        ECalBackendSExp *sexp = e_cal_backend_sexp_new (sexp_string);
633
 
        GSList *components, *l;
634
 
        time_t occur_start = -1, occur_end = -1;
635
 
        gboolean prunning_by_time;
636
 
 
637
 
        if (!sexp) {
638
 
                g_propagate_error (perror, EDC_ERROR (InvalidQuery));
639
 
                return;
640
 
        }
641
 
 
642
 
        *objects = NULL;
643
 
        prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (sexp,
644
 
                                                                    &occur_start,
645
 
                                                                    &occur_end);
646
 
 
647
 
        components = prunning_by_time ?
648
 
                e_cal_backend_store_get_components_occuring_in_range (priv->store, occur_start, occur_end)
649
 
                : e_cal_backend_store_get_components (priv->store);
650
 
 
651
 
        for (l = components; l != NULL; l = g_slist_next (l)) {
652
 
                if (e_cal_backend_sexp_match_comp (sexp, E_CAL_COMPONENT (l->data), E_CAL_BACKEND (backend)))
653
 
                        *objects = g_slist_append (*objects, e_cal_component_get_as_string (l->data));
654
 
        }
655
 
 
656
 
        g_slist_foreach (components, (GFunc) g_object_unref, NULL);
657
 
        g_slist_free (components);
658
 
        g_object_unref (sexp);
659
 
}
660
 
 
661
 
static void
662
 
e_cal_backend_weather_add_timezone (ECalBackendSync *backend,
663
 
                                    EDataCal *cal,
664
 
                                    GCancellable *cancellable,
665
 
                                    const gchar *tzobj,
666
 
                                    GError **error)
667
 
{
668
 
        ECalBackendWeather *cbw;
669
 
        ECalBackendWeatherPrivate *priv;
670
 
        icalcomponent *tz_comp;
671
 
        icaltimezone *zone;
672
 
        const gchar *tzid;
673
 
 
674
 
        cbw = (ECalBackendWeather *) backend;
675
 
 
676
 
        e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), InvalidArg);
677
 
        e_return_data_cal_error_if_fail (tzobj != NULL, InvalidArg);
678
 
 
679
 
        priv = cbw->priv;
680
 
 
681
 
        tz_comp = icalparser_parse_string (tzobj);
682
 
        e_return_data_cal_error_if_fail (tz_comp != NULL, InvalidObject);
683
 
 
684
 
        if (icalcomponent_isa (tz_comp) != ICAL_VTIMEZONE_COMPONENT) {
685
 
                g_propagate_error (error, EDC_ERROR (InvalidObject));
686
 
                return;
687
 
        }
688
 
 
689
 
        zone = icaltimezone_new ();
690
 
        icaltimezone_set_component (zone, tz_comp);
691
 
        tzid = icaltimezone_get_tzid (zone);
692
 
 
693
 
        if (g_hash_table_lookup (priv->zones, tzid)) {
694
 
                icaltimezone_free (zone, TRUE);
695
 
        } else {
696
 
                g_hash_table_insert (priv->zones, g_strdup (tzid), zone);
697
 
        }
698
 
}
699
 
 
700
 
static void
701
 
e_cal_backend_weather_get_free_busy (ECalBackendSync *backend,
702
 
                                     EDataCal *cal,
703
 
                                     GCancellable *cancellable,
704
 
                                     const GSList *users,
705
 
                                     time_t start,
706
 
                                     time_t end,
707
 
                                     GSList **freebusy,
708
 
                                     GError **perror)
709
 
{
710
 
        /* Weather doesn't count as busy time */
711
 
        icalcomponent *vfb = icalcomponent_new_vfreebusy ();
712
 
        icaltimezone *utc_zone = icaltimezone_get_utc_timezone ();
713
 
        gchar *calobj;
714
 
 
715
 
        icalcomponent_set_dtstart (vfb, icaltime_from_timet_with_zone (start, FALSE, utc_zone));
716
 
        icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone));
717
 
 
718
 
        calobj = icalcomponent_as_ical_string_r (vfb);
719
 
        *freebusy = g_slist_append (NULL, calobj);
720
 
        icalcomponent_free (vfb);
721
 
}
722
 
 
723
 
static void
724
 
e_cal_backend_weather_start_view (ECalBackend *backend,
725
 
                                  EDataCalView *query)
726
 
{
727
 
        ECalBackendWeather *cbw;
728
 
        ECalBackendWeatherPrivate *priv;
729
 
        ECalBackendSExp *sexp;
730
 
        GSList *components, *l;
731
 
        GSList *objects;
732
 
        GError *error;
733
 
        time_t occur_start = -1, occur_end = -1;
734
 
        gboolean prunning_by_time;
735
 
 
736
 
        cbw = E_CAL_BACKEND_WEATHER (backend);
737
 
        priv = cbw->priv;
738
 
 
739
 
        if (!priv->store) {
740
 
                error = EDC_ERROR (NoSuchCal);
741
 
                e_data_cal_view_notify_complete (query, error);
742
 
                g_error_free (error);
743
 
                return;
744
 
        }
745
 
 
746
 
        sexp = e_data_cal_view_get_object_sexp (query);
747
 
        if (!sexp) {
748
 
                error = EDC_ERROR (InvalidQuery);
749
 
                e_data_cal_view_notify_complete (query, error);
750
 
                g_error_free (error);
751
 
                return;
752
 
        }
753
 
 
754
 
        objects = NULL;
755
 
        prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (sexp, &occur_start, &occur_end);
756
 
        components = prunning_by_time ?
757
 
                e_cal_backend_store_get_components_occuring_in_range (priv->store, occur_start, occur_end)
758
 
                : e_cal_backend_store_get_components (priv->store);
759
 
 
760
 
        for (l = components; l != NULL; l = g_slist_next (l)) {
761
 
                if (e_cal_backend_sexp_match_comp (sexp, E_CAL_COMPONENT (l->data), backend))
762
 
                        objects = g_slist_prepend (objects, l->data);
763
 
        }
764
 
 
765
 
        if (objects)
766
 
                e_data_cal_view_notify_components_added (query, objects);
767
 
 
768
 
        g_slist_free_full (components, g_object_unref);
769
 
        g_slist_free (objects);
770
 
 
771
 
        e_data_cal_view_notify_complete (query, NULL /* Success */);
772
 
}
773
 
 
774
 
static void
775
 
e_cal_backend_weather_notify_online_cb (ECalBackend *backend,
776
 
                                        GParamSpec *pspec)
777
 
{
778
 
        ECalBackendWeather *cbw;
779
 
        ECalBackendWeatherPrivate *priv;
780
 
        gboolean loaded;
781
 
        gboolean online;
782
 
 
783
 
        cbw = E_CAL_BACKEND_WEATHER (backend);
784
 
        priv = cbw->priv;
785
 
 
786
 
        online = e_backend_get_online (E_BACKEND (backend));
787
 
        loaded = e_cal_backend_is_opened (backend);
788
 
 
789
 
        if (loaded && priv->reload_timeout_id) {
790
 
                g_source_remove (priv->reload_timeout_id);
791
 
                priv->reload_timeout_id = 0;
792
 
        }
793
 
 
794
 
        if (loaded) {
795
 
                e_cal_backend_notify_online (backend, online);
796
 
                e_cal_backend_notify_readonly (backend, TRUE);
797
 
        }
798
 
}
799
 
 
800
 
static icaltimezone *
801
 
e_cal_backend_weather_internal_get_timezone (ECalBackend *backend,
802
 
                                             const gchar *tzid)
803
 
{
804
 
        icaltimezone *zone;
805
 
 
806
 
        g_return_val_if_fail (tzid != NULL, NULL);
807
 
 
808
 
        if (!strcmp (tzid, "UTC")) {
809
 
                zone = icaltimezone_get_utc_timezone ();
810
 
        } else {
811
 
                ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend);
812
 
 
813
 
                g_return_val_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), NULL);
814
 
 
815
 
                zone = g_hash_table_lookup (cbw->priv->zones, tzid);
816
 
 
817
 
                if (!zone && E_CAL_BACKEND_CLASS (e_cal_backend_weather_parent_class)->internal_get_timezone)
818
 
                        zone = E_CAL_BACKEND_CLASS (e_cal_backend_weather_parent_class)->internal_get_timezone (backend, tzid);
819
 
        }
820
 
 
821
 
        return zone;
822
 
}
823
 
 
824
 
static void
825
 
free_zone (gpointer data)
826
 
{
827
 
        icaltimezone_free (data, TRUE);
828
 
}
829
 
 
830
 
/* Finalize handler for the weather backend */
831
 
static void
832
 
e_cal_backend_weather_finalize (GObject *object)
833
 
{
834
 
        ECalBackendWeatherPrivate *priv;
835
 
 
836
 
        priv = E_CAL_BACKEND_WEATHER_GET_PRIVATE (object);
837
 
 
838
 
        if (priv->reload_timeout_id)
839
 
                g_source_remove (priv->reload_timeout_id);
840
 
 
841
 
        if (priv->begin_retrival_id)
842
 
                g_source_remove (priv->begin_retrival_id);
843
 
 
844
 
        if (priv->store) {
845
 
                g_object_unref (priv->store);
846
 
                priv->store = NULL;
847
 
        }
848
 
 
849
 
        g_hash_table_destroy (priv->zones);
850
 
 
851
 
        g_free (priv->city);
852
 
 
853
 
        /* Chain up to parent's finalize() method. */
854
 
        G_OBJECT_CLASS (e_cal_backend_weather_parent_class)->finalize (object);
855
 
}
856
 
 
857
 
/* Object initialization function for the weather backend */
858
 
static void
859
 
e_cal_backend_weather_init (ECalBackendWeather *cbw)
860
 
{
861
 
        cbw->priv = E_CAL_BACKEND_WEATHER_GET_PRIVATE (cbw);
862
 
 
863
 
        cbw->priv->zones = g_hash_table_new_full (
864
 
                (GHashFunc) g_str_hash,
865
 
                (GEqualFunc) g_str_equal,
866
 
                (GDestroyNotify) g_free,
867
 
                (GDestroyNotify) free_zone);
868
 
 
869
 
        e_cal_backend_sync_set_lock (E_CAL_BACKEND_SYNC (cbw), TRUE);
870
 
 
871
 
        g_signal_connect (
872
 
                cbw, "notify::online",
873
 
                G_CALLBACK (e_cal_backend_weather_notify_online_cb), NULL);
874
 
}
875
 
 
876
 
/* Class initialization function for the weather backend */
877
 
static void
878
 
e_cal_backend_weather_class_init (ECalBackendWeatherClass *class)
879
 
{
880
 
        GObjectClass *object_class;
881
 
        ECalBackendClass *backend_class;
882
 
        ECalBackendSyncClass *sync_class;
883
 
 
884
 
        g_type_class_add_private (class, sizeof (ECalBackendWeatherPrivate));
885
 
 
886
 
        object_class = (GObjectClass *) class;
887
 
        backend_class = (ECalBackendClass *) class;
888
 
        sync_class = (ECalBackendSyncClass *) class;
889
 
 
890
 
        object_class->finalize = e_cal_backend_weather_finalize;
891
 
 
892
 
        sync_class->get_backend_property_sync   = e_cal_backend_weather_get_backend_property;
893
 
        sync_class->open_sync                   = e_cal_backend_weather_open;
894
 
        sync_class->refresh_sync                = e_cal_backend_weather_refresh;
895
 
        sync_class->remove_sync                 = e_cal_backend_weather_remove;
896
 
        sync_class->receive_objects_sync        = e_cal_backend_weather_receive_objects;
897
 
        sync_class->get_object_sync             = e_cal_backend_weather_get_object;
898
 
        sync_class->get_object_list_sync        = e_cal_backend_weather_get_object_list;
899
 
        sync_class->add_timezone_sync           = e_cal_backend_weather_add_timezone;
900
 
        sync_class->get_free_busy_sync          = e_cal_backend_weather_get_free_busy;
901
 
 
902
 
        backend_class->start_view               = e_cal_backend_weather_start_view;
903
 
        backend_class->internal_get_timezone    = e_cal_backend_weather_internal_get_timezone;
904
 
 
905
 
        /* Register our ESource extension. */
906
 
        E_TYPE_SOURCE_WEATHER;
907
 
}