/* Add_timezone handler for the file backend */ static void e_cal_backend_http_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **error) { ETimezoneCache *timezone_cache; icalcomponent *tz_comp; icaltimezone *zone; timezone_cache = E_TIMEZONE_CACHE (backend); tz_comp = icalparser_parse_string (tzobj); if (!tz_comp) { g_propagate_error (error, EDC_ERROR (InvalidObject)); return; } if (icalcomponent_isa (tz_comp) != ICAL_VTIMEZONE_COMPONENT) { icalcomponent_free (tz_comp); g_propagate_error (error, EDC_ERROR (InvalidObject)); return; } zone = icaltimezone_new (); icaltimezone_set_component (zone, tz_comp); e_timezone_cache_add_timezone (timezone_cache, zone); }
static gboolean deserialize (ScalixObject * object, const char *string) { ScalixAppointmentPrivate *priv; icalcomponent *icomp, *subcomp; icalcomponent_kind kind; icaltimezone *zone; priv = SCALIX_APPOINTMENT_GET_PRIVATE (SCALIX_APPOINTMENT (object)); icomp = icalparser_parse_string (string); if (icalcomponent_isa (icomp) != ICAL_VCALENDAR_COMPONENT) { g_warning ("No VCALENAR while deserializing! (%s)\n", string); icalcomponent_free (icomp); return FALSE; } /* Grab the timezone if any */ subcomp = icalcomponent_get_first_component (icomp, ICAL_VTIMEZONE_COMPONENT); if (subcomp != NULL) { zone = icaltimezone_new (); icalcomponent_remove_component (icomp, subcomp); if (icaltimezone_set_component (zone, subcomp)) priv->timezone = zone; } kind = ICAL_VEVENT_COMPONENT; /* Grab the main VEVENT */ subcomp = icalcomponent_get_first_component (icomp, kind); if (subcomp == NULL) { icalcomponent_free (icomp); return FALSE; } icalcomponent_remove_component (icomp, subcomp); e_cal_component_set_icalcomponent (E_CAL_COMPONENT (object), subcomp); e_cal_component_commit_sequence (E_CAL_COMPONENT (object)); priv->exceptions = NULL; while ((subcomp = icalcomponent_get_next_component (icomp, kind))) { icalcomponent_remove_component (icomp, subcomp); priv->exceptions = g_slist_prepend (priv->exceptions, subcomp); } icalcomponent_free (icomp); return TRUE; }
static gboolean set_ical_from_mime_part (CamelMimePart * part, ScalixObject * object) { CamelDataWrapper *content; CamelStream *stream; GByteArray *data; icalcomponent *icomp = NULL; icalcomponent *subcomp = NULL; ScalixAppointmentPrivate *priv; priv = SCALIX_APPOINTMENT_GET_PRIVATE (SCALIX_APPOINTMENT (object)); content = camel_medium_get_content_object (CAMEL_MEDIUM (part)); data = g_byte_array_new (); stream = camel_stream_mem_new_with_byte_array (data); camel_data_wrapper_decode_to_stream (content, stream); if (data == NULL || data->data == NULL) { g_print ("Found corrupt ical data\n"); return FALSE; } icomp = icalparser_parse_string ((const char *) data->data); if (icalcomponent_isa (icomp) != ICAL_VCALENDAR_COMPONENT) { icalcomponent_free (icomp); return FALSE; } /* Grab the timezone if any */ subcomp = icalcomponent_get_first_component (icomp, ICAL_VTIMEZONE_COMPONENT); if (subcomp != NULL) { icaltimezone *zone; zone = icaltimezone_new (); icaltimezone_set_component (zone, subcomp); priv->timezone = zone; } /* Grab the main VEVENT */ subcomp = icalcomponent_get_first_component (icomp, ICAL_VEVENT_COMPONENT); e_cal_component_set_icalcomponent (E_CAL_COMPONENT (object), subcomp); return TRUE; }
int main(int argc, char *argv[]) { char *dtstr = "20031026T190000"; icaltimezone *zone; struct icaltimetype tt; int utc_offset; if (argc > 1) { dtstr = argv[1]; } icalcomponent *zonecomp = icalcomponent_new_from_string(mytz); zone = icaltimezone_new(); icaltimezone_set_component(zone, zonecomp); tt = icaltime_from_string(dtstr); icaltime_set_timezone(&tt, zone); utc_offset = icaltimezone_get_utc_offset(zone, &tt, NULL); printf("OFFSET for %s is %d %p\n", dtstr, utc_offset, zone); }
gint main (gint argc, gchar **argv) { ECal *cal; gchar *uri = NULL; icalproperty *property; icalcomponent *component; icaltimezone *zone; icaltimezone *zone_final; g_type_init (); cal = ecal_test_utils_cal_new_temp (&uri, E_CAL_SOURCE_TYPE_EVENT); ecal_test_utils_cal_open (cal, FALSE); /* Build up new timezone */ component = icalcomponent_new_vtimezone (); property = icalproperty_new_tzid (TZID_NEW); icalcomponent_add_property (component, property); property = icalproperty_new_tzname (TZNAME_NEW); icalcomponent_add_property (component, property); zone = icaltimezone_new (); icaltimezone_set_component (zone, component); /* add */ ecal_test_utils_cal_add_timezone (cal, zone); /* verify */ zone_final = ecal_test_utils_cal_get_timezone (cal, TZID_NEW); g_assert (!g_strcmp0 (icaltimezone_get_tzid (zone), icaltimezone_get_tzid (zone_final))); g_assert (!g_strcmp0 (icaltimezone_get_tznames (zone), icaltimezone_get_tznames (zone_final))); ecal_test_utils_cal_remove (cal); icaltimezone_free (zone, TRUE); return 0; }
/** Get all timezones from the cache. * * @param cb 3E calendar backend. * @param cache Calendar backend cache object. * * @return List of icaltimezone objects (free them using icaltimezone_free(x, 1);). */ static GSList *e_cal_backend_cache_get_timezones(ECalBackend3e *cb, ECalBackendCache *cache) { GSList *keys, *iter; GSList *list = NULL; g_return_val_if_fail(E_IS_CAL_BACKEND_CACHE(cache), NULL); keys = e_file_cache_get_keys(E_FILE_CACHE(cache)); for (iter = keys; iter; iter = iter->next) { char *key = iter->data; const icaltimezone *zone; g_static_rw_lock_reader_lock(&cb->priv->cache_lock); zone = e_cal_backend_cache_get_timezone(cache, key); g_static_rw_lock_reader_unlock(&cb->priv->cache_lock); if (zone) { icalcomponent *zone_comp = icaltimezone_get_component((icaltimezone *)zone); icaltimezone *new_zone = icaltimezone_new(); /* make sure you have patched eds if you get segfaults here */ if (zone_comp == NULL) { g_critical("Patch your evolution-data-server or else..."); } icaltimezone_set_component(new_zone, icalcomponent_new_clone(zone_comp)); list = g_slist_prepend(list, new_zone); } } /* eds patch required here! */ g_slist_free(keys); return list; }
/** Sync changes from the server to the cache. * * @param cb 3E calendar backend. * * @return TRUE on success. * * @todo Handle UID/RID. * @todo Better server error handling. * @todo Conflict resolution. */ gboolean e_cal_backend_3e_sync_server_to_cache(ECalBackend3e *cb) { GError *local_err = NULL; gboolean update_sync = TRUE; icalcomponent *ical; icalcomponent *icomp; char filter[128]; struct tm tm; time_t stamp = MAX(e_cal_backend_3e_get_sync_timestamp(cb) - 60 * 60 * 24, 0); /*XXX: always add 1 day padding to prevent timezone problems */ /* prepare query filter string */ gmtime_r(&stamp, &tm); strftime(filter, sizeof(filter), "modified_since('%F %T')", &tm); ical = get_server_objects(cb, filter); if (ical == NULL) { return FALSE; } for (icomp = icalcomponent_get_first_component(ical, ICAL_ANY_COMPONENT); icomp; icomp = icalcomponent_get_next_component(ical, ICAL_ANY_COMPONENT)) { icalcomponent_kind kind = icalcomponent_isa(icomp); icalcomponent_set_cache_state(icomp, E_CAL_COMPONENT_CACHE_STATE_NONE); if (kind == ICAL_VEVENT_COMPONENT) { ECalComponent *comp; const char *uid = icalcomponent_get_uid(icomp); gboolean server_deleted = icalcomponent_3e_status_is_deleted(icomp); ECalComponentCacheState comp_state = E_CAL_COMPONENT_CACHE_STATE_NONE; g_static_rw_lock_reader_lock(&cb->priv->cache_lock); comp = e_cal_backend_cache_get_component(cb->priv->cache, uid, NULL); g_static_rw_lock_reader_unlock(&cb->priv->cache_lock); if (comp) { comp_state = e_cal_component_get_cache_state(comp); } if (server_deleted) { /* deleted by the server */ if (comp && e_cal_component_get_cache_state(comp) != E_CAL_COMPONENT_CACHE_STATE_CREATED && e_cal_component_get_cache_state(comp) != E_CAL_COMPONENT_CACHE_STATE_MODIFIED) { char *object = e_cal_component_get_as_string(comp); ECalComponentId *id = e_cal_component_get_id(comp); g_static_rw_lock_writer_lock(&cb->priv->cache_lock); e_cal_backend_cache_remove_component(cb->priv->cache, uid, NULL); g_static_rw_lock_writer_unlock(&cb->priv->cache_lock); e_cal_backend_notify_object_removed(E_CAL_BACKEND(cb), id, object, NULL); e_cal_component_free_id(id); g_free(object); } } else { char *old_object = NULL; char *object; ECalComponent *new_comp = e_cal_component_new(); e_cal_component_set_icalcomponent(new_comp, icalcomponent_new_clone(icomp)); e_cal_component_set_cache_state(new_comp, E_CAL_COMPONENT_CACHE_STATE_NONE); e_cal_backend_3e_convert_attachment_uris_to_local(cb, new_comp); if (comp) { old_object = e_cal_component_get_as_string(comp); } object = e_cal_component_get_as_string(new_comp); if (old_object == NULL) { if (e_cal_backend_3e_download_attachments(cb, new_comp, &local_err)) { /* not in cache yet */ g_static_rw_lock_writer_lock(&cb->priv->cache_lock); e_cal_backend_cache_put_component(cb->priv->cache, new_comp); g_static_rw_lock_writer_unlock(&cb->priv->cache_lock); e_cal_backend_notify_object_created(E_CAL_BACKEND(cb), object); } else { e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "Can't download attachment.", local_err); g_clear_error(&local_err); update_sync = FALSE; } } else if (strcmp(old_object, object)) { /* what is in cache and what is on server differs */ if (comp_state != E_CAL_COMPONENT_CACHE_STATE_NONE) { /* modified in cache, don't do anything */ } else { if (e_cal_backend_3e_download_attachments(cb, new_comp, &local_err)) { /* sync with server */ g_static_rw_lock_writer_lock(&cb->priv->cache_lock); e_cal_backend_cache_put_component(cb->priv->cache, new_comp); g_static_rw_lock_writer_unlock(&cb->priv->cache_lock); e_cal_backend_notify_object_modified(E_CAL_BACKEND(cb), old_object, object); } else { e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "Can't download attachment.", local_err); g_clear_error(&local_err); update_sync = FALSE; } } } g_free(old_object); g_free(object); g_object_unref(new_comp); } if (comp) { g_object_unref(comp); } } else if (kind == ICAL_VTIMEZONE_COMPONENT) { const char *tzid = icalcomponent_get_tzid(icomp); /* import non-existing timezones from the server */ if (!e_cal_backend_cache_get_timezone(cb->priv->cache, tzid)) { icaltimezone *zone = icaltimezone_new(); icalcomponent *zone_comp = icalcomponent_new_clone(icomp); if (icaltimezone_set_component(zone, zone_comp)) { g_static_rw_lock_writer_lock(&cb->priv->cache_lock); e_cal_backend_cache_put_timezone(cb->priv->cache, zone); g_static_rw_lock_writer_unlock(&cb->priv->cache_lock); } else { icalcomponent_free(zone_comp); } icaltimezone_free(zone, 1); } } else { g_warning("Unsupported component kind (%d) found on the 3e server.", kind); } } if (update_sync) { e_cal_backend_3e_set_sync_timestamp(cb, time(NULL)); } icalcomponent_free(ical); return TRUE; }
/** * e_cal_client_check_timezones: * @comp: a VCALENDAR containing a list of * VTIMEZONE and arbitrary other components, in * arbitrary order: these other components are * modified by this call * @comps: (element-type icalcomponent) (allow-none): a list of #icalcomponent * instances which also have to be patched; may be %NULL * @tzlookup: a callback function which is called to retrieve * a calendar's VTIMEZONE definition; the returned * definition is *not* freed by e_cal_client_check_timezones() * (to be compatible with e_cal_get_timezone()); * NULL indicates that no such timezone exists * or an error occurred * @ecalclient: an arbitrary pointer which is passed through to * the @tzlookup function * @cancellable: a #GCancellable to use in @tzlookup function * @error: an error description in case of a failure * * This function cleans up VEVENT, VJOURNAL, VTODO and VTIMEZONE * items which are to be imported into Evolution. * * Using VTIMEZONE definitions is problematic because they cannot be * updated properly when timezone definitions change. They are also * incomplete (for compatibility reason only one set of rules for * summer saving changes can be included, even if different rules * apply in different years). This function looks for matches of the * used TZIDs against system timezones and replaces such TZIDs with * the corresponding system timezone. This works for TZIDs containing * a location (found via a fuzzy string search) and for Outlook TZIDs * (via a hard-coded lookup table). * * Some programs generate broken meeting invitations with TZID, but * without including the corresponding VTIMEZONE. Importing such * invitations unchanged causes problems later on (meeting displayed * incorrectly, e_cal_get_component_as_string() fails). The situation * where this occurred in the past (found by a SyncEvolution user) is * now handled via the location based mapping. * * If this mapping fails, this function also deals with VTIMEZONE * conflicts: such conflicts occur when the calendar already contains * an old VTIMEZONE definition with the same TZID, but different * summer saving rules. Replacing the VTIMEZONE potentially breaks * displaying of old events, whereas not replacing it breaks the new * events (the behavior in Evolution <= 2.22.1). * * The way this problem is resolved is by renaming the new VTIMEZONE * definition until the TZID is unique. A running count is appended to * the TZID. All items referencing the renamed TZID are adapted * accordingly. * * Returns: %TRUE if successful, %FALSE otherwise. * * Since: 3.2 **/ gboolean e_cal_client_check_timezones (icalcomponent *comp, GList *comps, icaltimezone *(*tzlookup) (const gchar *tzid, gconstpointer ecalclient, GCancellable *cancellable, GError **error), gconstpointer ecalclient, GCancellable *cancellable, GError **error) { gboolean success = TRUE; icalcomponent *subcomp = NULL; icaltimezone *zone = icaltimezone_new (); gchar *key = NULL, *value = NULL; gchar *buffer = NULL; gchar *zonestr = NULL; gchar *tzid = NULL; GList *l; /* a hash from old to new tzid; strings dynamically allocated */ GHashTable *mapping = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); /* a hash of all system time zone IDs which have to be added; strings are shared with mapping hash */ GHashTable *systemtzids = g_hash_table_new (g_str_hash, g_str_equal); *error = NULL; if (!mapping || !zone) { goto nomem; } /* iterate over all VTIMEZONE definitions */ subcomp = icalcomponent_get_first_component (comp, ICAL_VTIMEZONE_COMPONENT); while (subcomp) { if (icaltimezone_set_component (zone, subcomp)) { g_free (tzid); tzid = g_strdup (icaltimezone_get_tzid (zone)); if (tzid) { const gchar *newtzid = e_cal_match_tzid (tzid); if (newtzid) { /* matched against system time zone */ g_free (key); key = g_strdup (tzid); if (!key) { goto nomem; } g_free (value); value = g_strdup (newtzid); if (!value) { goto nomem; } g_hash_table_insert (mapping, key, value); g_hash_table_insert (systemtzids, value, NULL); key = value = NULL; } else { gint counter; zonestr = icalcomponent_as_ical_string_r (subcomp); /* check for collisions with existing timezones */ for (counter = 0; counter < 100 /* sanity limit */; counter++) { icaltimezone *existing_zone; if (counter) { g_free (value); value = g_strdup_printf ("%s %d", tzid, counter); } existing_zone = tzlookup (counter ? value : tzid, ecalclient, cancellable, error); if (!existing_zone) { if (*error) { goto failed; } else { break; } } g_free (buffer); buffer = icalcomponent_as_ical_string_r (icaltimezone_get_component (existing_zone)); if (counter) { gchar *fulltzid = g_strdup_printf ("TZID:%s", value); gsize baselen = strlen ("TZID:") + strlen (tzid); gsize fulllen = strlen (fulltzid); gchar *tzidprop; /* * Map TZID with counter suffix back to basename. */ tzidprop = strstr (buffer, fulltzid); if (tzidprop) { memmove ( tzidprop + baselen, tzidprop + fulllen, strlen (tzidprop + fulllen) + 1); } g_free (fulltzid); } /* * If the strings are identical, then the * VTIMEZONE definitions are identical. If * they are not identical, then VTIMEZONE * definitions might still be semantically * correct and we waste some space by * needlesly duplicating the VTIMEZONE. This * is expected to occur rarely (if at all) in * practice. */ if (!strcmp (zonestr, buffer)) { break; } } if (!counter) { /* does not exist, nothing to do */ } else { /* timezone renamed */ icalproperty *prop = icalcomponent_get_first_property (subcomp, ICAL_TZID_PROPERTY); while (prop) { icalproperty_set_value_from_string (prop, value, "NO"); prop = icalcomponent_get_next_property (subcomp, ICAL_ANY_PROPERTY); } g_free (key); key = g_strdup (tzid); g_hash_table_insert (mapping, key, value); key = value = NULL; } } } } subcomp = icalcomponent_get_next_component (comp, ICAL_VTIMEZONE_COMPONENT); } /* * now replace all TZID parameters in place */ subcomp = icalcomponent_get_first_component (comp, ICAL_ANY_COMPONENT); while (subcomp) { /* * Leave VTIMEZONE unchanged, iterate over properties of * everything else. * * Note that no attempt is made to remove unused VTIMEZONE * definitions. That would just make the code more complex for * little additional gain. However, newly used time zones are * added below. */ patch_tzids (subcomp, mapping); subcomp = icalcomponent_get_next_component (comp, ICAL_ANY_COMPONENT); } for (l = comps; l; l = l->next) { patch_tzids (l->data, mapping); } /* * add system time zones that we mapped to: adding them ensures * that the VCALENDAR remains consistent */ g_hash_table_foreach (systemtzids, addsystemtz, comp); goto done; nomem: /* set gerror for "out of memory" if possible, otherwise abort via g_error() */ *error = g_error_new (E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR, "out of memory"); if (!*error) { g_error ("e_cal_check_timezones(): out of memory, cannot proceed - sorry!"); } failed: /* gerror should have been set already */ success = FALSE; done: if (mapping) { g_hash_table_destroy (mapping); } if (systemtzids) { g_hash_table_destroy (systemtzids); } if (zone) { icaltimezone_free (zone, 1); } g_free (tzid); g_free (zonestr); g_free (buffer); g_free (key); g_free (value); return success; }
nsresult calIcalProperty::getDatetime_(calIcalComponent * parent, icalproperty * prop, calIDateTime ** dtp) { icalvalue * const val = icalproperty_get_value(prop); icalvalue_kind const valkind = icalvalue_isa(val); if (valkind != ICAL_DATETIME_VALUE && valkind != ICAL_DATE_VALUE) { return NS_ERROR_UNEXPECTED; } icaltimetype itt = icalvalue_get_datetime(val); char const* tzid_ = nullptr; if (!itt.is_utc) { if (itt.zone) { tzid_ = icaltimezone_get_tzid(const_cast<icaltimezone *>(itt.zone)); } else { // Need to get the tzid param. Unfortunatly, libical tends to return raw // ics strings, with quotes and everything. That's not what we want. Need // to work around. icalparameter * const tzparam = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER); if (tzparam) { tzid_ = icalparameter_get_xvalue(tzparam); } } } nsCOMPtr<calITimezone> tz; if (tzid_) { nsDependentCString const tzid(tzid_); calIcalComponent * comp = nullptr; if (parent) { comp = parent->getParentVCalendarOrThis(); } // look up parent if timezone is already referenced: if (comp) { comp->mReferencedTimezones.Get(tzid, getter_AddRefs(tz)); } if (!tz) { if (parent) { // passed tz provider has precedence over timezone service: calITimezoneProvider * const tzProvider = parent->getTzProvider(); if (tzProvider) { tzProvider->GetTimezone(tzid, getter_AddRefs(tz)); NS_ASSERTION(tz, tzid_); } } if (!tz) { // look up tz in tz service. // this hides errors from incorrect ics files, which could state // a TZID that is not present in the ics file. // The other way round, it makes this product more error tolerant. nsresult rv = cal::getTimezoneService()->GetTimezone(tzid, getter_AddRefs(tz)); if (NS_FAILED(rv) || !tz) { icaltimezone const* zone = itt.zone; if (!zone && comp) { // look up parent VCALENDAR for VTIMEZONE: zone = icalcomponent_get_timezone(comp->mComponent, tzid_); NS_ASSERTION(zone, tzid_); } if (zone) { // We need to decouple this (inner) VTIMEZONE from the parent VCALENDAR to avoid // running into circular references (referenced timezones): icaltimezone * const clonedZone = icaltimezone_new(); CAL_ENSURE_MEMORY(clonedZone); icalcomponent * const clonedZoneComp = icalcomponent_new_clone(icaltimezone_get_component(const_cast<icaltimezone *>(zone))); if (!clonedZoneComp) { icaltimezone_free(clonedZone, 1 /* free struct */); CAL_ENSURE_MEMORY(clonedZoneComp); } if (!icaltimezone_set_component(clonedZone, clonedZoneComp)) { icaltimezone_free(clonedZone, 1 /* free struct */); return NS_ERROR_INVALID_ARG; } nsCOMPtr<calIIcalComponent> const tzComp(new calIcalComponent(clonedZone, clonedZoneComp)); CAL_ENSURE_MEMORY(tzComp); tz = new calTimezone(tzid, tzComp); CAL_ENSURE_MEMORY(tz); } else { // install phantom timezone, so the data could be repaired: tz = new calTimezone(tzid, nullptr); CAL_ENSURE_MEMORY(tz); } } } if (comp && tz) { // assure timezone is known: comp->AddTimezoneReference(tz); } } if (tz) { // correct itt which would else appear floating: itt.zone = cal::getIcalTimezone(tz); itt.is_utc = 0; } else { cal::logMissingTimezone(tzid_); } } *dtp = new calDateTime(&itt, tz); CAL_ENSURE_MEMORY(*dtp); NS_ADDREF(*dtp); return NS_OK; }
icaltimezone * calendar_config_get_icaltimezone (void) { char *location; icaltimezone *zone = NULL; calendar_config_init (); location = calendar_config_get_timezone (); if (location) { icalcomponent *icalcomp, *dl_comp; zone = icaltimezone_get_builtin_timezone (location); icalcomp = icaltimezone_get_component (zone); if (!(dl_comp = icalcomponent_get_first_component (icalcomp, ICAL_XDAYLIGHT_COMPONENT))) { g_free (location); return zone; } if (!calendar_config_get_daylight_saving () && zone) { icalcomponent *zone_comp, *s_comp; icalproperty *tz_prop, *offset_to; icaltimezone *st_zone = NULL; int offset; char *n_tzid, *tzid; tzid = icaltimezone_get_tzid (zone); n_tzid = g_strconcat (tzid, "-(Standard)", NULL); if (!custom_zones) { custom_zones = g_hash_table_new (g_str_hash, g_str_equal); } else if ((st_zone = g_hash_table_lookup (custom_zones, n_tzid))) { g_free (n_tzid); g_free (location); return st_zone; } zone_comp = icalcomponent_new_clone (icalcomp); s_comp = icalcomponent_get_first_component (zone_comp, ICAL_XSTANDARD_COMPONENT); if (!s_comp) { g_free (n_tzid); icalcomponent_free (zone_comp); g_free (location); return zone; } offset_to = icalcomponent_get_first_property (s_comp, ICAL_TZOFFSETTO_PROPERTY); offset = icalproperty_get_tzoffsetto (offset_to); set_standard_offsets (zone_comp, offset); tz_prop = icalcomponent_get_first_property (zone_comp, ICAL_TZID_PROPERTY); if (tz_prop) { icalcomponent_remove_property (zone_comp, tz_prop); } tz_prop = icalproperty_new_tzid (n_tzid); icalcomponent_add_property (zone_comp, tz_prop); st_zone = icaltimezone_new (); icaltimezone_set_component (st_zone, zone_comp); zone = st_zone; g_hash_table_insert (custom_zones, n_tzid, zone); } g_free (location); } return zone; }
static gboolean cal_backend_http_load (ECalBackendHttp *backend, const gchar *uri, gchar **out_certificate_pem, GTlsCertificateFlags *out_certificate_errors, GCancellable *cancellable, GError **error) { ECalBackendHttpPrivate *priv = backend->priv; ETimezoneCache *timezone_cache; SoupMessage *soup_message; SoupSession *soup_session; icalcomponent *icalcomp, *subcomp; icalcomponent_kind kind; const gchar *newuri; SoupURI *uri_parsed; GHashTable *old_cache; GSList *comps_in_cache; ESource *source; guint status_code; gulong cancel_id = 0; struct { SoupSession *soup_session; SoupMessage *soup_message; } cancel_data; timezone_cache = E_TIMEZONE_CACHE (backend); soup_session = backend->priv->soup_session; soup_message = cal_backend_http_new_message (backend, uri); if (soup_message == NULL) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: %s"), uri); return FALSE; } if (G_IS_CANCELLABLE (cancellable)) { cancel_data.soup_session = soup_session; cancel_data.soup_message = soup_message; cancel_id = g_cancellable_connect ( cancellable, G_CALLBACK (cal_backend_http_cancelled), &cancel_data, (GDestroyNotify) NULL); } source = e_backend_get_source (E_BACKEND (backend)); e_soup_ssl_trust_connect (soup_message, source); e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING); status_code = soup_session_send_message (soup_session, soup_message); if (G_IS_CANCELLABLE (cancellable)) g_cancellable_disconnect (cancellable, cancel_id); if (status_code == SOUP_STATUS_NOT_MODIFIED) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); /* attempts with ETag can result in 304 status code */ g_object_unref (soup_message); priv->opened = TRUE; return TRUE; } /* Handle redirection ourselves */ if (SOUP_STATUS_IS_REDIRECTION (status_code)) { gboolean success; newuri = soup_message_headers_get_list ( soup_message->response_headers, "Location"); d (g_message ("Redirected from %s to %s\n", async_context->uri, newuri)); if (newuri != NULL) { gchar *redirected_uri; if (newuri[0]=='/') { g_warning ("Hey! Relative URI returned! Working around...\n"); uri_parsed = soup_uri_new (uri); soup_uri_set_path (uri_parsed, newuri); soup_uri_set_query (uri_parsed, NULL); /* g_free (newuri); */ newuri = soup_uri_to_string (uri_parsed, FALSE); g_message ("Translated URI: %s\n", newuri); soup_uri_free (uri_parsed); } redirected_uri = webcal_to_http_method (newuri, FALSE); success = cal_backend_http_load ( backend, redirected_uri, out_certificate_pem, out_certificate_errors, cancellable, error); g_free (redirected_uri); } else { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_BAD_REQUEST, _("Redirected to Invalid URI")); success = FALSE; } if (success) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); } else { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED); } g_object_unref (soup_message); return success; } /* check status code */ if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { /* because evolution knows only G_IO_ERROR_CANCELLED */ if (status_code == SOUP_STATUS_CANCELLED) g_set_error ( error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "%s", soup_message->reason_phrase); else g_set_error ( error, SOUP_HTTP_ERROR, status_code, "%s", soup_message->reason_phrase); if (status_code == SOUP_STATUS_SSL_FAILED) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED); cal_backend_http_extract_ssl_failed_data (soup_message, out_certificate_pem, out_certificate_errors); } else { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED); } g_object_unref (soup_message); empty_cache (backend); return FALSE; } e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); if (priv->store) { const gchar *etag; etag = soup_message_headers_get_one ( soup_message->response_headers, "ETag"); if (etag != NULL && *etag == '\0') etag = NULL; e_cal_backend_store_put_key_value (priv->store, "ETag", etag); } /* get the calendar from the response */ icalcomp = icalparser_parse_string (soup_message->response_body->data); if (!icalcomp) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Bad file format.")); g_object_unref (soup_message); empty_cache (backend); return FALSE; } if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Not a calendar.")); icalcomponent_free (icalcomp); g_object_unref (soup_message); empty_cache (backend); return FALSE; } g_object_unref (soup_message); soup_message = NULL; /* Update cache */ old_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); comps_in_cache = e_cal_backend_store_get_components (priv->store); while (comps_in_cache != NULL) { const gchar *uid; ECalComponent *comp = comps_in_cache->data; e_cal_component_get_uid (comp, &uid); g_hash_table_insert (old_cache, g_strdup (uid), e_cal_component_get_as_string (comp)); comps_in_cache = g_slist_remove (comps_in_cache, comps_in_cache->data); g_object_unref (comp); } kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend)); subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); e_cal_backend_store_freeze_changes (priv->store); while (subcomp) { ECalComponent *comp; icalcomponent_kind subcomp_kind; icalproperty *prop = NULL; subcomp_kind = icalcomponent_isa (subcomp); prop = icalcomponent_get_first_property (subcomp, ICAL_UID_PROPERTY); if (!prop && subcomp_kind == kind) { gchar *new_uid = e_cal_component_gen_uid (); icalcomponent_set_uid (subcomp, new_uid); g_free (new_uid); } if (subcomp_kind == kind) { comp = e_cal_component_new (); if (e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) { const gchar *uid; gpointer orig_key, orig_value; e_cal_component_get_uid (comp, &uid); if (!put_component_to_store (backend, comp)) { g_hash_table_remove (old_cache, uid); } else if (g_hash_table_lookup_extended (old_cache, uid, &orig_key, &orig_value)) { ECalComponent *orig_comp = e_cal_component_new_from_string (orig_value); e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend), orig_comp, comp); g_hash_table_remove (old_cache, uid); if (orig_comp) g_object_unref (orig_comp); } else { e_cal_backend_notify_component_created (E_CAL_BACKEND (backend), comp); } } g_object_unref (comp); } else if (subcomp_kind == ICAL_VTIMEZONE_COMPONENT) { icaltimezone *zone; zone = icaltimezone_new (); icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp)); e_timezone_cache_add_timezone (timezone_cache, zone); icaltimezone_free (zone, 1); } subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT); } e_cal_backend_store_thaw_changes (priv->store); /* notify the removals */ g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, backend); g_hash_table_destroy (old_cache); /* free memory */ icalcomponent_free (icalcomp); priv->opened = TRUE; return TRUE; }
static GtkWidget * ical_get_preview (icalcomponent *icalcomp) { GtkWidget *preview; GtkTreeView *tree_view; GtkTreeSelection *selection; GtkListStore *store; GtkTreeIter iter; GHashTable *timezones; icalcomponent *subcomp; icaltimezone *users_zone; if (!icalcomp || !is_icalcomp_usable (icalcomp)) return NULL; store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, E_TYPE_CAL_COMPONENT); timezones = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_zone_cb); users_zone = get_users_timezone (); /* get timezones first */ for (subcomp = icalcomponent_get_first_component (icalcomp, ICAL_VTIMEZONE_COMPONENT); subcomp; subcomp = icalcomponent_get_next_component (icalcomp, ICAL_VTIMEZONE_COMPONENT)) { icaltimezone *zone = icaltimezone_new (); if (!icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp)) || !icaltimezone_get_tzid (zone)) { icaltimezone_free (zone, 1); } else { g_hash_table_insert (timezones, (gchar *) icaltimezone_get_tzid (zone), zone); } } /* then each component */ for (subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); subcomp; subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT)) { icalcomponent_kind kind = icalcomponent_isa (subcomp); if (kind == ICAL_VEVENT_COMPONENT || kind == ICAL_VTODO_COMPONENT || kind == ICAL_VJOURNAL_COMPONENT) { ECalComponent *comp = e_cal_component_new (); ECalComponentText summary = { 0 }; ECalComponentDateTime dt = { 0 }; gchar *formatted_dt; if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) { g_object_unref (comp); continue; } e_cal_component_get_summary (comp, &summary); e_cal_component_get_dtstart (comp, &dt); formatted_dt = format_dt (&dt, timezones, users_zone); gtk_list_store_append (store, &iter); gtk_list_store_set ( store, &iter, 0, kind == ICAL_VEVENT_COMPONENT ? (e_cal_component_has_attendees (comp) ? C_("iCalImp", "Meeting") : C_("iCalImp", "Event")) : kind == ICAL_VTODO_COMPONENT ? C_("iCalImp", "Task") : kind == ICAL_VJOURNAL_COMPONENT ? C_("iCalImp", "Memo") : "??? Other ???", 1, formatted_dt ? formatted_dt : "", 2, summary.value && *summary.value ? summary.value : summary.altrep && *summary.altrep ? summary.altrep : "", 3, comp, -1); g_free (formatted_dt); e_cal_component_free_datetime (&dt); g_object_unref (comp); } } if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) { g_object_unref (store); g_hash_table_destroy (timezones); return NULL; } preview = e_web_view_preview_new (); gtk_widget_show (preview); g_object_set_data_full (G_OBJECT (preview), "iCalImp-timezones", timezones, (GDestroyNotify) g_hash_table_destroy); g_object_set_data (G_OBJECT (preview), "iCalImp-userszone", users_zone); tree_view = e_web_view_preview_get_tree_view (E_WEB_VIEW_PREVIEW (preview)); g_return_val_if_fail (tree_view != NULL, NULL); gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (store)); g_object_unref (store); /* Translators: Column header for a component type; it can be Event, Task or Memo */ gtk_tree_view_insert_column_with_attributes ( tree_view, -1, C_("iCalImp", "Type"), gtk_cell_renderer_text_new (), "text", 0, NULL); /* Translators: Column header for a component start date/time */ gtk_tree_view_insert_column_with_attributes ( tree_view, -1, C_("iCalImp", "Start"), gtk_cell_renderer_text_new (), "text", 1, NULL); /* Translators: Column header for a component summary */ gtk_tree_view_insert_column_with_attributes ( tree_view, -1, C_("iCalImp", "Summary"), gtk_cell_renderer_text_new (), "text", 2, NULL); if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL) > 1) e_web_view_preview_show_tree_view (E_WEB_VIEW_PREVIEW (preview)); selection = gtk_tree_view_get_selection (tree_view); gtk_tree_selection_select_iter (selection, &iter); g_signal_connect ( selection, "changed", G_CALLBACK (preview_selection_changed_cb), preview); preview_selection_changed_cb (selection, E_WEB_VIEW_PREVIEW (preview)); return preview; }