Esempio n. 1
0
/** Load calendar name, owner and permission from the ESource.
 *
 * @param cb 3E calendar backend.
 *
 * @return TRUE on success, FALSE otherwise.
 */
gboolean e_cal_backend_3e_calendar_info_load(ECalBackend3e *cb)
{
    ESource *source;
    const char *immediate_sync;

    source = e_cal_backend_get_source(E_CAL_BACKEND(cb));
    immediate_sync = e_source_get_property(source, "eee-immediate-sync");

    g_free(cb->priv->calname);
    g_free(cb->priv->owner);
    g_free(cb->priv->perm);
    cb->priv->calname = g_strdup(e_source_get_property(source, "eee-calname"));
    cb->priv->owner = g_strdup(e_source_get_property(source, "eee-owner"));
    cb->priv->perm = g_strdup(e_source_get_property(source, "eee-perm"));
    cb->priv->sync_immediately = (immediate_sync == NULL || !strcmp(immediate_sync, "1"));

    g_free(cb->priv->calspec);
    cb->priv->calspec = g_strdup_printf("%s:%s", cb->priv->owner, cb->priv->calname);

    if (cb->priv->calname == NULL || cb->priv->owner == NULL)
    {
        return FALSE;
    }

    return TRUE;
}
const char *e_cal_backend_3e_get_cache_path(ECalBackend3e *cb)
{
    if (cb->priv->cache_path == NULL)
    {
        char *mangled_uri = g_strdup(e_cal_backend_get_cache_dir(E_CAL_BACKEND(cb)));
        guint i;

        for (i = 0; i < strlen(mangled_uri); i++)
        {
            if (mangled_uri[i] == ':' || mangled_uri[i] == '/')
            {
                mangled_uri[i] = '_';
            }
        }

        cb->priv->cache_path = g_build_filename(e_cal_backend_get_cache_dir (E_CAL_BACKEND(cb)), "calendar3e", mangled_uri, NULL);
        g_free(mangled_uri);
    }

    return cb->priv->cache_path;
}
static gchar *
subprocess_cal_factory_open (ESubprocessFactory *subprocess_factory,
			     EBackend *backend,
			     GDBusConnection *connection,
			     gpointer data,
			     GCancellable *cancellable,
			     GError **error)
{
	EDataCal *data_cal;
	gchar *object_path;

	/* If the backend already has an EDataCal installed, return its
	 * object path.  Otherwise we need to install a new EDataCal. */
	data_cal = e_cal_backend_ref_data_cal (E_CAL_BACKEND (backend));

	if (data_cal != NULL) {
		object_path = g_strdup (e_data_cal_get_object_path (data_cal));
	} else {
		object_path = e_subprocess_factory_construct_path ();

		/* The EDataCal will attach itself to ECalBackend,
		 * so no need to call e_cal_backend_set_data_cal(). */
		data_cal = e_data_cal_new (
			E_CAL_BACKEND (backend),
			connection, object_path, error);

		if (data_cal != NULL) {
			e_subprocess_factory_set_backend_callbacks (
				subprocess_factory, backend, data);
		} else {
			g_free (object_path);
			object_path = NULL;
		}
	}

	g_clear_object (&data_cal);

	return object_path;
}
Esempio n. 4
0
/* Get_free_busy handler for the file backend */
static void
e_cal_backend_http_get_free_busy (ECalBackendSync *backend,
                                  EDataCal *cal,
                                  GCancellable *cancellable,
                                  const GSList *users,
                                  time_t start,
                                  time_t end,
                                  GSList **freebusy,
                                  GError **error)
{
	ESourceRegistry *registry;
	ECalBackendHttp *cbhttp;
	ECalBackendHttpPrivate *priv;
	gchar *address, *name;
	icalcomponent *vfb;
	gchar *calobj;

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

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

	registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));

	if (users == NULL) {
		if (e_cal_backend_mail_account_get_default (registry, &address, &name)) {
			vfb = create_user_free_busy (cbhttp, address, name, start, end);
			calobj = icalcomponent_as_ical_string_r (vfb);
                        *freebusy = g_slist_append (*freebusy, calobj);
			icalcomponent_free (vfb);
			g_free (address);
			g_free (name);
		}
	} else {
		const GSList *l;
		for (l = users; l != NULL; l = l->next ) {
			address = l->data;
			if (e_cal_backend_mail_account_is_valid (registry, address, &name)) {
				vfb = create_user_free_busy (cbhttp, address, name, start, end);
				calobj = icalcomponent_as_ical_string_r (vfb);
                                *freebusy = g_slist_append (*freebusy, calobj);
				icalcomponent_free (vfb);
				g_free (name);
			}
		}
	}
}
static void
e_data_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
	EDataCalView *query;
	EDataCalViewPrivate *priv;

	query = QUERY (object);
	priv = query->priv;

	switch (property_id) {
	case PROP_BACKEND:
		priv->backend = E_CAL_BACKEND (g_value_dup_object (value));
		break;
	case PROP_SEXP:
		priv->sexp = E_CAL_BACKEND_SEXP (g_value_dup_object (value));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}
Esempio n. 6
0
static gboolean
notify_and_remove_from_cache (gpointer key,
                              gpointer value,
                              gpointer user_data)
{
	const gchar *calobj = value;
	ECalBackendHttp *cbhttp = E_CAL_BACKEND_HTTP (user_data);
	ECalComponent *comp = e_cal_component_new_from_string (calobj);
	ECalComponentId *id = e_cal_component_get_id (comp);

	if (id) {
		e_cal_backend_store_remove_component (cbhttp->priv->store, id->uid, id->rid);
		e_cal_backend_notify_component_removed (E_CAL_BACKEND (cbhttp), id, comp, NULL);

		e_cal_component_free_id (id);
	}

	g_object_unref (comp);

	return TRUE;
}
/**
 * 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);
			}
		}
	}
}
Esempio n. 8
0
static gchar *
e_cal_backend_http_get_backend_property (ECalBackend *backend,
                                         const gchar *prop_name)
{
	g_return_val_if_fail (prop_name != NULL, NULL);

	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
		return g_strjoin (
			","
			CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS,
			CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED,
			NULL);

	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
		   g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
		/* A HTTP backend has no particular email address associated
		 * with it (although that would be a useful feature some day).
		 */
		return NULL;

	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
		icalcomponent *icalcomp;
		icalcomponent_kind kind;
		gchar *prop_value;

		kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
		icalcomp = e_cal_util_new_component (kind);
		prop_value = icalcomponent_as_ical_string_r (icalcomp);
		icalcomponent_free (icalcomp);

		return prop_value;
	}

	/* Chain up to parent's get_backend_property() method. */
	return E_CAL_BACKEND_CLASS (e_cal_backend_http_parent_class)->
		get_backend_property (backend, prop_name);
}
Esempio n. 9
0
/** Setup 3E server connection information.
 *
 * @param cb 3E calendar backend.
 * @param username Username used for authentication.
 * @param password Password.
 * @param err Error pointer.
 */
gboolean e_cal_backend_3e_setup_connection(ECalBackend3e *cb, const char *username, const char *password)
{
    ESource *source;

    g_return_val_if_fail(cb != NULL, FALSE);
    g_return_val_if_fail(username != NULL, FALSE);
    g_return_val_if_fail(password != NULL, FALSE);

    source = e_cal_backend_get_source(E_CAL_BACKEND(cb));

    g_free(cb->priv->username);
    g_free(cb->priv->password);
    g_free(cb->priv->server_uri);
    cb->priv->server_uri = NULL;

    if (e_source_get_property(source, "eee-server"))
    {
        cb->priv->server_uri = g_strdup_printf("https://%s/RPC2", e_source_get_property(source, "eee-server"));
    }
    cb->priv->username = g_strdup(username);
    cb->priv->password = g_strdup(password);

    return TRUE;
}
Esempio n. 10
0
/** Check if calendar is online (i.e. network operations should be enabled).
 *
 * @param cb 3e calendar backend.
 *
 * @return TRUE if it is OK to run network communication.
 */
gboolean e_cal_backend_3e_calendar_is_online(ECalBackend3e *cb)
{
    return e_cal_backend_is_online (E_CAL_BACKEND(cb));
//    return cb->priv->mode == CAL_MODE_REMOTE;
}
Esempio n. 11
0
static void
begin_retrieval_cb (GTask *task,
		    gpointer source_object,
		    gpointer task_tada,
		    GCancellable *cancellable)
{
	ECalBackendHttp *backend = source_object;
	const gchar *uri;
	gchar *certificate_pem = NULL;
	GTlsCertificateFlags certificate_errors = 0;
	GError *error = NULL;

	if (!e_backend_get_online (E_BACKEND (backend)) ||
	    backend->priv->is_loading)
		return;

	d (g_message ("Starting retrieval...\n"));

	backend->priv->is_loading = TRUE;

	uri = cal_backend_http_ensure_uri (backend);
	cal_backend_http_load (backend, uri, &certificate_pem, &certificate_errors, cancellable, &error);

	if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
	    g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
		GError *local_error = NULL;
		ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;

		if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
			reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
		}

		e_backend_credentials_required_sync (E_BACKEND (backend),
			reason, certificate_pem, certificate_errors, error, cancellable, &local_error);

		g_clear_error (&error);
		error = local_error;
	} else if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
		GError *local_error = NULL;

		e_backend_credentials_required_sync (E_BACKEND (backend), E_SOURCE_CREDENTIALS_REASON_REJECTED,
			certificate_pem, certificate_errors, error, cancellable, &local_error);

		g_clear_error (&error);
		error = local_error;
	}

	g_free (certificate_pem);
	backend->priv->is_loading = FALSE;

	/* Ignore cancellations. */
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
		g_error_free (error);

	} else if (error != NULL) {
		e_cal_backend_notify_error (
			E_CAL_BACKEND (backend),
			error->message);
		empty_cache (backend);
		g_error_free (error);
	}

	d (g_message ("Retrieval really done.\n"));
}
Esempio n. 12
0
static gboolean
cal_backend_http_load (ECalBackendHttp *backend,
                       const gchar *uri,
		       gchar **out_certificate_pem,
		       GTlsCertificateFlags *out_certificate_errors,
                       GCancellable *cancellable,
                       GError **error)
{
	ECalBackendHttpPrivate *priv = backend->priv;
	ETimezoneCache *timezone_cache;
	SoupMessage *soup_message;
	SoupSession *soup_session;
	icalcomponent *icalcomp, *subcomp;
	icalcomponent_kind kind;
	const gchar *newuri;
	SoupURI *uri_parsed;
	GHashTable *old_cache;
	GSList *comps_in_cache;
	ESource *source;
	guint status_code;
	gulong cancel_id = 0;

	struct {
		SoupSession *soup_session;
		SoupMessage *soup_message;
	} cancel_data;

	timezone_cache = E_TIMEZONE_CACHE (backend);

	soup_session = backend->priv->soup_session;
	soup_message = cal_backend_http_new_message (backend, uri);

	if (soup_message == NULL) {
		g_set_error (
			error, SOUP_HTTP_ERROR,
			SOUP_STATUS_MALFORMED,
			_("Malformed URI: %s"), uri);
		return FALSE;
	}

	if (G_IS_CANCELLABLE (cancellable)) {
		cancel_data.soup_session = soup_session;
		cancel_data.soup_message = soup_message;

		cancel_id = g_cancellable_connect (
			cancellable,
			G_CALLBACK (cal_backend_http_cancelled),
			&cancel_data, (GDestroyNotify) NULL);
	}

	source = e_backend_get_source (E_BACKEND (backend));

	e_soup_ssl_trust_connect (soup_message, source);

	e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);

	status_code = soup_session_send_message (soup_session, soup_message);

	if (G_IS_CANCELLABLE (cancellable))
		g_cancellable_disconnect (cancellable, cancel_id);

	if (status_code == SOUP_STATUS_NOT_MODIFIED) {
		e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);

		/* attempts with ETag can result in 304 status code */
		g_object_unref (soup_message);
		priv->opened = TRUE;
		return TRUE;
	}

	/* Handle redirection ourselves */
	if (SOUP_STATUS_IS_REDIRECTION (status_code)) {
		gboolean success;

		newuri = soup_message_headers_get_list (
			soup_message->response_headers, "Location");

		d (g_message ("Redirected from %s to %s\n", async_context->uri, newuri));

		if (newuri != NULL) {
			gchar *redirected_uri;

			if (newuri[0]=='/') {
				g_warning ("Hey! Relative URI returned! Working around...\n");

				uri_parsed = soup_uri_new (uri);
				soup_uri_set_path (uri_parsed, newuri);
				soup_uri_set_query (uri_parsed, NULL);
				/* g_free (newuri); */

				newuri = soup_uri_to_string (uri_parsed, FALSE);
				g_message ("Translated URI: %s\n", newuri);
				soup_uri_free (uri_parsed);
			}

			redirected_uri =
				webcal_to_http_method (newuri, FALSE);
			success = cal_backend_http_load (
				backend, redirected_uri, out_certificate_pem, out_certificate_errors, cancellable, error);
			g_free (redirected_uri);

		} else {
			g_set_error (
				error, SOUP_HTTP_ERROR,
				SOUP_STATUS_BAD_REQUEST,
				_("Redirected to Invalid URI"));
			success = FALSE;
		}

		if (success) {
			e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
		} else {
			e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
		}

		g_object_unref (soup_message);
		return success;
	}

	/* check status code */
	if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) {
		/* because evolution knows only G_IO_ERROR_CANCELLED */
		if (status_code == SOUP_STATUS_CANCELLED)
			g_set_error (
				error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
				"%s", soup_message->reason_phrase);
		else
			g_set_error (
				error, SOUP_HTTP_ERROR, status_code,
				"%s", soup_message->reason_phrase);

		if (status_code == SOUP_STATUS_SSL_FAILED) {
			e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
			cal_backend_http_extract_ssl_failed_data (soup_message, out_certificate_pem, out_certificate_errors);
		} else {
			e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
		}

		g_object_unref (soup_message);
		empty_cache (backend);
		return FALSE;
	}

	e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);

	if (priv->store) {
		const gchar *etag;

		etag = soup_message_headers_get_one (
			soup_message->response_headers, "ETag");

		if (etag != NULL && *etag == '\0')
			etag = NULL;

		e_cal_backend_store_put_key_value (priv->store, "ETag", etag);
	}

	/* get the calendar from the response */
	icalcomp = icalparser_parse_string (soup_message->response_body->data);

	if (!icalcomp) {
		g_set_error (
			error, SOUP_HTTP_ERROR,
			SOUP_STATUS_MALFORMED,
			_("Bad file format."));
		g_object_unref (soup_message);
		empty_cache (backend);
		return FALSE;
	}

	if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) {
		g_set_error (
			error, SOUP_HTTP_ERROR,
			SOUP_STATUS_MALFORMED,
			_("Not a calendar."));
		icalcomponent_free (icalcomp);
		g_object_unref (soup_message);
		empty_cache (backend);
		return FALSE;
	}

	g_object_unref (soup_message);
	soup_message = NULL;

	/* Update cache */
	old_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);

	comps_in_cache = e_cal_backend_store_get_components (priv->store);
	while (comps_in_cache != NULL) {
		const gchar *uid;
		ECalComponent *comp = comps_in_cache->data;

		e_cal_component_get_uid (comp, &uid);
		g_hash_table_insert (old_cache, g_strdup (uid), e_cal_component_get_as_string (comp));

		comps_in_cache = g_slist_remove (comps_in_cache, comps_in_cache->data);
		g_object_unref (comp);
	}

	kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
	subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT);
	e_cal_backend_store_freeze_changes (priv->store);
	while (subcomp) {
		ECalComponent *comp;
		icalcomponent_kind subcomp_kind;
		icalproperty *prop = NULL;

		subcomp_kind = icalcomponent_isa (subcomp);
		prop = icalcomponent_get_first_property (subcomp, ICAL_UID_PROPERTY);
		if (!prop && subcomp_kind == kind) {
			gchar *new_uid = e_cal_component_gen_uid ();
			icalcomponent_set_uid (subcomp, new_uid);
			g_free (new_uid);
		}

		if (subcomp_kind == kind) {
			comp = e_cal_component_new ();
			if (e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) {
				const gchar *uid;
				gpointer orig_key, orig_value;

				e_cal_component_get_uid (comp, &uid);

				if (!put_component_to_store (backend, comp)) {
					g_hash_table_remove (old_cache, uid);
				} else if (g_hash_table_lookup_extended (old_cache, uid, &orig_key, &orig_value)) {
					ECalComponent *orig_comp = e_cal_component_new_from_string (orig_value);

					e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend), orig_comp, comp);

					g_hash_table_remove (old_cache, uid);
					if (orig_comp)
						g_object_unref (orig_comp);
				} else {
					e_cal_backend_notify_component_created (E_CAL_BACKEND (backend), comp);
				}
			}

			g_object_unref (comp);
		} else if (subcomp_kind == ICAL_VTIMEZONE_COMPONENT) {
			icaltimezone *zone;

			zone = icaltimezone_new ();
			icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp));
			e_timezone_cache_add_timezone (timezone_cache, zone);

			icaltimezone_free (zone, 1);
		}

		subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT);
	}

	e_cal_backend_store_thaw_changes (priv->store);

	/* notify the removals */
	g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, backend);
	g_hash_table_destroy (old_cache);

	/* free memory */
	icalcomponent_free (icalcomp);

	priv->opened = TRUE;

	return TRUE;
}
Esempio n. 13
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;
}
Esempio n. 14
0
/** 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;
    GList *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;
    }

    sync_timezones_to_server(cb);

    g_static_rw_lock_reader_lock(&cb->priv->cache_lock);
    components = e_cal_backend_cache_get_components(cb->priv->cache);
    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);
        ECalComponentCacheState state = e_cal_component_get_cache_state(comp);
        /* remove client properties before sending component to the server */
        e_cal_component_set_x_property(comp, "X-EVOLUTION-STATUS", NULL);
        e_cal_component_set_cache_state(comp, E_CAL_COMPONENT_CACHE_STATE_NONE);
        e_cal_component_set_x_property(comp, "X-3E-DELETED", NULL);
        remote_comp = e_cal_component_clone(comp);
        gboolean attachments_converted = e_cal_backend_3e_convert_attachment_uris_to_remote(cb, remote_comp);
        char *remote_object = e_cal_component_get_as_string(remote_comp);
        char *object = e_cal_component_get_as_string(comp);

        if (!attachments_converted)
        {
            goto next;
        }

        if (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;
            }
        }

        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_cache_put_component(cb->priv->cache, 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_cache_put_component(cb->priv->cache, 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_cache_remove_component(cb->priv->cache, 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_list_free(components);

    e_cal_backend_3e_close_connection(cb);

    return TRUE;
}
Esempio n. 15
0
/* Open handler for the file backend */
static void
e_cal_backend_http_open (ECalBackendSync *backend,
                         EDataCal *cal,
                         GCancellable *cancellable,
                         gboolean only_if_exists,
                         GError **perror)
{
	ECalBackendHttp *cbhttp;
	ECalBackendHttpPrivate *priv;
	ESource *source;
	ESourceWebdav *webdav_extension;
	const gchar *extension_name;
	const gchar *cache_dir;
	gboolean opened = TRUE;
	gchar *tmp;
	GError *local_error = NULL;

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

	/* already opened, thus can skip all this initialization */
	if (priv->opened)
		return;

	source = e_backend_get_source (E_BACKEND (backend));
	cache_dir = e_cal_backend_get_cache_dir (E_CAL_BACKEND (backend));

	extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
	webdav_extension = e_source_get_extension (source, extension_name);

	e_source_webdav_unset_temporary_ssl_trust (webdav_extension);

	if (priv->source_changed_id == 0) {
		priv->source_changed_id = g_signal_connect (
			source, "changed",
			G_CALLBACK (source_changed_cb), cbhttp);
	}

	/* always read uri again */
	tmp = priv->uri;
	priv->uri = NULL;
	g_free (tmp);

	if (priv->store == NULL) {
		/* remove the old cache while migrating to ECalBackendStore */
		e_cal_backend_cache_remove (cache_dir, "cache.xml");
		priv->store = e_cal_backend_store_new (
			cache_dir, E_TIMEZONE_CACHE (backend));
		e_cal_backend_store_load (priv->store);

		if (!priv->store) {
			g_propagate_error (
				perror, EDC_ERROR_EX (OtherError,
				_("Could not create cache file")));
			return;
		}
	}

	e_cal_backend_set_writable (E_CAL_BACKEND (backend), FALSE);

	if (e_backend_get_online (E_BACKEND (backend))) {
		gchar *certificate_pem = NULL;
		GTlsCertificateFlags certificate_errors = 0;
		const gchar *uri;

		uri = cal_backend_http_ensure_uri (cbhttp);

		opened = cal_backend_http_load (cbhttp, uri, &certificate_pem,
			&certificate_errors, cancellable, &local_error);

		if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
		    g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) ||
		    (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN) &&
		    !cbhttp->priv->password)) {
			GError *local_error2 = NULL;
			ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;

			if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
				reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
			}

			e_backend_credentials_required_sync (E_BACKEND (cbhttp), reason, certificate_pem,
				certificate_errors, local_error, cancellable, &local_error2);
			g_clear_error (&local_error);
			local_error = local_error2;
		} else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
			GError *local_error2 = NULL;

			e_backend_credentials_required_sync (E_BACKEND (cbhttp), E_SOURCE_CREDENTIALS_REASON_REJECTED,
				certificate_pem, certificate_errors, local_error, cancellable, &local_error2);

			g_clear_error (&local_error);
			local_error = local_error2;
		}

		g_free (certificate_pem);

		if (local_error != NULL)
			g_propagate_error (perror, local_error);
	}

	if (opened) {
		if (!priv->reload_timeout_id)
			priv->reload_timeout_id = e_source_refresh_add_timeout (source, NULL, http_cal_reload_cb, backend, NULL);
	}
}
Esempio n. 16
0
/** Sync changes from the server to the cache.
 *
 * @param cb 3E calendar backend.
 *
 * @return TRUE on success.
 *
 * @todo Handle UID/RID.
 * @todo Better server error handling.
 * @todo Conflict resolution.
 */
gboolean e_cal_backend_3e_sync_server_to_cache(ECalBackend3e *cb)
{
    GError *local_err = NULL;
    gboolean update_sync = TRUE;
    icalcomponent *ical;
    icalcomponent *icomp;
    char filter[128];
    struct tm tm;
    time_t stamp = MAX(e_cal_backend_3e_get_sync_timestamp(cb) - 60 * 60 * 24, 0); /*XXX: always add 1 day padding to prevent timezone problems */

    /* prepare query filter string */
    gmtime_r(&stamp, &tm);
    strftime(filter, sizeof(filter), "modified_since('%F %T')", &tm);

    ical = get_server_objects(cb, filter);
    if (ical == NULL)
    {
        return FALSE;
    }

    for (icomp = icalcomponent_get_first_component(ical, ICAL_ANY_COMPONENT);
         icomp;
         icomp = icalcomponent_get_next_component(ical, ICAL_ANY_COMPONENT))
    {
        icalcomponent_kind kind = icalcomponent_isa(icomp);
        icalcomponent_set_cache_state(icomp, E_CAL_COMPONENT_CACHE_STATE_NONE);

        if (kind == ICAL_VEVENT_COMPONENT)
        {
            ECalComponent *comp;
            const char *uid = icalcomponent_get_uid(icomp);
            gboolean server_deleted = icalcomponent_3e_status_is_deleted(icomp);
            ECalComponentCacheState comp_state = E_CAL_COMPONENT_CACHE_STATE_NONE;

            g_static_rw_lock_reader_lock(&cb->priv->cache_lock);
            comp = e_cal_backend_cache_get_component(cb->priv->cache, uid, NULL);
            g_static_rw_lock_reader_unlock(&cb->priv->cache_lock);
            if (comp)
            {
                comp_state = e_cal_component_get_cache_state(comp);
            }

            if (server_deleted)
            {
                /* deleted by the server */
                if (comp && e_cal_component_get_cache_state(comp) != E_CAL_COMPONENT_CACHE_STATE_CREATED &&
                    e_cal_component_get_cache_state(comp) != E_CAL_COMPONENT_CACHE_STATE_MODIFIED)
                {
                    char *object = e_cal_component_get_as_string(comp);
                    ECalComponentId *id = e_cal_component_get_id(comp);

                    g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
                    e_cal_backend_cache_remove_component(cb->priv->cache, uid, NULL);
                    g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);

                    e_cal_backend_notify_object_removed(E_CAL_BACKEND(cb), id, object, NULL);

                    e_cal_component_free_id(id);
                    g_free(object);
                }
            }
            else
            {
                char *old_object = NULL;
                char *object;
                ECalComponent *new_comp = e_cal_component_new();

                e_cal_component_set_icalcomponent(new_comp, icalcomponent_new_clone(icomp));
                e_cal_component_set_cache_state(new_comp, E_CAL_COMPONENT_CACHE_STATE_NONE);
                e_cal_backend_3e_convert_attachment_uris_to_local(cb, new_comp);
                if (comp)
                {
                    old_object = e_cal_component_get_as_string(comp);
                }
                object = e_cal_component_get_as_string(new_comp);

                if (old_object == NULL)
                {
                    if (e_cal_backend_3e_download_attachments(cb, new_comp, &local_err))
                    {
                        /* not in cache yet */
                        g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
                        e_cal_backend_cache_put_component(cb->priv->cache, new_comp);
                        g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);

                        e_cal_backend_notify_object_created(E_CAL_BACKEND(cb), object);
                    }
                    else
                    {
                        e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "Can't download attachment.", local_err);
                        g_clear_error(&local_err);
                        update_sync = FALSE;
                    }
                }
                else if (strcmp(old_object, object))
                {
                    /* what is in cache and what is on server differs */
                    if (comp_state != E_CAL_COMPONENT_CACHE_STATE_NONE)
                    {
                        /* modified in cache, don't do anything */
                    }
                    else
                    {
                        if (e_cal_backend_3e_download_attachments(cb, new_comp, &local_err))
                        {
                            /* sync with server */
                            g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
                            e_cal_backend_cache_put_component(cb->priv->cache, new_comp);
                            g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);

                            e_cal_backend_notify_object_modified(E_CAL_BACKEND(cb), old_object, object);
                        }
                        else
                        {
                            e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "Can't download attachment.", local_err);
                            g_clear_error(&local_err);
                            update_sync = FALSE;
                        }
                    }
                }

                g_free(old_object);
                g_free(object);
                g_object_unref(new_comp);
            }

            if (comp)
            {
                g_object_unref(comp);
            }
        }
        else if (kind == ICAL_VTIMEZONE_COMPONENT)
        {
            const char *tzid = icalcomponent_get_tzid(icomp);

            /* import non-existing timezones from the server */
            if (!e_cal_backend_cache_get_timezone(cb->priv->cache, tzid))
            {
                icaltimezone *zone = icaltimezone_new();
                icalcomponent *zone_comp = icalcomponent_new_clone(icomp);
                if (icaltimezone_set_component(zone, zone_comp))
                {
                    g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
                    e_cal_backend_cache_put_timezone(cb->priv->cache, zone);
                    g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);
                }
                else
                {
                    icalcomponent_free(zone_comp);
                }
                icaltimezone_free(zone, 1);
            }
        }
        else
        {
            g_warning("Unsupported component kind (%d) found on the 3e server.", kind);
        }
    }

    if (update_sync)
    {
        e_cal_backend_3e_set_sync_timestamp(cb, time(NULL));
    }

    icalcomponent_free(ical);
    return TRUE;
}
static gboolean
impl_CalFactory_get_cal (EGdbusCalFactory *object,
                         GDBusMethodInvocation *invocation,
                         const gchar * const *in_source_type,
                         EDataCalFactory *factory)
{
	EDataCal *calendar;
	EBackend *backend;
	EDataCalFactoryPrivate *priv = factory->priv;
	GDBusConnection *connection;
	ESource *source;
	gchar *uri;
	gchar *path = NULL;
	const gchar *sender;
	GList *list;
	GError *error = NULL;
	gchar *source_xml = NULL;
	guint type = 0;

	sender = g_dbus_method_invocation_get_sender (invocation);
	connection = g_dbus_method_invocation_get_connection (invocation);

	if (!e_gdbus_cal_factory_decode_get_cal (in_source_type, &source_xml, &type)) {
		error = g_error_new (
			E_DATA_CAL_ERROR, NoSuchCal, _("Invalid call"));
		g_dbus_method_invocation_return_gerror (invocation, error);
		g_error_free (error);

		return TRUE;
	}

	source = e_source_new_from_standalone_xml (source_xml);
	g_free (source_xml);

	if (!source) {
		error = g_error_new (
			E_DATA_CAL_ERROR,
			NoSuchCal,
			_("Invalid source"));
		g_dbus_method_invocation_return_gerror (invocation, error);
		g_error_free (error);

		return TRUE;
	}

	uri = e_source_get_uri (source);

	if (uri == NULL || *uri == '\0') {
		g_object_unref (source);
		g_free (uri);

		error = g_error_new (
			E_DATA_CAL_ERROR,
			NoSuchCal,
			_("Empty URI"));
		g_dbus_method_invocation_return_gerror (invocation, error);
		g_error_free (error);

		return TRUE;
	}

	backend = e_data_cal_factory_get_backend (factory, source, uri, type);

	if (backend == NULL) {
		error = g_error_new (
			E_DATA_CAL_ERROR,
			NoSuchCal,
			_("Invalid source"));
		g_dbus_method_invocation_return_gerror (invocation, error);
		g_error_free (error);

		return TRUE;
	}

	g_mutex_lock (priv->calendars_lock);

	e_dbus_server_hold (E_DBUS_SERVER (factory));

	path = construct_cal_factory_path ();
	calendar = e_data_cal_new (E_CAL_BACKEND (backend));
	g_hash_table_insert (priv->calendars, g_strdup (path), calendar);
	e_cal_backend_add_client (E_CAL_BACKEND (backend), calendar);
	e_data_cal_register_gdbus_object (calendar, connection, path, &error);
	g_object_weak_ref (
		G_OBJECT (calendar), (GWeakNotify)
		calendar_freed_cb, factory);

	/* Update the hash of open connections. */
	g_mutex_lock (priv->connections_lock);
	list = g_hash_table_lookup (priv->connections, sender);
	list = g_list_prepend (list, calendar);
	g_hash_table_insert (priv->connections, g_strdup (sender), list);
	g_mutex_unlock (priv->connections_lock);

	g_mutex_unlock (priv->calendars_lock);

	g_object_unref (source);
	g_free (uri);

	e_gdbus_cal_factory_complete_get_cal (
		object, invocation, path, error);

	if (error)
		g_error_free (error);

	g_free (path);

	return TRUE;
}