static void insert_tz_comps (icalparameter *param, gpointer cb_data) { const gchar *tzid; CompTzData *tdata = cb_data; icaltimezone *zone = NULL; icalcomponent *tzcomp; GError *error = NULL; tzid = icalparameter_get_tzid (param); if (g_hash_table_lookup (tdata->zones, tzid)) return; e_cal_client_get_timezone_sync ( tdata->client, tzid, &zone, NULL, &error); if (error != NULL) { g_warning ( "Could not get the timezone information for %s: %s", tzid, error->message); g_error_free (error); return; } tzcomp = icalcomponent_new_clone (icaltimezone_get_component (zone)); g_hash_table_insert (tdata->zones, (gpointer) tzid, (gpointer) tzcomp); }
static void add_timezone_cb (icalparameter *param, gpointer data) { icaltimezone *tz; const gchar *tzid; icalcomponent *vtz_comp; ForeachTzidData *f_data = (ForeachTzidData *) data; tzid = icalparameter_get_tzid (param); if (!tzid) return; tz = icalcomponent_get_timezone (f_data->vcal_comp, tzid); if (tz) return; tz = icalcomponent_get_timezone (f_data->icalcomp, tzid); if (!tz) { tz = icaltimezone_get_builtin_timezone_from_tzid (tzid); if (!tz) return; } vtz_comp = icaltimezone_get_component (tz); if (!vtz_comp) return; icalcomponent_add_component ( f_data->vcal_comp, icalcomponent_new_clone (vtz_comp)); }
nsresult calIcalComponent::Serialize(char **icalstr) { NS_ENSURE_ARG_POINTER(icalstr); // add the timezone bits if (icalcomponent_isa(mComponent) == ICAL_VCALENDAR_COMPONENT && mReferencedTimezones.Count() > 0) { for (auto iter = mReferencedTimezones.ConstIter(); !iter.Done(); iter.Next() ) { icaltimezone * icaltz = cal::getIcalTimezone(iter.Data()); if (icaltz) { icalcomponent * const tzcomp = icalcomponent_new_clone(icaltimezone_get_component(icaltz)); icalcomponent_add_component(mComponent, tzcomp); } } } *icalstr = icalcomponent_as_ical_string(mComponent); if (!*icalstr) { // xxx todo: what about NS_ERROR_OUT_OF_MEMORY? #ifdef DEBUG fprintf(stderr, "Error serializing: %d (%s)\n", icalerrno, icalerror_strerror(icalerrno)); #endif // The return values in calIError match with libical errnos, // so no need for a conversion table or anything. return static_cast<nsresult>(calIErrors::ICS_ERROR_BASE + icalerrno); } return NS_OK; }
static PLDHashOperator AddTimezoneComponentToIcal(nsACString const& /*tzid*/, calITimezone * tz, void * arg) { icalcomponent * const comp = static_cast<icalcomponent *>(arg); icaltimezone * icaltz = cal::getIcalTimezone(tz); if (icaltz) { icalcomponent * const tzcomp = icalcomponent_new_clone(icaltimezone_get_component(icaltz)); icalcomponent_add_component(comp, tzcomp); } return PL_DHASH_NEXT; }
/** Wrapper for e_cal_backend_cache_put_timezone(). * * Put timezone into cache. Timezone component cache state will be set to * E_CAL_COMPONENT_CACHE_STATE_CREATED. * * @param cb 3E calendar backend. * @param cache Calendar backend cache object. * @param zone icaltimezone object. * * @return TRUE if successfully stored. */ gboolean e_cal_backend_3e_cache_put_timezone(ECalBackend3e *cb, ECalBackendCache *cache, const icaltimezone *zone) { gboolean retval; icalcomponent_set_cache_state(icaltimezone_get_component((icaltimezone *)zone), E_CAL_COMPONENT_CACHE_STATE_CREATED); g_static_rw_lock_writer_lock(&cb->priv->cache_lock); retval = e_cal_backend_cache_put_timezone(cache, zone); g_static_rw_lock_writer_unlock(&cb->priv->cache_lock); return retval; }
static void addsystemtz(gpointer key, gpointer value, gpointer user_data) { const char *tzid = key; icalcomponent *comp = user_data; icaltimezone *zone; zone = icaltimezone_get_builtin_timezone_from_tzid(tzid); if (zone) { icalcomponent_add_component(comp, icalcomponent_new_clone(icaltimezone_get_component(zone))); } }
static char * serialize (ScalixObject * object) { ScalixAppointmentPrivate *priv; icalcomponent *icomp, *toplevel_comp; ECalComponent *comp; GSList *iter; char *result = NULL; priv = SCALIX_APPOINTMENT_GET_PRIVATE (SCALIX_APPOINTMENT (object)); scalix_appointment_unset (SCALIX_APPOINTMENT (object), "X-SCALIX-DESCRIPTION-CHANGED"); comp = E_CAL_COMPONENT (object); e_cal_component_commit_sequence (comp); icomp = e_cal_component_get_icalcomponent (comp); if (icomp) { toplevel_comp = e_cal_util_new_top_level (); /* add timezone if one exists */ if (priv->timezone) { icalcomponent_add_component (toplevel_comp, icalcomponent_new_clone (icaltimezone_get_component (priv->timezone))); } /* add the main vevent */ icalcomponent_add_component (toplevel_comp, icalcomponent_new_clone (icomp)); /* add exceptions if they exist */ for (iter = priv->exceptions; iter; iter = iter->next) { icalcomponent_add_component (toplevel_comp, icalcomponent_new_clone ((icalcomponent*) iter->data)); } result = icalcomponent_as_ical_string (toplevel_comp); if (result != NULL) { result = g_strdup (result); } icalcomponent_free (toplevel_comp); } return result; }
/** * e_cal_backend_sync_get_timezone: * @backend: An ECalBackendSync object. * @cal: An EDataCal object. * @cancellable: a #GCancellable for the operation * @tzid: ID of the timezone to retrieve. * @tzobject: Placeholder for the returned timezone. * @error: Out parameter for a #GError. * * Calls the get_timezone_sync method on the given backend. * This method is not mandatory on the backend, because here * is used internal_get_timezone call to fetch timezone from * it and that is transformed to a string. In other words, * any object deriving from ECalBackendSync can implement only * internal_get_timezone and can skip implementation of * get_timezone_sync completely. */ void e_cal_backend_sync_get_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzid, gchar **tzobject, GError **error) { e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg); if (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->get_timezone_sync) { LOCK_WRAPPER (get_timezone_sync, (backend, cal, cancellable, tzid, tzobject, error)); } if (tzobject && !*tzobject) { icaltimezone *zone = NULL; if (backend->priv->mutex_lock) g_mutex_lock (backend->priv->sync_mutex); zone = e_cal_backend_internal_get_timezone (E_CAL_BACKEND (backend), tzid); if (backend->priv->mutex_lock) g_mutex_unlock (backend->priv->sync_mutex); if (!zone) { g_propagate_error (error, e_data_cal_create_error (ObjectNotFound, NULL)); } else { icalcomponent *icalcomp; icalcomp = icaltimezone_get_component (zone); if (!icalcomp) { g_propagate_error (error, e_data_cal_create_error (InvalidObject, NULL)); } else { *tzobject = icalcomponent_as_ical_string_r (icalcomp); } } } }
/** 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 new timezones from the cache to the server. * * Assumes caller opened connection using e_cal_backend_3e_open_connection(). * * @param cb 3E calendar backend. * * @return TRUE on success. */ static gboolean sync_timezones_to_server(ECalBackend3e *cb) { GError *local_err = NULL; GSList *timezones, *iter; timezones = e_cal_backend_cache_get_timezones(cb, cb->priv->cache); for (iter = timezones; iter; iter = iter->next) { icaltimezone *zone = iter->data; icalcomponent *zone_comp = icaltimezone_get_component(zone); ECalComponentCacheState state = icalcomponent_get_cache_state(zone_comp); icalcomponent_set_cache_state(zone_comp, E_CAL_COMPONENT_CACHE_STATE_NONE); char *object = icalcomponent_as_ical_string(zone_comp); //XXX: always try to add all timezones from the cache //if (state == E_CAL_COMPONENT_CACHE_STATE_CREATED) { ESClient_addObject(cb->priv->conn, cb->priv->calspec, object, &local_err); if (local_err) { g_clear_error(&local_err); break; } 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); } icaltimezone_free(zone, 1); } g_slist_free(timezones); return TRUE; }
/** Sync cache changes to the server and unmark them. * * @param cb 3E calendar backend. * * @return TRUE on success. * * @todo Conflict resolution. */ gboolean e_cal_backend_3e_sync_cache_to_server(ECalBackend3e *cb) { GError *local_err = NULL; GSList *components, *iter; if (!e_cal_backend_3e_open_connection(cb, &local_err)) { g_warning("Sync failed. Can't open connection to the 3e server. (%s)", local_err ? local_err->message : "Unknown error"); g_clear_error(&local_err); return FALSE; } g_static_rw_lock_reader_lock(&cb->priv->cache_lock); components = e_cal_backend_store_get_components(cb->priv->store); g_static_rw_lock_reader_unlock(&cb->priv->cache_lock); for (iter = components; iter && !e_cal_backend_3e_sync_should_stop(cb); iter = iter->next) { ECalComponent *comp = E_CAL_COMPONENT(iter->data); ECalComponent *remote_comp; ECalComponentId *id = e_cal_component_get_id(comp); ECalComponentVType type = e_cal_component_get_vtype (comp); ECalComponentCacheState state = e_cal_component_get_cache_state(comp); /* remove client properties before sending component to the server */ e_cal_component_set_outofsync (comp, FALSE); e_cal_component_set_cache_state(comp, E_CAL_COMPONENT_CACHE_STATE_NONE); remote_comp = e_cal_component_clone(comp); char *remote_object = e_cal_component_get_as_string(remote_comp); char *object = e_cal_component_get_as_string(comp); if (type == E_CAL_COMPONENT_EVENT && !e_cal_backend_3e_convert_attachment_uris_to_remote(cb, remote_comp)) goto next; if (type == E_CAL_COMPONENT_EVENT && (state == E_CAL_COMPONENT_CACHE_STATE_CREATED || state == E_CAL_COMPONENT_CACHE_STATE_MODIFIED)) { if (!e_cal_backend_3e_upload_attachments(cb, remote_comp, &local_err)) { e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "3e attachemnts sync failure", local_err); g_clear_error(&local_err); goto next; } /* add timezone */ const icaltimezone *zone = NULL; ECalComponentDateTime datetime; e_cal_component_get_dtstart (comp, &datetime); g_static_rw_lock_reader_lock (&cb->priv->cache_lock); zone = e_cal_backend_store_get_timezone (cb->priv->store, datetime.tzid); g_static_rw_lock_reader_unlock (&cb->priv->cache_lock); e_cal_component_free_datetime (&datetime); if (zone) { icalcomponent *zone_comp = icaltimezone_get_component (zone); char *object = icalcomponent_as_ical_string (zone_comp); ESClient_addObject (cb->priv->conn, cb->priv->calspec, object, &local_err); if (local_err) g_clear_error (&local_err); } } switch (state) { case E_CAL_COMPONENT_CACHE_STATE_CREATED: { ESClient_addObject(cb->priv->conn, cb->priv->calspec, remote_object, &local_err); if (local_err) { e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "3e sync failure", local_err); g_clear_error(&local_err); break; } char *new_object = e_cal_component_get_as_string(comp); e_cal_backend_notify_object_modified(E_CAL_BACKEND(cb), object, new_object); g_free(new_object); g_static_rw_lock_writer_lock(&cb->priv->cache_lock); e_cal_backend_store_put_component(cb->priv->store, comp); g_static_rw_lock_writer_unlock(&cb->priv->cache_lock); break; } case E_CAL_COMPONENT_CACHE_STATE_MODIFIED: { ESClient_updateObject(cb->priv->conn, cb->priv->calspec, remote_object, &local_err); if (local_err) { e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "3e sync failure", local_err); g_clear_error(&local_err); break; } char *new_object = e_cal_component_get_as_string(comp); e_cal_backend_notify_object_modified(E_CAL_BACKEND(cb), object, new_object); g_free(new_object); g_static_rw_lock_writer_lock(&cb->priv->cache_lock); e_cal_backend_store_put_component(cb->priv->store, comp); g_static_rw_lock_writer_unlock(&cb->priv->cache_lock); break; } case E_CAL_COMPONENT_CACHE_STATE_REMOVED: { char *oid = id->rid ? g_strdup_printf("%s@%s", id->uid, id->rid) : g_strdup(id->uid); ESClient_deleteObject(cb->priv->conn, cb->priv->calspec, oid, &local_err); g_free(oid); if (local_err) { // ignore the error if component doesn't exist anymore if (local_err->code == ES_XMLRPC_ERROR_UNKNOWN_COMPONENT) { g_clear_error(&local_err); local_err = NULL; } else { e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "3e sync failure", local_err); g_clear_error(&local_err); break; } } g_static_rw_lock_writer_lock(&cb->priv->cache_lock); e_cal_backend_store_remove_component(cb->priv->store, id->uid, id->rid); g_static_rw_lock_writer_unlock(&cb->priv->cache_lock); break; } case E_CAL_COMPONENT_CACHE_STATE_NONE: default: break; } next: g_object_unref(comp); g_object_unref(remote_comp); e_cal_component_free_id(id); g_free(object); g_free(remote_object); } g_slist_free(components); e_cal_backend_3e_close_connection(cb); return TRUE; }
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; }
CamelMimeMessage * scalix_appointment_to_mime_message (ScalixObject * object) { CamelMimeMessage *message; CamelMultipart *multipart; CamelMimePart *part; CamelMedium *medium; CamelStream *stream; CamelDataWrapper *wrapper; ECalComponentDateTime dtstart, dtend; ECalComponent *comp; ECalComponentText text; icalcomponent_kind kind; icalcomponent *icalcomp, *toplevel_comp; icaltimezone *zone = NULL; GSList *attachment_list = NULL; GSList *attachment_list_new = NULL; GSList *siter = NULL; GList *part_list = NULL; GList *iter = NULL; char *msgid; char *str, *meeting_status; const char *ouid = NULL; char *file_contents = NULL; char *full_path, *filename, *mime_filename; char *cid; int size; g_object_get (SCALIX_APPOINTMENT (object), "timezone", &zone, NULL); comp = E_CAL_COMPONENT (scalix_object_clone (object)); message = camel_mime_message_new (); medium = CAMEL_MEDIUM (message); camel_medium_add_header (medium, "X-Scalix-Class", "IPM.Appointment"); /* Preserve msg id if there is already one */ if (scalix_appointment_get (SCALIX_APPOINTMENT (comp), X_SCALIX_MSG_ID, &msgid)) { scalix_appointment_unset (SCALIX_APPOINTMENT (comp), X_SCALIX_MSG_ID); } else { msgid = camel_header_msgid_generate (); } camel_mime_message_set_message_id (message, msgid); /* subject */ e_cal_component_get_summary (comp, &text); if (text.value != NULL) { camel_mime_message_set_subject (message, text.value); } /* start day */ e_cal_component_get_dtstart (comp, &dtstart); if (!icaltime_get_timezone (*dtstart.value)) icaltime_set_timezone (dtstart.value, icaltimezone_get_builtin_timezone_from_tzid (dtstart.tzid)); /* end day */ e_cal_component_get_dtend (comp, &dtend); if (!icaltime_get_timezone (*dtend.value)) icaltime_set_timezone (dtend.value, icaltimezone_get_builtin_timezone_from_tzid (dtend.tzid)); /* set From: and Sender: */ if (e_cal_component_has_organizer (comp)) { ECalComponentOrganizer organizer; e_cal_component_get_organizer (comp, &organizer); if (!strncasecmp (organizer.value, "MAILTO:", 7)) { camel_medium_add_header (medium, "Sender", organizer.value + 7); camel_medium_add_header (medium, "From", organizer.value + 7); } } /* set the appropriate recipient headers from the recipient table */ if (e_cal_component_has_attendees (comp) && e_cal_component_has_organizer (comp)) { GSList *iter, *attendees = NULL; CamelInternetAddress *recipients_to = NULL; CamelInternetAddress *recipients_cc = NULL; meeting_status = "1"; e_cal_component_get_attendee_list (comp, &attendees); for (iter = attendees; iter; iter = iter->next) { ECalComponentAttendee *attendee = iter->data; const char *mail = NULL; /* attendee entries must start with MAILTO: */ if (strncasecmp (attendee->value, "MAILTO:", 7)) { continue; } mail = attendee->value + 7; if (attendee->role == ICAL_ROLE_REQPARTICIPANT) { if (recipients_to == NULL) { recipients_to = camel_internet_address_new (); } camel_internet_address_add (recipients_to, attendee->cn, mail); } else if (attendee->role == ICAL_ROLE_OPTPARTICIPANT) { if (recipients_cc == NULL) { recipients_cc = camel_internet_address_new (); } camel_internet_address_add (recipients_cc, attendee->cn, mail); } else { continue; } } if (recipients_to != NULL) { camel_mime_message_set_recipients (message, "To", recipients_to); camel_object_unref (recipients_to); } if (recipients_cc != NULL) { camel_mime_message_set_recipients (message, "Cc", recipients_cc); camel_object_unref (recipients_cc); } } else { meeting_status = "0"; } /* Clear properties */ scalix_appointment_unset (SCALIX_APPOINTMENT (comp), X_SCALIX_IMAP_UID); /* Render the text/calendar */ e_cal_component_commit_sequence (comp); icalcomp = e_cal_component_get_icalcomponent (comp); kind = icalcomponent_isa (icalcomp); if (kind != ICAL_VCALENDAR_COMPONENT) { /* If its not a VCALENDAR, make it one to simplify below */ toplevel_comp = e_cal_util_new_top_level (); icalcomponent_add_component (toplevel_comp, icalcomp); icalcomp = toplevel_comp; } /* set METHOD to PUSBLISH */ icalcomponent_set_method (icalcomp, ICAL_METHOD_PUBLISH); /* Add the VTIMEZONE components for start- and/or end-times */ if (zone) { icalcomponent_add_component (icalcomp, icaltimezone_get_component (zone)); } else if (dtstart.tzid) { icalcomponent_add_component (icalcomp, icaltimezone_get_component (icaltimezone_get_builtin_timezone_from_tzid (dtstart.tzid))); } if (dtstart.tzid && dtend.tzid && strcmp (dtstart.tzid, dtend.tzid) != 0) { icalcomponent_add_component (icalcomp, icaltimezone_get_component (icaltimezone_get_builtin_timezone_from_tzid (dtend.tzid))); } /* FIXME: do we leek icalcomponents here? */ if (e_cal_component_has_attachments (comp)) { multipart = camel_multipart_new (); camel_multipart_set_boundary (multipart, NULL); e_cal_component_get_uid (comp, &ouid); e_cal_component_get_attachment_list (comp, &attachment_list); for (siter = attachment_list; siter; siter = siter->next) { if (siter->data == NULL) continue; if (strstr (siter->data, "file://") != siter->data) continue; full_path = ((char *) siter->data) + strlen ("file://"); filename = g_strrstr (full_path, "/") + 1; mime_filename = filename + strlen (ouid) + 1; size = 0; file_contents = get_file_contents (full_path, &size); if (file_contents == NULL) continue; stream = camel_stream_mem_new_with_buffer (file_contents, size); wrapper = camel_data_wrapper_new (); camel_data_wrapper_construct_from_stream (wrapper, stream); camel_object_unref (stream); part = camel_mime_part_new (); camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper); camel_mime_part_set_filename (part, mime_filename); camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64); cid = camel_header_msgid_generate (); camel_mime_part_set_content_id (part, cid); camel_mime_part_set_description (part, mime_filename); camel_mime_part_set_disposition (part, "attachment"); part_list = g_list_append (part_list, part); attachment_list_new = g_slist_append (attachment_list_new, g_strdup_printf ("CID:%s", cid)); g_free (cid); } e_cal_component_set_attachment_list (comp, attachment_list_new); str = icalcomponent_as_ical_string (icalcomp); part = camel_mime_part_new (); camel_mime_part_set_content (part, str, strlen (str), "text/calendar; method=PUBLISH; charset=UTF-8"); part_list = g_list_prepend (part_list, part); for (iter = part_list; iter; iter = iter->next) { part = (CamelMimePart *) iter->data; camel_multipart_add_part (multipart, part); camel_object_unref (part); } camel_medium_set_content_object (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart)); camel_object_unref (multipart); g_slist_free (attachment_list); g_slist_free (attachment_list_new); g_list_free (part_list); } else { str = icalcomponent_as_ical_string (icalcomp); camel_mime_part_set_content (CAMEL_MIME_PART (message), str, strlen (str), "text/calendar; method=PUBLISH; charset=UTF-8"); } scalix_appointment_set (SCALIX_APPOINTMENT (object), X_SCALIX_MSG_ID, msgid); return message; }
int main() { icalarray *timezones; icaltimezone *zone, *utc_zone; char *zone_location; size_t i; int ret = 0; unsigned int total_failed = 0; unsigned int total_okay = 0; unsigned int percent_failed = 0; int verbose = 0; int day; time_t start_time; struct tm start_tm; time_t curr_time; struct tm curr_tm; struct icaltimetype curr_tt; int failed = 0; int curr_failed; int zonedef_printed = 0; #if !defined(HAVE_SETENV) static char new_tz[256]; #endif set_zone_directory("../../zoneinfo"); icaltimezone_set_tzid_prefix("/softwarestudio.org/"); timezones = icaltimezone_get_builtin_timezones(); utc_zone = icaltimezone_get_utc_timezone(); /* for all known time zones... */ for (i = 0; i < timezones->num_elements; i++) { zone = (icaltimezone *)icalarray_element_at(timezones, i); zone_location = (char *)icaltimezone_get_location(zone); if (!zone_location) continue; /* * select this location for glibc: needs support for TZ=<location> * which is not POSIX */ #if defined(HAVE_SETENV) setenv("TZ", zone_location, 1); #else new_tz[0] = '\0'; strncat(new_tz, "TZ=", 255); strncat(new_tz, zone_location, 255 - strlen(new_tz)); putenv(new_tz); #endif tzset(); /* * determine current local time and date: always use midday in * the current zone and first day of first month in the year */ start_time = time(NULL); localtime_r(&start_time, &start_tm); start_tm.tm_hour = 12; start_tm.tm_min = 0; start_tm.tm_sec = 0; start_tm.tm_mday = 1; start_tm.tm_mon = 0; start_time = mktime(&start_tm); /* check time conversion for the next 365 days */ for (day = 0, curr_time = start_time; day < 365; day++, curr_time += 24 * 60 * 60) { /* determine date/time with glibc */ localtime_r(&curr_time, &curr_tm); /* determine date/time with libical */ curr_tt = icaltime_from_timet_with_zone(curr_time, 0, utc_zone); curr_tt.zone = utc_zone; /* workaround: icaltime_from_timet_with_zone() should do this, but doesn't! */ curr_tt = icaltime_convert_to_zone(curr_tt, zone); /* compare... */ curr_failed = curr_tm.tm_year + 1900 != curr_tt.year || curr_tm.tm_mon + 1 != curr_tt.month || curr_tm.tm_mday != curr_tt.day || curr_tm.tm_hour != curr_tt.hour || curr_tm.tm_min != curr_tt.minute || curr_tm.tm_sec != curr_tt.second; /* only print first failed day and first day which is okay again */ if (verbose || curr_failed != failed) { struct tm utc_tm; if (!gmtime_r(&curr_time, &utc_tm)) memset(&utc_tm, 0, sizeof(utc_tm)); printf( "%s: day %03d: %s: %04d-%02d-%02d %02d:%02d:%02d UTC = " "libc %04d-%02d-%02d %02d:%02d:%02d dst %d", zone_location, day, verbose ? (curr_failed ? "failed" : "okay") : (curr_failed ? "first failed" : "okay again"), utc_tm.tm_year + 1900, utc_tm.tm_mon + 1, utc_tm.tm_mday, utc_tm.tm_hour, utc_tm.tm_min, utc_tm.tm_sec, curr_tm.tm_year + 1900, curr_tm.tm_mon + 1, curr_tm.tm_mday, curr_tm.tm_hour, curr_tm.tm_min, curr_tm.tm_sec, curr_tm.tm_isdst); if (curr_failed) { printf(" != libical %04d-%02d-%02d %02d:%02d:%02d dst %d", curr_tt.year, curr_tt.month, curr_tt.day, curr_tt.hour, curr_tt.minute, curr_tt.second, curr_tt.is_daylight); ret = 1; } printf("\n"); failed = curr_failed; if (!zonedef_printed) { icalcomponent *comp = icaltimezone_get_component(zone); if (comp) { printf("%s\n", icalcomponent_as_ical_string(comp)); } zonedef_printed = 1; } } if (curr_failed) { total_failed++; } else { total_okay++; } } } if (total_failed || total_okay) { percent_failed = total_failed * 100 / (total_failed + total_okay); printf(" *** Summary: %lu zones tested, %u days failed, %u okay => %u%% failed ***\n", (unsigned long)timezones->num_elements, total_failed, total_okay, percent_failed); if (!icaltzutil_get_exact_vtimezones_support()) { if (!percent_failed) { ret = 0; printf(" *** Expect some small error rate with inter-operable vtimezones *** \n"); } } } icaltimezone_free_builtin_timezones(); return ret; }
/** * 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; }
static void cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzid) { GError *error = NULL; gchar *object = NULL; e_cal_backend_sync_get_timezone (E_CAL_BACKEND_SYNC (backend), cal, cancellable, tzid, &object, &error); if (!object && tzid) { /* fallback if tzid contains only the location of timezone */ gint i, slashes = 0; for (i = 0; tzid[i]; i++) { if (tzid[i] == '/') slashes++; } if (slashes == 1) { icalcomponent *icalcomp = NULL, *free_comp = NULL; icaltimezone *zone = icaltimezone_get_builtin_timezone (tzid); if (!zone) { /* Try fetching the timezone from zone directory. There are some timezones like MST, US/Pacific etc. which do not appear in zone.tab, so they will not be available in the libical builtin timezone */ icalcomp = free_comp = icaltzutil_fetch_timezone (tzid); } if (zone) icalcomp = icaltimezone_get_component (zone); if (icalcomp) { icalcomponent *clone = icalcomponent_new_clone (icalcomp); icalproperty *prop; prop = icalcomponent_get_first_property (clone, ICAL_TZID_PROPERTY); if (prop) { /* change tzid to our, because the component has the buildin tzid */ icalproperty_set_tzid (prop, tzid); object = icalcomponent_as_ical_string_r (clone); g_clear_error (&error); } icalcomponent_free (clone); } if (free_comp) icalcomponent_free (free_comp); } /* also cache this timezone to backend */ if (object) e_cal_backend_sync_add_timezone (E_CAL_BACKEND_SYNC (backend), cal, cancellable, object, NULL); } e_data_cal_respond_get_timezone (cal, opid, error, object); g_free (object); }