[evolution-mapi] Implement fast-transfer for address book backend
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-mapi] Implement fast-transfer for address book backend
- Date: Tue, 22 Nov 2011 14:41:32 +0000 (UTC)
commit 9843a63eb02f4da54c21e20f4d1db4d3e220d8df
Author: Milan Crha <mcrha redhat com>
Date: Tue Nov 22 15:40:45 2011 +0100
Implement fast-transfer for address book backend
src/addressbook/e-book-backend-mapi-contacts.c | 438 ++++++++++++++++--------
src/addressbook/e-book-backend-mapi-gal.c | 102 ++++---
src/addressbook/e-book-backend-mapi.c | 354 +++++++++-----------
src/addressbook/e-book-backend-mapi.h | 32 ++-
src/libexchangemapi/e-mapi-utils.c | 20 --
src/libexchangemapi/e-mapi-utils.h | 5 +-
6 files changed, 524 insertions(+), 427 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-mapi-contacts.c b/src/addressbook/e-book-backend-mapi-contacts.c
index ddac53c..4f0df9e 100644
--- a/src/addressbook/e-book-backend-mapi-contacts.c
+++ b/src/addressbook/e-book-backend-mapi-contacts.c
@@ -555,137 +555,152 @@ struct FetchContactItemData
};
static gboolean
-fetch_contact_item_cb (FetchItemsCallbackData *item_data,
- gpointer data,
- GCancellable *cancellable,
- GError **perror)
+transfer_contact_cb (EMapiConnection *conn,
+ TALLOC_CTX *mem_ctx,
+ /* const */ EMapiObject *object,
+ guint32 obj_index,
+ guint32 obj_total,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
{
- struct FetchContactItemData *fcid = data;
+ struct FetchContactItemData *fcid = user_data;
- g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (fcid != NULL, FALSE);
g_return_val_if_fail (fcid->ebma != NULL, FALSE);
+ g_return_val_if_fail (object != NULL, FALSE);
- fcid->contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (fcid->ebma), item_data->properties, NULL);
+ fcid->contact = mapi_book_utils_contact_from_props (conn, E_BOOK_BACKEND_MAPI_CONTACTS (fcid->ebma)->priv->fid, e_book_backend_mapi_get_book_uri (fcid->ebma), &object->properties, NULL);
if (fcid->contact) {
- gchar *suid = e_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+ const mapi_id_t *pmid;
+
+ pmid = e_mapi_util_find_array_propval (&object->properties, PidTagMid);
+ if (pmid) {
+ gchar *suid = e_mapi_util_mapi_id_to_string (*pmid);
- /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
- e_contact_set (fcid->contact, E_CONTACT_UID, suid);
+ /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+ e_contact_set (fcid->contact, E_CONTACT_UID, suid);
+
+ if (!e_book_backend_mapi_notify_contact_update (fcid->ebma, NULL, fcid->contact, obj_index, obj_total, NULL)) {
+ g_free (suid);
+ return FALSE;
+ }
- if (!e_book_backend_mapi_notify_contact_update (fcid->ebma, NULL, fcid->contact, NULL, item_data->index, item_data->total, NULL)) {
g_free (suid);
- return FALSE;
+ } else {
+ g_debug ("%s: No PidTagMid found", G_STRFUNC);
}
-
- g_free (suid);
}
return TRUE;
}
-struct CreateContactListData
-{
- EBookBackendMAPI *ebma;
- GSList **vCards;
-};
-
static gboolean
-create_contact_list_cb (FetchItemsCallbackData *item_data,
- gpointer data,
+gather_contact_mids_cb (EMapiConnection *conn,
+ mapi_id_t fid,
+ TALLOC_CTX *mem_ctx,
+ const ListObjectsData *object_data,
+ guint32 obj_index,
+ guint32 obj_total,
+ gpointer user_data,
GCancellable *cancellable,
GError **perror)
{
- struct CreateContactListData *ccld = data;
- EContact *contact;
-
- g_return_val_if_fail (data != NULL, FALSE);
- g_return_val_if_fail (ccld->ebma != NULL, FALSE);
- g_return_val_if_fail (ccld->vCards != NULL, FALSE);
-
- contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (ccld->ebma), item_data->properties, NULL);
- if (contact) {
- gchar *suid = e_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
-
- e_contact_set (contact, E_CONTACT_UID, suid);
+ GSList *pmids = user_data;
+ mapi_id_t *pmid;
- *ccld->vCards = g_slist_prepend (*ccld->vCards, e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30));
+ g_return_val_if_fail (object_data != NULL, FALSE);
+ g_return_val_if_fail (pmids != NULL, FALSE);
- e_book_backend_mapi_notify_contact_update (ccld->ebma, NULL, contact, NULL, -1, -1, NULL);
+ pmid = g_new0 (mapi_id_t, 1);
+ *pmid = object_data->mid;
- g_object_unref (contact);
- g_free (suid);
- }
+ pmids = g_slist_prepend (pmids, pmid);
return TRUE;
}
-struct FetchContactsData
+struct TransferContactsData
{
EBookBackendMAPI *ebma;
EDataBookView *book_view;
gpointer notify_contact_data;
+ GSList **cards;
};
static gboolean
-fetch_contacts_cb (FetchItemsCallbackData *item_data,
- gpointer data,
- GCancellable *cancellable,
- GError **perror)
+transfer_contacts_cb (EMapiConnection *conn,
+ TALLOC_CTX *mem_ctx,
+ /* const */ EMapiObject *object,
+ guint32 obj_index,
+ guint32 obj_total,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
{
- struct FetchContactsData *fcd = data;
+ struct TransferContactsData *tcd = user_data;
EContact *contact;
- g_return_val_if_fail (data != NULL, FALSE);
- g_return_val_if_fail (fcd->ebma != NULL, FALSE);
- g_return_val_if_fail (fcd->ebma->priv != NULL, FALSE);
-
- contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (fcd->ebma), item_data->properties, NULL);
+ g_return_val_if_fail (tcd != NULL, FALSE);
+ g_return_val_if_fail (object != NULL, FALSE);
+ g_return_val_if_fail (tcd->ebma != NULL, FALSE);
+ contact = mapi_book_utils_contact_from_props (conn, E_BOOK_BACKEND_MAPI_CONTACTS (tcd->ebma)->priv->fid, e_book_backend_mapi_get_book_uri (tcd->ebma), &object->properties, NULL);
if (contact) {
- gchar *suid;
- struct timeval *last_modification = NULL, tv = { 0 };
+ const mapi_id_t *pmid;
+
+ pmid = e_mapi_util_find_array_propval (&object->properties, PidTagMid);
+ if (pmid) {
+ gchar *suid = e_mapi_util_mapi_id_to_string (*pmid);
+
+ e_contact_set (contact, E_CONTACT_UID, suid);
+ g_free (suid);
- suid = e_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
- e_contact_set (contact, E_CONTACT_UID, suid);
- g_free (suid);
+ if (tcd->cards)
+ *tcd->cards = g_slist_prepend (*tcd->cards, e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30));
- if (get_mapi_SPropValue_array_date_timeval (&tv, item_data->properties, PR_LAST_MODIFICATION_TIME) == MAPI_E_SUCCESS)
- last_modification = &tv;
+ if (!e_book_backend_mapi_notify_contact_update (tcd->ebma, tcd->book_view, contact, obj_index, obj_total, tcd->notify_contact_data)) {
+ g_object_unref (contact);
+ return FALSE;
+ }
- if (!e_book_backend_mapi_notify_contact_update (fcd->ebma, fcd->book_view, contact, last_modification, item_data->index, item_data->total, fcd->notify_contact_data)) {
g_object_unref (contact);
- return FALSE;
+ } else {
+ g_debug ("%s: No PidTagMid found", G_STRFUNC);
}
-
- g_object_unref (contact);
+ } else {
+ g_debug ("%s: [%d/%d] Failed to transform to contact", G_STRFUNC, obj_index, obj_total);
}
return TRUE;
}
-struct FetchContactsUidsData
-{
- GCancellable *cancellable;
- GHashTable *uids;
-};
-
static gboolean
-fetch_contacts_uids_cb (FetchItemsCallbackData *item_data,
- gpointer data,
- GCancellable *cancellable,
- GError **perror)
+gather_known_uids_cb (EMapiConnection *conn,
+ mapi_id_t fid,
+ TALLOC_CTX *mem_ctx,
+ const ListObjectsData *object_data,
+ guint32 obj_index,
+ guint32 obj_total,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
{
- struct FetchContactsUidsData *fcud = data;
+ struct ListKnownUidsData *lku = user_data;
gchar *suid;
- g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (lku != NULL, FALSE);
+ g_return_val_if_fail (lku->uid_to_rev != NULL, FALSE);
- suid = e_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
- if (suid)
- g_hash_table_insert (fcud->uids, suid, GINT_TO_POINTER (1));
+ suid = e_mapi_util_mapi_id_to_string (object_data->mid);
+ if (suid) {
+ g_hash_table_insert (lku->uid_to_rev, suid, mapi_book_utils_timet_to_string (object_data->last_modified));
+ if (lku->latest_last_modify < object_data->last_modified)
+ lku->latest_last_modify = object_data->last_modified;
+ }
- return !g_cancellable_is_cancelled (fcud->cancellable);
+ return TRUE;
}
static void
@@ -825,7 +840,7 @@ ebbm_contacts_create_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
return;
}
- id = e_mapi_util_mapi_ids_to_uid (priv->fid, mid);
+ 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);
@@ -868,16 +883,18 @@ ebbm_contacts_remove_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
to_remove = NULL;
for (l = id_list; l; l = l->next) {
- mapi_id_t mid, fid;
+ mapi_id_t mid;
const gchar *uid = l->data;
struct id_list *idl = g_new0 (struct id_list, 1);
- e_mapi_util_mapi_ids_from_uid (uid, &fid, &mid);
-
- idl->id = mid;
- to_remove = g_slist_prepend (to_remove, idl);
+ if (e_mapi_util_mapi_id_from_string (uid, &mid)) {
+ idl->id = mid;
+ to_remove = g_slist_prepend (to_remove, idl);
- *removed_ids = g_slist_prepend (*removed_ids, g_strdup (uid));
+ *removed_ids = g_slist_prepend (*removed_ids, g_strdup (uid));
+ } else {
+ g_debug ("%s: Failed to decode MID from '%s'", G_STRFUNC, uid);
+ }
}
e_mapi_connection_remove_items (conn, olFolderContacts, priv->fid, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, to_remove, cancellable, &mapi_error);
@@ -907,7 +924,7 @@ ebbm_contacts_modify_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
MapiCreateitemData mcd;
EContact *contact;
GError *mapi_error = NULL;
- mapi_id_t fid, mid;
+ mapi_id_t mid;
e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
@@ -944,18 +961,20 @@ ebbm_contacts_modify_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
e_book_backend_mapi_get_db (ebma, &mcd.db);
mcd.contact = contact;
- e_mapi_util_mapi_ids_from_uid (e_contact_get_const (contact, E_CONTACT_UID), &fid, &mid);
-
- if (!e_mapi_connection_modify_item (conn, olFolderContacts, priv->fid, mid,
- mapi_book_write_props, &mcd, NULL, NULL, NULL, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, cancellable, &mapi_error)) {
+ if (e_mapi_util_mapi_id_from_string (e_contact_get_const (contact, E_CONTACT_UID), &mid)) {
+ if (!e_mapi_connection_modify_item (conn, olFolderContacts, priv->fid, mid,
+ mapi_book_write_props, &mcd, NULL, NULL, NULL, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, cancellable, &mapi_error)) {
- 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);
+ 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);
+ g_object_unref (contact);
+ } else {
+ *modified_contacts = g_slist_append (NULL, contact);
+ }
} else {
- *modified_contacts = g_slist_append (NULL, contact);
+ 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);
@@ -967,9 +986,10 @@ ebbm_contacts_get_contact (EBookBackendMAPI *ebma, GCancellable *cancellable, co
EBookBackendMAPIContacts *ebmac;
EBookBackendMAPIContactsPrivate *priv;
EMapiConnection *conn;
- mapi_id_t fid, mid;
- guint32 options;
+ mapi_id_t mid;
+ mapi_object_t obj_folder;
struct FetchContactItemData fcid = { 0 };
+ gboolean status;
GError *mapi_error = NULL;
e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
@@ -1004,18 +1024,26 @@ ebbm_contacts_get_contact (EBookBackendMAPI *ebma, GCancellable *cancellable, co
return;
}
- options = MAPI_OPTIONS_FETCH_ALL;
if (priv->is_public_folder)
- options |= MAPI_OPTIONS_USE_PFSTORE;
+ status = e_mapi_connection_open_public_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
+ else
+ status = e_mapi_connection_open_personal_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
+
+ 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);
+ }
+ }
- fcid.ebma = ebma;
- fcid.contact = NULL;
- e_mapi_util_mapi_ids_from_uid (id, &fid, &mid);
+ if (status) {
+ fcid.ebma = ebma;
+ fcid.contact = NULL;
- e_mapi_connection_fetch_item (conn, priv->fid, mid,
- priv->is_public_folder ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- fetch_contact_item_cb, &fcid,
- options, cancellable, &mapi_error);
+ e_mapi_connection_transfer_object (conn, &obj_folder, mid, transfer_contact_cb, &fcid, cancellable, &mapi_error);
+ }
+
+ e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
if (fcid.contact) {
*vcard = e_vcard_to_string (E_VCARD (fcid.contact), EVC_FORMAT_VCARD_30);
@@ -1040,10 +1068,11 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
EBookBackendMAPIContacts *ebmac;
EBookBackendMAPIContactsPrivate *priv;
EMapiConnection *conn;
- guint32 options;
- struct CreateContactListData ccld = { 0 };
GError *mapi_error = NULL;
- gboolean get_all;
+ gboolean get_all, status;
+ mapi_object_t obj_folder;
+ GSList *mids = NULL;
+ struct TransferContactsData tcd = { 0 };
e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
@@ -1068,10 +1097,6 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
if (*vCards)
return;
- options = MAPI_OPTIONS_FETCH_ALL;
- if (priv->is_public_folder)
- options |= MAPI_OPTIONS_USE_PFSTORE;
-
e_book_backend_mapi_lock_connection (ebma);
conn = e_book_backend_mapi_get_connection (ebma);
@@ -1082,8 +1107,8 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
return;
}
- ccld.ebma = ebma;
- ccld.vCards = vCards;
+ tcd.ebma = ebma;
+ tcd.cards = vCards;
get_all = g_ascii_strcasecmp (query, "(contains \"x-evolution-any-field\" \"\")") == 0;
if (!get_all && !build_restriction_emails_contains (NULL, 0, NULL, NULL, (gpointer) query, NULL, NULL)) {
@@ -1093,9 +1118,26 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
return;
}
- if (!e_mapi_connection_fetch_items (conn, priv->fid, get_all ? NULL : build_restriction_emails_contains, (gpointer) query, NULL,
- priv->is_public_folder ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- create_contact_list_cb, &ccld, options, cancellable, &mapi_error)) {
+ if (priv->is_public_folder)
+ status = e_mapi_connection_open_public_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
+ else
+ status = e_mapi_connection_open_personal_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
+
+ if (status) {
+ status = e_mapi_connection_list_objects (conn, &obj_folder,
+ get_all ? NULL : build_restriction_emails_contains, (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);
+ }
+
+ 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);
@@ -1123,23 +1165,26 @@ ebbm_contacts_get_status_message (EBookBackendMAPI *ebma, gint index, gint total
}
static void
-ebbm_contacts_fetch_contacts (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb, gpointer build_rs_cb_data, EDataBookView *book_view, gpointer notify_contact_data, GError **error)
+ebbm_contacts_get_contacts_count (EBookBackendMAPI *ebma,
+ guint32 *obj_total,
+ GCancellable *cancellable,
+ GError **error)
{
EBookBackendMAPIContacts *ebmac;
EBookBackendMAPIContactsPrivate *priv;
EMapiConnection *conn;
- guint32 options;
- struct FetchContactsData fcd = { 0 };
+ gboolean status;
+ mapi_object_t obj_folder;
GError *mapi_error = NULL;
e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
- e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (obj_total != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (ebmac->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
priv = ebmac->priv;
- e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
e_book_backend_mapi_lock_connection (ebma);
@@ -1147,44 +1192,53 @@ ebbm_contacts_fetch_contacts (EBookBackendMAPI *ebma, BuildRestrictionsCB build_
if (!conn) {
e_book_backend_mapi_unlock_connection (ebma);
g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
-
return;
}
- fcd.ebma = ebma;
- fcd.book_view = book_view;
- fcd.notify_contact_data = notify_contact_data;
-
- options = MAPI_OPTIONS_FETCH_ALL;
if (priv->is_public_folder)
- options |= MAPI_OPTIONS_USE_PFSTORE;
-
- if (!e_mapi_connection_fetch_items (conn, priv->fid, build_rs_cb, build_rs_cb_data, NULL,
- mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- fetch_contacts_cb, &fcd, options, NULL, &mapi_error)) {
- mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
+ status = e_mapi_connection_open_public_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
+ else
+ status = e_mapi_connection_open_personal_folder (conn, priv->fid, &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);
+ }
- if (mapi_error)
- g_error_free (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
-ebbm_contacts_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancellable, GHashTable *uids, GError **error)
+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;
EBookBackendMAPIContactsPrivate *priv;
EMapiConnection *conn;
+ gboolean status;
+ mapi_object_t obj_folder;
GError *mapi_error = NULL;
- struct FetchContactsUidsData fcud = { 0 };
- guint32 options;
e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
- e_return_data_book_error_if_fail (cancellable != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
- e_return_data_book_error_if_fail (uids != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (lku != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_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_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
@@ -1201,19 +1255,21 @@ ebbm_contacts_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancellabl
return;
}
- options = MAPI_OPTIONS_DONT_OPEN_MESSAGE;
if (priv->is_public_folder)
- options |= MAPI_OPTIONS_USE_PFSTORE;
+ status = e_mapi_connection_open_public_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
+ else
+ status = e_mapi_connection_open_personal_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
- fcud.cancellable = cancellable;
- fcud.uids = uids;
+ 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_fetch_items (conn, priv->fid, NULL, NULL, NULL,
- mapi_book_utils_get_prop_list, GET_UIDS_ONLY,
- fetch_contacts_uids_cb, &fcud, options, cancellable, &mapi_error);
+ e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
+ }
if (mapi_error) {
- mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
+ 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);
}
@@ -1221,6 +1277,85 @@ ebbm_contacts_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancellabl
}
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_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_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_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebmac->priv;
+ e_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);
+ if (!conn) {
+ e_book_backend_mapi_unlock_connection (ebma);
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+ return;
+ }
+
+ tcd.ebma = ebma;
+ tcd.book_view = book_view;
+ tcd.notify_contact_data = notify_contact_data;
+
+ if (priv->is_public_folder)
+ status = e_mapi_connection_open_public_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
+ else
+ status = e_mapi_connection_open_personal_folder (conn, priv->fid, &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);
+ }
+
+ 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
e_book_backend_mapi_contacts_init (EBookBackendMAPIContacts *backend)
{
backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContactsPrivate);
@@ -1246,8 +1381,9 @@ e_book_backend_mapi_contacts_class_init (EBookBackendMAPIContactsClass *klass)
parent_class->op_connection_status_changed = ebbm_contacts_connection_status_changed;
parent_class->op_get_status_message = ebbm_contacts_get_status_message;
- parent_class->op_fetch_contacts = ebbm_contacts_fetch_contacts;
- parent_class->op_fetch_known_uids = ebbm_contacts_fetch_known_uids;
+ parent_class->op_get_contacts_count = ebbm_contacts_get_contacts_count;
+ parent_class->op_list_known_uids = ebbm_contacts_list_known_uids;
+ parent_class->op_transfer_contacts = ebbm_contacts_transfer_contacts;
}
EBookBackend *
diff --git a/src/addressbook/e-book-backend-mapi-gal.c b/src/addressbook/e-book-backend-mapi-gal.c
index bf37fab..da4ac39 100644
--- a/src/addressbook/e-book-backend-mapi-gal.c
+++ b/src/addressbook/e-book-backend-mapi-gal.c
@@ -32,7 +32,7 @@ struct _EBookBackendMAPIGALPrivate
};
static gchar *
-get_uid_from_row (struct SRow *aRow, uint32_t row_index, mapi_id_t fid)
+get_uid_from_row (struct SRow *aRow, uint32_t row_index)
{
gchar *suid = NULL;
const gchar *str;
@@ -48,7 +48,7 @@ get_uid_from_row (struct SRow *aRow, uint32_t row_index, mapi_id_t fid)
midptr = e_mapi_util_find_row_propval (aRow, PR_MID);
- suid = e_mapi_util_mapi_ids_to_uid (fid, midptr ? *midptr : row_index);
+ suid = e_mapi_util_mapi_id_to_string (midptr ? *midptr : row_index);
}
return suid;
@@ -72,8 +72,6 @@ fetch_gal_cb (EMapiConnection *conn,
GError **perror)
{
struct FetchGalData *fgd = data;
- struct timeval *last_modification = NULL, tv = { 0 };
- struct SPropValue *spropval;
EContact *contact;
g_return_val_if_fail (conn != NULL, FALSE);
@@ -89,16 +87,12 @@ fetch_gal_cb (EMapiConnection *conn,
if (!e_contact_get_const (contact, E_CONTACT_UID)) {
gchar *suid;
- suid = get_uid_from_row (aRow, row_index, fgd->fid);
+ suid = get_uid_from_row (aRow, row_index);
e_contact_set (contact, E_CONTACT_UID, suid);
g_free (suid);
}
- spropval = get_SPropValue_SRow (aRow, PR_LAST_MODIFICATION_TIME);
- if (spropval && get_mapi_SPropValue_date_timeval (&tv, *spropval) == MAPI_E_SUCCESS)
- last_modification = &tv;
-
- if (!e_book_backend_mapi_notify_contact_update (fgd->ebma, fgd->book_view, contact, last_modification, row_index, n_rows, fgd->notify_contact_data)) {
+ if (!e_book_backend_mapi_notify_contact_update (fgd->ebma, fgd->book_view, contact, row_index, n_rows, fgd->notify_contact_data)) {
g_object_unref (contact);
return FALSE;
}
@@ -108,34 +102,37 @@ fetch_gal_cb (EMapiConnection *conn,
return TRUE;
}
-struct FetchGalUidsData
-{
- GCancellable *cancellable;
- GHashTable *uids;
- mapi_id_t fid; /* folder ID of contacts */
-};
-
static gboolean
-fetch_gal_uids_cb (EMapiConnection *conn,
- uint32_t row_index,
- uint32_t n_rows,
- struct SRow *aRow,
- gpointer data,
- GCancellable *cancellable,
- GError **perror)
+list_gal_uids_cb (EMapiConnection *conn,
+ uint32_t row_index,
+ uint32_t n_rows,
+ struct SRow *aRow,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
{
gchar *uid;
- struct FetchGalUidsData *fgud = data;
+ struct ListKnownUidsData *lku = user_data;
g_return_val_if_fail (conn != NULL, FALSE);
g_return_val_if_fail (aRow != NULL, FALSE);
- g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (lku != NULL, FALSE);
+
+ uid = get_uid_from_row (aRow, row_index);
+ if (uid) {
+ const struct FILETIME *ft;
+ time_t tt;
- uid = get_uid_from_row (aRow, row_index, fgud->fid);
- if (uid)
- g_hash_table_insert (fgud->uids, uid, GINT_TO_POINTER (1));
+ ft = e_mapi_util_find_row_propval (aRow, PidTagLastModificationTime);
+ tt = ft ? e_mapi_util_filetime_to_time_t (ft) : 1;
- return !g_cancellable_is_cancelled (fgud->cancellable);
+ if (lku->latest_last_modify < tt)
+ lku->latest_last_modify = tt;
+
+ g_hash_table_insert (lku->uid_to_rev, uid, mapi_book_utils_timet_to_string (tt));
+ }
+
+ return !g_cancellable_is_cancelled (cancellable);
}
static void
@@ -175,7 +172,12 @@ ebbm_gal_get_status_message (EBookBackendMAPI *ebma, gint index, gint total)
}
static void
-ebbm_gal_fetch_contacts (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb, gpointer build_rs_cb_data, EDataBookView *book_view, gpointer notify_contact_data, GError **error)
+ebbm_gal_transfer_contacts (EBookBackendMAPI *ebma,
+ const GSList *uids,
+ EDataBookView *book_view,
+ gpointer notify_contact_data,
+ GCancellable *cancellable,
+ GError **error)
{
GError *mapi_error = NULL;
struct FetchGalData fgd = { 0 };
@@ -215,7 +217,7 @@ ebbm_gal_fetch_contacts (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb
fgd.notify_contact_data = notify_contact_data;
fgd.fid = e_mapi_connection_get_default_folder_id (conn, olFolderContacts, NULL, NULL);
- fetch_successful = e_mapi_connection_fetch_gal (conn, build_rs_cb, build_rs_cb_data,
+ fetch_successful = e_mapi_connection_fetch_gal (conn, NULL, NULL,
mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
fetch_gal_cb, &fgd, NULL, &mapi_error);
@@ -240,15 +242,32 @@ ebbm_gal_fetch_contacts (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb
}
static void
-ebbm_gal_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancellable, GHashTable *uids, GError **error)
+ebbm_gal_get_contacts_count (EBookBackendMAPI *ebma,
+ guint32 *obj_total,
+ GCancellable *cancellable,
+ GError **error)
+{
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (obj_total != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ /* just a fake value, to check by ids */
+ *obj_total = -1;
+}
+
+static void
+ebbm_gal_list_known_uids (EBookBackendMAPI *ebma,
+ BuildRestrictionsCB build_rs_cb,
+ gpointer build_rs_cb_data,
+ struct ListKnownUidsData *lku,
+ GCancellable *cancellable,
+ GError **error)
{
EMapiConnection *conn;
GError *mapi_error = NULL;
- struct FetchGalUidsData fgud = { 0 };
g_return_if_fail (ebma != NULL);
- g_return_if_fail (cancellable != NULL);
- g_return_if_fail (uids != NULL);
+ g_return_if_fail (lku != NULL);
+ g_return_if_fail (lku->uid_to_rev != NULL);
e_book_backend_mapi_lock_connection (ebma);
@@ -259,13 +278,9 @@ ebbm_gal_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancellable, GH
return;
}
- fgud.cancellable = cancellable;
- fgud.uids = uids;
- fgud.fid = e_mapi_connection_get_default_folder_id (conn, olFolderContacts, cancellable, NULL);
-
e_mapi_connection_fetch_gal (conn, NULL, NULL,
mapi_book_utils_get_prop_list, GET_UIDS_ONLY,
- fetch_gal_uids_cb, &fgud, cancellable, &mapi_error);
+ list_gal_uids_cb, lku, cancellable, &mapi_error);
if (mapi_error) {
mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
@@ -296,8 +311,9 @@ e_book_backend_mapi_gal_class_init (EBookBackendMAPIGALClass *klass)
parent_class->op_modify_contacts = ebbm_gal_modify_contacts;
parent_class->op_get_status_message = ebbm_gal_get_status_message;
- parent_class->op_fetch_contacts = ebbm_gal_fetch_contacts;
- parent_class->op_fetch_known_uids = ebbm_gal_fetch_known_uids;
+ parent_class->op_get_contacts_count = ebbm_gal_get_contacts_count;
+ parent_class->op_list_known_uids = ebbm_gal_list_known_uids;
+ parent_class->op_transfer_contacts = ebbm_gal_transfer_contacts;
}
/**
diff --git a/src/addressbook/e-book-backend-mapi.c b/src/addressbook/e-book-backend-mapi.c
index cdc3901..3e74584 100644
--- a/src/addressbook/e-book-backend-mapi.c
+++ b/src/addressbook/e-book-backend-mapi.c
@@ -57,9 +57,13 @@ struct _EBookBackendMAPIPrivate
GThread *update_cache_thread;
GCancellable *update_cache;
+ time_t last_update_cache;
EBookBackendSqliteDB *db;
GHashTable *running_book_views;
+
+ guint32 last_server_contact_count;
+ time_t last_modify_time;
};
#define ELEMENT_TYPE_MASK 0xF /* mask where the real type of the element is stored */
@@ -124,60 +128,6 @@ static const struct field_element_mapping {
};
static gboolean
-ebbm_get_cache_time (EBookBackendMAPI *ebma, glong *cache_seconds)
-{
- GError *error = NULL;
- GTimeVal tv = { 0 };
- gchar *last_update;
- gboolean ret = TRUE;
-
- g_return_val_if_fail (ebma != NULL, FALSE);
- g_return_val_if_fail (ebma->priv != NULL, FALSE);
- g_return_val_if_fail (ebma->priv->db != NULL, FALSE);
- g_return_val_if_fail (cache_seconds != NULL, FALSE);
-
- last_update = e_book_backend_sqlitedb_get_sync_data (ebma->priv->db, EMA_EBB_CACHE_FOLDERID, &error);
- ret = !error && last_update && g_time_val_from_iso8601 (last_update, &tv);
- if (error)
- g_error_free (error);
- g_free (last_update);
-
- if (ret)
- *cache_seconds = tv.tv_sec;
-
- return ret;
-}
-
-static void
-ebbm_set_cache_time (EBookBackendMAPI *ebma, glong cache_seconds)
-{
- GError *error = NULL;
- gchar *iso_time = NULL;
-
- g_return_if_fail (ebma != NULL);
- g_return_if_fail (ebma->priv != NULL);
- g_return_if_fail (ebma->priv->db != NULL);
-
- if (cache_seconds > 0) {
- GTimeVal tv = { 0 };
-
- tv.tv_sec = cache_seconds;
- iso_time = g_time_val_to_iso8601 (&tv);
- }
-
- e_book_backend_sqlitedb_set_sync_data (ebma->priv->db,
- EMA_EBB_CACHE_FOLDERID,
- iso_time ? iso_time : "0",
- &error);
- g_free (iso_time);
-
- if (error) {
- e_mapi_debug_print ("%s: Failed to set value: %s", G_STRFUNC, error->message);
- g_error_free (error);
- }
-}
-
-static gboolean
pick_view_cb (EDataBookView *view, gpointer user_data)
{
EDataBookView **pick = user_data;
@@ -213,12 +163,6 @@ complete_views (EBookBackendMAPI *ebma)
e_book_backend_foreach_view (E_BOOK_BACKEND (ebma), complete_view_cb, NULL);
}
-struct FetchContactsData
-{
- glong last_notification;
- glong last_modification;
-};
-
static void
ebbm_notify_connection_status (EBookBackendMAPI *ebma, gboolean is_online)
{
@@ -235,10 +179,14 @@ ebbm_notify_connection_status (EBookBackendMAPI *ebma, gboolean is_online)
}
static void
-ebbm_fetch_contacts (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb, gpointer build_rs_cb_data, EDataBookView *book_view, glong *last_modification_secs, GError **error)
+ebbm_transfer_contacts (EBookBackendMAPI *ebma,
+ const GSList *uids,
+ EDataBookView *book_view,
+ GCancellable *cancellable,
+ GError **error)
{
EBookBackendMAPIClass *ebmac;
- struct FetchContactsData notify_data = { 0 };
+ glong last_notification = 0;
g_return_if_fail (ebma != NULL);
g_return_if_fail (ebma->priv != NULL);
@@ -246,12 +194,9 @@ ebbm_fetch_contacts (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb, gp
ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
g_return_if_fail (ebmac != NULL);
- g_return_if_fail (ebmac->op_fetch_contacts != NULL);
+ g_return_if_fail (ebmac->op_transfer_contacts != NULL);
- ebmac->op_fetch_contacts (ebma, build_rs_cb, build_rs_cb_data, book_view, ¬ify_data, error);
-
- if (last_modification_secs && *last_modification_secs < notify_data.last_modification)
- *last_modification_secs = notify_data.last_modification;
+ ebmac->op_transfer_contacts (ebma, uids, book_view, &last_notification, cancellable, error);
}
static gboolean
@@ -266,59 +211,17 @@ unref_backend_idle_cb (gpointer data)
return FALSE;
}
-static gboolean
-ebbm_build_cache_update_restriction (EMapiConnection *conn,
- mapi_id_t fid,
- TALLOC_CTX *mem_ctx,
- struct mapi_SRestriction **restrictions,
- gpointer user_data,
- GCancellable *cancellable,
- GError **perror)
-{
- EBookBackendMAPI *ebma = user_data;
- struct mapi_SRestriction *restriction;
- EBookBackendMAPIPrivate *priv;
- struct SPropValue sprop;
- struct timeval t = { 0 };
- glong last_update_secs = 0;
-
- g_return_val_if_fail (ebma != NULL, FALSE);
- g_return_val_if_fail (mem_ctx != NULL, FALSE);
- g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
- g_return_val_if_fail (restrictions != NULL, FALSE);
-
- priv = ebma->priv;
- g_return_val_if_fail (priv != NULL, FALSE);
- g_return_val_if_fail (priv->db != NULL, FALSE);
-
- if (!ebbm_get_cache_time (ebma, &last_update_secs) || last_update_secs <= 0)
- return TRUE;
-
- restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
- g_return_val_if_fail (restriction != NULL, FALSE);
-
- restriction->rt = RES_PROPERTY;
- restriction->res.resProperty.relop = RELOP_GE;
- restriction->res.resProperty.ulPropTag = PR_LAST_MODIFICATION_TIME;
-
- t.tv_sec = last_update_secs;
- t.tv_usec = 0;
-
- set_SPropValue_proptag_date_timeval (&sprop, PR_LAST_MODIFICATION_TIME, &t);
- cast_mapi_SPropValue (mem_ctx, &(restriction->res.resProperty.lpProp), &sprop);
-
- *restrictions = restriction;
-
- return TRUE;
-}
-
static gpointer
ebbm_update_cache_cb (gpointer data)
{
EBookBackendMAPI *ebma = (EBookBackendMAPI *) data;
EBookBackendMAPIPrivate *priv;
EBookBackendMAPIClass *ebmac;
- glong last_modification_secs = 0;
+ guint32 server_stored_contacts = 0;
+ GHashTable *local_known_uids, *server_known_uids;
+ time_t restr_tt = 0;
+ gboolean partial_update = FALSE;
+ GCancellable *cancellable;
GError *error = NULL;
g_return_val_if_fail (ebma != NULL, NULL);
@@ -332,45 +235,74 @@ ebbm_update_cache_cb (gpointer data)
ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
g_return_val_if_fail (ebmac != NULL, NULL);
- g_cancellable_reset (priv->update_cache);
+ cancellable = priv->update_cache;
+ g_cancellable_reset (cancellable);
- if (!g_cancellable_is_cancelled (priv->update_cache) && ebmac->op_fetch_contacts) {
- /* get time stored in a cache, to always use the latest last modification time */
- if (!ebbm_get_cache_time (ebma, &last_modification_secs))
- last_modification_secs = 0;
+ local_known_uids = e_book_backend_sqlitedb_get_uids_and_rev (priv->db, EMA_EBB_CACHE_FOLDERID, &error);
+ server_known_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
- ebbm_fetch_contacts (ebma, ebbm_build_cache_update_restriction, ebma, NULL, &last_modification_secs, &error);
- e_book_backend_sqlitedb_set_is_populated (priv->db, EMA_EBB_CACHE_FOLDERID, error != NULL, NULL);
+ if (!error && !g_cancellable_is_cancelled (cancellable) && ebmac->op_get_contacts_count) {
+ ebmac->op_get_contacts_count (ebma, &server_stored_contacts, cancellable, &error);
}
- if (!error && !g_cancellable_is_cancelled (priv->update_cache) && ebmac->op_fetch_known_uids) {
- GHashTable *uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+ if (!error && !g_cancellable_is_cancelled (cancellable) && ebmac->op_list_known_uids) {
+ struct ListKnownUidsData lku;
- ebmac->op_fetch_known_uids (ebma, priv->update_cache, uids, &error);
+ restr_tt = priv->last_modify_time && server_stored_contacts == g_hash_table_size (local_known_uids) ? priv->last_modify_time + 1 : 0;
+ partial_update = restr_tt > 0;
- if (!error && !g_cancellable_is_cancelled (priv->update_cache)) {
- GSList *cache_keys, *c;
+ lku.uid_to_rev = server_known_uids;
+ lku.latest_last_modify = priv->last_modify_time;
- cache_keys = e_book_backend_sqlitedb_search_uids (priv->db, EMA_EBB_CACHE_FOLDERID, NULL, NULL, NULL);
+ ebmac->op_list_known_uids (ebma, partial_update ? e_mapi_utils_build_last_modify_restriction : NULL, &restr_tt, &lku, cancellable, &error);
- for (c = cache_keys; c; c = c->next) {
- const gchar *uid = c->data;
+ restr_tt = lku.latest_last_modify;
+ }
- if (!uid || g_hash_table_lookup (uids, uid))
- continue;
+ if (!error && !g_cancellable_is_cancelled (cancellable) && ebmac->op_transfer_contacts && local_known_uids) {
+ GSList *uids = NULL;
+ GHashTableIter iter;
+ gpointer key, value;
- e_book_backend_mapi_notify_contact_removed (ebma, uid);
+ g_hash_table_iter_init (&iter, server_known_uids);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ const gchar *uid = key, *rev = value, *local_rev;
+
+ local_rev = g_hash_table_lookup (local_known_uids, uid);
+ if (g_strcmp0 (local_rev, rev) != 0) {
+ uids = g_slist_prepend (uids, (gpointer) uid);
}
- ebbm_set_cache_time (ebma, last_modification_secs);
+ g_hash_table_remove (local_known_uids, uid);
+ }
+
+ if (uids)
+ ebbm_transfer_contacts (ebma, uids, NULL, cancellable, &error);
+
+ if (!error && !g_cancellable_is_cancelled (cancellable) && !partial_update) {
+ g_hash_table_iter_init (&iter, local_known_uids);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ const gchar *uid = key;
- g_slist_foreach (cache_keys, (GFunc) g_free, NULL);
- g_slist_free (cache_keys);
+ if (!uid)
+ continue;
+
+ e_book_backend_mapi_notify_contact_removed (ebma, uid);
+ }
}
- g_hash_table_destroy (uids);
+ priv->last_server_contact_count = server_stored_contacts;
+ priv->last_modify_time = restr_tt;
+
+ /* has borrowed data from server_known_uids */
+ g_slist_free (uids);
}
+ priv->last_update_cache = time(NULL);
+
+ g_hash_table_destroy (server_known_uids);
+ if (local_known_uids)
+ g_hash_table_destroy (local_known_uids);
if (error)
g_error_free (error);
@@ -386,6 +318,34 @@ ebbm_update_cache_cb (gpointer data)
}
static void
+ebbm_maybe_invoke_cache_update (EBookBackendMAPI *ebma)
+{
+ EBookBackendMAPIPrivate *priv;
+
+ g_return_if_fail (ebma != NULL);
+ g_return_if_fail (ebma->priv != NULL);
+
+ priv = ebma->priv;
+
+ if (priv->update_cache_thread) {
+ if (!g_cancellable_is_cancelled (priv->update_cache))
+ return;
+
+ g_thread_join (priv->update_cache_thread);
+ priv->update_cache_thread = NULL;
+ }
+
+ /* do not update more often than each 10 minutes */
+ if (time (NULL) - priv->last_update_cache >= 60 * 10) {
+ g_object_ref (ebma);
+
+ priv->update_cache_thread = g_thread_create (ebbm_update_cache_cb, ebma, TRUE, NULL);
+ if (!priv->update_cache_thread)
+ g_object_unref (ebma);
+ }
+}
+
+static void
ebbm_connect_user (EBookBackendMAPI *ebma, GCancellable *cancellable, const gchar *password, GError **error)
{
EBookBackendMAPIPrivate *priv = ebma->priv;
@@ -445,11 +405,7 @@ ebbm_connect_user (EBookBackendMAPI *ebma, GCancellable *cancellable, const gcha
ebbm_notify_connection_status (ebma, TRUE);
if (!g_cancellable_is_cancelled (cancellable) /* && priv->marked_for_offline */) {
- g_object_ref (ebma);
-
- priv->update_cache_thread = g_thread_create (ebbm_update_cache_cb, ebma, TRUE, NULL);
- if (!priv->update_cache_thread)
- g_object_unref (ebma);
+ ebbm_maybe_invoke_cache_update (ebma);
}
}
}
@@ -745,19 +701,9 @@ ebbm_book_view_thread (gpointer data)
ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (bvtd->ebma);
if (ebmac && ebmac->op_book_view_thread)
- ebmac->op_book_view_thread (bvtd->ebma, bvtd->book_view, &error);
-
- if (!error && !e_book_backend_sqlitedb_get_is_populated (priv->db, EMA_EBB_CACHE_FOLDERID, &error)) {
- /* todo: create restriction based on the book_view */
- if (!error) {
- g_cancellable_reset (priv->update_cache);
- ebbm_fetch_contacts (bvtd->ebma, NULL, NULL, bvtd->book_view, NULL, &error);
- g_cancellable_cancel (priv->update_cache);
- }
+ ebmac->op_book_view_thread (bvtd->ebma, bvtd->book_view, priv->update_cache, &error);
- if (!error)
- e_book_backend_sqlitedb_set_is_populated (priv->db, EMA_EBB_CACHE_FOLDERID, TRUE, &error);
- }
+ ebbm_maybe_invoke_cache_update (bvtd->ebma);
}
if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
@@ -891,7 +837,7 @@ ebbm_operation_cb (OperationBase *op, gboolean cancelled, EBookBackend *backend)
const GSList *l;
for (l = added_contacts; l; l = l->next) {
- e_book_backend_mapi_notify_contact_update (ebma, NULL, E_CONTACT (l->data), NULL, -1, -1, NULL);
+ e_book_backend_mapi_notify_contact_update (ebma, NULL, E_CONTACT (l->data), -1, -1, NULL);
}
}
@@ -947,7 +893,7 @@ ebbm_operation_cb (OperationBase *op, gboolean cancelled, EBookBackend *backend)
const GSList *l;
for (l = modified_contacts; l; l = l->next) {
- e_book_backend_mapi_notify_contact_update (ebma, NULL, E_CONTACT (l->data), NULL, -1, -1, NULL);
+ e_book_backend_mapi_notify_contact_update (ebma, NULL, E_CONTACT (l->data), -1, -1, NULL);
}
}
@@ -1317,6 +1263,9 @@ e_book_backend_mapi_init (EBookBackendMAPI *ebma)
ebma->priv->update_cache = g_cancellable_new ();
ebma->priv->update_cache_thread = NULL;
+ ebma->priv->last_update_cache = 0;
+ ebma->priv->last_server_contact_count = 0;
+ ebma->priv->last_modify_time = 0;
g_signal_connect (
ebma, "notify::online",
@@ -1371,30 +1320,31 @@ e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
g_type_class_add_private (klass, sizeof (EBookBackendMAPIPrivate));
- object_class->dispose = ebbm_dispose;
-
- backend_class->open = ebbm_op_open;
- backend_class->remove = ebbm_op_remove;
- backend_class->create_contacts = ebbm_op_create_contacts;
- backend_class->remove_contacts = ebbm_op_remove_contacts;
- backend_class->modify_contacts = ebbm_op_modify_contacts;
- backend_class->get_contact = ebbm_op_get_contact;
- backend_class->get_contact_list = ebbm_op_get_contact_list;
- backend_class->start_book_view = ebbm_op_start_book_view;
- backend_class->stop_book_view = ebbm_op_stop_book_view;
- backend_class->authenticate_user = ebbm_op_authenticate_user;
- backend_class->get_backend_property = ebbm_op_get_backend_property;
- klass->op_open = ebbm_open;
- klass->op_remove = ebbm_remove;
- klass->op_authenticate_user = ebbm_authenticate_user;
- klass->op_get_contact = ebbm_get_contact;
- klass->op_get_contact_list = ebbm_get_contact_list;
-
- klass->op_connection_status_changed = NULL;
- klass->op_get_status_message = NULL;
- klass->op_book_view_thread = NULL;
- klass->op_fetch_contacts = NULL;
- klass->op_fetch_known_uids = NULL;
+ object_class->dispose = ebbm_dispose;
+
+ backend_class->open = ebbm_op_open;
+ backend_class->remove = ebbm_op_remove;
+ backend_class->create_contacts = ebbm_op_create_contacts;
+ backend_class->remove_contacts = ebbm_op_remove_contacts;
+ backend_class->modify_contacts = ebbm_op_modify_contacts;
+ backend_class->get_contact = ebbm_op_get_contact;
+ backend_class->get_contact_list = ebbm_op_get_contact_list;
+ backend_class->start_book_view = ebbm_op_start_book_view;
+ backend_class->stop_book_view = ebbm_op_stop_book_view;
+ backend_class->authenticate_user = ebbm_op_authenticate_user;
+ backend_class->get_backend_property = ebbm_op_get_backend_property;
+ klass->op_open = ebbm_open;
+ klass->op_remove = ebbm_remove;
+ klass->op_authenticate_user = ebbm_authenticate_user;
+ klass->op_get_contact = ebbm_get_contact;
+ klass->op_get_contact_list = ebbm_get_contact_list;
+
+ klass->op_connection_status_changed = NULL;
+ klass->op_get_status_message = NULL;
+ klass->op_book_view_thread = NULL;
+ klass->op_get_contacts_count = NULL;
+ klass->op_list_known_uids = NULL;
+ klass->op_transfer_contacts = NULL;
}
gboolean
@@ -1529,14 +1479,14 @@ get_current_time_ms (void)
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
-/* called from op_fetch_contacts - book_view and notify_contact_data are taken from there;
- notify_contact_data is a pointer to FetchContactsData, if not NULL;
+/* called from op_transfer_contacts - book_view and notify_contact_data are taken from there;
+ notify_contact_data is a pointer to glong last_notification, if not NULL;
returns whether can continue with fetching */
gboolean
-e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *pbook_view, EContact *contact, const struct timeval *pr_last_modification_time, gint index, gint total, gpointer notify_contact_data)
+e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *pbook_view, EContact *contact, gint index, gint total, gpointer notify_contact_data)
{
EBookBackendMAPIPrivate *priv;
- struct FetchContactsData *fcd = notify_contact_data;
+ glong *last_notification = notify_contact_data;
EDataBookView *book_view = pbook_view;
GError *error = NULL;
@@ -1553,13 +1503,13 @@ e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView
book_view = ebbm_pick_book_view (ebma);
if (book_view) {
- guint32 current_time;
+ glong current_time;
if (!e_book_backend_mapi_book_view_is_running (ebma, book_view))
return FALSE;
current_time = get_current_time_ms ();
- if (index > 0 && fcd && current_time - fcd->last_notification > 333) {
+ if (index > 0 && last_notification && current_time - *last_notification > 333) {
gchar *status_msg = NULL;
EBookBackendMAPIClass *ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
@@ -1571,7 +1521,7 @@ e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView
g_free (status_msg);
- fcd->last_notification = current_time;
+ *last_notification = current_time;
}
}
@@ -1583,14 +1533,11 @@ e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView
FALSE, &error);
if (!error) {
e_book_backend_notify_update (E_BOOK_BACKEND (ebma), contact);
-
- if (fcd && pr_last_modification_time) {
- if (fcd->last_modification < pr_last_modification_time->tv_sec)
- fcd->last_modification = pr_last_modification_time->tv_sec;
- }
return TRUE;
}
+
g_error_free (error);
+
return FALSE;
}
@@ -1708,9 +1655,10 @@ mapi_book_utils_get_prop_list (EMapiConnection *conn,
};
static uint32_t uids_only_ids[] = {
- PR_FID,
- PR_MID,
- PR_EMAIL_ADDRESS_UNICODE
+ PidTagFolderId,
+ PidTagMid,
+ PidTagLastModificationTime,
+ PidTagEmailAddress
};
/* do not make this array static, the function modifies it on run */
@@ -1879,13 +1827,8 @@ mapi_book_utils_contact_from_props (EMapiConnection *conn, mapi_id_t fid, const
if (value && mappings[i].element_type == PT_SYSTIME) {
const struct FILETIME *t = value;
gchar *buff = NULL;
- GTimeVal tv;
-
- tv.tv_sec = e_mapi_util_filetime_to_time_t (t);
- tv.tv_usec = 0;
-
- buff = g_time_val_to_iso8601 (&tv);
+ buff = mapi_book_utils_timet_to_string (e_mapi_util_filetime_to_time_t (t));
if (buff)
e_contact_set (contact, mappings[i].field_id, buff);
@@ -2006,3 +1949,14 @@ mapi_error_to_edb_error (GError **perror, const GError *mapi_error, EDataBookSta
g_free (err_msg);
}
+
+gchar *
+mapi_book_utils_timet_to_string (time_t tt)
+{
+ GTimeVal tv;
+
+ tv.tv_sec = tt;
+ tv.tv_usec = 0;
+
+ return g_time_val_to_iso8601 (&tv);
+}
diff --git a/src/addressbook/e-book-backend-mapi.h b/src/addressbook/e-book-backend-mapi.h
index ffce6d5..5a65f95 100644
--- a/src/addressbook/e-book-backend-mapi.h
+++ b/src/addressbook/e-book-backend-mapi.h
@@ -50,6 +50,12 @@ typedef struct
EBookBackendMAPIPrivate *priv;
} EBookBackendMAPI;
+struct ListKnownUidsData
+{
+ GHashTable *uid_to_rev;
+ time_t latest_last_modify;
+};
+
typedef struct
{
EBookBackendClass parent_class;
@@ -74,17 +80,21 @@ typedef struct
/* function called for each new book_view, in a separate thread;
this function is optional, contacts from cache are always processed
before this function call */
- void (*op_book_view_thread) (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error);
+ void (*op_book_view_thread) (EBookBackendMAPI *ebma, EDataBookView *book_view, GCancellable *cancellable, GError **error);
- /* function called to populate cache or similar operations;
- restriction and book_view can be NULL, call e_book_backend_mapi_notify_contact_update for each
- fetched contact with this book_view and notify_contact_data */
- void (*op_fetch_contacts) (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb, gpointer build_rs_cb_data, EDataBookView *book_view, gpointer notify_contact_data, GError **error);
+ /* gets current count of contacts in the folder corresponding to the backend */
+ void (*op_get_contacts_count) (EBookBackendMAPI *ebma, guint32 *obj_total, GCancellable *cancellable, GError **error);
/* function to fetch list of known uids (strings) on the server;
- it's used to synchronize local cache with deleted items;
- uids has the uid key, as a newly allocated string; value should be GINT_TO_POINTER(1) always */
- void (*op_fetch_known_uids) (EBookBackendMAPI *ebma, GCancellable *cancellable, GHashTable *uids, GError **error);
+ it's used to synchronize local cache with available items;
+ uids has the uid key, as a newly allocated string;
+ value is a revision (REV) field value as newly allocated string */
+ void (*op_list_known_uids) (EBookBackendMAPI *ebma, BuildRestrictionsCB build_rs_cb, gpointer build_rs_cb_data, struct ListKnownUidsData *lku, GCancellable *cancellable, GError **error);
+
+ /* function called to populate cache or similar operations;
+ book_view can be NULL, call e_book_backend_mapi_notify_contact_update for each
+ transferred contact with this book_view and notify_contact_data */
+ void (*op_transfer_contacts) (EBookBackendMAPI *ebma, const GSList *uids, EDataBookView *book_view, gpointer notify_contact_data, GCancellable *cancellable, GError **error);
} EBookBackendMAPIClass;
GType e_book_backend_mapi_get_type (void);
@@ -98,7 +108,7 @@ void e_book_backend_mapi_get_db (EBookBackendMAPI *ebma, EBookBackendSqliteDB **
gboolean e_book_backend_mapi_book_view_is_running (EBookBackendMAPI *ebma, EDataBookView *book_view);
void e_book_backend_mapi_update_view_by_cache (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error);
gboolean e_book_backend_mapi_is_marked_for_offline (EBookBackendMAPI *ebma);
-gboolean e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *book_view, EContact *contact, const struct timeval *pr_last_modification_time, gint index, gint total, gpointer notify_contact_data);
+gboolean e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *book_view, EContact *contact, gint index, gint total, gpointer notify_contact_data);
void e_book_backend_mapi_notify_contact_removed (EBookBackendMAPI *ebma, const gchar *uid);
void e_book_backend_mapi_cache_set (EBookBackendMAPI *ebma, const gchar *key, const gchar *value);
gchar *e_book_backend_mapi_cache_get (EBookBackendMAPI *ebma, const gchar *key);
@@ -135,6 +145,10 @@ gboolean mapi_book_utils_get_prop_list (EMapiConnection *conn,
/* only one of mapi_properties and aRow can be set */
EContact *mapi_book_utils_contact_from_props (EMapiConnection *conn, mapi_id_t fid, const gchar *book_uri, struct mapi_SPropValue_array *mapi_properties, struct SRow *aRow);
+/* converts time_t to string, suitable for E_CONTACT_REV field value;
+ free returned pointer with g_free() */
+gchar *mapi_book_utils_timet_to_string (time_t tt);
+
G_END_DECLS
#endif /* __E_BOOK_BACKEND_MAPI_H__ */
diff --git a/src/libexchangemapi/e-mapi-utils.c b/src/libexchangemapi/e-mapi-utils.c
index 58ac349..6d3ff42 100644
--- a/src/libexchangemapi/e-mapi-utils.c
+++ b/src/libexchangemapi/e-mapi-utils.c
@@ -66,26 +66,6 @@ e_mapi_util_mapi_id_from_string (const gchar *str, mapi_id_t *id)
return (n == 1);
}
-/* NOTE: We use the UID as a combination of the folder-id and the message-id.
- * Specifically, it is in this format: ("%016" G_GINT64_MODIFIER "X%016" G_GINT64_MODIFIER "X", fid, mid).
- */
-inline gchar *
-e_mapi_util_mapi_ids_to_uid (mapi_id_t fid, mapi_id_t mid)
-{
- return g_strdup_printf ("%016" G_GINT64_MODIFIER "X%016" G_GINT64_MODIFIER "X", fid, mid);
-}
-
-inline gboolean
-e_mapi_util_mapi_ids_from_uid (const gchar *str, mapi_id_t *fid, mapi_id_t *mid)
-{
- gint n = 0;
-
- if (str && *str)
- n = sscanf (str, "%016" G_GINT64_MODIFIER "X%016" G_GINT64_MODIFIER "X", fid, mid);
-
- return (n == 2);
-}
-
/*
* Retrieve the property value for a given SPropValue and property tag.
*
diff --git a/src/libexchangemapi/e-mapi-utils.h b/src/libexchangemapi/e-mapi-utils.h
index 79fd661..a40d39f 100644
--- a/src/libexchangemapi/e-mapi-utils.h
+++ b/src/libexchangemapi/e-mapi-utils.h
@@ -31,9 +31,6 @@
gchar * e_mapi_util_mapi_id_to_string (mapi_id_t id);
gboolean e_mapi_util_mapi_id_from_string (const gchar *str, mapi_id_t *id);
-gchar * e_mapi_util_mapi_ids_to_uid (mapi_id_t fid, mapi_id_t mid);
-gboolean e_mapi_util_mapi_ids_from_uid (const gchar *str, mapi_id_t *fid, mapi_id_t *mid);
-
gconstpointer e_mapi_util_find_SPropVal_array_propval (struct SPropValue *values, uint32_t proptag);
gconstpointer e_mapi_util_find_SPropVal_array_namedid (struct SPropValue *values, EMapiConnection *conn, mapi_id_t fid, uint32_t namedid);
gconstpointer e_mapi_util_find_row_propval (struct SRow *aRow, uint32_t proptag);
@@ -116,7 +113,7 @@ gboolean e_mapi_utils_build_last_modify_restriction (EMapiConnection *conn,
mapi_id_t fid,
TALLOC_CTX *mem_ctx,
struct mapi_SRestriction **restrictions,
- gpointer user_data,
+ gpointer user_data, /* const time_t * */
GCancellable *cancellable,
GError **perror);
struct FolderBasicPropertiesData
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]