/* Evolution calendar - weather backend * * Copyright (C) 2005 Novell, Inc (www.novell.com) * * Authors: David Trowbridge * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU Lesser General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "e-cal-backend-weather.h" #include "e-weather-source.h" #define WEATHER_UID_EXT "-weather" static gboolean reload_cb (ECalBackendWeather *cbw); static gboolean begin_retrieval_cb (ECalBackendWeather *cbw); static ECalComponent* create_weather (ECalBackendWeather *cbw, WeatherForecast *report); static ECalBackendSyncStatus e_cal_backend_weather_add_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj); /* Private part of the ECalBackendWeather structure */ struct _ECalBackendWeatherPrivate { /* URI to get remote weather data from */ char *uri; /* Local/remote mode */ CalMode mode; /* The file cache */ ECalBackendCache *cache; /* The calendar's default timezone, used for resolving DATE and floating DATE-TIME values. */ icaltimezone *default_zone; GHashTable *zones; /* Reload */ guint reload_timeout_id; guint source_changed_id; guint is_loading : 1; /* Flags */ gboolean opened; /* City (for summary) */ gchar *city; /* Weather source */ EWeatherSource *source; guint begin_retrival_id; }; static ECalBackendSyncClass *parent_class; static gboolean reload_cb (ECalBackendWeather *cbw) { ECalBackendWeatherPrivate *priv; priv = cbw->priv; if (priv->is_loading) return TRUE; priv->reload_timeout_id = 0; priv->opened = TRUE; begin_retrieval_cb (cbw); return FALSE; } static void source_changed (ESource *source, ECalBackendWeather *cbw) { /* FIXME * We should force a reload of the data when this gets called. Unfortunately, * this signal isn't getting through from evolution to the backend */ } static void maybe_start_reload_timeout (ECalBackendWeather *cbw) { ECalBackendWeatherPrivate *priv; ESource *source; const gchar *refresh_str; priv = cbw->priv; if (priv->reload_timeout_id) return; source = e_cal_backend_get_source (E_CAL_BACKEND (cbw)); if (!source) { g_warning ("Could not get source for ECalBackendWeather reload."); return; } if (priv->source_changed_id == 0) priv->source_changed_id = g_signal_connect (G_OBJECT (source), "changed", G_CALLBACK (source_changed), cbw); refresh_str = e_source_get_property (source, "refresh"); /* By default, reload every 4 hours. At least for CCF, the forecasts only come out * twice a day, and chances are while the NWS and similar organizations have some * serious bandwidth, they would appreciate it if we didn't hammer their servers */ priv->reload_timeout_id = g_timeout_add ((refresh_str ? atoi (refresh_str) : 240) * 60000, (GSourceFunc) reload_cb, cbw); } static void finished_retrieval_cb (GList *forecasts, ECalBackendWeather *cbw) { ECalBackendWeatherPrivate *priv; ECalComponent *comp; icalcomponent *icomp; GList *l; priv = cbw->priv; if (forecasts == NULL) { e_cal_backend_notify_error (E_CAL_BACKEND (cbw), _("Could not retrieve weather data")); return; } /* update cache */ l = e_cal_backend_cache_get_components (priv->cache); for (; l != NULL; l = g_list_next (l)) { ECalComponentId *id; icomp = e_cal_component_get_icalcomponent (E_CAL_COMPONENT (l->data)); id = e_cal_component_get_id (E_CAL_COMPONENT (l->data)); e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbw), id, icalcomponent_as_ical_string (icomp), NULL); e_cal_component_free_id (id); g_object_unref (G_OBJECT (l->data)); } g_list_free (l); e_file_cache_clean (E_FILE_CACHE (priv->cache)); for (l = forecasts; l != NULL; l = g_list_next (l)) { comp = create_weather (cbw, l->data); e_cal_backend_cache_put_component (priv->cache, comp); icomp = e_cal_component_get_icalcomponent (comp); e_cal_backend_notify_object_created (E_CAL_BACKEND (cbw), icalcomponent_as_ical_string (icomp)); } priv->is_loading = FALSE; } static gboolean begin_retrieval_cb (ECalBackendWeather *cbw) { ECalBackendWeatherPrivate *priv = cbw->priv; GSource *source; if (priv->mode != CAL_MODE_REMOTE) return TRUE; maybe_start_reload_timeout (cbw); if (priv->source == NULL) priv->source = e_weather_source_new (e_cal_backend_get_uri (E_CAL_BACKEND (cbw))); source = g_main_current_source (); if (priv->begin_retrival_id == g_source_get_id (source)) priv->begin_retrival_id = 0; if (priv->is_loading) return FALSE; priv->is_loading = TRUE; e_weather_source_parse (priv->source, (EWeatherSourceFinished) finished_retrieval_cb, cbw); return FALSE; } static const char* getConditions (WeatherForecast *report) { switch (report->conditions) { case WEATHER_FAIR: return _("Fair"); case WEATHER_SNOW_SHOWERS: return _("Snow showers"); case WEATHER_SNOW: return _("Snow"); case WEATHER_PARTLY_CLOUDY: return _("Partly cloudy"); case WEATHER_SMOKE: return _("Smoke"); case WEATHER_THUNDERSTORMS: return _("Thunderstorms"); case WEATHER_CLOUDY: return _("Cloudy"); case WEATHER_DRIZZLE: return _("Drizzle"); case WEATHER_SUNNY: return _("Sunny"); case WEATHER_DUST: return _("Dust"); case WEATHER_CLEAR: return _("Clear"); case WEATHER_MOSTLY_CLOUDY: return _("Mostly cloudy"); case WEATHER_WINDY: return _("Windy"); case WEATHER_RAIN_SHOWERS: return _("Rain showers"); case WEATHER_FOGGY: return _("Foggy"); case WEATHER_RAIN_OR_SNOW_MIXED: return _("Rain/snow mixed"); case WEATHER_SLEET: return _("Sleet"); case WEATHER_VERY_HOT_OR_HOT_HUMID: return _("Very hot/humid"); case WEATHER_BLIZZARD: return _("Blizzard"); case WEATHER_FREEZING_RAIN: return _("Freezing rain"); case WEATHER_HAZE: return _("Haze"); case WEATHER_BLOWING_SNOW: return _("Blowing snow"); case WEATHER_FREEZING_DRIZZLE: return _("Freezing drizzle"); case WEATHER_VERY_COLD_WIND_CHILL: return _("Very cold/wind chill"); case WEATHER_RAIN: return _("Rain"); default: return NULL; } } static const char* getCategory (WeatherForecast *report) { /* Right now this is based on which icons we have available */ switch (report->conditions) { case WEATHER_FAIR: return _("Weather: Sunny"); case WEATHER_SNOW_SHOWERS: return _("Weather: Snow"); case WEATHER_SNOW: return _("Weather: Snow"); case WEATHER_PARTLY_CLOUDY: return _("Weather: Partly Cloudy"); case WEATHER_SMOKE: return _("Weather: Fog"); case WEATHER_THUNDERSTORMS: return _("Weather: Thunderstorms"); case WEATHER_CLOUDY: return _("Weather: Cloudy"); case WEATHER_DRIZZLE: return _("Weather: Rain"); case WEATHER_SUNNY: return _("Weather: Sunny"); case WEATHER_DUST: return _("Weather: Fog"); case WEATHER_CLEAR: return _("Weather: Sunny"); case WEATHER_MOSTLY_CLOUDY: return _("Weather: Cloudy"); case WEATHER_WINDY: return ""; case WEATHER_RAIN_SHOWERS: return _("Weather: Rain"); case WEATHER_FOGGY: return _("Weather: Fog"); case WEATHER_RAIN_OR_SNOW_MIXED: return _("Weather: Rain"); case WEATHER_SLEET: return _("Weather: Rain"); case WEATHER_VERY_HOT_OR_HOT_HUMID: return _("Weather: Sunny"); case WEATHER_BLIZZARD: return _("Weather: Snow"); case WEATHER_FREEZING_RAIN: return _("Weather: Rain"); case WEATHER_HAZE: return _("Weather: Fog"); case WEATHER_BLOWING_SNOW: return _("Weather: Snow"); case WEATHER_FREEZING_DRIZZLE: return _("Weather: Rain"); case WEATHER_VERY_COLD_WIND_CHILL: return ""; case WEATHER_RAIN: return _("Weather: Rain"); default: return NULL; } } static float ctof (float c) { return ((c * 9.0f / 5.0f) + 32.0f); } static float cmtoin (float cm) { return cm / 2.54f; } static ECalComponent* create_weather (ECalBackendWeather *cbw, WeatherForecast *report) { ECalBackendWeatherPrivate *priv; ECalComponent *cal_comp; ECalComponentText comp_summary; icalcomponent *ical_comp; struct icaltimetype itt; ECalComponentDateTime dt; const char *uid; GSList *text_list = NULL; ECalComponentText *description; char *pop, *snow; ESource *source; gboolean metric; const char *format; g_return_val_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), NULL); priv = cbw->priv; source = e_cal_backend_get_source (E_CAL_BACKEND (cbw)); format = e_source_get_property (source, "units"); if (format == NULL) { format = e_source_get_property (source, "temperature"); if (format == NULL) metric = FALSE; else metric = (strcmp (format, "fahrenheit") != 0); } else { metric = (strcmp (format, "metric") == 0); } /* create the component and event object */ ical_comp = icalcomponent_new (ICAL_VEVENT_COMPONENT); cal_comp = e_cal_component_new (); e_cal_component_set_icalcomponent (cal_comp, ical_comp); /* set uid */ uid = e_cal_component_gen_uid (); e_cal_component_set_uid (cal_comp, uid); /* Set all-day event's date from forecast data */ itt = icaltime_from_timet (report->date, 1); dt.value = &itt; dt.tzid = NULL; e_cal_component_set_dtstart (cal_comp, &dt); itt = icaltime_from_timet (report->date, 1); icaltime_adjust (&itt, 1, 0, 0, 0); dt.value = &itt; dt.tzid = NULL; /* We have to add 1 day to DTEND, as it is not inclusive. */ e_cal_component_set_dtend (cal_comp, &dt); /* The summary is the high or high/low temperatures */ if (report->high == report->low) { if (metric) comp_summary.value = g_strdup_printf (_("%.1f°C - %s"), report->high, priv->city); else comp_summary.value = g_strdup_printf (_("%.1f°F - %s"), ctof (report->high), priv->city); } else { if (metric) comp_summary.value = g_strdup_printf (_("%.1f/%.1f°C - %s"), report->high, report->low, priv->city); else comp_summary.value = g_strdup_printf (_("%.1f/%.1f°F - %s"), ctof (report->high), ctof (report->low), priv->city); } comp_summary.altrep = NULL; e_cal_component_set_summary (cal_comp, &comp_summary); if (report->pop != 0) pop = g_strdup_printf (_("%d%% chance of precipitation\n"), report->pop); else pop = g_strdup (""); if (report->snowhigh == 0) snow = g_strdup (""); else if (report->snowhigh == report->snowlow) { if (metric) snow = g_strdup_printf (_("%.1fcm snow\n"), report->snowhigh); else snow = g_strdup_printf (_("%.1fin snow\n"), cmtoin(report->snowhigh)); } else { if (metric) snow = g_strdup_printf (_("%.1f-%.1fcm snow\n"), report->snowlow, report->snowhigh); else snow = g_strdup_printf (_("%.1f-%.1fin snow\n"), cmtoin(report->snowlow), cmtoin(report->snowhigh)); } description = g_new0 (ECalComponentText, 1); description->value = g_strdup_printf ("%s\n%s%s", getConditions (report), pop, snow); description->altrep = ""; text_list = g_slist_append (text_list, description); e_cal_component_set_description_list (cal_comp, text_list); /* Set category and visibility */ e_cal_component_set_categories (cal_comp, getCategory (report)); e_cal_component_set_classification (cal_comp, E_CAL_COMPONENT_CLASS_PUBLIC); /* Weather is shown as free time */ e_cal_component_set_transparency (cal_comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT); e_cal_component_commit_sequence (cal_comp); g_free (pop); g_free (snow); return cal_comp; } static ECalBackendSyncStatus e_cal_backend_weather_is_read_only (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only) { *read_only = TRUE; return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_get_cal_address (ECalBackendSync *backend, EDataCal *cal, char **address) { /* Weather has no particular email addresses associated with it */ *address = NULL; return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal, char **address) { /* Weather has no particular email addresses associated with it */ *address = NULL; return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal, char **attribute) { *attribute = NULL; return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal, char **capabilities) { *capabilities = g_strdup (CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT "," CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS "," CAL_STATIC_CAPABILITY_NO_DISPLAY_ALARMS "," CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS "," CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT "," CAL_STATIC_CAPABILITY_NO_THISANDFUTURE "," CAL_STATIC_CAPABILITY_NO_THISANDPRIOR); return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists, const char *username, const char *password) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; const char *uri; cbw = E_CAL_BACKEND_WEATHER (backend); priv = cbw->priv; uri = e_cal_backend_get_uri (E_CAL_BACKEND (backend)); if (priv->city) g_free (priv->city); priv->city = g_strdup (strrchr (uri, '/') + 1); if (!priv->cache) { priv->cache = e_cal_backend_cache_new (uri, E_CAL_SOURCE_TYPE_EVENT); if (!priv->cache) { e_cal_backend_notify_error (E_CAL_BACKEND (cbw), _("Could not create cache file")); return GNOME_Evolution_Calendar_OtherError; } if (priv->default_zone) { icalcomponent *icalcomp = icaltimezone_get_component (priv->default_zone); icaltimezone *zone = icaltimezone_new (); icaltimezone_set_component (zone, icalcomponent_new_clone (icalcomp)); g_hash_table_insert (priv->zones, g_strdup (icaltimezone_get_tzid (zone)), zone); } if (priv->mode == CAL_MODE_LOCAL) return GNOME_Evolution_Calendar_Success; if (!priv->begin_retrival_id) priv->begin_retrival_id = g_idle_add ((GSourceFunc) begin_retrieval_cb, cbw); } return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_remove (ECalBackendSync *backend, EDataCal *cal) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; cbw = E_CAL_BACKEND_WEATHER (backend); priv = cbw->priv; if (!priv->cache) return GNOME_Evolution_Calendar_OtherError; e_file_cache_remove (E_FILE_CACHE (priv->cache)); return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_discard_alarm (ECalBackendSync *backend, EDataCal *cal, const char *uid, const char *auid) { return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_receive_objects (ECalBackendSync *backend, EDataCal *cal, const char *calobj) { return GNOME_Evolution_Calendar_PermissionDenied; } static ECalBackendSyncStatus e_cal_backend_weather_get_default_object (ECalBackendSync *backend, EDataCal *cal, char **object) { return GNOME_Evolution_Calendar_UnsupportedMethod; } static ECalBackendSyncStatus e_cal_backend_weather_get_object (ECalBackendSync *backend, EDataCal *cal, const char *uid, const char *rid, char **object) { ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend); ECalBackendWeatherPrivate *priv = cbw->priv; ECalComponent *comp; g_return_val_if_fail (uid != NULL, GNOME_Evolution_Calendar_ObjectNotFound); g_return_val_if_fail (priv->cache != NULL, GNOME_Evolution_Calendar_ObjectNotFound); comp = e_cal_backend_cache_get_component (priv->cache, uid, rid); g_return_val_if_fail (comp != NULL, GNOME_Evolution_Calendar_ObjectNotFound); *object = e_cal_component_get_as_string (comp); g_object_unref (comp); return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_get_object_list (ECalBackendSync *backend, EDataCal *cal, const char *sexp_string, GList **objects) { ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend); ECalBackendWeatherPrivate *priv = cbw->priv; ECalBackendSExp *sexp = e_cal_backend_sexp_new (sexp_string); GList *components, *l; if (!sexp) return GNOME_Evolution_Calendar_InvalidQuery; *objects = NULL; components = e_cal_backend_cache_get_components (priv->cache); for (l = components; l != NULL; l = g_list_next (l)) { if (e_cal_backend_sexp_match_comp (sexp, E_CAL_COMPONENT (l->data), E_CAL_BACKEND (backend))) *objects = g_list_append (*objects, e_cal_component_get_as_string (l->data)); } g_list_foreach (components, (GFunc) g_object_unref, NULL); g_list_free (components); g_object_unref (sexp); return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_get_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzid, char **object) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; icaltimezone *zone; icalcomponent *icalcomp; cbw = E_CAL_BACKEND_WEATHER (backend); priv = cbw->priv; g_return_val_if_fail (tzid != NULL, GNOME_Evolution_Calendar_ObjectNotFound); zone = e_cal_backend_internal_get_timezone (E_CAL_BACKEND (backend), tzid); if (!zone) return GNOME_Evolution_Calendar_ObjectNotFound; icalcomp = icaltimezone_get_component (zone); if (!icalcomp) return GNOME_Evolution_Calendar_InvalidObject; *object = g_strdup (icalcomponent_as_ical_string (icalcomp)); return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_add_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; icalcomponent *tz_comp; icaltimezone *zone; char *tzid; cbw = (ECalBackendWeather*) backend; g_return_val_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), GNOME_Evolution_Calendar_OtherError); g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError); priv = cbw->priv; tz_comp = icalparser_parse_string (tzobj); g_return_val_if_fail (tz_comp != NULL, GNOME_Evolution_Calendar_InvalidObject); if (icalcomponent_isa (tz_comp) != ICAL_VTIMEZONE_COMPONENT) return GNOME_Evolution_Calendar_InvalidObject; zone = icaltimezone_new (); icaltimezone_set_component (zone, tz_comp); tzid = icaltimezone_get_tzid (zone); if (g_hash_table_lookup (priv->zones, tzid)) { icaltimezone_free (zone, TRUE); return GNOME_Evolution_Calendar_Success; } g_hash_table_insert (priv->zones, g_strdup (tzid), zone); return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj) { icalcomponent *tz_comp; ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; icaltimezone *zone; cbw = (ECalBackendWeather *) backend; g_return_val_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), GNOME_Evolution_Calendar_OtherError); g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError); priv = cbw->priv; tz_comp = icalparser_parse_string (tzobj); if (!tz_comp) return GNOME_Evolution_Calendar_InvalidObject; zone = icaltimezone_new (); icaltimezone_set_component (zone, tz_comp); if (priv->default_zone) icaltimezone_free (priv->default_zone, 1); /* Set the default timezone to it. */ priv->default_zone = zone; return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList *users, time_t start, time_t end, GList **freebusy) { /* Weather doesn't count as busy time */ icalcomponent *vfb = icalcomponent_new_vfreebusy (); icaltimezone *utc_zone = icaltimezone_get_utc_timezone (); char *calobj; icalcomponent_set_dtstart (vfb, icaltime_from_timet_with_zone (start, FALSE, utc_zone)); icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone)); calobj = icalcomponent_as_ical_string (vfb); *freebusy = g_list_append (NULL, g_strdup (calobj)); icalcomponent_free (vfb); return GNOME_Evolution_Calendar_Success; } static ECalBackendSyncStatus e_cal_backend_weather_get_changes (ECalBackendSync *backend, EDataCal *cal, const char *change_id, GList **adds, GList **modifies, GList **deletes) { return GNOME_Evolution_Calendar_Success; } static gboolean e_cal_backend_weather_is_loaded (ECalBackend *backend) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; cbw = E_CAL_BACKEND_WEATHER (backend); priv = cbw->priv; if (!priv->cache) return FALSE; return TRUE; } static void e_cal_backend_weather_start_query (ECalBackend *backend, EDataCalView *query) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; ECalBackendSExp *sexp; GList *components, *l, *objects; cbw = E_CAL_BACKEND_WEATHER (backend); priv = cbw->priv; if (!priv->cache) { e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_NoSuchCal); return; } sexp = e_data_cal_view_get_object_sexp (query); if (!sexp) { e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_InvalidQuery); return; } objects = NULL; components = e_cal_backend_cache_get_components (priv->cache); for (l = components; l != NULL; l = g_list_next (l)) { if (e_cal_backend_sexp_match_comp (sexp, E_CAL_COMPONENT (l->data), backend)) objects = g_list_append (objects, e_cal_component_get_as_string (l->data)); } if (objects) e_data_cal_view_notify_objects_added (query, (const GList *) objects); g_list_foreach (components, (GFunc) g_object_unref, NULL); g_list_free (components); g_list_foreach (objects, (GFunc) g_free, NULL); g_list_free (objects); g_object_unref (sexp); e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_Success); } static CalMode e_cal_backend_weather_get_mode (ECalBackend *backend) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; cbw = E_CAL_BACKEND_WEATHER (backend); priv = cbw->priv; return priv->mode; } static void e_cal_backend_weather_set_mode (ECalBackend *backend, CalMode mode) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; GNOME_Evolution_Calendar_CalMode set_mode; gboolean loaded; cbw = E_CAL_BACKEND_WEATHER (backend); priv = cbw->priv; loaded = e_cal_backend_weather_is_loaded (backend); switch (mode) { case CAL_MODE_LOCAL: case CAL_MODE_REMOTE: priv->mode = mode; set_mode = cal_mode_to_corba (mode); if (loaded && priv->reload_timeout_id) { g_source_remove (priv->reload_timeout_id); priv->reload_timeout_id = 0; } break; case CAL_MODE_ANY: priv->mode = mode; set_mode = cal_mode_to_corba (mode); if (loaded && !priv->begin_retrival_id) priv->begin_retrival_id = g_idle_add ((GSourceFunc) begin_retrieval_cb, backend); break; default: set_mode = GNOME_Evolution_Calendar_MODE_ANY; break; } if (loaded) { if (set_mode == GNOME_Evolution_Calendar_MODE_ANY) e_cal_backend_notify_mode (backend, GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED, cal_mode_to_corba (priv->mode)); else e_cal_backend_notify_mode (backend, GNOME_Evolution_Calendar_CalListener_MODE_SET, set_mode); } } static icaltimezone * e_cal_backend_weather_internal_get_default_timezone (ECalBackend *backend) { ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend); return cbw->priv->default_zone; } static icaltimezone * e_cal_backend_weather_internal_get_timezone (ECalBackend *backend, const char *tzid) { icaltimezone *zone; if (!strcmp (tzid, "UTC")) zone = icaltimezone_get_utc_timezone (); else zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); return zone; } static void free_zone (gpointer data) { icaltimezone_free (data, TRUE); } /* Finalize handler for the weather backend */ static void e_cal_backend_weather_finalize (GObject *object) { ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (E_IS_CAL_BACKEND_WEATHER (object)); cbw = (ECalBackendWeather *) object; priv = cbw->priv; if (priv->reload_timeout_id) { g_source_remove (priv->reload_timeout_id); priv->reload_timeout_id = 0; } if (priv->begin_retrival_id) { g_source_remove (priv->begin_retrival_id); priv->begin_retrival_id = 0; } if (priv->cache) { g_object_unref (priv->cache); priv->cache = NULL; } g_hash_table_destroy (priv->zones); if (priv->city) { g_free (priv->city); priv->city = NULL; } if (priv->default_zone) { icaltimezone_free (priv->default_zone, 1); priv->default_zone = NULL; } g_free (priv); cbw->priv = NULL; if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); } /* Object initialization function for the weather backend */ static void e_cal_backend_weather_init (ECalBackendWeather *cbw, ECalBackendWeatherClass *class) { ECalBackendWeatherPrivate *priv; priv = g_new0 (ECalBackendWeatherPrivate, 1); cbw->priv = priv; priv->reload_timeout_id = 0; priv->source_changed_id = 0; priv->begin_retrival_id = 0; priv->opened = FALSE; priv->source = NULL; priv->cache = NULL; priv->city = NULL; priv->zones = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_zone); e_cal_backend_sync_set_lock (E_CAL_BACKEND_SYNC (cbw), TRUE); } /* Class initialization function for the weather backend */ static void e_cal_backend_weather_class_init (ECalBackendWeatherClass *class) { GObjectClass *object_class; ECalBackendClass *backend_class; ECalBackendSyncClass *sync_class; object_class = (GObjectClass *) class; backend_class = (ECalBackendClass *) class; sync_class = (ECalBackendSyncClass *) class; parent_class = (ECalBackendSyncClass *) g_type_class_peek_parent (class); object_class->finalize = e_cal_backend_weather_finalize; sync_class->is_read_only_sync = e_cal_backend_weather_is_read_only; sync_class->get_cal_address_sync = e_cal_backend_weather_get_cal_address; sync_class->get_alarm_email_address_sync = e_cal_backend_weather_get_alarm_email_address; sync_class->get_ldap_attribute_sync = e_cal_backend_weather_get_ldap_attribute; sync_class->get_static_capabilities_sync = e_cal_backend_weather_get_static_capabilities; sync_class->open_sync = e_cal_backend_weather_open; sync_class->remove_sync = e_cal_backend_weather_remove; sync_class->discard_alarm_sync = e_cal_backend_weather_discard_alarm; sync_class->receive_objects_sync = e_cal_backend_weather_receive_objects; sync_class->get_default_object_sync = e_cal_backend_weather_get_default_object; sync_class->get_object_sync = e_cal_backend_weather_get_object; sync_class->get_object_list_sync = e_cal_backend_weather_get_object_list; sync_class->get_timezone_sync = e_cal_backend_weather_get_timezone; sync_class->add_timezone_sync = e_cal_backend_weather_add_timezone; sync_class->set_default_zone_sync = e_cal_backend_weather_set_default_zone; sync_class->get_freebusy_sync = e_cal_backend_weather_get_free_busy; sync_class->get_changes_sync = e_cal_backend_weather_get_changes; backend_class->is_loaded = e_cal_backend_weather_is_loaded; backend_class->start_query = e_cal_backend_weather_start_query; backend_class->get_mode = e_cal_backend_weather_get_mode; backend_class->set_mode = e_cal_backend_weather_set_mode; backend_class->internal_get_default_timezone = e_cal_backend_weather_internal_get_default_timezone; backend_class->internal_get_timezone = e_cal_backend_weather_internal_get_timezone; } /** * e_cal_backend_weather_get_type: * @void: * * Registers the #ECalBackendWeather class if necessary, and returns * the type ID associated to it. * * Return value: The type ID of the #ECalBackendWeather class. **/ GType e_cal_backend_weather_get_type (void) { static GType e_cal_backend_weather_type = 0; if (!e_cal_backend_weather_type) { static GTypeInfo info = { sizeof (ECalBackendWeatherClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) e_cal_backend_weather_class_init, NULL, NULL, sizeof (ECalBackendWeather), 0, (GInstanceInitFunc) e_cal_backend_weather_init }; e_cal_backend_weather_type = g_type_register_static (E_TYPE_CAL_BACKEND_SYNC, "ECalBackendWeather", &info, 0); } return e_cal_backend_weather_type; }