[evolution-ews/gnome-3-28] eds-I#12 - vCard REV attribute should be a timestamp



commit 84f62bac0fee267d789a09965e19aa7c764b6d02
Author: Milan Crha <mcrha redhat com>
Date:   Thu Jun 21 16:31:44 2018 +0200

    eds-I#12 - vCard REV attribute should be a timestamp
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/issues/12

 src/addressbook/e-book-backend-ews.c | 123 ++++++++++++++++++++++++++++-------
 src/server/e-ews-item.c              |  13 ++++
 src/server/e-ews-item.h              |   2 +
 3 files changed, 115 insertions(+), 23 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-ews.c b/src/addressbook/e-book-backend-ews.c
index d19050c9..9fc05540 100644
--- a/src/addressbook/e-book-backend-ews.c
+++ b/src/addressbook/e-book-backend-ews.c
@@ -51,12 +51,23 @@
 #include "ews-oab-decoder.h"
 #include "ews-oab-decompress.h"
 
+#ifdef G_OS_WIN32
+#ifdef gmtime_r
+#undef gmtime_r
+#endif
+
+/* The gmtime() in Microsoft's C library is MT-safe */
+#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
+#endif
+
 #define d(x)
 
 #define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
 #define EDB_ERROR_EX(_code,_msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg)
 
 #define X_EWS_ORIGINAL_VCARD "X-EWS-ORIGINAL-VCARD"
+#define X_EWS_CHANGEKEY "X-EWS-CHANGEKEY"
+#define X_EWS_GAL_SHA1 "X-EWS-GAL-SHA1"
 
 #define EWS_MAX_FETCH_COUNT 500
 
@@ -66,7 +77,7 @@
 /* passing field uris for PhysicalAddress, PhoneNumbers causes error, so we
  * use Default view to fetch them. Thus the summary props just have attachments
  * and some additional properties that are not return with Default view */
-#define CONTACT_ITEM_PROPS "item:Attachments item:HasAttachments item:Body contacts:Manager 
contacts:Department contacts:SpouseName contacts:AssistantName contacts:BusinessHomePage contacts:Birthday"
+#define CONTACT_ITEM_PROPS "item:Attachments item:HasAttachments item:Body item:LastModifiedTime 
contacts:Manager contacts:Department contacts:SpouseName contacts:AssistantName contacts:BusinessHomePage 
contacts:Birthday"
 
 struct _EBookBackendEwsPrivate {
        GRecMutex cnc_lock;
@@ -186,6 +197,31 @@ static const struct phone_field_mapping {
        {E_CONTACT_PHONE_TTYTDD, "TtyTddPhone"}
 };
 
+static void
+ebews_populate_rev (EContact *contact,
+                   EEwsItem *item)
+{
+       struct tm stm;
+       time_t tt = 0;
+       gchar time_string[100] = { 0 };
+
+       g_return_if_fail (E_IS_CONTACT (contact));
+
+       if (item) {
+               g_return_if_fail (E_IS_EWS_ITEM (item));
+
+               tt = e_ews_item_get_last_modified_time (item);
+       }
+
+       if (tt <= 0)
+               tt = time (NULL);
+
+       gmtime_r (&tt, &stm);
+       strftime (time_string, 100, "%Y-%m-%dT%H:%M:%SZ", &stm);
+
+       e_contact_set (contact, E_CONTACT_REV, time_string);
+}
+
 static void
 ebews_populate_uid (EBookBackendEws *bbews,
                    EContact *contact,
@@ -198,7 +234,8 @@ ebews_populate_uid (EBookBackendEws *bbews,
        id = e_ews_item_get_id (item);
        if (id) {
                e_contact_set (contact, E_CONTACT_UID, id->id);
-               e_contact_set (contact, E_CONTACT_REV, id->change_key);
+               ebews_populate_rev (contact, item);
+               e_vcard_util_set_x_attribute (E_VCARD (contact), X_EWS_CHANGEKEY, id->change_key);
        }
 }
 
@@ -860,7 +897,9 @@ set_photo (EBookBackendEws *bbews,
        if (!item_id) {
                id = g_new0 (EwsId, 1);
                id->id = e_contact_get (contact, E_CONTACT_UID);
-               id->change_key = e_contact_get (contact, E_CONTACT_REV);
+               id->change_key = e_vcard_util_dup_x_attribute (E_VCARD (contact), X_EWS_CHANGEKEY);
+               if (!id->change_key)
+                       id->change_key = e_contact_get (contact, E_CONTACT_REV);
 
                item_id = id;
        }
@@ -1442,15 +1481,24 @@ ebb_ews_convert_dl_to_updatexml_cb (ESoapMessage *msg,
        ConvertData *cd = user_data;
        EContact *old_contact = cd->old_contact;
        EContact *new_contact = cd->new_contact;
+       gchar *change_key = NULL;
+
+       if (!cd->change_key) {
+               change_key = e_vcard_util_dup_x_attribute (E_VCARD (old_contact), X_EWS_CHANGEKEY);
+               if (!change_key)
+                       change_key = e_contact_get (old_contact, E_CONTACT_REV);
+       }
 
        e_ews_message_start_item_change (msg, E_EWS_ITEMCHANGE_TYPE_ITEM,
                e_contact_get_const (old_contact, E_CONTACT_UID),
-               cd->change_key ? cd->change_key : e_contact_get_const (old_contact, E_CONTACT_REV),
+               cd->change_key ? cd->change_key : change_key,
                0);
        e_ews_message_start_set_item_field (msg, "Members", "distributionlist", "DistributionList");
        ebb_ews_write_dl_members (msg, new_contact);
        e_ews_message_end_set_item_field (msg);
        e_ews_message_end_item_change (msg);
+
+       g_free (change_key);
 }
 
 static void
@@ -1461,6 +1509,7 @@ ebb_ews_convert_contact_to_updatexml_cb (ESoapMessage *msg,
        EContact *old_contact = cd->old_contact;
        EContact *new_contact = cd->new_contact;
        gchar *value = NULL, *old_value = NULL;
+       gchar *change_key = NULL;
        gint i, element_type;
 
        /* Pre-flight, to update the ChangeKey if needed */
@@ -1482,9 +1531,15 @@ ebb_ews_convert_contact_to_updatexml_cb (ESoapMessage *msg,
                }
        }
 
+       if (!cd->change_key) {
+               change_key = e_vcard_util_dup_x_attribute (E_VCARD (old_contact), X_EWS_CHANGEKEY);
+               if (!change_key)
+                       change_key = e_contact_get (old_contact, E_CONTACT_REV);
+       }
+
        e_ews_message_start_item_change (msg, E_EWS_ITEMCHANGE_TYPE_ITEM,
                e_contact_get_const (old_contact, E_CONTACT_UID),
-               cd->change_key ? cd->change_key : e_contact_get_const (old_contact, E_CONTACT_REV),
+               cd->change_key ? cd->change_key : change_key,
                0);
 
        /* Iterate for each field in contact */
@@ -1516,6 +1571,8 @@ ebb_ews_convert_contact_to_updatexml_cb (ESoapMessage *msg,
        }
 
        e_ews_message_end_item_change (msg);
+
+       g_free (change_key);
 }
 
 static EContact *
@@ -1675,6 +1732,7 @@ ebb_ews_traverse_dl (EBookBackendEws *bbews,
 
 static EContact *
 ebb_ews_get_dl_info (EBookBackendEws *bbews,
+                    EEwsItem *item,
                     const EwsId *id,
                     const gchar *d_name,
                     GSList *members,
@@ -1687,7 +1745,8 @@ ebb_ews_get_dl_info (EBookBackendEws *bbews,
 
        contact = e_contact_new ();
        e_contact_set (contact, E_CONTACT_UID, id->id);
-       e_contact_set (contact, E_CONTACT_REV, id->change_key);
+       e_vcard_util_set_x_attribute (E_VCARD (contact), X_EWS_CHANGEKEY, id->change_key);
+       ebews_populate_rev (contact, item);
 
        e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
        e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
@@ -1739,6 +1798,7 @@ ebb_ews_get_dl_info_gal (EBookBackendEws *bbews,
 
 static gboolean
 ebb_ews_contacts_append_dl (EBookBackendEws *bbews,
+                           EEwsItem *item,
                            const EwsId *id,
                            const gchar *d_name,
                            GSList *members,
@@ -1749,7 +1809,7 @@ ebb_ews_contacts_append_dl (EBookBackendEws *bbews,
        EContact *contact;
        EVCardAttribute *attr;
 
-       contact = ebb_ews_get_dl_info (bbews, id, d_name, members, cancellable, error);
+       contact = ebb_ews_get_dl_info (bbews, item, id, d_name, members, cancellable, error);
        if (contact == NULL)
                return FALSE;
 
@@ -1837,7 +1897,7 @@ ebb_ews_fetch_items_sync (EBookBackendEws *bbews,
                if (e_ews_connection_expand_dl_sync (
                        bbews->priv->cnc, EWS_PRIORITY_MEDIUM, mb, &members,
                        &includes_last, cancellable, &local_error)) {
-                       ret = ebb_ews_contacts_append_dl (bbews, id, d_name, members, contacts, cancellable, 
error);
+                       ret = ebb_ews_contacts_append_dl (bbews, item, id, d_name, members, contacts, 
cancellable, error);
                        g_slist_free_full (members, (GDestroyNotify) e_ews_mailbox_free);
                } else {
                        ret = g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NAMERESOLUTIONNORESULTS);
@@ -2165,9 +2225,10 @@ ebb_ews_gal_store_contact (EContact *contact,
                const gchar *uid = e_contact_get_const (contact, E_CONTACT_UID);
                EBookMetaBackendInfo *nfo;
 
-               e_contact_set (contact, E_CONTACT_REV, sha1);
+               ebews_populate_rev (contact, NULL);
+               e_vcard_util_set_x_attribute (E_VCARD (contact), X_EWS_GAL_SHA1, sha1);
 
-               nfo = e_book_meta_backend_info_new (uid, sha1, NULL, NULL);
+               nfo = e_book_meta_backend_info_new (uid, e_contact_get_const (contact, E_CONTACT_REV), NULL, 
NULL);
                nfo->object = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
 
                if (g_hash_table_remove (data->uids, uid)) {
@@ -2197,18 +2258,27 @@ ebb_ews_gather_existing_uids_cb (EBookCache *book_cache,
                                 gpointer user_data)
 {
        struct _db_data *data = user_data;
-       gchar *dup_uid, *dup_rev;
+       EVCard *vcard;
+       gchar *dup_uid, *dup_sha1 = NULL;
 
        g_return_val_if_fail (data != NULL, FALSE);
        g_return_val_if_fail (data->uids != NULL, FALSE);
        g_return_val_if_fail (data->sha1s != NULL, FALSE);
+       g_return_val_if_fail (object != NULL, FALSE);
+
+       vcard = e_vcard_new_from_string (object);
+       if (vcard) {
+               dup_sha1 = e_vcard_util_dup_x_attribute (vcard, X_EWS_GAL_SHA1);
+               g_object_unref (vcard);
+       }
 
        dup_uid = g_strdup (uid);
-       dup_rev = g_strdup (revision);
+       if (!dup_sha1)
+               dup_sha1 = g_strdup (revision);
 
-       g_hash_table_insert (data->uids, dup_uid, dup_rev);
-       if (dup_rev)
-               g_hash_table_insert (data->sha1s, dup_rev, dup_uid);
+       g_hash_table_insert (data->uids, dup_uid, dup_sha1);
+       if (dup_sha1)
+               g_hash_table_insert (data->sha1s, dup_sha1, dup_uid);
 
        return TRUE;
 }
@@ -2603,7 +2673,6 @@ ebb_ews_update_cache_for_expression (EBookBackendEws *bbews,
                                EContact *contact = NULL;
                                gboolean is_public_dl = FALSE;
                                const gchar *str;
-                               gchar *fake_rev;
 
                                if (g_strcmp0 (mb->mailbox_type, "PublicDL") == 0) {
                                        contact = e_contact_new ();
@@ -2626,11 +2695,7 @@ ebb_ews_update_cache_for_expression (EBookBackendEws *bbews,
 
                                /* There is no ChangeKey provided either, thus make up some revision,
                                   to have the contact always updated in the local cache. */
-                               fake_rev = e_util_generate_uid ();
-
-                               e_contact_set (contact, E_CONTACT_REV, fake_rev);
-
-                               g_free (fake_rev);
+                               ebews_populate_rev (contact, NULL);
 
                                str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
                                if (!str || !*str)
@@ -2739,8 +2804,20 @@ ebb_ews_verify_changes (EBookCache *book_cache,
                        EContact *existing = NULL;
 
                        if (e_book_cache_get_contact (book_cache, id->id, TRUE, &existing, cancellable, NULL) 
&&
-                           existing && g_strcmp0 (e_contact_get_const (existing, E_CONTACT_REV), 
id->change_key) == 0) {
-                               g_object_unref (item);
+                           existing) {
+                               gchar *change_key;
+
+                               change_key = e_vcard_util_dup_x_attribute (E_VCARD (existing), 
X_EWS_CHANGEKEY);
+                               if (!change_key)
+                                       change_key = e_contact_get (existing, E_CONTACT_REV);
+
+                               if (g_strcmp0 (change_key, id->change_key) == 0) {
+                                       g_object_unref (item);
+                               } else {
+                                       items = g_slist_prepend (items, item);
+                               }
+
+                               g_free (change_key);
                        } else {
                                items = g_slist_prepend (items, item);
                        }
diff --git a/src/server/e-ews-item.c b/src/server/e-ews-item.c
index 956a8d69..c912d02e 100644
--- a/src/server/e-ews-item.c
+++ b/src/server/e-ews-item.c
@@ -113,6 +113,7 @@ struct _EEwsItemPrivate {
        time_t date_received;
        time_t date_sent;
        time_t date_created;
+       time_t last_modified_time;
 
        gsize size;
        gchar *msg_id;
@@ -1075,6 +1076,10 @@ e_ews_item_set_from_soap_parameter (EEwsItem *item,
                        value = e_soap_parameter_get_string_value (subparam);
                        priv->date_created = ews_item_parse_date (value);
                        g_free (value);
+               } else if (!g_ascii_strcasecmp (name, "LastModifiedTime")) {
+                       value = e_soap_parameter_get_string_value (subparam);
+                       priv->last_modified_time = ews_item_parse_date (value);
+                       g_free (value);
                } else if (!g_ascii_strcasecmp (name, "HasAttachments")) {
                        value = e_soap_parameter_get_string_value (subparam);
                        priv->has_attachments = (!g_ascii_strcasecmp (value, "true"));
@@ -1367,6 +1372,14 @@ e_ews_item_get_date_created (EEwsItem *item)
        return item->priv->date_created;
 }
 
+time_t
+e_ews_item_get_last_modified_time (EEwsItem *item)
+{
+       g_return_val_if_fail (E_IS_EWS_ITEM (item), -1);
+
+       return item->priv->last_modified_time;
+}
+
 gboolean
 e_ews_item_has_attachments (EEwsItem *item,
                             gboolean *has_attachments)
diff --git a/src/server/e-ews-item.h b/src/server/e-ews-item.h
index f5ee3df3..cd67f8c1 100644
--- a/src/server/e-ews-item.h
+++ b/src/server/e-ews-item.h
@@ -190,6 +190,8 @@ const gchar *       e_ews_item_get_date_header      (EEwsItem *item);
 time_t         e_ews_item_get_date_received    (EEwsItem *item);
 time_t         e_ews_item_get_date_sent        (EEwsItem *item);
 time_t         e_ews_item_get_date_created     (EEwsItem *item);
+time_t         e_ews_item_get_last_modified_time
+                                               (EEwsItem *item);
 gboolean       e_ews_item_has_attachments      (EEwsItem *item,
                                                 gboolean *has_attachments);
 gboolean       e_ews_item_is_read              (EEwsItem *item,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]