From 4294cd7cfec747d888e323ef5a029ef09cc6dc74 Mon Sep 17 00:00:00 2001 From: Niels De Graef Date: Mon, 25 Dec 2017 14:50:54 +0100 Subject: Port contacts-esd-setup to Vala. --- meson.build | 1 + po/POTFILES.in | 2 +- src/contacts-contact.vala | 8 +- src/contacts-esd-setup.c | 323 -------------------------------------------- src/contacts-esd-setup.h | 11 -- src/contacts-esd-setup.vala | 193 ++++++++++++++++++++++++++ src/meson.build | 14 +- vapi/custom.vapi | 18 --- 8 files changed, 202 insertions(+), 368 deletions(-) delete mode 100644 src/contacts-esd-setup.c delete mode 100644 src/contacts-esd-setup.h create mode 100644 src/contacts-esd-setup.vala diff --git a/meson.build b/meson.build index 8cd97db..2746fec 100644 --- a/meson.build +++ b/meson.build @@ -81,6 +81,7 @@ conf.set_quoted('PACKAGE_VERSION', meson.project_version()) conf.set_quoted('PKGDATADIR', pkgdatadir) conf.set_quoted('PKGLIBDIR', pkglibdir) conf.set_quoted('VERSION', meson.project_version()) +conf.set('GOA_API_IS_SUBJECT_TO_CHANGE', true) configure_file(output: 'config.h', configuration: conf) # Post-install scripts diff --git a/po/POTFILES.in b/po/POTFILES.in index 778d939..1ac14a4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -22,7 +22,7 @@ src/contacts-contact-list.vala src/contacts-contact-pane.vala src/contacts-contact-sheet.vala src/contacts-contact.vala -src/contacts-esd-setup.c +src/contacts-esd-setup.vala src/contacts-linked-accounts-dialog.vala src/contacts-link-suggestion-grid.vala src/contacts-settings.vala diff --git a/src/contacts-contact.vala b/src/contacts-contact.vala index e7180ee..08dcc12 100644 --- a/src/contacts-contact.vala +++ b/src/contacts-contact.vala @@ -655,9 +655,9 @@ public class Contacts.Contact : GLib.Object { public static string format_persona_store_name (PersonaStore store) { if (store.type_id == "eds") { - unowned string? eds_name = lookup_esource_name_by_uid (store.id); + string? eds_name = lookup_esource_name_by_uid (store.id); if (eds_name != null) - return eds_name; + return eds_name; } #if HAVE_TELEPATHY if (store.type_id == "telepathy") { @@ -750,9 +750,9 @@ public class Contacts.Contact : GLib.Object { else if (persona_is_google_other (persona)) return _("Google"); - unowned string? eds_name = lookup_esource_name_by_uid_for_contact (store.id); + string? eds_name = lookup_esource_name_by_uid_for_contact (store.id); if (eds_name != null) - return eds_name; + return eds_name; } #if HAVE_TELEPATHY if (store.type_id == "telepathy") { diff --git a/src/contacts-esd-setup.c b/src/contacts-esd-setup.c deleted file mode 100644 index 936be16..0000000 --- a/src/contacts-esd-setup.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * This code is from evolution with this license: - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - */ - -#include "config.h" -#include -#include -#include - -#define GOA_API_IS_SUBJECT_TO_CHANGE -#include -#include - -static void -eds_show_source_error (const gchar *where, - const gchar *what, - ESource *source, - const GError *error) -{ - if (!error || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - /* TODO Show the error in UI, somehow */ - g_warning ("%s: %s '%s': %s", where, what, e_source_get_display_name (source), error->message); -} - -static void -eds_source_invoke_authenticate_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - ESource *source = E_SOURCE (source_object); - GError *error = NULL; - - if (!e_source_invoke_authenticate_finish (source, result, &error) && - !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - eds_show_source_error (G_STRFUNC, "Failed to invoke authenticate", source, error); - } - - g_clear_error (&error); -} - -static void -eds_source_trust_prompt_done_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - ETrustPromptResponse response = E_TRUST_PROMPT_RESPONSE_UNKNOWN; - ESource *source = E_SOURCE (source_object); - GError *error = NULL; - - if (!e_trust_prompt_run_for_source_finish (source, result, &response, &error)) { - eds_show_source_error (G_STRFUNC, "Failed to prompt for trust for", source, error); - } else if (response == E_TRUST_PROMPT_RESPONSE_ACCEPT || response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY) { - /* Use NULL credentials to reuse those from the last time. */ - e_source_invoke_authenticate (source, NULL, NULL /* cancellable */, eds_source_invoke_authenticate_cb, NULL); - } - - g_clear_error (&error); -} - -static void -eds_source_credentials_required_cb (ESourceRegistry *registry, - ESource *source, - ESourceCredentialsReason reason, - const gchar *certificate_pem, - GTlsCertificateFlags certificate_errors, - const GError *op_error, - ECredentialsPrompter *credentials_prompter) -{ - if (e_credentials_prompter_get_auto_prompt_disabled_for (credentials_prompter, source)) - return; - - if (reason == E_SOURCE_CREDENTIALS_REASON_SSL_FAILED) { - e_trust_prompt_run_for_source (e_credentials_prompter_get_dialog_parent (credentials_prompter), - source, certificate_pem, certificate_errors, op_error ? op_error->message : NULL, - TRUE /* allow_source_save */, NULL /* cancellable */, eds_source_trust_prompt_done_cb, NULL); - } else if (reason == E_SOURCE_CREDENTIALS_REASON_ERROR && op_error) { - eds_show_source_error (G_STRFUNC, "Failed to authenticate", source, op_error); - } -} - -ESourceRegistry *eds_source_registry = NULL; -static ECredentialsPrompter *eds_credentials_prompter = NULL; - -gboolean contacts_ensure_eds_accounts (gboolean allow_interaction) -{ - ESourceCredentialsProvider *credentials_provider; - GList *list, *link; - GError *error = NULL; - - if (eds_source_registry) - return TRUE; - - /* XXX This blocks while connecting to the D-Bus service. - * Maybe it should be created in the Contacts class - * and passed in as needed? */ - - eds_source_registry = e_source_registry_new_sync (NULL, &error); - - /* If this fails it's game over. */ - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - return FALSE; - } - - eds_credentials_prompter = e_credentials_prompter_new (eds_source_registry); - - if (!allow_interaction) - e_credentials_prompter_set_auto_prompt (eds_credentials_prompter, FALSE); - - /* First disable credentials prompt for all but addressbook sources... */ - list = e_source_registry_list_sources (eds_source_registry, NULL); - - for (link = list; link != NULL; link = g_list_next (link)) { - ESource *source = E_SOURCE (link->data); - - /* Mark for skip also currently disabled sources */ - if (!e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) - e_credentials_prompter_set_auto_prompt_disabled_for (eds_credentials_prompter, source, TRUE); - } - - g_list_free_full (list, g_object_unref); - - credentials_provider = e_credentials_prompter_get_provider (eds_credentials_prompter); - - /* ...then enable credentials prompt for credential source of the addressbook sources, - which can be a collection source. */ - list = e_source_registry_list_sources (eds_source_registry, E_SOURCE_EXTENSION_ADDRESS_BOOK); - - for (link = list; link != NULL; link = g_list_next (link)) { - ESource *source = E_SOURCE (link->data), *cred_source; - - cred_source = e_source_credentials_provider_ref_credentials_source (credentials_provider, source); - if (cred_source && !e_source_equal (source, cred_source)) - e_credentials_prompter_set_auto_prompt_disabled_for (eds_credentials_prompter, cred_source, FALSE); - g_clear_object (&cred_source); - } - - g_list_free_full (list, g_object_unref); - - /* The eds_credentials_prompter responses to REQUIRED and REJECTED reasons, - the SSL_FAILED should be handled elsewhere. */ - g_signal_connect (eds_source_registry, "credentials-required", - G_CALLBACK (eds_source_credentials_required_cb), eds_credentials_prompter); - - e_credentials_prompter_process_awaiting_credentials (eds_credentials_prompter); - - return TRUE; -} - -gboolean contacts_has_goa_account (void) -{ - GList *list, *link; - gboolean has_goa_contacts = FALSE; - - list = e_source_registry_list_sources (eds_source_registry, E_SOURCE_EXTENSION_GOA); - - for (link = list; link != NULL; link = g_list_next (link)) { - ESource *source = E_SOURCE (link->data); - ESourceCollection *extension; - - /* Ignore disabled accounts. */ - if (!e_source_get_enabled (source)) - continue; - - /* All ESources with a [GNOME Online Accounts] extension - * should also have a [Collection] extension. Verify it. */ - if (!e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION)) - continue; - - extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION); - - /* This corresponds to the Contacts ON/OFF switch in GOA. */ - if (e_source_collection_get_contacts_enabled (extension)) { - has_goa_contacts = TRUE; - break; - } - } - - g_list_free_full (list, (GDestroyNotify) g_object_unref); - - return has_goa_contacts; -} - -gboolean -contacts_esource_uid_is_google (const char *uid) -{ - ESource *source; - gboolean uid_is_google = FALSE; - - source = e_source_registry_ref_source (eds_source_registry, uid); - if (source == NULL) - return FALSE; - - /* Make sure it's really an address book. */ - if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) { - ESourceBackend *extension; - const gchar *backend_name; - - extension = e_source_get_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK); - backend_name = e_source_backend_get_backend_name (extension); - - uid_is_google = (g_strcmp0 (backend_name, "google") == 0); - } - - g_object_unref (source); - - return uid_is_google; -} - -const char * -contacts_lookup_esource_name_by_uid (const char *uid) -{ - ESource *source; - ESource *builtin_address_book; - const gchar *display_name; - - source = e_source_registry_ref_source (eds_source_registry, uid); - if (source == NULL) - return NULL; - - builtin_address_book = e_source_registry_ref_builtin_address_book (eds_source_registry); - - if (e_source_equal (source, builtin_address_book)) - display_name = _("Local Address Book"); - - else if (contacts_esource_uid_is_google (uid)) - display_name = _("Google"); - - else - display_name = e_source_get_display_name (source); - - g_object_unref (builtin_address_book); - g_object_unref (source); - - return display_name; -} - -const char * -contacts_lookup_esource_name_by_uid_for_contact (const char *uid) -{ - ESource *source; - ESource *builtin_address_book; - const gchar *display_name; - - source = e_source_registry_ref_source (eds_source_registry, uid); - if (source == NULL) - return NULL; - - builtin_address_book = e_source_registry_ref_builtin_address_book (eds_source_registry); - - if (e_source_equal (source, builtin_address_book)) - return _("Local Contact"); - - else if (contacts_esource_uid_is_google (uid)) - display_name = _("Google"); - - else - display_name = e_source_get_display_name (source); - - g_object_unref (builtin_address_book); - g_object_unref (source); - - return display_name; -} - -GtkWidget* -contacts_get_icon_for_goa_account (const char* goa_id) -{ - GoaClient *client; - GoaObject *goa_object; - GoaAccount *goa_account; - GError *error; - - const gchar* icon_data; - GIcon *provider_icon; - GtkWidget *image_icon; - - error = NULL; - client = goa_client_new_sync (NULL, &error); - if (client == NULL) - { - g_error_free (error); - return NULL; - } - - goa_object = goa_client_lookup_by_id (client, goa_id); - goa_account = goa_object_get_account (goa_object); - - icon_data = goa_account_get_provider_icon (goa_account); - - error = NULL; - provider_icon = g_icon_new_for_string (icon_data, &error); - if (provider_icon == NULL) - { - g_debug ("Error obtaining provider_icon"); - g_error_free (error); - } - image_icon = gtk_image_new_from_gicon (provider_icon, GTK_ICON_SIZE_DIALOG); - - g_object_unref (goa_account); - g_object_unref (goa_object); - - g_clear_object (&client); - - return image_icon; -} diff --git a/src/contacts-esd-setup.h b/src/contacts-esd-setup.h deleted file mode 100644 index 0096618..0000000 --- a/src/contacts-esd-setup.h +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include - -gboolean contacts_ensure_eds_accounts (gboolean allow_interaction); -const char *contacts_lookup_esource_name_by_uid (const char *uid); -const char *contacts_lookup_esource_name_by_uid_for_contact (const char *uid); -gboolean contacts_esource_uid_is_google (const char *uid); -gboolean contacts_has_goa_account (void); -extern ESourceRegistry *eds_source_registry; -extern gboolean contacts_avoid_goa_workaround; -GtkWidget* contacts_get_icon_for_goa_account (const char* goa_id); diff --git a/src/contacts-esd-setup.vala b/src/contacts-esd-setup.vala new file mode 100644 index 0000000..51ba791 --- /dev/null +++ b/src/contacts-esd-setup.vala @@ -0,0 +1,193 @@ +/* + * This code is ported to Vala from evolution with this license: + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +// FIXME: the async bindings seem to be broken for this function. +extern void e_trust_prompt_run_for_source (Gtk.Window parent, E.Source source, string certificate_pem, GLib.TlsCertificateFlags certificate_errors, string? error_text, bool allow_source_save, GLib.Cancellable? cancellable, AsyncReadyCallback callback); +extern bool e_trust_prompt_run_for_source_finish (E.Source source, AsyncResult result, out E.TrustPromptResponse response) throws GLib.Error; + +namespace Contacts { + +public E.SourceRegistry? eds_source_registry = null; +private E.CredentialsPrompter? eds_credentials_prompter = null; + +public bool ensure_eds_accounts (bool allow_interaction) { + if (eds_source_registry != null) + return true; + + // XXX This blocks while connecting to the D-Bus service. + // Maybe it should be created in the Contacts class and passed in as needed? + + try { + eds_source_registry = new E.SourceRegistry.sync (null); + } catch (Error e) { // If this fails it's game over. + warning ("Couldn't load EDS SourceRegistry: %s", e.message); + return false; + } + + eds_credentials_prompter = new E.CredentialsPrompter (eds_source_registry); + + if (!allow_interaction) + eds_credentials_prompter.set_auto_prompt (false); + + var credentials_provider = eds_credentials_prompter.get_provider (); + + // First disable credentials prompt for all but addressbook sources... + foreach (var source in eds_source_registry.list_sources (null)) { + // Mark for skip also currently disabled sources + if (!source.has_extension (E.SOURCE_EXTENSION_ADDRESS_BOOK)) + eds_credentials_prompter.set_auto_prompt_disabled_for (source, true); + } + + // ...then enable credentials prompt for credential source of the addressbook sources, + // which can be a collection source. + foreach (var source in eds_source_registry.list_sources (E.SOURCE_EXTENSION_ADDRESS_BOOK)) { + var cred_source = credentials_provider.ref_credentials_source (source); + if (cred_source != null && !source.equal (cred_source)) + eds_credentials_prompter.set_auto_prompt_disabled_for (cred_source, false); + } + + // The eds_credentials_prompter responses to REQUIRED and REJECTED reasons, + // the SSL_FAILED should be handled elsewhere. + eds_source_registry.credentials_required.connect((src, reason, cert_pem, cert_err, err) => { + on_credentials_required.begin (src, reason, cert_pem, cert_err, err); + }); + + eds_credentials_prompter.process_awaiting_credentials (); + + return true; +} + +private async void on_credentials_required (E.Source source, E.SourceCredentialsReason reason, string cert_pem, TlsCertificateFlags cert_errors, Error err) { + if (eds_credentials_prompter.get_auto_prompt_disabled_for (source)) + return; + + if (reason == E.SourceCredentialsReason.ERROR && err != null) { + warning ("Failed to autheticate for source \"%s\": %s", source.display_name, err.message); + return; + } + + if (reason == E.SourceCredentialsReason.SSL_FAILED) { + e_trust_prompt_run_for_source (eds_credentials_prompter.get_dialog_parent (), + source, cert_pem, cert_errors, (err != null)? err.message : null, true, + null, (obj, res) => on_source_trust_prompt_has_run.begin (source, res)); + } +} + +private async void on_source_trust_prompt_has_run (E.Source source, AsyncResult res) { + try { + e_trust_prompt_run_for_source_finish (source, res, null); + } catch (Error e) { + warning ("Failed to prompt for trust for source \"%s\": %s", source.display_name, e.message); + return; + } + + try { + // Use null credentials to reuse those from the last time. + yield source.invoke_authenticate (null, null); + } catch (Error e) { + warning ("Failed to invoke authenticate() for source \"%s\": %s", source.display_name, e.message); + } +} + +public bool has_goa_account () { + foreach (var source in eds_source_registry.list_sources (E.SOURCE_EXTENSION_GOA)) { + // Ignore disabled accounts. + if (!source.enabled) + continue; + + // All ESources with a [GNOME Online Accounts] extension + // should also have a [Collection] extension. Verify it. + if (!source.has_extension (E.SOURCE_EXTENSION_COLLECTION)) + continue; + + // This corresponds to the Contacts ON/OFF switch in GOA. */ + if (((E.SourceCollection) source.get_extension (E.SOURCE_EXTENSION_COLLECTION)).contacts_enabled) { + return true; + } + } + + return false; +} + +public bool esource_uid_is_google (string uid) { + var source = eds_source_registry.ref_source (uid); + if (source == null) + return false; + + /* Make sure it's really an address book. */ + if (source.has_extension (E.SOURCE_EXTENSION_ADDRESS_BOOK)) { + var extension = source.get_extension (E.SOURCE_EXTENSION_ADDRESS_BOOK); + return ((E.SourceBackend) extension).backend_name == "google"; + } + + return false; +} + +public string? lookup_esource_name_by_uid (string uid) { + var source = eds_source_registry.ref_source (uid); + if (source == null) + return null; + + var builtin_address_book = eds_source_registry.ref_builtin_address_book (); + + if (source.equal (builtin_address_book)) + return _("Local Address Book"); + + if (esource_uid_is_google (uid)) + return _("Google"); + + return source.display_name; +} + +public string? lookup_esource_name_by_uid_for_contact (string uid) { + var source = eds_source_registry.ref_source (uid); + if (source == null) + return null; + + var builtin_address_book = eds_source_registry.ref_builtin_address_book (); + if (source.equal (builtin_address_book)) + return _("Local Contact"); + + if (esource_uid_is_google (uid)) + return _("Google"); + + return source.display_name; +} + +public Gtk.Image? get_icon_for_goa_account (string goa_id) { + Goa.Client client; + try { + client = new Goa.Client.sync (null); + } catch (Error e) { + debug ("Couldn't load GOA client \"%s\": %s", goa_id, e.message); + return null; + } + + var goa_object = client.lookup_by_id (goa_id); + + Icon provider_icon; + try { + provider_icon = Icon.new_for_string (goa_object.account.provider_icon); + } catch (Error e) { + debug ("Couldn't load icon for GOA provider \"%s\"", goa_id); + return null; + } + + return new Gtk.Image.from_gicon (provider_icon, Gtk.IconSize.DIALOG); +} +} diff --git a/src/meson.build b/src/meson.build index b072ad0..14f2604 100644 --- a/src/meson.build +++ b/src/meson.build @@ -15,6 +15,7 @@ contacts_vala_sources = [ 'contacts-contact-pane.vala', 'contacts-contact-sheet.vala', 'contacts-contact.vala', + 'contacts-esd-setup.vala', 'contacts-in-app-notification.vala', 'contacts-link-suggestion-grid.vala', 'contacts-linked-accounts-dialog.vala', @@ -38,7 +39,6 @@ contacts_vala_args = [ contacts_c_sources = [ 'cc-crop-area.c', - 'contacts-esd-setup.c', ] contacts_c_args = [ @@ -96,23 +96,15 @@ executable('gnome-contacts', contacts_sources, ) # The search provider -contact_search_provider_vala_sources = [ +contact_search_provider_sources = [ 'contacts-contact.vala', + 'contacts-esd-setup.vala', 'contacts-shell-search-provider.vala', 'contacts-store.vala', 'contacts-types.vala', 'contacts-utils.vala', ] -contact_search_provider_c_sources = [ - 'contacts-esd-setup.c', -] - -contact_search_provider_sources = [ - contact_search_provider_vala_sources, - contact_search_provider_c_sources, -] - executable('gnome-contacts-search-provider', contact_search_provider_sources, include_directories: config_h_dir, vala_args: contacts_vala_args, diff --git a/vapi/custom.vapi b/vapi/custom.vapi index 5fe3561..c48e3e8 100644 --- a/vapi/custom.vapi +++ b/vapi/custom.vapi @@ -1,21 +1,3 @@ -[CCode (cprefix = "Contacts", lower_case_cprefix = "contacts_", cheader_filename = "contacts-esd-setup.h")] -namespace Contacts { - [CCode (cname = "contacts_ensure_eds_accounts")] - public static bool ensure_eds_accounts (bool allow_interaction); - [CCode (cname = "contacts_lookup_esource_name_by_uid")] - public static unowned string? lookup_esource_name_by_uid (string uid); - [CCode (cname = "contacts_lookup_esource_name_by_uid_for_contact")] - public static unowned string? lookup_esource_name_by_uid_for_contact (string uid); - [CCode (cname = "contacts_esource_uid_is_google")] - public static bool esource_uid_is_google (string uid); - [CCode (cname = "contacts_has_goa_account")] - public static bool has_goa_account (); - [CCode (cname = "eds_source_registry")] - public static E.SourceRegistry eds_source_registry; - [CCode (cname = "contacts_get_icon_for_goa_account")] - public static unowned Gtk.Widget get_icon_for_goa_account (string goa_id); -} - [CCode (cprefix = "Cc", lower_case_cprefix = "cc_", cheader_filename = "cc-crop-area.h")] namespace Cc { public class CropArea : Gtk.DrawingArea { -- cgit v1.2.1