/** Wrapper for e_cal_backend_store_remove_component().
 *
 * This function does not actually remove component from cache in most cases. If
 * component already existed in cache and did not have cache state
 * E_CAL_COMPONENT_CACHE_STATE_CREATED, its state will be set to
 * E_CAL_COMPONENT_CACHE_STATE_REMOVED, otherwise it will be removed from cache.
 *
 * @param cb 3e calendar backend.
 * @param cache Calendar backend cache object.
 * @param uid UID of the calendar component.
 * @param rid RID of the detached instance of recurring event.
 *
 * @return TRUE if successfully removed, FALSE on failure (storage problem or not
 * found).
 */
gboolean e_cal_backend_3e_store_remove_component(ECalBackend3e *cb, ECalBackendStore *store, const char *uid, const char *rid)
{
    ECalComponent *existing;
    gboolean retval;

    g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
    existing = e_cal_backend_store_get_component(store, uid, rid);
    if (existing)
    {
        if (e_cal_component_get_cache_state(existing) == E_CAL_COMPONENT_CACHE_STATE_CREATED)
        {
            retval = e_cal_backend_store_remove_component(store, uid, rid);
        }
        else
        {
            e_cal_component_set_cache_state(existing, E_CAL_COMPONENT_CACHE_STATE_REMOVED);
            retval = e_cal_backend_store_put_component(store, existing);
        }

        g_object_unref(existing);
    }
    else
    {
        retval = FALSE;
    }
    g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);

    return retval;
}
/** Wrapper for e_cal_backend_store_put_component().
 *
 * Keeps track of cache state of the component by using
 * e_cal_component_set_cache_state(). If component already existed in cache and
 * did not have cache state E_CAL_COMPONENT_CACHE_STATE_CREATED, its cache state will
 * be set to E_CAL_COMPONENT_CACHE_STATE_MODIFIED, in all other cases it will be
 * set to will be set to E_CAL_COMPONENT_CACHE_STATE_CREATED.
 *
 * @param cb 3e calendar backend.
 * @param cache Calendar backend cache object.
 * @param comp ECalComponent object.
 *
 * @return TRUE if successfully stored.
 */
gboolean e_cal_backend_3e_store_put_component(ECalBackend3e *cb, ECalBackendStore *store, ECalComponent *comp)
{
    ECalComponentId *id;
    ECalComponentCacheState cache_state = E_CAL_COMPONENT_CACHE_STATE_CREATED;
    gboolean retval;

    id = e_cal_component_get_id(comp);
    if (id)
    {
        g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
        ECalComponent *existing = e_cal_backend_store_get_component(store, id->uid, id->rid);
        if (existing)
        {
            if (e_cal_component_get_cache_state(existing) != E_CAL_COMPONENT_CACHE_STATE_CREATED)
            {
                cache_state = E_CAL_COMPONENT_CACHE_STATE_MODIFIED;
            }

            g_object_unref(existing);
        }

        e_cal_component_set_cache_state(comp, cache_state);
        retval = e_cal_backend_store_put_component(store, comp);
        g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);

        e_cal_component_free_id(id);
        return retval;
    }

    return FALSE;
}
/** Wrapper for e_cal_backend_store_get_component().
 *
 * Get single component from cache. If component exists in cache but have cache
 * state E_CAL_COMPONENT_CACHE_STATE_REMOVED, NULL will be returned.
 *
 * @param cb 3E calendar backend.
 * @param cache Calendar backend cache object.
 * @param uid UID of the calendar component.
 * @param rid RID of the detached instance of recurring event.
 *
 * @return ECalComponent object or NULL.
 */
ECalComponent *e_cal_backend_3e_store_get_component(ECalBackend3e *cb, ECalBackendStore *store, const char *uid, const char *rid)
{
    ECalComponent *comp;

    g_static_rw_lock_reader_lock(&cb->priv->cache_lock);
    comp = e_cal_backend_store_get_component(store, uid, rid);
    g_static_rw_lock_reader_unlock(&cb->priv->cache_lock);
    if (comp && e_cal_component_get_cache_state(comp) == E_CAL_COMPONENT_CACHE_STATE_REMOVED)
    {
        g_object_unref(comp);
        return NULL;
    }

    return comp;
}
Exemple #4
0
/* Get_object_component handler for the http backend */
static void
e_cal_backend_http_get_object (ECalBackendSync *backend,
                               EDataCal *cal,
                               GCancellable *cancellable,
                               const gchar *uid,
                               const gchar *rid,
                               gchar **object,
                               GError **error)
{
	ECalBackendHttp *cbhttp;
	ECalBackendHttpPrivate *priv;
	ECalComponent *comp = NULL;

	cbhttp = E_CAL_BACKEND_HTTP (backend);
	priv = cbhttp->priv;

	if (!priv->store) {
		g_propagate_error (error, EDC_ERROR (ObjectNotFound));
		return;
	}

	if (rid && *rid) {
		comp = e_cal_backend_store_get_component (priv->store, uid, rid);
		if (!comp) {
			g_propagate_error (error, EDC_ERROR (ObjectNotFound));
			return;
		}

		*object = e_cal_component_get_as_string (comp);
		g_object_unref (comp);
	} else {
		*object = e_cal_backend_store_get_components_by_uid_as_ical_string (priv->store, uid);
		if (!*object)
			g_propagate_error (error, EDC_ERROR (ObjectNotFound));
	}
}
/** 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_store_get_component(cb->priv->store, 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_store_remove_component(cb->priv->store, 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_store_put_component(cb->priv->store, 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 (g_strcmp0(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_store_put_component(cb->priv->store, 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_store_get_timezone(cb->priv->store, 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_store_put_timezone(cb->priv->store, 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;
}
Exemple #6
0
static gboolean
put_component_to_store (ECalBackendHttp *cb,
                        ECalComponent *comp)
{
	time_t time_start, time_end;
	ECalBackendHttpPrivate *priv;
	ECalComponent *cache_comp;
	const gchar *uid;
	gchar *rid;

	priv = cb->priv;

	e_cal_component_get_uid (comp, &uid);
	rid = e_cal_component_get_recurid_as_string (comp);
	cache_comp = e_cal_backend_store_get_component (priv->store, uid, rid);
	g_free (rid);

	if (cache_comp) {
		gboolean changed = TRUE;
		struct icaltimetype stamp1, stamp2;

		stamp1 = icaltime_null_time ();
		stamp2 = icaltime_null_time ();

		e_cal_component_get_dtstamp (comp, &stamp1);
		e_cal_component_get_dtstamp (cache_comp, &stamp2);

		changed = (icaltime_is_null_time (stamp1) && !icaltime_is_null_time (stamp2)) ||
			  (!icaltime_is_null_time (stamp1) && icaltime_is_null_time (stamp2)) ||
			  (icaltime_compare (stamp1, stamp2) != 0);

		if (!changed) {
			struct icaltimetype *last_modified1 = NULL, *last_modified2 = NULL;

			e_cal_component_get_last_modified (comp, &last_modified1);
			e_cal_component_get_last_modified (cache_comp, &last_modified2);

			changed = (last_modified1 != NULL && last_modified2 == NULL) ||
				  (last_modified1 == NULL && last_modified2 != NULL) ||
				  (last_modified1 != NULL && last_modified2 != NULL && icaltime_compare (*last_modified1, *last_modified2) != 0);

			if (last_modified1)
				e_cal_component_free_icaltimetype (last_modified1);
			if (last_modified2)
				e_cal_component_free_icaltimetype (last_modified2);

			if (!changed) {
				gint *sequence1 = NULL, *sequence2 = NULL;

				e_cal_component_get_sequence (comp, &sequence1);
				e_cal_component_get_sequence (cache_comp, &sequence2);

				changed = (sequence1 != NULL && sequence2 == NULL) ||
					  (sequence1 == NULL && sequence2 != NULL) ||
					  (sequence1 != NULL && sequence2 != NULL && *sequence1 != *sequence2);

				if (sequence1)
					e_cal_component_free_sequence (sequence1);
				if (sequence2)
					e_cal_component_free_sequence (sequence2);
			}
		}

		g_object_unref (cache_comp);

		if (!changed)
			return FALSE;
	}

	e_cal_util_get_component_occur_times (
		comp, &time_start, &time_end,
		resolve_tzid, cb, icaltimezone_get_utc_timezone (),
		e_cal_backend_get_kind (E_CAL_BACKEND (cb)));

	e_cal_backend_store_put_component_with_time_range (priv->store, comp, time_start, time_end);

	return TRUE;
}