Exemple #1
0
/* Dispose handler for the file backend */
static void
e_cal_backend_http_dispose (GObject *object)
{
	ECalBackendHttp *cbhttp;
	ECalBackendHttpPrivate *priv;

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

	if (priv->reload_timeout_id) {
		ESource *source = e_backend_get_source (E_BACKEND (cbhttp));
		e_source_refresh_remove_timeout (source, priv->reload_timeout_id);
		priv->reload_timeout_id = 0;
	}

	if (priv->soup_session) {
		soup_session_abort (priv->soup_session);
		g_object_unref (priv->soup_session);
		priv->soup_session = NULL;
	}
	if (priv->source_changed_id) {
		g_signal_handler_disconnect (
			e_backend_get_source (E_BACKEND (cbhttp)),
			priv->source_changed_id);
		priv->source_changed_id = 0;
	}

	/* Chain up to parent's dispose() method. */
	G_OBJECT_CLASS (e_cal_backend_http_parent_class)->dispose (object);
}
/** 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_backend_get_source(E_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 || !g_strcmp0(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;
}
static void
ebbm_contacts_open (EBookBackendMAPI *ebma, GCancellable *cancellable, gboolean only_if_exists, GError **perror)
{
	ESource *source = e_backend_get_source (E_BACKEND (ebma));
	ESourceMapiFolder *ext_mapi_folder;
	EBookBackendMAPIContactsPrivate *priv = ((EBookBackendMAPIContacts *) ebma)->priv;
	GError *err = NULL;

	if (e_book_backend_is_opened (E_BOOK_BACKEND (ebma))) {
		if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_open)
			E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_open (ebma, cancellable, only_if_exists, perror);
		return;
	}

	ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);

	priv->fid = e_source_mapi_folder_get_id (ext_mapi_folder);
	priv->is_public_folder = e_source_mapi_folder_is_public (ext_mapi_folder);
	priv->foreign_username = e_source_mapi_folder_dup_foreign_username (ext_mapi_folder);

	if (priv->foreign_username && !*priv->foreign_username) {
		g_free (priv->foreign_username);
		priv->foreign_username = NULL;
	}

	/* Chain up to parent's op_load_source() method. */
	if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_open)
		E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_open (ebma, cancellable, only_if_exists, &err);

	if (err)
		g_propagate_error (perror, err);
}
Exemple #4
0
static const gchar *
cal_backend_http_ensure_uri (ECalBackendHttp *backend)
{
	ESource *source;
	ESourceSecurity *security_extension;
	ESourceWebdav *webdav_extension;
	SoupURI *soup_uri;
	gboolean secure_connection;
	const gchar *extension_name;
	gchar *uri_string;

	if (backend->priv->uri != NULL)
		return backend->priv->uri;

	source = e_backend_get_source (E_BACKEND (backend));

	extension_name = E_SOURCE_EXTENSION_SECURITY;
	security_extension = e_source_get_extension (source, extension_name);

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

	secure_connection = e_source_security_get_secure (security_extension);

	soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
	uri_string = soup_uri_to_string (soup_uri, FALSE);
	soup_uri_free (soup_uri);

	backend->priv->uri = webcal_to_http_method (
		uri_string, secure_connection);

	g_free (uri_string);

	return backend->priv->uri;
}
static void
e_book_backend_webdav_remove_contacts (EBookBackend *backend,
                                       EDataBook *book,
                                       guint32 opid,
                                       GCancellable *cancellable,
                                       const GSList *id_list)
{
	EBookBackendWebdav        *webdav      = E_BOOK_BACKEND_WEBDAV (backend);
	EBookBackendWebdavPrivate *priv        = webdav->priv;
	gchar                     *uid         = id_list->data;
	GSList                     deleted_ids = {NULL,};
	guint                      status;

	if (!e_backend_get_online (E_BACKEND (backend))) {
		e_data_book_respond_remove_contacts (
			book, opid,
			EDB_ERROR (REPOSITORY_OFFLINE), NULL);
		return;
	}

	/* We make the assumption that the ID list we're passed is always exactly one element long, since we haven't specified "bulk-removes"
	 * in our static capability list. */
	if (id_list->next != NULL) {
		e_data_book_respond_remove_contacts (
			book, opid,
			EDB_ERROR_EX (NOT_SUPPORTED,
			_("The backend does not support bulk removals")),
			NULL);
		return;
	}

	status = delete_contact (webdav, uid, cancellable);
	if (status != 204) {
		if (status == 401 || status == 407) {
			e_data_book_respond_remove_contacts (
				book, opid,
				webdav_handle_auth_request (webdav), NULL);
		} else {
			g_warning ("DELETE failed with HTTP status %d", status);
			e_data_book_respond_remove_contacts (
				book, opid,
				e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR,
				_("DELETE failed with HTTP status %d"), status),
				NULL);
		}
		return;
	}

	g_mutex_lock (&priv->cache_lock);
	e_book_backend_cache_remove_contact (priv->cache, uid);
	g_mutex_unlock (&priv->cache_lock);

	deleted_ids.data = uid;
	e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (SUCCESS), &deleted_ids);
}
static ESourceAuthenticationResult
book_backend_webdav_try_password_sync (ESourceAuthenticator *authenticator,
                                       const GString *password,
                                       GCancellable *cancellable,
                                       GError **error)
{
	EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (authenticator);
	ESourceAuthentication *auth_extension;
	ESourceAuthenticationResult result;
	ESource *source;
	SoupMessage *message;
	const gchar *extension_name;

	source = e_backend_get_source (E_BACKEND (authenticator));
	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
	auth_extension = e_source_get_extension (source, extension_name);

	webdav->priv->username =
		e_source_authentication_dup_user (auth_extension);
	webdav->priv->password = g_strdup (password->str);

	/* Send a PROPFIND to test whether user/password is correct. */
	message = send_propfind (webdav, cancellable);

	switch (message->status_code) {
		case SOUP_STATUS_OK:
		case SOUP_STATUS_MULTI_STATUS:
			result = E_SOURCE_AUTHENTICATION_ACCEPTED;
			break;

		case SOUP_STATUS_UNAUTHORIZED:
		case SOUP_STATUS_PROXY_UNAUTHORIZED:  /* XXX really? */
			g_free (webdav->priv->username);
			webdav->priv->username = NULL;
			g_free (webdav->priv->password);
			webdav->priv->password = NULL;
			result = E_SOURCE_AUTHENTICATION_REJECTED;
			break;

		default:
			g_set_error (
				error, SOUP_HTTP_ERROR,
				message->status_code,
				"%s", message->reason_phrase);
			result = E_SOURCE_AUTHENTICATION_ERROR;
			break;
	}

	g_object_unref (message);

	return result;
}
static void
outlook_backend_child_added (ECollectionBackend *backend,
                             ESource *child_source)
{
	ESource *collection_source;
	const gchar *extension_name;
	gboolean is_mail = FALSE;

	collection_source = e_backend_get_source (E_BACKEND (backend));

	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
	is_mail |= e_source_has_extension (child_source, extension_name);

	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
	is_mail |= e_source_has_extension (child_source, extension_name);

	extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
	is_mail |= e_source_has_extension (child_source, extension_name);

	/* Synchronize mail-related user with the collection identity. */
	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
	if (is_mail && e_source_has_extension (child_source, extension_name)) {
		ESourceAuthentication *auth_child_extension;
		ESourceCollection *collection_extension;
		const gchar *collection_identity;
		const gchar *auth_child_user;

		extension_name = E_SOURCE_EXTENSION_COLLECTION;
		collection_extension = e_source_get_extension (
			collection_source, extension_name);
		collection_identity = e_source_collection_get_identity (
			collection_extension);

		extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
		auth_child_extension = e_source_get_extension (
			child_source, extension_name);
		auth_child_user = e_source_authentication_get_user (
			auth_child_extension);

		/* XXX Do not override an existing user name setting.
		 *     The IMAP or (especially) SMTP configuration may
		 *     have been modified to use a non-Outlook server. */
		if (auth_child_user == NULL)
			e_source_authentication_set_user (
				auth_child_extension,
				collection_identity);
	}

	/* Chain up to parent's child_added() method. */
	E_COLLECTION_BACKEND_CLASS (e_outlook_backend_parent_class)->
		child_added (backend, child_source);
}
Exemple #8
0
static void
http_cal_reload_cb (ESource *source,
                    gpointer user_data)
{
	ECalBackendHttp *cbhttp = user_data;

	g_return_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp));

	if (!e_backend_get_online (E_BACKEND (cbhttp)))
		return;

	http_cal_schedule_begin_retrieval (cbhttp);
}
Exemple #9
0
/* Set_mode handler for the http backend */
static void
e_cal_backend_http_notify_online_cb (ECalBackend *backend,
                                     GParamSpec *pspec)
{
	gboolean loaded;
	gboolean online;

	online = e_backend_get_online (E_BACKEND (backend));
	loaded = e_cal_backend_is_opened (backend);

	if (online && loaded)
		http_cal_schedule_begin_retrieval (E_CAL_BACKEND_HTTP (backend));
}
static void
google_backend_add_tasks (ECollectionBackend *backend)
{
	ESource *source;
	ESource *collection_source;
	ESourceRegistryServer *server;
	ESourceExtension *extension;
	ESourceCollection *collection_extension;
	const gchar *backend_name;
	const gchar *extension_name;
	const gchar *resource_id;

	collection_source = e_backend_get_source (E_BACKEND (backend));

	resource_id = GOOGLE_TASKS_RESOURCE_ID;
	source = e_collection_backend_new_child (backend, resource_id);
	e_source_set_display_name (source, _("Tasks"));

	collection_extension = e_source_get_extension (
		collection_source, E_SOURCE_EXTENSION_COLLECTION);

	/* Configure the tasks source. */

	backend_name = GOOGLE_TASKS_BACKEND_NAME;

	extension_name = E_SOURCE_EXTENSION_TASK_LIST;
	extension = e_source_get_extension (source, extension_name);

	e_source_backend_set_backend_name (
		E_SOURCE_BACKEND (extension), backend_name);

	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
	extension = e_source_get_extension (source, extension_name);

	g_object_bind_property (
		collection_extension, "identity",
		extension, "user",
		G_BINDING_SYNC_CREATE);

	extension_name = E_SOURCE_EXTENSION_SECURITY;
	extension = e_source_get_extension (source, extension_name);

	e_source_security_set_secure (
		E_SOURCE_SECURITY (extension), TRUE);

	server = e_collection_backend_ref_server (backend);
	e_source_registry_server_add_source (server, source);
	g_object_unref (server);

	g_object_unref (source);
}
static void
google_backend_add_contacts (ECollectionBackend *backend)
{
	ESource *source;
	ESource *collection_source;
	ESourceRegistryServer *server;
	ESourceExtension *extension;
	ESourceCollection *collection_extension;
	const gchar *backend_name;
	const gchar *extension_name;
	const gchar *resource_id;

	collection_source = e_backend_get_source (E_BACKEND (backend));

	resource_id = GOOGLE_CONTACTS_RESOURCE_ID;
	source = e_collection_backend_new_child (backend, resource_id);
	e_source_set_display_name (source, _("Contacts"));

	/* Add the address book source to the collection. */
	collection_extension = e_source_get_extension (
		collection_source, E_SOURCE_EXTENSION_COLLECTION);

	/* Configure the address book source. */

	backend_name = GOOGLE_CONTACTS_BACKEND_NAME;

	extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
	extension = e_source_get_extension (source, extension_name);

	e_source_backend_set_backend_name (
		E_SOURCE_BACKEND (extension), backend_name);

	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
	extension = e_source_get_extension (source, extension_name);

	e_source_authentication_set_host (
		E_SOURCE_AUTHENTICATION (extension),
		GOOGLE_CONTACTS_HOST);

	g_object_bind_property (
		collection_extension, "identity",
		extension, "user",
		G_BINDING_SYNC_CREATE);

	server = e_collection_backend_ref_server (backend);
	e_source_registry_server_add_source (server, source);
	g_object_unref (server);

	g_object_unref (source);
}
static void
eee_backend_child_added (ECollectionBackend *backend,
                         ESource *child_source)
{
	ESource *collection_source;
	const gchar *extension_name;
	gboolean is_mail = FALSE;

	collection_source = e_backend_get_source (E_BACKEND (backend));

	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
	is_mail |= e_source_has_extension (child_source, extension_name);

	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
	is_mail |= e_source_has_extension (child_source, extension_name);

	extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
	is_mail |= e_source_has_extension (child_source, extension_name);

	/* Synchronize mail-related display names with the collection. */
	if (is_mail)
		g_object_bind_property (
			collection_source, "display-name",
			child_source, "display-name",
			G_BINDING_SYNC_CREATE);

	/* Synchronize mail-related user with the collection identity. */
	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
	if (is_mail && e_source_has_extension (child_source, extension_name)) {
		ESourceAuthentication *auth_child_extension;
		ESourceCollection *collection_extension;

		extension_name = E_SOURCE_EXTENSION_COLLECTION;
		collection_extension = e_source_get_extension (
			collection_source, extension_name);

		extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
		auth_child_extension = e_source_get_extension (
			child_source, extension_name);

		g_object_bind_property (
			collection_extension, "identity",
			auth_child_extension, "user",
			G_BINDING_SYNC_CREATE);
	}

	/* Chain up to parent's child_added() method. */
	E_COLLECTION_BACKEND_CLASS (e_eee_backend_parent_class)->
		child_added (backend, child_source);
}
static void
e_book_backend_webdav_notify_online_cb (EBookBackend *backend,
                                        GParamSpec *pspec)
{
	/* set_mode is called before the backend is loaded */
	if (!e_book_backend_is_opened (backend))
		return;

	if (!e_backend_get_online (E_BACKEND (backend))) {
		e_book_backend_notify_readonly (backend, TRUE);
		e_book_backend_notify_online (backend, FALSE);
	} else {
		e_book_backend_notify_readonly (backend, FALSE);
		e_book_backend_notify_online (backend, TRUE);
	}
}
static void
ebbm_contacts_connection_status_changed (EBookBackendMAPI *ebma, gboolean is_online)
{
	ESource *source;
	ESourceMapiFolder *ext_mapi_folder;

	e_book_backend_set_writable (E_BOOK_BACKEND (ebma), is_online);

	if (!is_online)
		return;

	source = e_backend_get_source (E_BACKEND (ebma));
	ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);

	if (e_source_mapi_folder_get_server_notification (ext_mapi_folder)) {
		EMapiConnection *conn;
		mapi_object_t obj_folder;
		gboolean status;
		GError *mapi_error = NULL;

		e_book_backend_mapi_lock_connection (ebma);

		conn = e_book_backend_mapi_get_connection (ebma, NULL, NULL);
		if (!conn) {
			e_book_backend_mapi_unlock_connection (ebma);
			return;
		}

		status = ebbm_contacts_open_folder (E_BOOK_BACKEND_MAPI_CONTACTS (ebma), conn, &obj_folder, NULL, &mapi_error);

		if (status) {
			e_mapi_connection_enable_notifications (conn, &obj_folder,
				fnevObjectCreated | fnevObjectModified | fnevObjectDeleted | fnevObjectMoved | fnevObjectCopied,
				NULL, &mapi_error);

			e_mapi_connection_close_folder (conn, &obj_folder, NULL, &mapi_error);
		}

		e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
		g_clear_error (&mapi_error);

		g_signal_connect (conn, "server-notification", G_CALLBACK (ebbmc_server_notification_cb), ebma);

		e_book_backend_mapi_unlock_connection (ebma);
	}
}
/** Periodic sync callback.
 *
 * @param cb 3e calendar backend.
 *
 * @return Always TRUE (continue sync).
 */
static gpointer sync_thread(ECalBackend3e *cb)
{
    int timeout = 5;

    while (TRUE)
    {
        switch (g_atomic_int_get(&cb->priv->sync_request))
        {
        case SYNC_NORMAL:
            g_usleep(1000000);
            if (--timeout > 0)
            {
                break;
            }

        case SYNC_NOW:
            if (g_atomic_int_get(&cb->priv->sync_request) == SYNC_STOP)
            {
                return NULL;
            }
            timeout = 5;

            g_atomic_int_set(&cb->priv->sync_request, SYNC_NORMAL);
            if (e_backend_get_online(E_BACKEND(cb)) && e_cal_backend_3e_calendar_load_perm(cb))
            {
                e_cal_backend_3e_sync_server_to_cache(cb);

                if (e_cal_backend_3e_calendar_has_perm(cb, "write"))
                {
                    e_cal_backend_3e_sync_cache_to_server(cb);
                }
            }
            break;

        case SYNC_PAUSE:
            g_usleep(1000000);
            break;

        case SYNC_STOP:
            return NULL;
        }
    }

    return NULL;
}
static void
e_book_backend_webdav_get_contact_list_uids (EBookBackend *backend,
                                             EDataBook *book,
                                             guint32 opid,
                                             GCancellable *cancellable,
                                             const gchar *query)
{
	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
	EBookBackendWebdavPrivate *priv   = webdav->priv;
	GList                     *contact_list;
	GSList                    *uids_list;
	GList                     *c;

	if (e_backend_get_online (E_BACKEND (backend))) {
		/* make sure the cache is up to date */
		GError *error = download_contacts (webdav, NULL, NULL, cancellable);

		if (error) {
			e_data_book_respond_get_contact_list_uids (book, opid, error, NULL);
			return;
		}
	}

	/* answer query from cache */
	g_mutex_lock (&priv->cache_lock);
	contact_list = e_book_backend_cache_get_contacts (priv->cache, query);
	g_mutex_unlock (&priv->cache_lock);

	uids_list   = NULL;
	for (c = contact_list; c != NULL; c = g_list_next (c)) {
		EContact *contact = c->data;

		uids_list = g_slist_append (uids_list, e_contact_get (contact, E_CONTACT_UID));

		g_object_unref (contact);
	}
	g_list_free (contact_list);

	e_data_book_respond_get_contact_list_uids (book, opid, EDB_ERROR (SUCCESS), uids_list);

	g_slist_foreach (uids_list, (GFunc) g_free, NULL);
	g_slist_free (uids_list);
}
static EBackend *
subprocess_cal_factory_ref_backend (ESourceRegistry *registry,
				     ESource *source,
				     const gchar *backend_factory_type_name)
{
	ECalBackend *backend;
	ECalBackendFactoryClass *backend_factory_class;
	GType backend_factory_type;

	backend_factory_type = g_type_from_name (backend_factory_type_name);
	backend_factory_class = g_type_class_ref (backend_factory_type);

	backend = g_object_new (
		backend_factory_class->backend_type,
		"kind", backend_factory_class->component_kind,
		"registry", registry,
		"source", source, NULL);

	return E_BACKEND (backend);
}
static guint
send_and_handle_ssl (EBookBackendWebdav *webdav,
                     SoupMessage *message,
                     GCancellable *cancellable)
{
	guint status_code;

	status_code = soup_session_send_message (webdav->priv->session, message);
	if (status_code == SOUP_STATUS_SSL_FAILED) {
		ESource *source;
		ESourceWebdav *extension;
		ESourceRegistry *registry;
		EBackend *backend;
		ETrustPromptResponse response;
		ENamedParameters *parameters;

		backend = E_BACKEND (webdav);
		source = e_backend_get_source (backend);
		registry = e_book_backend_get_registry (E_BOOK_BACKEND (backend));
		extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);

		parameters = e_named_parameters_new ();

		response = e_source_webdav_prepare_ssl_trust_prompt (extension, message, registry, parameters);
		if (response == E_TRUST_PROMPT_RESPONSE_UNKNOWN) {
			response = e_backend_trust_prompt_sync (backend, parameters, cancellable, NULL);
			if (response != E_TRUST_PROMPT_RESPONSE_UNKNOWN)
				e_source_webdav_store_ssl_trust_prompt (extension, message, response);
		}

		e_named_parameters_free (parameters);

		if (response == E_TRUST_PROMPT_RESPONSE_ACCEPT ||
		    response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY) {
			g_object_set (webdav->priv->session, SOUP_SESSION_SSL_STRICT, FALSE, NULL);
			status_code = soup_session_send_message (webdav->priv->session, message);
		}
	}

	return status_code;
}
Exemple #19
0
static void
e_cal_backend_http_refresh (ECalBackendSync *backend,
                            EDataCal *cal,
                            GCancellable *cancellable,
                            GError **perror)
{
	ECalBackendHttp *cbhttp;
	ECalBackendHttpPrivate *priv;
	ESource *source;

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

	if (!priv->opened ||
	    priv->is_loading)
		return;

	source = e_backend_get_source (E_BACKEND (cbhttp));
	g_return_if_fail (source != NULL);

	e_source_refresh_force_timeout (source);
}
static void
e_book_backend_webdav_start_view (EBookBackend *backend,
                                  EDataBookView *book_view)
{
	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
	EBookBackendWebdavPrivate *priv   = webdav->priv;
	EBookBackendSExp *sexp;
	const gchar *query;
	GList *contacts;
	GList *l;

	sexp = e_data_book_view_get_sexp (book_view);
	query = e_book_backend_sexp_text (sexp);

	g_mutex_lock (&priv->cache_lock);
	contacts = e_book_backend_cache_get_contacts (priv->cache, query);
	g_mutex_unlock (&priv->cache_lock);

	for (l = contacts; l != NULL; l = g_list_next (l)) {
		EContact *contact = l->data;
		e_data_book_view_notify_update (book_view, contact);
		g_object_unref (contact);
	}
	g_list_free (contacts);

	/* this way the UI is notified about cached contacts immediately,
	 * and the update thread notifies about possible changes only */
	e_data_book_view_notify_complete (book_view, NULL /* Success */);

	if (e_backend_get_online (E_BACKEND (backend))) {
		WebdavBackendSearchClosure *closure
			= init_closure (book_view, E_BOOK_BACKEND_WEBDAV (backend));

		closure->thread
			= g_thread_new (NULL, book_view_thread, book_view);

		e_flag_wait (closure->running);
	}
}
static void
e_book_backend_webdav_stop_view (EBookBackend *backend,
                                 EDataBookView *book_view)
{
	WebdavBackendSearchClosure *closure;
	gboolean                    need_join;

	if (!e_backend_get_online (E_BACKEND (backend)))
		return;

	closure = get_closure (book_view);
	if (closure == NULL)
		return;

	need_join = e_flag_is_set (closure->running);
	e_flag_clear (closure->running);

	if (need_join) {
		g_thread_join (closure->thread);
		closure->thread = NULL;
	}
}
static void
e_book_backend_webdav_get_contact (EBookBackend *backend,
                                   EDataBook *book,
                                   guint32 opid,
                                   GCancellable *cancellable,
                                   const gchar *uid)
{
	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
	EBookBackendWebdavPrivate *priv   = webdav->priv;
	EContact                  *contact;
	gchar                      *vcard;

	if (!e_backend_get_online (E_BACKEND (backend))) {
		g_mutex_lock (&priv->cache_lock);
		contact = e_book_backend_cache_get_contact (priv->cache, uid);
		g_mutex_unlock (&priv->cache_lock);
	} else {
		contact = download_contact (webdav, uid, cancellable);
		/* update cache as we possibly have changes */
		if (contact != NULL) {
			g_mutex_lock (&priv->cache_lock);
			e_book_backend_cache_remove_contact (priv->cache, uid);
			e_book_backend_cache_add_contact (priv->cache, contact);
			g_mutex_unlock (&priv->cache_lock);
		}
	}

	if (contact == NULL) {
		e_data_book_respond_get_contact (book, opid, EDB_ERROR (CONTACT_NOT_FOUND), NULL);
		return;
	}

	vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
	e_data_book_respond_get_contact (book, opid, EDB_ERROR (SUCCESS), vcard);
	g_free (vcard);
	g_object_unref (contact);
}
Exemple #23
0
static void
soup_authenticate (SoupSession *session,
                   SoupMessage *msg,
                   SoupAuth *auth,
                   gboolean retrying,
                   gpointer data)
{
	ECalBackendHttp *cbhttp;
	ESourceAuthentication *auth_extension;
	ESource *source;
	const gchar *extension_name;
	const gchar *username;
	gchar *auth_user;

	if (retrying)
		return;

	cbhttp = E_CAL_BACKEND_HTTP (data);

	source = e_backend_get_source (E_BACKEND (data));
	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
	auth_extension = e_source_get_extension (source, extension_name);

	auth_user = e_source_authentication_dup_user (auth_extension);

	username = cbhttp->priv->username;
	if (!username || !*username)
		username = auth_user;

	if (!username || !*username || !cbhttp->priv->password)
		soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
	else
		soup_auth_authenticate (auth, username, cbhttp->priv->password);

	g_free (auth_user);
}
/** 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_backend_get_source(E_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;
}
/** Open connection to the 3e server and authenticate user.
 *
 * This function will do nothing and return TRUE if connection is already
 * opened.
 *
 * @param cb 3E calendar backend.
 * @param err Error pointer.
 *
 * @return TRUE if connection was already open, FALSE on error.
 */
gboolean e_cal_backend_3e_open_connection(ECalBackend3e *cb, GError * *err)
{
    GError *local_err = NULL;

    g_return_val_if_fail(cb != NULL, FALSE);
    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);

    cb->priv->last_conn_failed = FALSE;

    /* if user tried to open connection in offline mode, close current connection
       if any and return error. this shouldn't happen, but let's check it anyway */
    if (!e_backend_get_online(E_BACKEND(cb)))
    {
        g_set_error(err, 0, -1, "Can't open 3e server connection in offline mode.");
        e_cal_backend_3e_close_connection(cb);
        return FALSE;
    }

    g_static_rec_mutex_lock(&cb->priv->conn_mutex);

    /* resolve server URI from DNS TXT if necessary */
    if (cb->priv->server_uri == NULL)
    {
        char *server_hostname = get_eee_server_hostname(cb->priv->username);
        if (server_hostname == NULL)
        {
            g_set_error(err, 0, -1, "Can't resolve server URI for username '%s'", cb->priv->username);
            goto err;
        }
        cb->priv->server_uri = g_strdup_printf("https://%s/RPC2", server_hostname);
        g_free(server_hostname);
    }

    /* check that we have all info that is necessary to create conn */
    if (cb->priv->username == NULL || cb->priv->password == NULL || cb->priv->server_uri == NULL)
    {
        g_set_error(err, 0, -1, "Connection was not setup correctly, can't open.");
        goto err;
    }

    /* create conn object */
    if (cb->priv->conn == NULL)
    {
        cb->priv->conn = xr_client_new(err);
        if (cb->priv->conn == NULL)
        {
            goto err;
        }
        cb->priv->is_open = FALSE;
    }

    if (cb->priv->is_open)
    {
        /* was already locked in this thread */
        g_static_rec_mutex_unlock(&cb->priv->conn_mutex);
        return TRUE;
    }

    if (!xr_client_open(cb->priv->conn, cb->priv->server_uri, err))
    {
        goto err;
    }

    ESClient_authenticate(cb->priv->conn, cb->priv->username, cb->priv->password, &local_err);
    if (local_err)
    {
        g_propagate_error(err, local_err);
        xr_client_close(cb->priv->conn);
        goto err;
    }

    cb->priv->is_open = TRUE;

    return TRUE;

err:
    cb->priv->last_conn_failed = TRUE;
    g_static_rec_mutex_unlock(&cb->priv->conn_mutex);
    return FALSE;
}
static void
e_book_backend_webdav_modify_contacts (EBookBackend *backend,
                                       EDataBook *book,
                                       guint32 opid,
                                       GCancellable *cancellable,
                                       const GSList *vcards)
{
	EBookBackendWebdav        *webdav  = E_BOOK_BACKEND_WEBDAV (backend);
	EBookBackendWebdavPrivate *priv    = webdav->priv;
	EContact                  *contact;
	GSList                     modified_contacts = {NULL,};
	const gchar                *uid;
	const gchar                *etag;
	guint status;
	gchar *status_reason = NULL;
	const gchar *vcard = vcards->data;

	if (!e_backend_get_online (E_BACKEND (backend))) {
		e_data_book_respond_create_contacts (
			book, opid,
			EDB_ERROR (REPOSITORY_OFFLINE), NULL);
		return;
	}

	/* We make the assumption that the vCard list we're passed is always exactly one element long, since we haven't specified "bulk-modifies"
	 * in our static capability list. This is because there is no clean way to roll back changes in case of an error. */
	if (vcards->next != NULL) {
		e_data_book_respond_modify_contacts (
			book, opid,
			EDB_ERROR_EX (
				NOT_SUPPORTED,
				_("The backend does not support bulk modifications")),
			NULL);
		return;
	}

	/* modify contact */
	contact = e_contact_new_from_vcard (vcard);
	status = upload_contact (webdav, contact, &status_reason, cancellable);
	if (status != 201 && status != 204) {
		g_object_unref (contact);
		if (status == 401 || status == 407) {
			e_data_book_respond_modify_contacts (book, opid, webdav_handle_auth_request (webdav), NULL);
			g_free (status_reason);
			return;
		}
		/* data changed on server while we were editing */
		if (status == 412) {
			/* too bad no special error code in evolution for this... */
			e_data_book_respond_modify_contacts (book, opid,
				e_data_book_create_error_fmt (
				E_DATA_BOOK_STATUS_OTHER_ERROR,
				_("Contact on server changed -> not modifying")),
				NULL);
			g_free (status_reason);
			return;
		}

		e_data_book_respond_modify_contacts (book, opid,
			e_data_book_create_error_fmt (
			E_DATA_BOOK_STATUS_OTHER_ERROR,
			_("Modify contact failed with HTTP status: %d (%s)"),
			status, status_reason),
			NULL);
		g_free (status_reason);
		return;
	}

	g_free (status_reason);

	uid = e_contact_get_const (contact, E_CONTACT_UID);
	g_mutex_lock (&priv->cache_lock);
	e_book_backend_cache_remove_contact (priv->cache, uid);

	etag = e_contact_get_const (contact, E_CONTACT_REV);

	/* PUT request didn't return an etag? try downloading to get one */
	if (etag == NULL || (etag[0] == 'W' && etag[1] == '/')) {
		EContact *new_contact;

		g_warning ("Server didn't return etag for modified address resource");
		new_contact = download_contact (webdav, uid, cancellable);
		if (new_contact != NULL) {
			contact = new_contact;
		}
	}
	e_book_backend_cache_add_contact (priv->cache, contact);
	g_mutex_unlock (&priv->cache_lock);

	modified_contacts.data = contact;
	e_data_book_respond_modify_contacts (book, opid, EDB_ERROR (SUCCESS), &modified_contacts);

	g_object_unref (contact);
}
/** Check if backend method should call sync immediately after cache
 * modification.
 *
 * @param cb 3e calendar backend.
 *
 * @return TRUE if sync is needed.
 */
gboolean e_cal_backend_3e_calendar_needs_immediate_sync(ECalBackend3e *cb)
{
    return cb->priv->sync_immediately && e_backend_get_online(E_BACKEND(cb)) && !cb->priv->last_conn_failed;
}
static void
e_book_backend_webdav_create_contacts (EBookBackend *backend,
                                       EDataBook *book,
                                       guint32 opid,
                                       GCancellable *cancellable,
                                       const GSList *vcards)
{
	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
	EBookBackendWebdavPrivate *priv   = webdav->priv;
	EContact                  *contact;
	gchar                     *uid;
	guint                      status;
	gchar                     *status_reason = NULL;
	const gchar               *vcard = (const gchar *) vcards->data;
	GSList                     added_contacts = {NULL,};

	/* We make the assumption that the vCard list we're passed is always exactly one element long, since we haven't specified "bulk-adds"
	 * in our static capability list. This is because there is no clean way to roll back changes in case of an error. */
	if (vcards->next != NULL) {
		e_data_book_respond_create_contacts (
			book, opid,
			EDB_ERROR_EX (NOT_SUPPORTED,
			_("The backend does not support bulk additions")),
			NULL);
		return;
	}

	if (!e_backend_get_online (E_BACKEND (backend))) {
		e_data_book_respond_create_contacts (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
		return;
	}

	/* do 3 rand() calls to construct a unique ID... poor way but should be
	 * good enough for us */
	uid = g_strdup_printf (
		"%s%08X-%08X-%08X.vcf",
		priv->uri, rand (), rand (), rand ());

	contact = e_contact_new_from_vcard_with_uid (vcard, uid);

	/* kill revision field (might have been set by some other backend) */
	e_contact_set (contact, E_CONTACT_REV, NULL);

	status = upload_contact (webdav, contact, &status_reason, cancellable);
	if (status != 201 && status != 204) {
		g_object_unref (contact);
		if (status == 401 || status == 407) {
			e_data_book_respond_create_contacts (book, opid, webdav_handle_auth_request (webdav), NULL);
		} else {
			e_data_book_respond_create_contacts (
				book, opid,
				e_data_book_create_error_fmt (
				E_DATA_BOOK_STATUS_OTHER_ERROR,
				_("Create resource '%s' failed with HTTP status: %d (%s)"),
				uid, status, status_reason),
					NULL);
		}
		g_free (uid);
		g_free (status_reason);
		return;
	}

	g_free (status_reason);

	/* PUT request didn't return an etag? try downloading to get one */
	if (e_contact_get_const (contact, E_CONTACT_REV) == NULL) {
		const gchar *new_uid;
		EContact *new_contact;

		g_warning ("Server didn't return etag for new address resource");
		new_uid = e_contact_get_const (contact, E_CONTACT_UID);
		new_contact = download_contact (webdav, new_uid, cancellable);
		g_object_unref (contact);

		if (new_contact == NULL) {
			e_data_book_respond_create_contacts (
				book, opid,
				EDB_ERROR (OTHER_ERROR), NULL);
			g_free (uid);
			return;
		}
		contact = new_contact;
	}

	g_mutex_lock (&priv->cache_lock);
	e_book_backend_cache_add_contact (priv->cache, contact);
	g_mutex_unlock (&priv->cache_lock);

	added_contacts.data = contact;
	e_data_book_respond_create_contacts (book, opid, EDB_ERROR (SUCCESS), &added_contacts);

	g_object_unref (contact);
	g_free (uid);
}
static guint
upload_contact (EBookBackendWebdav *webdav,
                EContact *contact,
                gchar **reason,
                GCancellable *cancellable)
{
	ESource     *source;
	ESourceWebdav *webdav_extension;
	SoupMessage *message;
	gchar       *uri;
	gchar       *etag;
	const gchar  *new_etag, *redir_uri;
	gchar        *request;
	guint        status;
	gboolean     avoid_ifmatch;
	const gchar *extension_name;

	source = e_backend_get_source (E_BACKEND (webdav));

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

	source = e_backend_get_source (E_BACKEND (webdav));

	uri = e_contact_get (contact, E_CONTACT_UID);
	if (uri == NULL) {
		g_warning ("can't upload contact without UID");
		return 400;
	}

	message = soup_message_new (SOUP_METHOD_PUT, uri);
	soup_message_headers_append (message->request_headers, "User-Agent", USERAGENT);
	soup_message_headers_append (message->request_headers, "Connection", "close");

	avoid_ifmatch = e_source_webdav_get_avoid_ifmatch (webdav_extension);

	/* some servers (like apache < 2.2.8) don't handle If-Match, correctly so
	 * we can leave it out */
	if (!avoid_ifmatch) {
		/* only override if etag is still the same on the server */
		etag = e_contact_get (contact, E_CONTACT_REV);
		if (etag == NULL) {
			soup_message_headers_append (
				message->request_headers,
				"If-None-Match", "*");
		} else if (etag[0] == 'W' && etag[1] == '/') {
			g_warning ("we only have a weak ETag, don't use If-Match synchronisation");
		} else {
			soup_message_headers_append (
				message->request_headers,
				"If-Match", etag);
			g_free (etag);
		}
	}

	request = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
	soup_message_set_request (
		message, "text/vcard", SOUP_MEMORY_TEMPORARY,
		request, strlen (request));

	status   = send_and_handle_ssl (webdav, message, cancellable);
	new_etag = soup_message_headers_get_list (message->response_headers, "ETag");

	redir_uri = soup_message_headers_get_list (message->response_headers, "Location");

	/* set UID and REV fields */
	e_contact_set (contact, E_CONTACT_REV, (gconstpointer) new_etag);
	if (redir_uri && *redir_uri) {
		if (!strstr (redir_uri, "://")) {
			/* it's a relative URI */
			SoupURI *suri = soup_uri_new (uri);
			gchar *full_uri;

			soup_uri_set_path (suri, redir_uri);
			full_uri = soup_uri_to_string (suri, TRUE);

			e_contact_set (contact, E_CONTACT_UID, full_uri);

			g_free (full_uri);
			soup_uri_free (suri);
		} else {
			e_contact_set (contact, E_CONTACT_UID, redir_uri);
		}
	} else {
		e_contact_set (contact, E_CONTACT_UID, uri);
	}

	if (reason) {
		*reason = g_strdup (message->reason_phrase && *message->reason_phrase ? message->reason_phrase :
				    (soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : _("Unknown error")));
	}

	g_object_unref (message);
	g_free (request);
	g_free (uri);

	return status;
}
static void
e_book_backend_webdav_open (EBookBackend *backend,
                            EDataBook *book,
                            guint opid,
                            GCancellable *cancellable,
                            gboolean only_if_exists)
{
	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
	EBookBackendWebdavPrivate *priv   = webdav->priv;
	ESourceAuthentication     *auth_extension;
	ESourceOffline            *offline_extension;
	ESourceWebdav             *webdav_extension;
	ESource                   *source;
	const gchar               *extension_name;
	const gchar               *cache_dir;
	gchar                     *filename;
	SoupSession               *session;
	SoupURI                   *suri;
	GError                    *error = NULL;

	/* will try fetch ctag for the first time, if it fails then sets this to FALSE */
	priv->supports_getctag = TRUE;

	source = e_backend_get_source (E_BACKEND (backend));
	cache_dir = e_book_backend_get_cache_dir (backend);

	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
	auth_extension = e_source_get_extension (source, extension_name);

	extension_name = E_SOURCE_EXTENSION_OFFLINE;
	offline_extension = e_source_get_extension (source, extension_name);

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

	priv->marked_for_offline =
		e_source_offline_get_stay_synchronized (offline_extension);

	if (!e_backend_get_online (E_BACKEND (backend)) && !priv->marked_for_offline ) {
		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
		return;
	}

	suri = e_source_webdav_dup_soup_uri (webdav_extension);

	priv->uri = soup_uri_to_string (suri, FALSE);
	if (!priv->uri || !*priv->uri) {
		g_free (priv->uri);
		priv->uri = NULL;
		soup_uri_free (suri);
		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, _("Cannot transform SoupURI to string")));
		return;
	}

	g_mutex_lock (&priv->cache_lock);

	/* make sure the priv->uri ends with a forward slash */
	if (priv->uri[strlen (priv->uri) - 1] != '/') {
		gchar *tmp = priv->uri;
		priv->uri = g_strconcat (tmp, "/", NULL);
		g_free (tmp);
	}

	if (!priv->cache) {
		filename = g_build_filename (cache_dir, "cache.xml", NULL);
		priv->cache = e_book_backend_cache_new (filename);
		g_free (filename);
	}
	g_mutex_unlock (&priv->cache_lock);

	session = soup_session_sync_new ();
	g_object_set (
		session,
		SOUP_SESSION_TIMEOUT, 90,
		SOUP_SESSION_SSL_STRICT, TRUE,
		SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
		NULL);

	e_source_webdav_unset_temporary_ssl_trust (webdav_extension);

	g_signal_connect (
		session, "authenticate",
		G_CALLBACK (soup_authenticate), webdav);

	priv->session = session;
	priv->proxy = e_proxy_new ();
	e_proxy_setup_proxy (priv->proxy);
	g_signal_connect (
		priv->proxy, "changed",
		G_CALLBACK (proxy_settings_changed), priv);
	proxy_settings_changed (priv->proxy, priv);
	webdav_debug_setup (priv->session);

	e_book_backend_notify_online (backend, TRUE);
	e_book_backend_notify_readonly (backend, FALSE);

	if (e_source_authentication_required (auth_extension))
		e_backend_authenticate_sync (
			E_BACKEND (backend),
			E_SOURCE_AUTHENTICATOR (backend),
			cancellable, &error);

	soup_uri_free (suri);

	/* This function frees the GError passed to it. */
	e_book_backend_respond_opened (backend, book, opid, error);
}