2 * module-online-accounts.c
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
19 /* XXX Yeah, yeah... */
20 #define GOA_API_IS_SUBJECT_TO_CHANGE
24 #include <gnome-keyring.h>
26 #include <libebackend/libebackend.h>
28 #include "goaewsclient.h"
30 /* Standard GObject macros */
31 #define E_TYPE_ONLINE_ACCOUNTS \
32 (e_online_accounts_get_type ())
33 #define E_ONLINE_ACCOUNTS(obj) \
34 (G_TYPE_CHECK_INSTANCE_CAST \
35 ((obj), E_TYPE_ONLINE_ACCOUNTS, EOnlineAccounts))
37 #define CAMEL_OAUTH_MECHANISM_NAME "XOAUTH"
39 typedef struct _EOnlineAccounts EOnlineAccounts;
40 typedef struct _EOnlineAccountsClass EOnlineAccountsClass;
42 struct _EOnlineAccounts {
45 GoaClient *goa_client;
46 GCancellable *create_client;
48 /* GoaAccount ID -> ESource UID */
49 GHashTable *goa_to_eds;
52 struct _EOnlineAccountsClass {
53 EExtensionClass parent_class;
56 /* The keyring definintions are copied from e-authentication-session.c */
58 #define KEYRING_ITEM_ATTRIBUTE_NAME "e-source-uid"
59 #define KEYRING_ITEM_DISPLAY_FORMAT "Evolution Data Source %s"
61 #ifdef HAVE_GOA_PASSWORD_BASED
62 static GnomeKeyringPasswordSchema schema = {
63 GNOME_KEYRING_ITEM_GENERIC_SECRET,
65 { KEYRING_ITEM_ATTRIBUTE_NAME,
66 GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
70 #endif /* HAVE_GOA_PASSWORD_BASED */
72 /* Module Entry Points */
73 void e_module_load (GTypeModule *type_module);
74 void e_module_unload (GTypeModule *type_module);
76 /* Forward Declarations */
77 GType e_online_accounts_get_type (void);
79 G_DEFINE_DYNAMIC_TYPE (
85 online_accounts_get_backend_name (const gchar *goa_provider_type)
87 const gchar *eds_backend_name = NULL;
89 /* This is a mapping between GoaAccount provider types and
90 * ESourceCollection backend names. It requires knowledge
91 * of other registry modules, possibly even from 3rd party
92 * packages. No way around it. */
94 if (g_strcmp0 (goa_provider_type, "exchange") == 0)
95 eds_backend_name = "ews";
97 if (g_strcmp0 (goa_provider_type, "google") == 0)
98 eds_backend_name = "google";
100 else if (g_strcmp0 (goa_provider_type, "yahoo") == 0)
101 eds_backend_name = "yahoo";
103 return eds_backend_name;
106 static ESourceRegistryServer *
107 online_accounts_get_server (EOnlineAccounts *extension)
109 EExtensible *extensible;
111 extensible = e_extension_get_extensible (E_EXTENSION (extension));
113 return E_SOURCE_REGISTRY_SERVER (extensible);
117 online_accounts_provider_type_to_backend_name (GBinding *binding,
118 const GValue *source_value,
119 GValue *target_value,
122 const gchar *provider_type;
123 const gchar *backend_name;
125 provider_type = g_value_get_string (source_value);
126 backend_name = online_accounts_get_backend_name (provider_type);
127 g_return_val_if_fail (backend_name != NULL, FALSE);
128 g_value_set_string (target_value, backend_name);
134 online_accounts_object_is_non_null (GBinding *binding,
135 const GValue *source_value,
136 GValue *target_value,
141 v_object = g_value_get_object (source_value);
142 g_value_set_boolean (target_value, v_object != NULL);
148 online_accounts_new_source (EOnlineAccounts *extension)
150 ESourceRegistryServer *server;
153 GError *error = NULL;
155 /* This being a brand new data source, creating the instance
156 * should never fail but we'll check for errors just the same. */
157 server = online_accounts_get_server (extension);
158 file = e_server_side_source_new_user_file (NULL);
159 source = e_server_side_source_new (server, file, &error);
160 g_object_unref (file);
163 g_warn_if_fail (source == NULL);
164 g_warning ("%s: %s", G_STRFUNC, error->message);
165 g_error_free (error);
172 online_accounts_config_exchange (EOnlineAccounts *extension,
174 GoaObject *goa_object)
176 #ifdef HAVE_GOA_PASSWORD_BASED
177 ESourceExtension *source_extension;
178 const gchar *extension_name;
179 gchar *as_url = NULL;
180 gchar *oab_url = NULL;
182 GError *error = NULL;
184 if (goa_object_peek_exchange (goa_object) == NULL)
187 /* This should force the ESourceCamelEws type to be registered.
188 * It will also tell us if Evolution-EWS is even installed. */
189 class = g_type_class_ref (g_type_from_name ("EEwsBackend"));
191 g_type_class_unref (class);
194 "%s: Could not locate EEwsBackendClass. "
195 "Is Evolution-EWS installed?", G_STRFUNC);
199 /* XXX GNOME Online Accounts already runs autodiscover to test
200 * the user-entered values but doesn't share the discovered
201 * URLs. It only provides us a host name and expects us to
202 * re-run autodiscover for ourselves.
204 * So I've copied a slab of code from GOA which was in turn
205 * copied from Evolution-EWS which does the autodiscovery.
207 * I've already complained to Debarshi Ray about the lack
208 * of useful info in GOA's Exchange interface so hopefully
209 * it will someday publish discovered URLs and then we can
210 * remove this hack. */
212 goa_ews_autodiscover_sync (
213 goa_object, &as_url, &oab_url, NULL, &error);
216 g_warning ("%s: %s", G_STRFUNC, error->message);
217 g_error_free (error);
221 g_return_if_fail (as_url != NULL);
222 g_return_if_fail (oab_url != NULL);
224 /* XXX We don't have direct access to CamelEwsSettings from here
225 * since it's defined in Evolution-EWS. But we can find out
226 * its extension name and set properties by name. */
228 extension_name = e_source_camel_get_extension_name ("ews");
229 source_extension = e_source_get_extension (source, extension_name);
231 /* This will be NULL if Evolution-EWS is not installed. */
232 if (source_extension != NULL) {
240 "%s: Failed to create [%s] extension",
241 G_STRFUNC, extension_name);
246 #endif /* HAVE_GOA_PASSWORD_BASED */
250 online_accounts_config_oauth (EOnlineAccounts *extension,
252 GoaObject *goa_object)
254 ESourceExtension *source_extension;
255 const gchar *extension_name;
257 if (goa_object_peek_oauth_based (goa_object) == NULL)
260 extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
261 source_extension = e_source_get_extension (source, extension_name);
263 e_source_authentication_set_method (
264 E_SOURCE_AUTHENTICATION (source_extension),
265 CAMEL_OAUTH_MECHANISM_NAME);
269 online_accounts_config_password (EOnlineAccounts *extension,
271 GoaObject *goa_object)
273 #ifdef HAVE_GOA_PASSWORD_BASED
274 GoaAccount *goa_account;
275 GoaPasswordBased *goa_password_based;
276 GnomeKeyringResult keyring_result;
277 EAsyncClosure *closure;
278 GAsyncResult *result;
282 gchar *password = NULL;
283 GError *error = NULL;
285 /* If the GNOME Online Account is password-based, we use its
286 * password to seed our own keyring entry for the collection
287 * source which avoids having to special-case authentication
288 * like we do for OAuth. Plus, if the stored password is no
289 * good we'll prompt for a new one instead of just giving up. */
291 goa_password_based = goa_object_get_password_based (goa_object);
293 if (goa_password_based == NULL)
296 closure = e_async_closure_new ();
298 /* XXX The GOA documentation doesn't explain the string
299 * argument in goa_password_based_get_password() so
300 * we'll pass in the identity and hope for the best. */
301 goa_account = goa_object_get_account (goa_object);
302 arg_id = goa_account_dup_identity (goa_account);
303 g_object_unref (goa_account);
305 goa_password_based_call_get_password (
306 goa_password_based, arg_id, NULL,
307 e_async_closure_callback, closure);
311 result = e_async_closure_wait (closure);
313 goa_password_based_call_get_password_finish (
314 goa_password_based, &password, result, &error);
317 g_warning ("%s: %s", G_STRFUNC, error->message);
318 g_error_free (error);
322 uid = e_source_get_uid (source);
323 display_name = g_strdup_printf (KEYRING_ITEM_DISPLAY_FORMAT, uid);
325 /* XXX Just call gnome-keyring synchronously. I know it's
326 * evil, but I want to know the password has been stored
327 * before returning from this function. We'll be moving
328 * to libsecret soon anyway, which is more GIO-based, so
329 * we could then reuse the EAsyncClosure here. */
330 keyring_result = gnome_keyring_store_password_sync (
331 &schema, GNOME_KEYRING_DEFAULT, display_name,
332 password, KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
334 g_free (display_name);
336 /* If we fail to store the password, we'll just end up prompting
337 * for a password like normal. Annoying, maybe, but not the end
338 * of the world. Still leave a breadcrumb for debugging though. */
339 if (keyring_result != GNOME_KEYRING_RESULT_OK) {
340 const gchar *message;
341 message = gnome_keyring_result_to_message (keyring_result);
342 g_warning ("%s: %s", G_STRFUNC, message);
346 e_async_closure_free (closure);
347 g_object_unref (goa_password_based);
348 #endif /* HAVE_GOA_PASSWORD_BASED */
352 online_accounts_config_collection (EOnlineAccounts *extension,
354 GoaObject *goa_object)
356 GoaAccount *goa_account;
357 ESourceExtension *source_extension;
358 const gchar *extension_name;
360 goa_account = goa_object_get_account (goa_object);
362 g_object_bind_property (
363 goa_account, "presentation-identity",
364 source, "display-name",
365 G_BINDING_SYNC_CREATE);
367 extension_name = E_SOURCE_EXTENSION_GOA;
368 source_extension = e_source_get_extension (source, extension_name);
370 g_object_bind_property (
372 source_extension, "account-id",
373 G_BINDING_SYNC_CREATE);
375 extension_name = E_SOURCE_EXTENSION_COLLECTION;
376 source_extension = e_source_get_extension (source, extension_name);
378 g_object_bind_property_full (
379 goa_account, "provider-type",
380 source_extension, "backend-name",
381 G_BINDING_SYNC_CREATE,
382 online_accounts_provider_type_to_backend_name,
384 NULL, (GDestroyNotify) NULL);
386 g_object_bind_property (
387 goa_account, "identity",
388 source_extension, "identity",
389 G_BINDING_SYNC_CREATE);
391 g_object_bind_property_full (
392 goa_object, "calendar",
393 source_extension, "calendar-enabled",
394 G_BINDING_SYNC_CREATE,
395 online_accounts_object_is_non_null,
397 NULL, (GDestroyNotify) NULL);
399 g_object_bind_property_full (
400 goa_object, "contacts",
401 source_extension, "contacts-enabled",
402 G_BINDING_SYNC_CREATE,
403 online_accounts_object_is_non_null,
405 NULL, (GDestroyNotify) NULL);
407 g_object_bind_property_full (
409 source_extension, "mail-enabled",
410 G_BINDING_SYNC_CREATE,
411 online_accounts_object_is_non_null,
413 NULL, (GDestroyNotify) NULL);
415 g_object_unref (goa_account);
417 /* Handle optional GOA interfaces. */
418 online_accounts_config_exchange (extension, source, goa_object);
419 online_accounts_config_password (extension, source, goa_object);
421 /* The data source should not be removable by clients. */
422 e_server_side_source_set_removable (
423 E_SERVER_SIDE_SOURCE (source), FALSE);
427 online_accounts_config_mail_account (EOnlineAccounts *extension,
429 GoaObject *goa_object)
431 EServerSideSource *server_side_source;
433 online_accounts_config_oauth (extension, source, goa_object);
435 /* XXX Need to defer the network security settings to the
436 * provider-specific module since "imap-use-tls" tells
437 * us neither the port number, nor whether to use IMAP
438 * over SSL versus STARTTLS. The module will know. */
440 /* Clients may change the source by may not remove it. */
441 server_side_source = E_SERVER_SIDE_SOURCE (source);
442 e_server_side_source_set_writable (server_side_source, TRUE);
443 e_server_side_source_set_removable (server_side_source, FALSE);
447 online_accounts_config_mail_identity (EOnlineAccounts *extension,
449 GoaObject *goa_object)
452 ESourceExtension *source_extension;
453 EServerSideSource *server_side_source;
454 const gchar *extension_name;
456 goa_mail = goa_object_get_mail (goa_object);
457 g_return_if_fail (goa_mail != NULL);
459 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
460 source_extension = e_source_get_extension (source, extension_name);
462 g_object_bind_property (
463 goa_mail, "email-address",
464 source_extension, "address",
465 G_BINDING_SYNC_CREATE);
467 g_object_unref (goa_mail);
469 /* Clients may change the source by may not remove it. */
470 server_side_source = E_SERVER_SIDE_SOURCE (source);
471 e_server_side_source_set_writable (server_side_source, TRUE);
472 e_server_side_source_set_removable (server_side_source, FALSE);
476 online_accounts_config_mail_transport (EOnlineAccounts *extension,
478 GoaObject *goa_object)
480 EServerSideSource *server_side_source;
482 online_accounts_config_oauth (extension, source, goa_object);
484 /* XXX Need to defer the network security settings to the
485 * provider-specific module since "smtp-use-tls" tells
486 * us neither the port number, nor whether to use SMTP
487 * over SSL versus STARTTLS. The module will know. */
489 /* Clients may change the source by may not remove it. */
490 server_side_source = E_SERVER_SIDE_SOURCE (source);
491 e_server_side_source_set_writable (server_side_source, TRUE);
492 e_server_side_source_set_removable (server_side_source, FALSE);
496 online_accounts_create_collection (EOnlineAccounts *extension,
497 EBackendFactory *backend_factory,
498 GoaObject *goa_object)
500 GoaAccount *goa_account;
501 ESourceRegistryServer *server;
502 ESource *collection_source;
503 ESource *mail_account_source;
504 ESource *mail_identity_source;
505 ESource *mail_transport_source;
506 const gchar *account_id;
507 const gchar *parent_uid;
509 server = online_accounts_get_server (extension);
511 collection_source = online_accounts_new_source (extension);
512 g_return_if_fail (E_IS_SOURCE (collection_source));
514 mail_account_source = online_accounts_new_source (extension);
515 g_return_if_fail (E_IS_SOURCE (mail_account_source));
517 mail_identity_source = online_accounts_new_source (extension);
518 g_return_if_fail (E_IS_SOURCE (mail_identity_source));
520 mail_transport_source = online_accounts_new_source (extension);
521 g_return_if_fail (E_IS_SOURCE (mail_transport_source));
523 /* Configure parent/child relationships. */
524 parent_uid = e_source_get_uid (collection_source);
525 e_source_set_parent (mail_account_source, parent_uid);
526 e_source_set_parent (mail_identity_source, parent_uid);
527 e_source_set_parent (mail_transport_source, parent_uid);
529 /* Give the factory first crack at mail configuration. */
530 e_collection_backend_factory_prepare_mail (
531 E_COLLECTION_BACKEND_FACTORY (backend_factory),
533 mail_identity_source,
534 mail_transport_source);
536 /* Now it's our turn. */
537 online_accounts_config_collection (
538 extension, collection_source, goa_object);
539 online_accounts_config_mail_account (
540 extension, mail_account_source, goa_object);
541 online_accounts_config_mail_identity (
542 extension, mail_identity_source, goa_object);
543 online_accounts_config_mail_transport (
544 extension, mail_transport_source, goa_object);
546 /* Export the new source collection. */
547 e_source_registry_server_add_source (server, collection_source);
548 e_source_registry_server_add_source (server, mail_account_source);
549 e_source_registry_server_add_source (server, mail_identity_source);
550 e_source_registry_server_add_source (server, mail_transport_source);
552 goa_account = goa_object_get_account (goa_object);
553 account_id = goa_account_get_id (goa_account);
555 g_hash_table_insert (
556 extension->goa_to_eds,
557 g_strdup (account_id),
558 g_strdup (parent_uid));
560 g_object_unref (goa_account);
562 g_object_unref (collection_source);
563 g_object_unref (mail_account_source);
564 g_object_unref (mail_identity_source);
565 g_object_unref (mail_transport_source);
569 online_accounts_remove_collection (EOnlineAccounts *extension,
572 GError *error = NULL;
574 /* This removes the entire subtree rooted at source.
575 * Deletes the corresponding on-disk key files too. */
576 e_source_remove_sync (source, NULL, &error);
579 g_warning ("%s: %s", G_STRFUNC, error->message);
580 g_error_free (error);
585 online_accounts_account_added_cb (GoaClient *goa_client,
586 GoaObject *goa_object,
587 EOnlineAccounts *extension)
589 GoaAccount *goa_account;
590 ESourceRegistryServer *server;
591 EBackendFactory *backend_factory = NULL;
592 const gchar *provider_type;
593 const gchar *backend_name;
594 const gchar *account_id;
595 const gchar *source_uid;
597 server = online_accounts_get_server (extension);
599 goa_account = goa_object_get_account (goa_object);
600 provider_type = goa_account_get_provider_type (goa_account);
601 backend_name = online_accounts_get_backend_name (provider_type);
603 account_id = goa_account_get_id (goa_account);
604 source_uid = g_hash_table_lookup (extension->goa_to_eds, account_id);
606 if (source_uid == NULL && backend_name != NULL)
607 backend_factory = e_data_factory_ref_backend_factory (
608 E_DATA_FACTORY (server), backend_name);
610 if (backend_factory != NULL) {
611 online_accounts_create_collection (
612 extension, backend_factory, goa_object);
613 g_object_unref (backend_factory);
616 g_object_unref (goa_account);
620 online_accounts_account_removed_cb (GoaClient *goa_client,
621 GoaObject *goa_object,
622 EOnlineAccounts *extension)
624 ESource *source = NULL;
625 ESourceRegistryServer *server;
626 GoaAccount *goa_account;
627 const gchar *account_id;
628 const gchar *source_uid;
630 server = online_accounts_get_server (extension);
632 goa_account = goa_object_get_account (goa_object);
634 account_id = goa_account_get_id (goa_account);
635 source_uid = g_hash_table_lookup (extension->goa_to_eds, account_id);
637 if (source_uid != NULL)
638 source = e_source_registry_server_ref_source (
641 if (source != NULL) {
642 online_accounts_remove_collection (extension, source);
643 g_object_unref (source);
646 g_object_unref (goa_account);
650 online_accounts_compare_id (GoaObject *goa_object,
651 const gchar *target_id)
653 GoaAccount *goa_account;
654 const gchar *account_id;
657 goa_account = goa_object_get_account (goa_object);
658 account_id = goa_account_get_id (goa_account);
659 result = g_strcmp0 (account_id, target_id);
660 g_object_unref (goa_account);
666 online_accounts_populate_accounts_table (EOnlineAccounts *extension,
669 ESourceRegistryServer *server;
670 GQueue trash = G_QUEUE_INIT;
672 const gchar *extension_name;
674 server = online_accounts_get_server (extension);
676 extension_name = E_SOURCE_EXTENSION_GOA;
677 list = e_source_registry_server_list_sources (server, extension_name);
679 for (link = list; link != NULL; link = g_list_next (link)) {
682 const gchar *account_id;
683 const gchar *source_uid;
686 source = E_SOURCE (link->data);
687 source_uid = e_source_get_uid (source);
689 extension_name = E_SOURCE_EXTENSION_GOA;
690 goa_ext = e_source_get_extension (source, extension_name);
691 account_id = e_source_goa_get_account_id (goa_ext);
693 if (account_id == NULL)
696 /* Verify the GOA account still exists. */
697 match = g_list_find_custom (
698 goa_objects, account_id,
699 (GCompareFunc) online_accounts_compare_id);
701 /* If a matching GoaObject was found, add its ID
702 * to our accounts hash table. Otherwise remove
703 * the ESource after we finish looping. */
705 GoaObject *goa_object;
707 g_hash_table_insert (
708 extension->goa_to_eds,
709 g_strdup (account_id),
710 g_strdup (source_uid));
712 goa_object = GOA_OBJECT (match->data);
713 online_accounts_config_collection (
714 extension, source, goa_object);
716 g_queue_push_tail (&trash, source);
720 /* Empty the trash. */
721 while (!g_queue_is_empty (&trash)) {
722 ESource *source = g_queue_pop_head (&trash);
723 online_accounts_remove_collection (extension, source);
726 g_list_free_full (list, (GDestroyNotify) g_object_unref);
730 online_accounts_create_client_cb (GObject *source_object,
731 GAsyncResult *result,
734 EOnlineAccounts *extension;
735 GoaClient *goa_client;
737 GError *error = NULL;
739 /* If we get back a G_IO_ERROR_CANCELLED then it means the
740 * EOnlineAccounts is already finalized, so be careful not
741 * to touch it until after we have a valid GoaClient. */
743 goa_client = goa_client_new_finish (result, &error);
746 g_warn_if_fail (goa_client == NULL);
748 "Unable to connect to the GNOME Online "
749 "Accounts service: %s", error->message);
750 g_error_free (error);
754 g_return_if_fail (GOA_IS_CLIENT (goa_client));
756 /* Should be safe to dereference the EOnlineAccounts now. */
758 extension = E_ONLINE_ACCOUNTS (user_data);
759 extension->goa_client = goa_client; /* takes ownership */
761 /* Don't need the GCancellable anymore. */
762 g_object_unref (extension->create_client);
763 extension->create_client = NULL;
765 list = goa_client_get_accounts (extension->goa_client);
767 /* This populates a hash table of GOA ID -> ESource UID strings by
768 * searching through available data sources for ones with a "GNOME
769 * Online Accounts" extension. If such an extension is found, but
770 * no corresponding GoaAccount (presumably meaning the GOA account
771 * was somehow deleted between E-D-S sessions) then the ESource in
772 * which the extension was found gets deleted. */
773 online_accounts_populate_accounts_table (extension, list);
775 for (link = list; link != NULL; link = g_list_next (link))
776 online_accounts_account_added_cb (
777 extension->goa_client,
778 GOA_OBJECT (link->data),
781 g_list_free_full (list, (GDestroyNotify) g_object_unref);
783 /* Listen for Online Account changes. */
785 extension->goa_client, "account-added",
786 G_CALLBACK (online_accounts_account_added_cb), extension);
788 extension->goa_client, "account-removed",
789 G_CALLBACK (online_accounts_account_removed_cb), extension);
793 online_accounts_bus_acquired_cb (EDBusServer *server,
794 GDBusConnection *connection,
795 EOnlineAccounts *extension)
797 /* Connect to the GNOME Online Accounts service. */
799 /* Note we don't reference the extension. If the
800 * extension gets destroyed before this completes
801 * we cancel the operation from dispose(). */
803 extension->create_client,
804 online_accounts_create_client_cb,
809 online_accounts_dispose (GObject *object)
811 EOnlineAccounts *extension;
813 extension = E_ONLINE_ACCOUNTS (object);
815 if (extension->goa_client != NULL) {
816 g_signal_handlers_disconnect_matched (
817 extension->goa_client,
819 0, 0, NULL, NULL, object);
820 g_object_unref (extension->goa_client);
821 extension->goa_client = NULL;
824 /* This cancels goa_client_new() in case it still
825 * hasn't completed. We're no longer interested. */
826 if (extension->create_client != NULL) {
827 g_cancellable_cancel (extension->create_client);
828 g_object_unref (extension->create_client);
829 extension->create_client = NULL;
832 /* Chain up to parent's dispose() method. */
833 G_OBJECT_CLASS (e_online_accounts_parent_class)->dispose (object);
837 online_accounts_finalize (GObject *object)
839 EOnlineAccounts *extension;
841 extension = E_ONLINE_ACCOUNTS (object);
843 g_hash_table_destroy (extension->goa_to_eds);
845 /* Chain up to parent's finalize() method. */
846 G_OBJECT_CLASS (e_online_accounts_parent_class)->finalize (object);
850 online_accounts_constructed (GObject *object)
852 EExtension *extension;
853 EExtensible *extensible;
855 extension = E_EXTENSION (object);
856 extensible = e_extension_get_extensible (extension);
858 /* Wait for the registry service to acquire its well-known
859 * bus name so we don't do anything destructive beforehand. */
862 extensible, "bus-acquired",
863 G_CALLBACK (online_accounts_bus_acquired_cb), extension);
865 /* Chain up to parent's constructed() method. */
866 G_OBJECT_CLASS (e_online_accounts_parent_class)->constructed (object);
870 e_online_accounts_class_init (EOnlineAccountsClass *class)
872 GObjectClass *object_class;
873 EExtensionClass *extension_class;
875 object_class = G_OBJECT_CLASS (class);
876 object_class->dispose = online_accounts_dispose;
877 object_class->finalize = online_accounts_finalize;
878 object_class->constructed = online_accounts_constructed;
880 extension_class = E_EXTENSION_CLASS (class);
881 extension_class->extensible_type = E_TYPE_SOURCE_REGISTRY_SERVER;
885 e_online_accounts_class_finalize (EOnlineAccountsClass *class)
890 e_online_accounts_init (EOnlineAccounts *extension)
892 /* Used to cancel unfinished goa_client_new(). */
893 extension->create_client = g_cancellable_new ();
895 extension->goa_to_eds = g_hash_table_new_full (
896 (GHashFunc) g_str_hash,
897 (GEqualFunc) g_str_equal,
898 (GDestroyNotify) g_free,
899 (GDestroyNotify) g_free);
903 e_module_load (GTypeModule *type_module)
905 e_online_accounts_register_type (type_module);
909 e_module_unload (GTypeModule *type_module)