/* 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); }
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); }
/** 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 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 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); }
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 ESourceAuthenticationResult e_cal_backend_http_authenticate_sync (EBackend *backend, const ENamedParameters *credentials, gchar **out_certificate_pem, GTlsCertificateFlags *out_certificate_errors, GCancellable *cancellable, GError **error) { ECalBackendHttp *cbhttp; ESourceAuthenticationResult result; const gchar *uri, *username; GError *local_error = NULL; cbhttp = E_CAL_BACKEND_HTTP (backend); g_free (cbhttp->priv->username); cbhttp->priv->username = NULL; g_free (cbhttp->priv->password); cbhttp->priv->password = g_strdup (e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_PASSWORD)); username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME); if (username && *username) { cbhttp->priv->username = g_strdup (username); } uri = cal_backend_http_ensure_uri (cbhttp); if (cal_backend_http_load (cbhttp, uri, out_certificate_pem, out_certificate_errors, cancellable, &local_error)) { if (!cbhttp->priv->reload_timeout_id) { ESource *source = e_backend_get_source (backend); cbhttp->priv->reload_timeout_id = e_source_refresh_add_timeout (source, NULL, http_cal_reload_cb, backend, NULL); } } if (local_error == NULL) { result = E_SOURCE_AUTHENTICATION_ACCEPTED; } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) { result = E_SOURCE_AUTHENTICATION_REJECTED; g_clear_error (&local_error); } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) { result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED; g_propagate_error (error, local_error); } else { result = E_SOURCE_AUTHENTICATION_ERROR; g_propagate_error (error, local_error); } return result; }
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); }
/** * kolab_util_backend_get_foldername: * @backend: an #EBackend * * Returns the Kolab foldername for @backend. * * Returns: the foldername for @backend **/ const gchar * kolab_util_backend_get_foldername (EBackend *backend) { ESource *source; ESourceResource *extension; const gchar *extension_name; g_return_val_if_fail (E_IS_BACKEND (backend), NULL); source = e_backend_get_source (backend); extension_name = E_SOURCE_EXTENSION_KOLAB_FOLDER; extension = e_source_get_extension (source, extension_name); return e_source_resource_get_identity (extension); }
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); } }
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; }
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); }
/** 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; }
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); }
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 eee_backend_add_calendar (ECollectionBackend *backend) { ESource *source; ESource *collection_source; ESourceRegistryServer *server; ESourceExtension *extension; ESourceCollection *collection_extension; const gchar *backend_name; const gchar *extension_name; const gchar *identity; const gchar *resource_id; gchar *path; /* FIXME As a future enhancement, we should query Eee * for a list of user calendars and add them to the * collection with matching display names and colors. */ collection_source = e_backend_get_source (E_BACKEND (backend)); /* resource_id = GOOGLE_CALENDAR_RESOURCE_ID; source = e_collection_backend_new_child (backend, resource_id); e_source_set_display_name (source, _("Calendar")); collection_extension = e_source_get_extension ( collection_source, E_SOURCE_EXTENSION_COLLECTION); */ /* Configure the calendar source. */ /* backend_name = "eee"; extension_name = E_SOURCE_EXTENSION_CALENDAR; 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_CALENDAR_HOST); 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); extension_name = E_SOURCE_EXTENSION_RESOURCE; extension = e_source_get_extension (source, extension_name); identity = e_source_collection_get_identity (collection_extension); path = g_strdup_printf (GOOGLE_CALENDAR_CALDAV_PATH, identity); e_source_webdav_set_resource_path ( E_SOURCE_WEBDAV (extension), path); g_free (path); 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 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); }
static gboolean cal_backend_http_load (ECalBackendHttp *backend, const gchar *uri, gchar **out_certificate_pem, GTlsCertificateFlags *out_certificate_errors, GCancellable *cancellable, GError **error) { ECalBackendHttpPrivate *priv = backend->priv; ETimezoneCache *timezone_cache; SoupMessage *soup_message; SoupSession *soup_session; icalcomponent *icalcomp, *subcomp; icalcomponent_kind kind; const gchar *newuri; SoupURI *uri_parsed; GHashTable *old_cache; GSList *comps_in_cache; ESource *source; guint status_code; gulong cancel_id = 0; struct { SoupSession *soup_session; SoupMessage *soup_message; } cancel_data; timezone_cache = E_TIMEZONE_CACHE (backend); soup_session = backend->priv->soup_session; soup_message = cal_backend_http_new_message (backend, uri); if (soup_message == NULL) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: %s"), uri); return FALSE; } if (G_IS_CANCELLABLE (cancellable)) { cancel_data.soup_session = soup_session; cancel_data.soup_message = soup_message; cancel_id = g_cancellable_connect ( cancellable, G_CALLBACK (cal_backend_http_cancelled), &cancel_data, (GDestroyNotify) NULL); } source = e_backend_get_source (E_BACKEND (backend)); e_soup_ssl_trust_connect (soup_message, source); e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING); status_code = soup_session_send_message (soup_session, soup_message); if (G_IS_CANCELLABLE (cancellable)) g_cancellable_disconnect (cancellable, cancel_id); if (status_code == SOUP_STATUS_NOT_MODIFIED) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); /* attempts with ETag can result in 304 status code */ g_object_unref (soup_message); priv->opened = TRUE; return TRUE; } /* Handle redirection ourselves */ if (SOUP_STATUS_IS_REDIRECTION (status_code)) { gboolean success; newuri = soup_message_headers_get_list ( soup_message->response_headers, "Location"); d (g_message ("Redirected from %s to %s\n", async_context->uri, newuri)); if (newuri != NULL) { gchar *redirected_uri; if (newuri[0]=='/') { g_warning ("Hey! Relative URI returned! Working around...\n"); uri_parsed = soup_uri_new (uri); soup_uri_set_path (uri_parsed, newuri); soup_uri_set_query (uri_parsed, NULL); /* g_free (newuri); */ newuri = soup_uri_to_string (uri_parsed, FALSE); g_message ("Translated URI: %s\n", newuri); soup_uri_free (uri_parsed); } redirected_uri = webcal_to_http_method (newuri, FALSE); success = cal_backend_http_load ( backend, redirected_uri, out_certificate_pem, out_certificate_errors, cancellable, error); g_free (redirected_uri); } else { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_BAD_REQUEST, _("Redirected to Invalid URI")); success = FALSE; } if (success) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); } else { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED); } g_object_unref (soup_message); return success; } /* check status code */ if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { /* because evolution knows only G_IO_ERROR_CANCELLED */ if (status_code == SOUP_STATUS_CANCELLED) g_set_error ( error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "%s", soup_message->reason_phrase); else g_set_error ( error, SOUP_HTTP_ERROR, status_code, "%s", soup_message->reason_phrase); if (status_code == SOUP_STATUS_SSL_FAILED) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED); cal_backend_http_extract_ssl_failed_data (soup_message, out_certificate_pem, out_certificate_errors); } else { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED); } g_object_unref (soup_message); empty_cache (backend); return FALSE; } e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); if (priv->store) { const gchar *etag; etag = soup_message_headers_get_one ( soup_message->response_headers, "ETag"); if (etag != NULL && *etag == '\0') etag = NULL; e_cal_backend_store_put_key_value (priv->store, "ETag", etag); } /* get the calendar from the response */ icalcomp = icalparser_parse_string (soup_message->response_body->data); if (!icalcomp) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Bad file format.")); g_object_unref (soup_message); empty_cache (backend); return FALSE; } if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Not a calendar.")); icalcomponent_free (icalcomp); g_object_unref (soup_message); empty_cache (backend); return FALSE; } g_object_unref (soup_message); soup_message = NULL; /* Update cache */ old_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); comps_in_cache = e_cal_backend_store_get_components (priv->store); while (comps_in_cache != NULL) { const gchar *uid; ECalComponent *comp = comps_in_cache->data; e_cal_component_get_uid (comp, &uid); g_hash_table_insert (old_cache, g_strdup (uid), e_cal_component_get_as_string (comp)); comps_in_cache = g_slist_remove (comps_in_cache, comps_in_cache->data); g_object_unref (comp); } kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend)); subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); e_cal_backend_store_freeze_changes (priv->store); while (subcomp) { ECalComponent *comp; icalcomponent_kind subcomp_kind; icalproperty *prop = NULL; subcomp_kind = icalcomponent_isa (subcomp); prop = icalcomponent_get_first_property (subcomp, ICAL_UID_PROPERTY); if (!prop && subcomp_kind == kind) { gchar *new_uid = e_cal_component_gen_uid (); icalcomponent_set_uid (subcomp, new_uid); g_free (new_uid); } if (subcomp_kind == kind) { comp = e_cal_component_new (); if (e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) { const gchar *uid; gpointer orig_key, orig_value; e_cal_component_get_uid (comp, &uid); if (!put_component_to_store (backend, comp)) { g_hash_table_remove (old_cache, uid); } else if (g_hash_table_lookup_extended (old_cache, uid, &orig_key, &orig_value)) { ECalComponent *orig_comp = e_cal_component_new_from_string (orig_value); e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend), orig_comp, comp); g_hash_table_remove (old_cache, uid); if (orig_comp) g_object_unref (orig_comp); } else { e_cal_backend_notify_component_created (E_CAL_BACKEND (backend), comp); } } g_object_unref (comp); } else if (subcomp_kind == ICAL_VTIMEZONE_COMPONENT) { icaltimezone *zone; zone = icaltimezone_new (); icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp)); e_timezone_cache_add_timezone (timezone_cache, zone); icaltimezone_free (zone, 1); } subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT); } e_cal_backend_store_thaw_changes (priv->store); /* notify the removals */ g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, backend); g_hash_table_destroy (old_cache); /* free memory */ icalcomponent_free (icalcomp); priv->opened = TRUE; return TRUE; }
static void yahoo_backend_config_calendar_child (ECollectionBackend *backend, ESource *source) { EYahooBackend *yahoo_backend; ESource *collection_source; ESource *mail_identity_source; ESourceExtension *extension; ESourceCollection *collection_extension; const gchar *extension_name; const gchar *identity; gchar *display_name = NULL; /* FIXME As a future enhancement, we should query Yahoo! * for a list of user calendars and add them to the * collection with matching display names and colors. */ yahoo_backend = E_YAHOO_BACKEND (backend); collection_source = e_backend_get_source (E_BACKEND (backend)); collection_extension = e_source_get_extension ( collection_source, E_SOURCE_EXTENSION_COLLECTION); identity = e_source_collection_get_identity (collection_extension); /* XXX Assume the calendar's display name can be derived from * the user's mail identity. As mentioned above, we should * really just query Yahoo! for a list of user calendars. */ mail_identity_source = g_weak_ref_get (&yahoo_backend->mail_identity_source); if (mail_identity_source != NULL) { extension = e_source_get_extension ( mail_identity_source, E_SOURCE_EXTENSION_MAIL_IDENTITY); display_name = e_source_mail_identity_dup_name ( E_SOURCE_MAIL_IDENTITY (extension)); if (display_name != NULL) g_strdelimit (display_name, " ", '_'); g_object_unref (mail_identity_source); } extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; extension = e_source_get_extension (source, extension_name); e_source_authentication_set_host ( E_SOURCE_AUTHENTICATION (extension), YAHOO_CALENDAR_HOST); e_binding_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); extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND; extension = e_source_get_extension (source, extension_name); e_source_webdav_set_display_name ( E_SOURCE_WEBDAV (extension), display_name); if (identity != NULL && display_name != NULL) { gchar *resource_path; resource_path = g_strdup_printf ( YAHOO_CALENDAR_CALDAV_PATH, identity, display_name); e_source_webdav_set_resource_path ( E_SOURCE_WEBDAV (extension), resource_path); g_free (resource_path); } g_free (display_name); }
static void yahoo_backend_child_added (ECollectionBackend *backend, ESource *child_source) { EYahooBackend *yahoo_backend; ESource *collection_source; const gchar *extension_name; gboolean is_mail = FALSE; /* Chain up to parent's child_added() method. */ E_COLLECTION_BACKEND_CLASS (e_yahoo_backend_parent_class)-> child_added (backend, child_source); yahoo_backend = E_YAHOO_BACKEND (backend); 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); /* Take special note of the mail identity source. * We need it to build the calendar CalDAV path. */ extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; if (e_source_has_extension (child_source, extension_name)) { GWeakRef *weak_ref; weak_ref = &yahoo_backend->mail_identity_source; g_weak_ref_set (weak_ref, child_source); is_mail = TRUE; } 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-Yahoo! server. */ if (auth_child_user == NULL) e_source_authentication_set_user ( auth_child_extension, collection_identity); } }
static void google_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-Google server. */ if (auth_child_user == NULL) e_source_authentication_set_user ( auth_child_extension, collection_identity); } /* 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)) { google_backend_calendar_update_auth_method (child_source); g_signal_connect ( child_source, "notify::oauth2-support", G_CALLBACK (google_backend_calendar_update_auth_method), NULL); } /* 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); g_signal_connect ( child_source, "notify::oauth2-support", G_CALLBACK (google_backend_contacts_update_auth_method), NULL); } /* Chain up to parent's child_added() method. */ E_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)-> child_added (backend, child_source); }
static void google_backend_add_calendar (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; /* FIXME As a future enhancement, we should query Google * for a list of user calendars and add them to the * collection with matching display names and colors. */ /* NOTE: Host name and WebDAV resource path are set in * google_backend_calendar_update_auth_method(), * since they depend on the auth method used. */ collection_source = e_backend_get_source (E_BACKEND (backend)); resource_id = GOOGLE_CALENDAR_RESOURCE_ID; source = e_collection_backend_new_child (backend, resource_id); e_source_set_display_name (source, _("Calendar")); collection_extension = e_source_get_extension ( collection_source, E_SOURCE_EXTENSION_COLLECTION); /* Configure the calendar source. */ backend_name = GOOGLE_CALENDAR_BACKEND_NAME; extension_name = E_SOURCE_EXTENSION_CALENDAR; 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); /* Make sure the WebDAV resource path is up-to-date, since * it's built from the "user" property that we just set. */ google_backend_calendar_update_auth_method (source); extension_name = E_SOURCE_EXTENSION_SECURITY; extension = e_source_get_extension (source, extension_name); e_source_security_set_secure ( E_SOURCE_SECURITY (extension), TRUE); extension_name = E_SOURCE_EXTENSION_ALARMS; extension = e_source_get_extension (source, extension_name); if (!e_source_alarms_get_last_notified (E_SOURCE_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 ( E_SOURCE_ALARMS (extension), today); g_free (today); } server = e_collection_backend_ref_server (backend); e_source_registry_server_add_source (server, source); g_object_unref (server); g_object_unref (source); }
/* Open handler for the file backend */ static void e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **perror) { ECalBackendHttp *cbhttp; ECalBackendHttpPrivate *priv; ESource *source; ESourceWebdav *webdav_extension; const gchar *extension_name; const gchar *cache_dir; gboolean opened = TRUE; gchar *tmp; GError *local_error = NULL; cbhttp = E_CAL_BACKEND_HTTP (backend); priv = cbhttp->priv; /* already opened, thus can skip all this initialization */ if (priv->opened) return; source = e_backend_get_source (E_BACKEND (backend)); cache_dir = e_cal_backend_get_cache_dir (E_CAL_BACKEND (backend)); extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND; webdav_extension = e_source_get_extension (source, extension_name); e_source_webdav_unset_temporary_ssl_trust (webdav_extension); if (priv->source_changed_id == 0) { priv->source_changed_id = g_signal_connect ( source, "changed", G_CALLBACK (source_changed_cb), cbhttp); } /* always read uri again */ tmp = priv->uri; priv->uri = NULL; g_free (tmp); if (priv->store == NULL) { /* remove the old cache while migrating to ECalBackendStore */ e_cal_backend_cache_remove (cache_dir, "cache.xml"); priv->store = e_cal_backend_store_new ( cache_dir, E_TIMEZONE_CACHE (backend)); e_cal_backend_store_load (priv->store); if (!priv->store) { g_propagate_error ( perror, EDC_ERROR_EX (OtherError, _("Could not create cache file"))); return; } } e_cal_backend_set_writable (E_CAL_BACKEND (backend), FALSE); if (e_backend_get_online (E_BACKEND (backend))) { gchar *certificate_pem = NULL; GTlsCertificateFlags certificate_errors = 0; const gchar *uri; uri = cal_backend_http_ensure_uri (cbhttp); opened = cal_backend_http_load (cbhttp, uri, &certificate_pem, &certificate_errors, cancellable, &local_error); if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) || g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) || (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN) && !cbhttp->priv->password)) { GError *local_error2 = NULL; ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED; if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) { reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED; } e_backend_credentials_required_sync (E_BACKEND (cbhttp), reason, certificate_pem, certificate_errors, local_error, cancellable, &local_error2); g_clear_error (&local_error); local_error = local_error2; } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) { GError *local_error2 = NULL; e_backend_credentials_required_sync (E_BACKEND (cbhttp), E_SOURCE_CREDENTIALS_REASON_REJECTED, certificate_pem, certificate_errors, local_error, cancellable, &local_error2); g_clear_error (&local_error); local_error = local_error2; } g_free (certificate_pem); if (local_error != NULL) g_propagate_error (perror, local_error); } if (opened) { if (!priv->reload_timeout_id) priv->reload_timeout_id = e_source_refresh_add_timeout (source, NULL, http_cal_reload_cb, backend, NULL); } }