Beispiel #1
0
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);
}
Beispiel #2
0
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;
}
Beispiel #12
0
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;
}
Beispiel #14
0
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);
}