/* * module-google-backend.c * * This library 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. * * This library 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 this library. If not, see . * */ #include "evolution-data-server-config.h" #include #include #include /* Standard GObject macros */ #define E_TYPE_GOOGLE_BACKEND \ (e_google_backend_get_type ()) #define E_GOOGLE_BACKEND(obj) \ (G_TYPE_CHECK_INSTANCE_CAST \ ((obj), E_TYPE_GOOGLE_BACKEND, EGoogleBackend)) /* Just for readability... */ #define METHOD(x) (CAMEL_NETWORK_SECURITY_METHOD_##x) #define GOOGLE_OAUTH2_METHOD "Google" /* IMAP Configuration Details */ #define GOOGLE_IMAP_BACKEND_NAME "imapx" #define GOOGLE_IMAP_HOST "imap.googlemail.com" #define GOOGLE_IMAP_PORT 993 #define GOOGLE_IMAP_SECURITY_METHOD METHOD (SSL_ON_ALTERNATE_PORT) /* SMTP Configuration Details */ #define GOOGLE_SMTP_BACKEND_NAME "smtp" #define GOOGLE_SMTP_HOST "smtp.googlemail.com" #define GOOGLE_SMTP_PORT 465 #define GOOGLE_SMTP_SECURITY_METHOD METHOD (SSL_ON_ALTERNATE_PORT) /* Tasks Configuration Details */ #define GOOGLE_TASKS_BACKEND_NAME "gtasks" typedef struct _EGoogleBackend EGoogleBackend; typedef struct _EGoogleBackendClass EGoogleBackendClass; typedef struct _EGoogleBackendFactory EGoogleBackendFactory; typedef struct _EGoogleBackendFactoryClass EGoogleBackendFactoryClass; struct _EGoogleBackend { EWebDAVCollectionBackend parent; }; struct _EGoogleBackendClass { EWebDAVCollectionBackendClass parent_class; }; struct _EGoogleBackendFactory { ECollectionBackendFactory parent; }; struct _EGoogleBackendFactoryClass { ECollectionBackendFactoryClass parent_class; }; /* Module Entry Points */ void e_module_load (GTypeModule *type_module); void e_module_unload (GTypeModule *type_module); /* Forward Declarations */ GType e_google_backend_get_type (void); GType e_google_backend_factory_get_type (void); G_DEFINE_DYNAMIC_TYPE ( EGoogleBackend, e_google_backend, E_TYPE_WEBDAV_COLLECTION_BACKEND) G_DEFINE_DYNAMIC_TYPE ( EGoogleBackendFactory, e_google_backend_factory, E_TYPE_COLLECTION_BACKEND_FACTORY) static gboolean google_backend_can_use_google_auth (ESource *source) { ESourceRegistryServer *registry; ESourceAuthentication *auth_extension; gboolean res; g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE); registry = e_server_side_source_get_server (E_SERVER_SIDE_SOURCE (source)); if (!e_oauth2_services_is_oauth2_alias (e_source_registry_server_get_oauth2_services (registry), GOOGLE_OAUTH2_METHOD)) return FALSE; g_object_ref (source); while (source && e_source_get_parent (source)) { ESource *adept_source; adept_source = e_source_registry_server_ref_source (registry, e_source_get_parent (source)); if (adept_source) { g_object_unref (source); source = adept_source; } else { break; } } auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); res = !e_source_authentication_get_is_external (auth_extension); g_object_unref (source); return res; } static gboolean host_ends_with (const gchar *host, const gchar *ends_with) { gint host_len, ends_with_len; if (!host || !ends_with) return FALSE; host_len = strlen (host); ends_with_len = strlen (ends_with); if (host_len <= ends_with_len) return FALSE; return g_ascii_strcasecmp (host + host_len - ends_with_len, ends_with) == 0; } static gboolean google_backend_is_google_host (ESourceAuthentication *auth_extension, gboolean *out_requires_oauth2) { gboolean is_google; gboolean requires_oauth2; gchar *host; g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (auth_extension), FALSE); host = e_source_authentication_dup_host (auth_extension); requires_oauth2 = host && host_ends_with (host, "googleusercontent.com"); is_google = requires_oauth2 || (host && ( host_ends_with (host, "gmail.com") || host_ends_with (host, "googlemail.com") || host_ends_with (host, "google.com"))); g_free (host); if (out_requires_oauth2) *out_requires_oauth2 = requires_oauth2; return is_google; } static gboolean google_backend_is_oauth2 (const gchar *method) { return g_strcmp0 (method, GOOGLE_OAUTH2_METHOD) == 0 || g_strcmp0 (method, "OAuth2") == 0 || g_strcmp0 (method, "XOAUTH2") == 0; } static gboolean google_backend_can_change_auth_method (ESourceAuthentication *auth_extension, const gchar *new_method) { gchar *cur_method; gboolean can_change; g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (auth_extension), FALSE); if (!new_method) return FALSE; cur_method = e_source_authentication_dup_method (auth_extension); /* Only when turning off OAuth2 */ can_change = google_backend_is_oauth2 (cur_method) && !google_backend_is_oauth2 (new_method); g_free (cur_method); return can_change; } static void google_backend_mail_update_auth_method (ECollectionBackend *collection_backend, ESource *child_source, ESource *master_source) { ESourceAuthentication *auth_extension; EOAuth2Support *oauth2_support; const gchar *method; gboolean can_use_google_auth; auth_extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION); if (!google_backend_is_google_host (auth_extension, NULL)) return; oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (child_source)); if (!oauth2_support && master_source) oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (master_source)); can_use_google_auth = google_backend_can_use_google_auth (child_source); if (!can_use_google_auth && master_source) can_use_google_auth = google_backend_can_use_google_auth (master_source); if (oauth2_support && !can_use_google_auth) { method = "XOAUTH2"; } else if (can_use_google_auth) { method = GOOGLE_OAUTH2_METHOD; } else { method = NULL; } if (method && (e_collection_backend_is_new_source (collection_backend, child_source) || google_backend_can_change_auth_method (auth_extension, method))) e_source_authentication_set_method (auth_extension, method); g_clear_object (&oauth2_support); } static void google_backend_mail_update_auth_method_cb (ESource *child_source, GParamSpec *param, EBackend *backend) { google_backend_mail_update_auth_method (E_COLLECTION_BACKEND (backend), child_source, e_backend_get_source (backend)); } static void google_backend_calendar_update_auth_method (ECollectionBackend *collection_backend, ESource *child_source, ESource *master_source) { EOAuth2Support *oauth2_support; ESourceAuthentication *auth_extension; const gchar *method; gboolean can_use_google_auth, requires_oauth2 = FALSE; auth_extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION); if (!google_backend_is_google_host (auth_extension, &requires_oauth2)) return; oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (child_source)); if (!oauth2_support && master_source) oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (master_source)); can_use_google_auth = google_backend_can_use_google_auth (child_source); if (!can_use_google_auth && master_source) can_use_google_auth = google_backend_can_use_google_auth (master_source); if (oauth2_support && !can_use_google_auth) { method = "OAuth2"; } else if (can_use_google_auth) { method = GOOGLE_OAUTH2_METHOD; } else { method = "plain/password"; } if (requires_oauth2 || e_collection_backend_is_new_source (collection_backend, child_source) || google_backend_can_change_auth_method (auth_extension, method)) e_source_authentication_set_method (auth_extension, method); g_clear_object (&oauth2_support); } static void google_backend_calendar_update_auth_method_cb (ESource *child_source, GParamSpec *param, EBackend *backend) { google_backend_calendar_update_auth_method (E_COLLECTION_BACKEND (backend), child_source, e_backend_get_source (backend)); } static void google_backend_contacts_update_auth_method (ESource *child_source, ESource *master_source) { EOAuth2Support *oauth2_support; ESourceAuthentication *extension; const gchar *method; gboolean can_use_google_auth; extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION); if (!google_backend_is_google_host (extension, NULL)) return; oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (child_source)); if (!oauth2_support && master_source) oauth2_support = e_server_side_source_ref_oauth2_support (E_SERVER_SIDE_SOURCE (master_source)); can_use_google_auth = google_backend_can_use_google_auth (child_source); if (!can_use_google_auth && master_source) can_use_google_auth = google_backend_can_use_google_auth (master_source); if (oauth2_support && !can_use_google_auth) method = "OAuth2"; else if (can_use_google_auth) method = GOOGLE_OAUTH2_METHOD; else method = "OAuth2"; /* "ClientLogin" for Contacts is not supported anymore, thus fallback to OAuth2 method regardless it's supported or not. */ e_source_authentication_set_method (extension, method); g_clear_object (&oauth2_support); } static void google_backend_contacts_update_auth_method_cb (ESource *child_source, GParamSpec *param, EBackend *backend) { google_backend_contacts_update_auth_method (child_source, e_backend_get_source (backend)); } static void google_add_task_list_uid_to_hashtable (gpointer source, gpointer known_sources) { ESourceResource *resource; gchar *uid, *rid; if (!e_source_has_extension (source, E_SOURCE_EXTENSION_RESOURCE) || !e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) return; resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE); uid = e_source_dup_uid (source); if (!uid || !*uid) { g_free (uid); return; } rid = e_source_resource_dup_identity (resource); if (!rid || !*rid) { g_free (rid); g_free (uid); return; } g_hash_table_insert (known_sources, rid, uid); } static void google_remove_unknown_sources_cb (gpointer resource_id, gpointer uid, gpointer user_data) { ESourceRegistryServer *server = user_data; ESource *source; source = e_source_registry_server_ref_source (server, uid); if (source) { e_source_remove_sync (source, NULL, NULL); g_object_unref (source); } } static void google_add_task_list (ECollectionBackend *collection, const gchar *resource_id, const gchar *display_name, GHashTable *known_sources) { ESourceRegistryServer *server; ESource *source; ESource *collection_source; ESourceExtension *extension; ESourceCollection *collection_extension; ESourceResource *resource; const gchar *source_uid; gchar *identity; gboolean is_new; collection_source = e_backend_get_source (E_BACKEND (collection)); server = e_collection_backend_ref_server (collection); if (!server) return; identity = g_strconcat (GOOGLE_TASKS_BACKEND_NAME, "::", resource_id, NULL); source_uid = g_hash_table_lookup (known_sources, identity); is_new = !source_uid; if (is_new) { source = e_collection_backend_new_child (collection, identity); g_warn_if_fail (source != NULL); } else { source = e_source_registry_server_ref_source (server, source_uid); g_warn_if_fail (source != NULL); g_hash_table_remove (known_sources, identity); } resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE); e_source_resource_set_identity (resource, identity); e_source_set_display_name (source, display_name); collection_extension = e_source_get_extension ( collection_source, E_SOURCE_EXTENSION_COLLECTION); /* Configure the calendar source. */ extension = e_source_get_extension (source, E_SOURCE_EXTENSION_TASK_LIST); e_source_backend_set_backend_name (E_SOURCE_BACKEND (extension), GOOGLE_TASKS_BACKEND_NAME); extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); e_source_authentication_set_host (E_SOURCE_AUTHENTICATION (extension), "www.google.com"); if (google_backend_can_use_google_auth (collection_source)) e_source_authentication_set_method (E_SOURCE_AUTHENTICATION (extension), GOOGLE_OAUTH2_METHOD); else e_source_authentication_set_method (E_SOURCE_AUTHENTICATION (extension), "OAuth2"); e_binding_bind_property ( collection_extension, "identity", extension, "user", G_BINDING_SYNC_CREATE); extension = e_source_get_extension (source, E_SOURCE_EXTENSION_ALARMS); e_source_alarms_set_include_me (E_SOURCE_ALARMS (extension), FALSE); if (is_new) { ESourceRegistryServer *server; server = e_collection_backend_ref_server (collection); e_source_registry_server_add_source (server, source); g_object_unref (server); } g_object_unref (source); g_object_unref (server); g_free (identity); } typedef struct _TaskListsData { ECollectionBackend *collection; GHashTable *known_sources; } TaskListsData; static gboolean google_backend_list_task_lists_cb (EGDataSession *gdata, JsonObject *tasklist, gpointer user_data) { TaskListsData *tld = user_data; google_add_task_list (tld->collection, e_gdata_tasklist_get_id (tasklist), e_gdata_tasklist_get_title (tasklist), tld->known_sources); return TRUE; } static ESourceAuthenticationResult google_backend_authenticate_sync (EBackend *backend, const ENamedParameters *credentials, gchar **out_certificate_pem, GTlsCertificateFlags *out_certificate_errors, GCancellable *cancellable, GError **error) { ECollectionBackend *collection = E_COLLECTION_BACKEND (backend); ESourceAuthentication *auth_extension = NULL; ESourceCollection *collection_extension; ESourceGoa *goa_extension = NULL; ESource *source; ESourceAuthenticationResult result = E_SOURCE_AUTHENTICATION_ERROR; GHashTable *known_sources; GList *sources; ENamedParameters *credentials_copy = NULL; const gchar *calendar_url; const gchar *contacts_url = NULL; g_return_val_if_fail (collection != NULL, E_SOURCE_AUTHENTICATION_ERROR); source = e_backend_get_source (backend); collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION); if (e_source_has_extension (source, E_SOURCE_EXTENSION_GOA)) goa_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_GOA); if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); g_return_val_if_fail (e_source_collection_get_calendar_enabled (collection_extension) || e_source_collection_get_contacts_enabled (collection_extension), E_SOURCE_AUTHENTICATION_ERROR); e_collection_backend_freeze_populate (collection); if (credentials && !e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME)) { credentials_copy = e_named_parameters_new_clone (credentials); e_named_parameters_set (credentials_copy, E_SOURCE_CREDENTIAL_USERNAME, e_source_collection_get_identity (collection_extension)); credentials = credentials_copy; } /* resource-id => source's UID */ known_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); sources = e_collection_backend_list_calendar_sources (collection); g_list_foreach (sources, google_add_task_list_uid_to_hashtable, known_sources); g_list_free_full (sources, g_object_unref); /* When the WebDAV extension is created, the auth method can be reset, thus ensure it's there before setting correct authentication method on the master source. */ (void) e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); google_backend_calendar_update_auth_method (collection, source, NULL); if (goa_extension) { calendar_url = e_source_goa_get_calendar_url (goa_extension); } else { calendar_url = "https://www.google.com/calendar/dav/"; if (auth_extension) { gchar *method; method = e_source_authentication_dup_method (auth_extension); if (g_strcmp0 (method, GOOGLE_OAUTH2_METHOD) == 0) calendar_url = "https://apidata.googleusercontent.com/caldav/v2/"; g_free (method); } } if (!e_source_collection_get_calendar_enabled (collection_extension)) calendar_url = NULL; if (e_source_collection_get_contacts_enabled (collection_extension)) contacts_url = "https://www.googleapis.com/.well-known/carddav"; if (calendar_url || contacts_url) { result = e_webdav_collection_backend_discover_sync (E_WEBDAV_COLLECTION_BACKEND (backend), calendar_url, contacts_url, credentials, out_certificate_pem, out_certificate_errors, cancellable, error); } else { result = E_SOURCE_AUTHENTICATION_ACCEPTED; } if (result == E_SOURCE_AUTHENTICATION_ACCEPTED && e_source_collection_get_calendar_enabled (collection_extension) && (goa_extension || e_oauth2_services_is_supported ())) { EGDataSession *gdata; TaskListsData tld; GError *local_error = NULL; gdata = e_gdata_session_new (e_backend_get_source (backend)); e_binding_bind_property ( backend, "proxy-resolver", gdata, "proxy-resolver", G_BINDING_SYNC_CREATE); tld.collection = collection; tld.known_sources = known_sources; if (!e_gdata_session_tasklists_list_sync (gdata, NULL, google_backend_list_task_lists_cb, &tld, cancellable, &local_error)) e_source_registry_debug_print ("%s: Failed to get tasks list: %s\n", G_STRFUNC, local_error ? local_error->message : "Unknown error"); g_clear_object (&gdata); g_clear_error (&local_error); } if (result == E_SOURCE_AUTHENTICATION_ACCEPTED) { ESourceRegistryServer *server; server = e_collection_backend_ref_server (collection); if (server) { g_hash_table_foreach (known_sources, google_remove_unknown_sources_cb, server); g_object_unref (server); } } g_hash_table_destroy (known_sources); e_named_parameters_free (credentials_copy); e_collection_backend_thaw_populate (collection); return result; } static gboolean google_backend_is_custom_source (EWebDAVCollectionBackend *webdav_backend, ESource *source) { g_return_val_if_fail (E_IS_SOURCE (source), FALSE); if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) return TRUE; /* Chain up to parent's method. */ return E_WEBDAV_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->is_custom_source (webdav_backend, source); } static void google_backend_populate (ECollectionBackend *backend) { ESourceAuthentication *authentication_extension; ESource *source; source = e_backend_get_source (E_BACKEND (backend)); authentication_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); /* When the WebDAV extension is created, the auth method can be reset, thus ensure it's there before setting correct authentication method on the master source. */ (void) e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); /* Force OAuth2 for Google accounts using external auth method and do it before calling parent method, thus it knows what authentication method it's supposed to use */ if (e_source_authentication_get_is_external (authentication_extension)) e_source_authentication_set_method (authentication_extension, "OAuth2"); /* Chain up to parent's method. */ E_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->populate (backend); } static gchar * google_backend_dup_resource_id (ECollectionBackend *backend, ESource *child_source) { if (e_source_has_extension (child_source, E_SOURCE_EXTENSION_CALENDAR) || e_source_has_extension (child_source, E_SOURCE_EXTENSION_MEMO_LIST) || e_source_has_extension (child_source, E_SOURCE_EXTENSION_TASK_LIST) || e_source_has_extension (child_source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) return E_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->dup_resource_id (backend, child_source); return NULL; } static void google_backend_child_added (ECollectionBackend *backend, ESource *child_source) { ESource *collection_source; const gchar *extension_name; gboolean is_mail = FALSE; /* Chain up to parent's child_added() method. */ E_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)-> child_added (backend, child_source); 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-Google server. */ if (auth_child_user == NULL) e_source_authentication_set_user ( auth_child_extension, collection_identity); if (e_source_has_extension (child_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT) || e_source_has_extension (child_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) { google_backend_mail_update_auth_method (backend, child_source, collection_source); g_signal_connect ( child_source, "notify::oauth2-support", G_CALLBACK (google_backend_mail_update_auth_method_cb), backend); } } /* Keep the calendar authentication method up-to-date. * * XXX Not using a property binding here in case I end up adding * other "support" interfaces which influence authentication. * Many-to-one property bindinds tend not to work so well. */ extension_name = E_SOURCE_EXTENSION_CALENDAR; if (e_source_has_extension (child_source, extension_name)) { ESourceAlarms *alarms_extension; /* To not notify about past reminders. */ alarms_extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_ALARMS); if (!e_source_alarms_get_last_notified (alarms_extension)) { GTimeVal today_tv; gchar *today; g_get_current_time (&today_tv); today = g_time_val_to_iso8601 (&today_tv); e_source_alarms_set_last_notified (alarms_extension, today); g_free (today); } google_backend_calendar_update_auth_method (backend, child_source, collection_source); g_signal_connect ( child_source, "notify::oauth2-support", G_CALLBACK (google_backend_calendar_update_auth_method_cb), backend); } /* Keep the contacts authentication method up-to-date. * * XXX Not using a property binding here in case I end up adding * other "support" interfaces which influence authentication. * Many-to-one property bindings tend not to work so well. */ extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK; if (e_source_has_extension (child_source, extension_name)) { google_backend_contacts_update_auth_method (child_source, collection_source); g_signal_connect ( child_source, "notify::oauth2-support", G_CALLBACK (google_backend_contacts_update_auth_method_cb), backend); } } static gboolean google_backend_get_destination_address (EBackend *backend, gchar **host, guint16 *port) { g_return_val_if_fail (host != NULL, FALSE); g_return_val_if_fail (port != NULL, FALSE); *host = g_strdup ("www.google.com"); *port = 443; return TRUE; } static void e_google_backend_class_init (EGoogleBackendClass *class) { EBackendClass *backend_class; ECollectionBackendClass *collection_backend_class; EWebDAVCollectionBackendClass *webdav_collection_backend_class; backend_class = E_BACKEND_CLASS (class); backend_class->authenticate_sync = google_backend_authenticate_sync; backend_class->get_destination_address = google_backend_get_destination_address; collection_backend_class = E_COLLECTION_BACKEND_CLASS (class); collection_backend_class->populate = google_backend_populate; collection_backend_class->dup_resource_id = google_backend_dup_resource_id; collection_backend_class->child_added = google_backend_child_added; webdav_collection_backend_class = E_WEBDAV_COLLECTION_BACKEND_CLASS (class); webdav_collection_backend_class->is_custom_source = google_backend_is_custom_source; } static void e_google_backend_class_finalize (EGoogleBackendClass *class) { } static void e_google_backend_init (EGoogleBackend *backend) { } static void google_backend_prepare_mail_account_source (ESource *source) { ESourceCamel *camel_extension; ESourceExtension *extension; CamelSettings *settings; const gchar *backend_name; const gchar *extension_name; backend_name = GOOGLE_IMAP_BACKEND_NAME; extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; extension = e_source_get_extension (source, extension_name); e_source_backend_set_backend_name ( E_SOURCE_BACKEND (extension), backend_name); extension_name = e_source_camel_get_extension_name (backend_name); camel_extension = e_source_get_extension (source, extension_name); settings = e_source_camel_get_settings (camel_extension); /* The "auth-mechanism" should be determined elsewhere. */ camel_network_settings_set_host ( CAMEL_NETWORK_SETTINGS (settings), GOOGLE_IMAP_HOST); camel_network_settings_set_port ( CAMEL_NETWORK_SETTINGS (settings), GOOGLE_IMAP_PORT); camel_network_settings_set_security_method ( CAMEL_NETWORK_SETTINGS (settings), GOOGLE_IMAP_SECURITY_METHOD); } static void google_backend_prepare_mail_transport_source (ESource *source) { ESourceCamel *camel_extension; ESourceExtension *extension; CamelSettings *settings; const gchar *backend_name; const gchar *extension_name; /* Configure the mail transport source. */ backend_name = GOOGLE_SMTP_BACKEND_NAME; extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT; extension = e_source_get_extension (source, extension_name); e_source_backend_set_backend_name ( E_SOURCE_BACKEND (extension), backend_name); extension_name = e_source_camel_get_extension_name (backend_name); camel_extension = e_source_get_extension (source, extension_name); settings = e_source_camel_get_settings (camel_extension); /* The "auth-mechanism" should be determined elsewhere. */ camel_network_settings_set_host ( CAMEL_NETWORK_SETTINGS (settings), GOOGLE_SMTP_HOST); camel_network_settings_set_port ( CAMEL_NETWORK_SETTINGS (settings), GOOGLE_SMTP_PORT); camel_network_settings_set_security_method ( CAMEL_NETWORK_SETTINGS (settings), GOOGLE_SMTP_SECURITY_METHOD); } static void google_backend_factory_prepare_mail (ECollectionBackendFactory *factory, ESource *mail_account_source, ESource *mail_identity_source, ESource *mail_transport_source) { ECollectionBackendFactoryClass *parent_class; /* Chain up to parent's prepare_mail() method. */ parent_class = E_COLLECTION_BACKEND_FACTORY_CLASS ( e_google_backend_factory_parent_class); parent_class->prepare_mail ( factory, mail_account_source, mail_identity_source, mail_transport_source); google_backend_prepare_mail_account_source (mail_account_source); google_backend_prepare_mail_transport_source (mail_transport_source); } static void e_google_backend_factory_class_init (EGoogleBackendFactoryClass *class) { ECollectionBackendFactoryClass *factory_class; factory_class = E_COLLECTION_BACKEND_FACTORY_CLASS (class); factory_class->factory_name = "google"; factory_class->backend_type = E_TYPE_GOOGLE_BACKEND; factory_class->prepare_mail = google_backend_factory_prepare_mail; } static void e_google_backend_factory_class_finalize (EGoogleBackendFactoryClass *class) { } static void e_google_backend_factory_init (EGoogleBackendFactory *factory) { } G_MODULE_EXPORT void e_module_load (GTypeModule *type_module) { e_google_backend_register_type (type_module); e_google_backend_factory_register_type (type_module); } G_MODULE_EXPORT void e_module_unload (GTypeModule *type_module) { }