static void e_book_backend_webdav_remove_contacts (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *id_list) { EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend); EBookBackendWebdavPrivate *priv = webdav->priv; gchar *uid = id_list->data; GSList deleted_ids = {NULL,}; guint status; if (!e_backend_get_online (E_BACKEND (backend))) { e_data_book_respond_remove_contacts ( book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL); return; } /* We make the assumption that the ID list we're passed is always exactly one element long, since we haven't specified "bulk-removes" * in our static capability list. */ if (id_list->next != NULL) { e_data_book_respond_remove_contacts ( book, opid, EDB_ERROR_EX (NOT_SUPPORTED, _("The backend does not support bulk removals")), NULL); return; } status = delete_contact (webdav, uid, cancellable); if (status != 204) { if (status == 401 || status == 407) { e_data_book_respond_remove_contacts ( book, opid, webdav_handle_auth_request (webdav), NULL); } else { g_warning ("DELETE failed with HTTP status %d", status); e_data_book_respond_remove_contacts ( book, opid, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, _("DELETE failed with HTTP status %d"), status), NULL); } return; } g_mutex_lock (&priv->cache_lock); e_book_backend_cache_remove_contact (priv->cache, uid); g_mutex_unlock (&priv->cache_lock); deleted_ids.data = uid; e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (SUCCESS), &deleted_ids); }
static void e_book_backend_vcf_modify_contact (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *vcard, EContact **contact, GError **perror) { EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend); GList *elem; const gchar *id; /* create a new ecard from the request data */ *contact = e_contact_new_from_vcard (vcard); id = e_contact_get_const (*contact, E_CONTACT_UID); g_mutex_lock (bvcf->priv->mutex); elem = g_hash_table_lookup (bvcf->priv->contacts, id); if (!elem) { g_mutex_unlock (bvcf->priv->mutex); g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND)); return; } g_free (elem->data); elem->data = g_strdup (vcard); bvcf->priv->dirty = TRUE; if (!bvcf->priv->flush_timeout_tag) bvcf->priv->flush_timeout_tag = g_timeout_add (FILE_FLUSH_TIMEOUT, vcf_flush_file, bvcf); g_mutex_unlock (bvcf->priv->mutex); }
static GError * webdav_handle_auth_request (EBookBackendWebdav *webdav) { EBookBackendWebdavPrivate *priv = webdav->priv; if (priv->username != NULL) { g_free (priv->username); priv->username = NULL; g_free (priv->password); priv->password = NULL; return EDB_ERROR (AUTHENTICATION_FAILED); } else { return EDB_ERROR (AUTHENTICATION_REQUIRED); } }
static void ebbm_contacts_list_known_uids (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb, gpointer build_rs_cb_data, struct ListKnownUidsData *lku, GCancellable *cancellable, GError **error) { EBookBackendMAPIContacts *ebmac; EMapiConnection *conn; gboolean status; mapi_object_t obj_folder; GError *mapi_error = NULL; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (lku != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (lku->uid_to_rev != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma); e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (ebmac->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { e_book_backend_mapi_unlock_connection (ebma); if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); return; } status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error); if (status) { status = e_mapi_connection_list_objects (conn, &obj_folder, build_rs_cb, build_rs_cb_data, gather_known_uids_cb, lku, cancellable, &mapi_error); e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error); } e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); if (mapi_error) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to list items from a server")); g_error_free (mapi_error); } e_book_backend_mapi_unlock_connection (ebma); }
static void ebbm_contacts_get_contacts_count (EBookBackendMAPI *ebma, guint32 *obj_total, GCancellable *cancellable, GError **error) { EBookBackendMAPIContacts *ebmac; EMapiConnection *conn; gboolean status; mapi_object_t obj_folder; GError *mapi_error = NULL; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (obj_total != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma); e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (ebmac->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { e_book_backend_mapi_unlock_connection (ebma); if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); return; } status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error); if (status) { struct FolderBasicPropertiesData fbp = { 0 }; status = e_mapi_connection_get_folder_properties (conn, &obj_folder, NULL, NULL, e_mapi_utils_get_folder_basic_properties_cb, &fbp, cancellable, &mapi_error); if (status) *obj_total = fbp.obj_total; e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error); } e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); if (mapi_error) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to count server contacts")); g_error_free (mapi_error); } e_book_backend_mapi_unlock_connection (ebma); }
static void e_book_backend_vcf_remove_contacts (EBookBackendSync *backend, EDataBook *book, guint32 opid, GList *id_list, GList **ids, GError **perror) { /* FIXME: make this handle bulk deletes like the file backend does */ EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend); gchar *id = id_list->data; GList *elem; g_mutex_lock (bvcf->priv->mutex); elem = g_hash_table_lookup (bvcf->priv->contacts, id); if (!elem) { g_mutex_unlock (bvcf->priv->mutex); g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND)); return; } if (!g_hash_table_remove (bvcf->priv->contacts, id)) { g_mutex_unlock (bvcf->priv->mutex); g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND)); return; } g_free (elem->data); bvcf->priv->contact_list = g_list_remove_link (bvcf->priv->contact_list, elem); bvcf->priv->dirty = TRUE; if (!bvcf->priv->flush_timeout_tag) bvcf->priv->flush_timeout_tag = g_timeout_add (FILE_FLUSH_TIMEOUT, vcf_flush_file, bvcf); g_mutex_unlock (bvcf->priv->mutex); *ids = g_list_append (*ids, id); }
static void e_book_backend_webdav_get_contact (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *uid) { EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend); EBookBackendWebdavPrivate *priv = webdav->priv; EContact *contact; gchar *vcard; if (!e_backend_get_online (E_BACKEND (backend))) { g_mutex_lock (&priv->cache_lock); contact = e_book_backend_cache_get_contact (priv->cache, uid); g_mutex_unlock (&priv->cache_lock); } else { contact = download_contact (webdav, uid, cancellable); /* update cache as we possibly have changes */ if (contact != NULL) { g_mutex_lock (&priv->cache_lock); e_book_backend_cache_remove_contact (priv->cache, uid); e_book_backend_cache_add_contact (priv->cache, contact); g_mutex_unlock (&priv->cache_lock); } } if (contact == NULL) { e_data_book_respond_get_contact (book, opid, EDB_ERROR (CONTACT_NOT_FOUND), NULL); return; } vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); e_data_book_respond_get_contact (book, opid, EDB_ERROR (SUCCESS), vcard); g_free (vcard); g_object_unref (contact); }
static void ebbm_contacts_remove (EBookBackendMAPI *ebma, GCancellable *cancellable, GError **error) { EBookBackendMAPIContactsPrivate *priv; GError *mapi_error = NULL; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG); priv = E_BOOK_BACKEND_MAPI_CONTACTS (ebma)->priv; e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_remove) E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_remove (ebma, cancellable, &mapi_error); if (mapi_error) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL); g_error_free (mapi_error); return; } if (!priv->is_public_folder && !priv->foreign_username) { EMapiConnection *conn; e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); } else { mapi_object_t *obj_store = NULL; if (e_mapi_connection_peek_store (conn, priv->foreign_username ? FALSE : priv->is_public_folder, priv->foreign_username, &obj_store, cancellable, &mapi_error)) e_mapi_connection_remove_folder (conn, obj_store, priv->fid, cancellable, &mapi_error); if (mapi_error) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to remove public folder")); e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); g_error_free (mapi_error); } } e_book_backend_mapi_unlock_connection (ebma); } }
static void e_book_backend_vcf_create_contact (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *vcard, EContact **contact, GError **perror) { EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend); *contact = do_create(bvcf, vcard, TRUE); if (!*contact) { /* XXX need a different call status for this case, i think */ g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND)); } }
static void e_book_backend_webdav_get_contact_list_uids (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *query) { EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend); EBookBackendWebdavPrivate *priv = webdav->priv; GList *contact_list; GSList *uids_list; GList *c; if (e_backend_get_online (E_BACKEND (backend))) { /* make sure the cache is up to date */ GError *error = download_contacts (webdav, NULL, NULL, cancellable); if (error) { e_data_book_respond_get_contact_list_uids (book, opid, error, NULL); return; } } /* answer query from cache */ g_mutex_lock (&priv->cache_lock); contact_list = e_book_backend_cache_get_contacts (priv->cache, query); g_mutex_unlock (&priv->cache_lock); uids_list = NULL; for (c = contact_list; c != NULL; c = g_list_next (c)) { EContact *contact = c->data; uids_list = g_slist_append (uids_list, e_contact_get (contact, E_CONTACT_UID)); g_object_unref (contact); } g_list_free (contact_list); e_data_book_respond_get_contact_list_uids (book, opid, EDB_ERROR (SUCCESS), uids_list); g_slist_foreach (uids_list, (GFunc) g_free, NULL); g_slist_free (uids_list); }
static void e_book_backend_vcf_get_contact (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *id, gchar **vcard, GError **perror) { EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend); GList *elem; elem = g_hash_table_lookup (bvcf->priv->contacts, id); if (elem) { *vcard = g_strdup (elem->data); } else { *vcard = g_strdup (""); g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND)); } }
static void ebbm_contacts_transfer_contacts (EBookBackendMAPI *ebma, const GSList *uids, EDataBookView *book_view, gpointer notify_contact_data, GCancellable *cancellable, GError **error) { EBookBackendMAPIContacts *ebmac; EBookBackendMAPIContactsPrivate *priv; EMapiConnection *conn; struct TransferContactsData tcd = { 0 }; mapi_object_t obj_folder; gboolean status; GError *mapi_error = NULL; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG); ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma); e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); priv = ebmac->priv; e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { e_book_backend_mapi_unlock_connection (ebma); if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); return; } tcd.ebma = ebma; tcd.book_view = book_view; tcd.notify_contact_data = notify_contact_data; status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error); if (status) { GSList *mids = NULL; const GSList *iter; for (iter = uids; iter; iter = iter->next) { const gchar *uid_str = iter->data; mapi_id_t mid, *pmid; if (!uid_str || !e_mapi_util_mapi_id_from_string (uid_str, &mid)) continue; pmid = g_new0 (mapi_id_t, 1); *pmid = mid; mids = g_slist_prepend (mids, pmid); } if (mids) status = e_mapi_connection_transfer_objects (conn, &obj_folder, mids, transfer_contacts_cb, &tcd, cancellable, &mapi_error); e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error); g_slist_free_full (mids, g_free); } e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); if (!status) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to transfer contacts from a server")); if (mapi_error) g_error_free (mapi_error); } e_book_backend_mapi_unlock_connection (ebma); }
static void ebbm_contacts_create_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, GSList **added_contacts, GError **error) { EBookBackendMAPIContacts *ebmac; EBookBackendMAPIContactsPrivate *priv; EMapiConnection *conn; EMapiCreateitemData mcd; GError *mapi_error = NULL; mapi_id_t mid = 0; mapi_object_t obj_folder; gboolean status; gchar *id; EContact *contact; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (vcards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (added_contacts != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma); e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); priv = ebmac->priv; e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); if (vcards->next) { g_propagate_error (error, EDB_ERROR_EX (NOT_SUPPORTED, _("The backend does not support bulk additions"))); return; } e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { e_book_backend_mapi_unlock_connection (ebma); if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); return; } contact = e_contact_new_from_vcard (vcards->data); if (!contact) { g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); e_book_backend_mapi_unlock_connection (ebma); return; } e_book_backend_mapi_get_db (ebma, &mcd.db); mcd.contact = contact; status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error); if (status) { e_mapi_connection_create_object (conn, &obj_folder, E_MAPI_CREATE_FLAG_NONE, ebbm_contact_to_object, &mcd, &mid, cancellable, &mapi_error); e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error); } e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); e_book_backend_mapi_unlock_connection (ebma); if (!mid) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to create item on a server")); if (mapi_error) g_error_free (mapi_error); g_object_unref (contact); return; } id = e_mapi_util_mapi_id_to_string (mid); /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/ e_contact_set (contact, E_CONTACT_UID, id); e_contact_set (contact, E_CONTACT_BOOK_UID, e_book_backend_mapi_get_book_uid (ebma)); g_free (id); *added_contacts = g_slist_append (NULL, contact); }
static void e_book_backend_vcf_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror) { g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL)); }
static void e_book_backend_vcf_load_source (EBookBackend *backend, ESource *source, gboolean only_if_exists, GError **perror) { EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend); gchar *dirname; gboolean writable = FALSE; gchar *uri; gint fd; uri = e_source_get_uri (source); dirname = e_book_backend_vcf_extract_path_from_uri (uri); bvcf->priv->filename = g_build_filename (dirname, "addressbook.vcf", NULL); fd = g_open (bvcf->priv->filename, O_RDWR | O_BINARY, 0); bvcf->priv->contacts = g_hash_table_new_full ( g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) NULL); if (fd != -1) { writable = TRUE; } else { fd = g_open (bvcf->priv->filename, O_RDONLY | O_BINARY, 0); if (fd == -1 && !only_if_exists) { gint rv; /* the database didn't exist, so we create the directory then the .vcf file */ rv = g_mkdir_with_parents (dirname, 0700); if (rv == -1 && errno != EEXIST) { g_warning ("failed to make directory %s: %s", dirname, g_strerror (errno)); if (errno == EACCES || errno == EPERM) { g_propagate_error (perror, EDB_ERROR (PERMISSION_DENIED)); } else { g_propagate_error (perror, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, "Failed to make directory %s: %s", dirname, g_strerror (errno))); } return; } fd = g_open (bvcf->priv->filename, O_CREAT | O_BINARY, 0666); if (fd != -1) { #ifdef CREATE_DEFAULT_VCARD EContact *contact; contact = do_create (bvcf, XIMIAN_VCARD, FALSE); save_file (bvcf); /* XXX check errors here */ g_object_unref (contact); #endif writable = TRUE; } } } if (fd == -1) { g_warning ("Failed to open addressbook at uri `%s'", uri); g_warning ("error == %s", g_strerror(errno)); g_propagate_error (perror, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, "Failed to open addressbook at uri '%s': %s", uri, g_strerror (errno))); g_free (uri); return; } load_file (bvcf, fd); e_book_backend_set_is_loaded (backend, TRUE); e_book_backend_set_is_writable (backend, writable); g_free (uri); }
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 void ebbm_contacts_remove_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *id_list, GSList **removed_ids, GError **error) { EBookBackendMAPIContacts *ebmac; EBookBackendMAPIContactsPrivate *priv; EMapiConnection *conn; GError *mapi_error = NULL; GSList *to_remove; const GSList *l; mapi_object_t obj_folder; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (id_list != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (removed_ids != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma); e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); priv = ebmac->priv; e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { e_book_backend_mapi_unlock_connection (ebma); if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); return; } to_remove = NULL; for (l = id_list; l; l = l->next) { const gchar *uid = l->data; mapi_id_t *pmid = g_new0 (mapi_id_t, 1); if (e_mapi_util_mapi_id_from_string (uid, pmid)) { to_remove = g_slist_prepend (to_remove, pmid); *removed_ids = g_slist_prepend (*removed_ids, g_strdup (uid)); } else { g_debug ("%s: Failed to decode MID from '%s'", G_STRFUNC, uid); g_free (pmid); } } if (ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error)) { e_mapi_connection_remove_items (conn, &obj_folder, to_remove, cancellable, &mapi_error); e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error); } e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); e_book_backend_mapi_unlock_connection (ebma); if (mapi_error) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL); g_error_free (mapi_error); g_slist_foreach (*removed_ids, (GFunc) g_free, NULL); g_slist_free (*removed_ids); *removed_ids = NULL; } g_slist_foreach (to_remove, (GFunc) g_free, NULL); g_slist_free (to_remove); }
static void e_book_backend_webdav_create_contacts (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *vcards) { EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend); EBookBackendWebdavPrivate *priv = webdav->priv; EContact *contact; gchar *uid; guint status; gchar *status_reason = NULL; const gchar *vcard = (const gchar *) vcards->data; GSList added_contacts = {NULL,}; /* We make the assumption that the vCard list we're passed is always exactly one element long, since we haven't specified "bulk-adds" * in our static capability list. This is because there is no clean way to roll back changes in case of an error. */ if (vcards->next != NULL) { e_data_book_respond_create_contacts ( book, opid, EDB_ERROR_EX (NOT_SUPPORTED, _("The backend does not support bulk additions")), NULL); return; } if (!e_backend_get_online (E_BACKEND (backend))) { e_data_book_respond_create_contacts (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL); return; } /* do 3 rand() calls to construct a unique ID... poor way but should be * good enough for us */ uid = g_strdup_printf ( "%s%08X-%08X-%08X.vcf", priv->uri, rand (), rand (), rand ()); contact = e_contact_new_from_vcard_with_uid (vcard, uid); /* kill revision field (might have been set by some other backend) */ e_contact_set (contact, E_CONTACT_REV, NULL); status = upload_contact (webdav, contact, &status_reason, cancellable); if (status != 201 && status != 204) { g_object_unref (contact); if (status == 401 || status == 407) { e_data_book_respond_create_contacts (book, opid, webdav_handle_auth_request (webdav), NULL); } else { e_data_book_respond_create_contacts ( book, opid, e_data_book_create_error_fmt ( E_DATA_BOOK_STATUS_OTHER_ERROR, _("Create resource '%s' failed with HTTP status: %d (%s)"), uid, status, status_reason), NULL); } g_free (uid); g_free (status_reason); return; } g_free (status_reason); /* PUT request didn't return an etag? try downloading to get one */ if (e_contact_get_const (contact, E_CONTACT_REV) == NULL) { const gchar *new_uid; EContact *new_contact; g_warning ("Server didn't return etag for new address resource"); new_uid = e_contact_get_const (contact, E_CONTACT_UID); new_contact = download_contact (webdav, new_uid, cancellable); g_object_unref (contact); if (new_contact == NULL) { e_data_book_respond_create_contacts ( book, opid, EDB_ERROR (OTHER_ERROR), NULL); g_free (uid); return; } contact = new_contact; } g_mutex_lock (&priv->cache_lock); e_book_backend_cache_add_contact (priv->cache, contact); g_mutex_unlock (&priv->cache_lock); added_contacts.data = contact; e_data_book_respond_create_contacts (book, opid, EDB_ERROR (SUCCESS), &added_contacts); g_object_unref (contact); g_free (uid); }
static void ebbm_contacts_modify_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, GSList **modified_contacts, GError **error) { EBookBackendMAPIContacts *ebmac; EBookBackendMAPIContactsPrivate *priv; EMapiConnection *conn; EMapiCreateitemData mcd; EContact *contact; GError *mapi_error = NULL; mapi_id_t mid; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (vcards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (modified_contacts != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma); e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); priv = ebmac->priv; e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); if (vcards->next != NULL) { g_propagate_error (error, EDB_ERROR_EX (NOT_SUPPORTED, _("The backend does not support bulk modifications"))); return; } e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { e_book_backend_mapi_unlock_connection (ebma); if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); return; } contact = e_contact_new_from_vcard (vcards->data); if (!contact) { g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); e_book_backend_mapi_unlock_connection (ebma); return; } e_book_backend_mapi_get_db (ebma, &mcd.db); mcd.contact = contact; if (e_mapi_util_mapi_id_from_string (e_contact_get_const (contact, E_CONTACT_UID), &mid)) { mapi_object_t obj_folder; gboolean status; status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error); if (status) { status = e_mapi_connection_modify_object (conn, &obj_folder, mid, ebbm_contact_to_object, &mcd, cancellable, &mapi_error); e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error); } e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); if (!status) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to modify item on a server")); if (mapi_error) g_error_free (mapi_error); g_object_unref (contact); } else { *modified_contacts = g_slist_append (NULL, contact); } } else { g_debug ("%s: Failed to decode MID from '%s'", G_STRFUNC, (const gchar *) e_contact_get_const (contact, E_CONTACT_UID)); } e_book_backend_mapi_unlock_connection (ebma); }
static void e_book_backend_webdav_modify_contacts (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *vcards) { EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend); EBookBackendWebdavPrivate *priv = webdav->priv; EContact *contact; GSList modified_contacts = {NULL,}; const gchar *uid; const gchar *etag; guint status; gchar *status_reason = NULL; const gchar *vcard = vcards->data; if (!e_backend_get_online (E_BACKEND (backend))) { e_data_book_respond_create_contacts ( book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL); return; } /* We make the assumption that the vCard list we're passed is always exactly one element long, since we haven't specified "bulk-modifies" * in our static capability list. This is because there is no clean way to roll back changes in case of an error. */ if (vcards->next != NULL) { e_data_book_respond_modify_contacts ( book, opid, EDB_ERROR_EX ( NOT_SUPPORTED, _("The backend does not support bulk modifications")), NULL); return; } /* modify contact */ contact = e_contact_new_from_vcard (vcard); status = upload_contact (webdav, contact, &status_reason, cancellable); if (status != 201 && status != 204) { g_object_unref (contact); if (status == 401 || status == 407) { e_data_book_respond_modify_contacts (book, opid, webdav_handle_auth_request (webdav), NULL); g_free (status_reason); return; } /* data changed on server while we were editing */ if (status == 412) { /* too bad no special error code in evolution for this... */ e_data_book_respond_modify_contacts (book, opid, e_data_book_create_error_fmt ( E_DATA_BOOK_STATUS_OTHER_ERROR, _("Contact on server changed -> not modifying")), NULL); g_free (status_reason); return; } e_data_book_respond_modify_contacts (book, opid, e_data_book_create_error_fmt ( E_DATA_BOOK_STATUS_OTHER_ERROR, _("Modify contact failed with HTTP status: %d (%s)"), status, status_reason), NULL); g_free (status_reason); return; } g_free (status_reason); uid = e_contact_get_const (contact, E_CONTACT_UID); g_mutex_lock (&priv->cache_lock); e_book_backend_cache_remove_contact (priv->cache, uid); etag = e_contact_get_const (contact, E_CONTACT_REV); /* PUT request didn't return an etag? try downloading to get one */ if (etag == NULL || (etag[0] == 'W' && etag[1] == '/')) { EContact *new_contact; g_warning ("Server didn't return etag for modified address resource"); new_contact = download_contact (webdav, uid, cancellable); if (new_contact != NULL) { contact = new_contact; } } e_book_backend_cache_add_contact (priv->cache, contact); g_mutex_unlock (&priv->cache_lock); modified_contacts.data = contact; e_data_book_respond_modify_contacts (book, opid, EDB_ERROR (SUCCESS), &modified_contacts); g_object_unref (contact); }
static void ebbm_contacts_get_contact (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *id, gchar **vcard, GError **error) { EBookBackendMAPIContacts *ebmac; EBookBackendMAPIContactsPrivate *priv; EMapiConnection *conn; mapi_id_t mid; mapi_object_t obj_folder; struct TransferContactData tc = { 0 }; gboolean status, has_obj_folder; GError *mapi_error = NULL; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (id != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (vcard != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma); e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); priv = ebmac->priv; e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact) E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact (ebma, cancellable, id, vcard, &mapi_error); if (mapi_error) { g_propagate_error (error, mapi_error); return; } /* found in a cache */ if (*vcard) return; e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { e_book_backend_mapi_unlock_connection (ebma); if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); return; } status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error); has_obj_folder = status; if (status) { status = e_mapi_util_mapi_id_from_string (id, &mid); if (!status) { g_debug ("%s: Failed to decode MID from '%s'", G_STRFUNC, id); } } if (status) { tc.ebma = ebma; tc.contact = NULL; e_mapi_connection_transfer_object (conn, &obj_folder, mid, transfer_contact_cb, &tc, cancellable, &mapi_error); } if (has_obj_folder) e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error); if (tc.contact) { *vcard = e_vcard_to_string (E_VCARD (tc.contact), EVC_FORMAT_VCARD_30); g_object_unref (tc.contact); } else { e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); if (!mapi_error || mapi_error->code == MAPI_E_NOT_FOUND) { g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND)); } else { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND, NULL); } if (mapi_error) g_error_free (mapi_error); } e_book_backend_mapi_unlock_connection (ebma); }
static GError * download_contacts (EBookBackendWebdav *webdav, EFlag *running, EDataBookView *book_view, GCancellable *cancellable) { EBookBackendWebdavPrivate *priv = webdav->priv; EBookBackend *book_backend; SoupMessage *message; guint status; xmlTextReaderPtr reader; response_element_t *elements; response_element_t *element; response_element_t *next; gint count; gint i; gchar *new_ctag = NULL; g_mutex_lock (&priv->update_lock); if (!check_addressbook_changed (webdav, &new_ctag, cancellable)) { g_free (new_ctag); g_mutex_unlock (&priv->update_lock); return EDB_ERROR (SUCCESS); } book_backend = E_BOOK_BACKEND (webdav); if (book_view != NULL) { e_data_book_view_notify_progress (book_view, -1, _("Loading Addressbook summary...")); } message = send_propfind (webdav, cancellable); status = message->status_code; if (status == 401 || status == 407) { g_object_unref (message); g_free (new_ctag); if (book_view) e_data_book_view_notify_progress (book_view, -1, NULL); g_mutex_unlock (&priv->update_lock); return webdav_handle_auth_request (webdav); } if (status != 207) { GError *error; error = e_data_book_create_error_fmt ( E_DATA_BOOK_STATUS_OTHER_ERROR, _("PROPFIND on webdav failed with HTTP status %d (%s)"), status, 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 (new_ctag); if (book_view) e_data_book_view_notify_progress (book_view, -1, NULL); g_mutex_unlock (&priv->update_lock); return error; } if (message->response_body == NULL) { g_warning ("No response body in webdav PROPFIND result"); g_object_unref (message); g_free (new_ctag); if (book_view) e_data_book_view_notify_progress (book_view, -1, NULL); g_mutex_unlock (&priv->update_lock); return e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, _("No response body in webdav PROPFIND result")); } /* parse response */ reader = xmlReaderForMemory ( message->response_body->data, message->response_body->length, NULL, NULL, XML_PARSE_NOWARNING); elements = parse_propfind_response (reader); /* count contacts */ count = 0; for (element = elements; element != NULL; element = element->next) { ++count; } /* download contacts */ i = 0; for (element = elements; element != NULL; element = element->next, ++i) { const gchar *uri; const gchar *etag; EContact *contact; gchar *complete_uri; /* stop downloading if search was aborted */ if (running != NULL && !e_flag_is_set (running)) break; if (book_view != NULL) { gfloat percent = 100.0 / count * i; gchar buf[100]; snprintf (buf, sizeof (buf), _("Loading Contacts (%d%%)"), (gint) percent); e_data_book_view_notify_progress (book_view, -1, buf); } /* skip collections */ uri = (const gchar *) element->href; if (uri[strlen (uri) - 1] == '/') continue; /* uri might be relative, construct complete one */ if (uri[0] == '/') { SoupURI *soup_uri = soup_uri_new (priv->uri); soup_uri->path = g_strdup (uri); complete_uri = soup_uri_to_string (soup_uri, 0); soup_uri_free (soup_uri); } else { complete_uri = g_strdup (uri); } etag = (const gchar *) element->etag; g_mutex_lock (&priv->cache_lock); contact = e_book_backend_cache_get_contact (priv->cache, complete_uri); g_mutex_unlock (&priv->cache_lock); /* download contact if it is not cached or its ETag changed */ if (contact == NULL || etag == NULL || strcmp (e_contact_get_const (contact, E_CONTACT_REV), etag) != 0) { contact = download_contact (webdav, complete_uri, cancellable); if (contact != NULL) { g_mutex_lock (&priv->cache_lock); if (e_book_backend_cache_remove_contact (priv->cache, complete_uri)) e_book_backend_notify_remove (book_backend, complete_uri); e_book_backend_cache_add_contact (priv->cache, contact); g_mutex_unlock (&priv->cache_lock); e_book_backend_notify_update (book_backend, contact); } } g_free (complete_uri); } /* free element list */ for (element = elements; element != NULL; element = next) { next = element->next; xmlFree (element->href); xmlFree (element->etag); g_free (element); } xmlFreeTextReader (reader); g_object_unref (message); if (new_ctag) { g_mutex_lock (&priv->cache_lock); if (!e_file_cache_replace_object (E_FILE_CACHE (priv->cache), WEBDAV_CTAG_KEY, new_ctag)) e_file_cache_add_object (E_FILE_CACHE (priv->cache), WEBDAV_CTAG_KEY, new_ctag); g_mutex_unlock (&priv->cache_lock); } g_free (new_ctag); if (book_view) e_data_book_view_notify_progress (book_view, -1, NULL); g_mutex_unlock (&priv->update_lock); return EDB_ERROR (SUCCESS); }
static void ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *query, GSList **vCards, GError **error) { EBookBackendMAPIContacts *ebmac; EBookBackendMAPIContactsPrivate *priv; EMapiConnection *conn; GError *mapi_error = NULL; gboolean status; mapi_object_t obj_folder; GSList *mids = NULL; struct TransferContactsData tcd = { 0 }; e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (query != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); e_mapi_return_data_book_error_if_fail (vCards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma); e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); priv = ebmac->priv; e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG); if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact_list) E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact_list (ebma, cancellable, query, vCards, &mapi_error); if (mapi_error) { g_propagate_error (error, mapi_error); return; } /* found some in cache, thus use them */ if (*vCards) return; e_book_backend_mapi_lock_connection (ebma); conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error); if (!conn) { e_book_backend_mapi_unlock_connection (ebma); if (!mapi_error) g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE)); else mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL); g_clear_error (&mapi_error); return; } tcd.ebma = ebma; tcd.cards = vCards; status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error); if (status) { status = e_mapi_connection_list_objects (conn, &obj_folder, e_mapi_book_utils_build_sexp_restriction, (gpointer) query, gather_contact_mids_cb, &mids, cancellable, &mapi_error); if (mids) status = e_mapi_connection_transfer_objects (conn, &obj_folder, mids, transfer_contacts_cb, &tcd, cancellable, &mapi_error); e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error); g_slist_free_full (mids, g_free); } e_book_backend_mapi_maybe_disconnect (ebma, mapi_error); if (!status) { mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server")); if (mapi_error) g_error_free (mapi_error); } e_book_backend_mapi_unlock_connection (ebma); }