[evolution-ews/evolution-ews-3-12] Bug #656805 - Read receipt handling doesn't work



commit 704e22bd01c81c0d88ce94db6472627426cce5f7
Author: Milan Crha <mcrha redhat com>
Date:   Wed May 7 12:48:19 2014 +0200

    Bug #656805 - Read receipt handling doesn't work

 src/camel/camel-ews-folder.c  |   87 +++++++++++++++++++++++++++++++++++++---
 src/camel/camel-ews-summary.h |    3 +-
 src/camel/camel-ews-utils.c   |   76 +++++++++++++++++++++++++++---------
 src/server/e-ews-item.c       |   17 ++++++--
 src/server/e-ews-item.h       |    1 +
 src/utils/ews-camel-common.c  |    2 +-
 6 files changed, 153 insertions(+), 33 deletions(-)
---
diff --git a/src/camel/camel-ews-folder.c b/src/camel/camel-ews-folder.c
index b22a7ec..0782409 100644
--- a/src/camel/camel-ews-folder.c
+++ b/src/camel/camel-ews-folder.c
@@ -145,26 +145,36 @@ ews_folder_get_summary_message_mapi_flags (void)
 
        list = ews_folder_get_summary_followup_mapi_flags ();
 
+       /* PidTagMessageFlags */
        ext_uri = e_ews_extended_field_uri_new ();
        ext_uri->prop_tag = g_strdup_printf ("%d", 0x0e07);
        ext_uri->prop_type = g_strdup ("Integer");
        list = g_slist_append (list, ext_uri);
 
+       /* PidTagMessageStatus */
        ext_uri = e_ews_extended_field_uri_new ();
        ext_uri->prop_tag = g_strdup_printf ("%d", 0x0e17);
        ext_uri->prop_type = g_strdup ("Integer");
        list = g_slist_append (list, ext_uri);
 
+       /* PidTagIconIndex */
        ext_uri = e_ews_extended_field_uri_new ();
        ext_uri->prop_tag = g_strdup_printf ("%d", 0x1080);
        ext_uri->prop_type = g_strdup ("Integer");
        list = g_slist_append (list, ext_uri);
 
+       /* PidTagLastVerbExecuted */
        ext_uri = e_ews_extended_field_uri_new ();
        ext_uri->prop_tag = g_strdup_printf ("%d", 0x1081);
        ext_uri->prop_type = g_strdup ("Integer");
        list = g_slist_append (list, ext_uri);
 
+       /* PidTagReadReceiptRequested */
+       ext_uri = e_ews_extended_field_uri_new ();
+       ext_uri->prop_tag = g_strdup_printf ("%d", 0x0029);
+       ext_uri->prop_type = g_strdup ("Boolean");
+       list = g_slist_append (list, ext_uri);
+
        return list;
 }
 
@@ -930,6 +940,38 @@ msg_update_flags (ESoapMessage *msg,
        }
 }
 
+static void
+ews_suppress_read_receipt (ESoapMessage *msg,
+                          gpointer user_data)
+{
+       /* the mi_list is owned by the caller */
+       const GSList *mi_list = user_data, *iter;
+       CamelEwsMessageInfo *mi;
+
+       for (iter = mi_list; iter; iter = g_slist_next (iter)) {
+               mi = iter->data;
+               if (!mi || (camel_message_info_flags (mi) & CAMEL_EWS_MESSAGE_MSGFLAG_RN_PENDING) == 0)
+                       continue;
+
+               /* There was requested a read-receipt, but it is handled by evolution-ews,
+                  thus prevent an automatic send of it by the server */
+               e_soap_message_start_element (msg, "SuppressReadReceipt", NULL, NULL);
+               e_soap_message_start_element (msg, "ReferenceItemId", NULL, NULL);
+               e_soap_message_add_attribute (msg, "Id", mi->info.uid, NULL, NULL);
+               e_soap_message_add_attribute (msg, "ChangeKey", mi->change_key, NULL, NULL);
+               e_soap_message_end_element (msg); /* "ReferenceItemId" */
+               e_soap_message_end_element (msg); /* SuppressReadReceipt */
+
+               mi->info.flags = mi->info.flags & (~CAMEL_EWS_MESSAGE_MSGFLAG_RN_PENDING);
+               mi->info.dirty = TRUE;
+
+               if (!camel_message_info_user_flag ((CamelMessageInfo *) mi, "receipt-handled"))
+                       camel_message_info_set_user_flag ((CamelMessageInfo *) mi, "receipt-handled", TRUE);
+
+               camel_folder_summary_touch (mi->info.summary);
+       }
+}
+
 static gboolean
 ews_sync_mi_flags (CamelFolder *folder,
                    const GSList *mi_list,
@@ -938,8 +980,9 @@ ews_sync_mi_flags (CamelFolder *folder,
 {
        CamelEwsStore *ews_store;
        EEwsConnection *cnc;
+       const GSList *iter;
        GError *local_error = NULL;
-       gboolean res;
+       gboolean res = TRUE;
 
        ews_store = (CamelEwsStore *) camel_folder_get_parent_store (folder);
 
@@ -949,12 +992,42 @@ ews_sync_mi_flags (CamelFolder *folder,
 
        cnc = camel_ews_store_ref_connection (ews_store);
 
-       res = e_ews_connection_update_items_sync (
-               cnc, EWS_PRIORITY_LOW,
-               "AlwaysOverwrite", "SaveOnly",
-               NULL, NULL,
-               msg_update_flags, (gpointer) mi_list, NULL,
-               cancellable, &local_error);
+       for (iter = mi_list; iter; iter = g_slist_next (iter)) {
+               CamelEwsMessageInfo *mi = iter->data;
+
+               if (mi && (camel_message_info_flags (mi) & CAMEL_EWS_MESSAGE_MSGFLAG_RN_PENDING) != 0)
+                       break;
+       }
+
+       /* NULL means all had been checked and none has the flag set */
+       if (iter) {
+               GSList *ids = NULL;
+
+               res = e_ews_connection_create_items_sync (
+                       cnc, EWS_PRIORITY_LOW,
+                       "SaveOnly", NULL, NULL,
+                       ews_suppress_read_receipt, (gpointer) mi_list,
+                       &ids, cancellable, &local_error);
+
+               g_slist_free_full (ids, g_object_unref);
+
+               /* ignore this error, it's not a big problem */
+               if (g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_READRECEIPTNOTPENDING)) {
+                       g_clear_error (&local_error);
+                       res = TRUE;
+               }
+       }
+
+       if (res) {
+               res = e_ews_connection_update_items_sync (
+                       cnc, EWS_PRIORITY_LOW,
+                       "AlwaysOverwrite", "SaveOnly",
+                       NULL, NULL,
+                       msg_update_flags, (gpointer) mi_list, NULL,
+                       cancellable, &local_error);
+       }
+
+       camel_folder_summary_save_to_db (folder->summary, NULL);
 
        if (local_error) {
                camel_ews_store_maybe_disconnect (ews_store, local_error);
diff --git a/src/camel/camel-ews-summary.h b/src/camel/camel-ews-summary.h
index eb47a7a..b28d4e1 100644
--- a/src/camel/camel-ews-summary.h
+++ b/src/camel/camel-ews-summary.h
@@ -52,8 +52,7 @@ typedef struct _CamelEwsMessageContentInfo CamelEwsMessageContentInfo;
 
 /* extra summary flags*/
 enum {
-       CAMEL_EWS_MESSAGE_JUNK = 1 << 17,
-       CAMEL_EWS_MESSAGE_NOJUNK = 1 << 18
+       CAMEL_EWS_MESSAGE_MSGFLAG_RN_PENDING = CAMEL_MESSAGE_FOLDER_FLAGGED << 1
 };
 
 struct _CamelEwsMessageInfo {
diff --git a/src/camel/camel-ews-utils.c b/src/camel/camel-ews-utils.c
index 87e9eab..ab1bf1e 100644
--- a/src/camel/camel-ews-utils.c
+++ b/src/camel/camel-ews-utils.c
@@ -40,6 +40,8 @@
 #define SUBFOLDER_DIR_NAME     "subfolders"
 #define SUBFOLDER_DIR_NAME_LEN 10
 
+#define EWS_MAPI_MSGFLAG_RN_PENDING 0x100
+
 CamelFolderInfo *
 camel_ews_utils_build_folder_info (CamelEwsStore *store,
                                    const gchar *fid)
@@ -418,6 +420,16 @@ ews_utils_rename_label (const gchar *cat,
        return cat;
 }
 
+static gboolean
+ews_utils_is_system_user_flag (const gchar *name)
+{
+       if (!name)
+               return FALSE;
+
+       return g_str_equal (name, "receipt-handled") ||
+               g_str_equal (name, "$has-cal");
+}
+
 void
 ews_utils_replace_server_user_flags (ESoapMessage *msg,
                                      CamelEwsMessageInfo *mi)
@@ -431,14 +443,12 @@ ews_utils_replace_server_user_flags (ESoapMessage *msg,
                const gchar *n = ews_utils_rename_label (flag->name, 0);
                if (*n == '\0')
                        continue;
-               /* This is a mismatch between evolution flags and
-                * exchange categories.  Evolution uses a
-                * receipt-handled flag for message receipts, which we
-                * don't want showing up in the categories, so
-                * silently drop it here */
-               if (strcmp (n, "receipt-handled") == 0 ||
-                   strcmp (n, "$has-cal") == 0)
+
+               /* Skip evolution-defined flags which are not supposed to
+                  be categories on an Exchange server */
+               if (ews_utils_is_system_user_flag (n))
                        continue;
+
                e_ews_message_write_string_parameter (msg, "String", NULL, n);
        }
 }
@@ -453,14 +463,16 @@ ews_utils_merge_server_user_flags (EEwsItem *item,
 
        /* transfer camel flags to a list */
        for (flag = camel_message_info_user_flags (&mi->info); flag;
-            flag = flag->next)
-               list = g_slist_append (list, (gchar *) flag->name);
+            flag = flag->next) {
+               if (!ews_utils_is_system_user_flag (flag->name))
+                       list = g_slist_prepend (list, (gchar *) flag->name);
+       }
 
-       /* we're transferring from server only, so just dump them */
        for (p = list; p; p = p->next) {
-               camel_flag_set (&mi->info.user_flags, p->data, 0);
+               /* remove custom user flags */
+               camel_flag_set (&mi->info.user_flags, p->data, FALSE);
        }
-       //g_slist_foreach (list, (GFunc) g_free, NULL);
+
        g_slist_free (list);
 
        /* now transfer over all the categories */
@@ -471,12 +483,12 @@ ews_utils_merge_server_user_flags (EEwsItem *item,
        }
 }
 
-static gint
+static guint32
 ews_utils_get_server_flags (EEwsItem *item)
 {
        gboolean flag;
        EwsImportance importance;
-       gint server_flags = 0;
+       guint32 server_flags = 0, msg_flags;
 
        e_ews_item_is_read (item, &flag);
        if (flag)
@@ -500,6 +512,10 @@ ews_utils_get_server_flags (EEwsItem *item)
        if (importance == EWS_ITEM_HIGH)
                server_flags |= CAMEL_MESSAGE_FLAGGED;
 
+       msg_flags = e_ews_item_get_message_flags (item);
+       if ((msg_flags & EWS_MAPI_MSGFLAG_RN_PENDING) != 0)
+               server_flags |= CAMEL_EWS_MESSAGE_MSGFLAG_RN_PENDING;
+
        /* TODO Update replied flags */
 
        return server_flags;
@@ -707,6 +723,23 @@ camel_ews_utils_update_follow_up_flags (EEwsItem *item,
        return changed;
 }
 
+static gboolean
+camel_ews_utils_update_read_receipt_flags (EEwsItem *item,
+                                          CamelMessageInfo *info,
+                                          guint32 server_flags,
+                                          gboolean requests_read_receipt)
+{
+       gboolean changed = FALSE;
+
+       /* PidTagReadReceiptRequested */
+       if ((requests_read_receipt || e_ews_item_get_extended_property_as_boolean (item, NULL, 0x0029, NULL)) 
&&
+           (server_flags & CAMEL_EWS_MESSAGE_MSGFLAG_RN_PENDING) == 0) {
+               changed = camel_message_info_set_user_flag (info, "receipt-handled", TRUE) || changed;
+       }
+
+       return changed;
+}
+
 void
 camel_ews_utils_sync_updated_items (CamelEwsFolder *ews_folder,
                                     GSList *items_updated)
@@ -732,16 +765,18 @@ camel_ews_utils_sync_updated_items (CamelEwsFolder *ews_folder,
                mi = (CamelEwsMessageInfo *)
                        camel_folder_summary_get (folder->summary, id->id);
                if (mi) {
-                       gint server_flags;
+                       guint32 server_flags;
                        gboolean changed, was_changed;
 
                        was_changed = (mi->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0;
+
                        server_flags = ews_utils_get_server_flags (item);
                        ews_utils_merge_server_user_flags (item, mi);
                        changed = camel_ews_update_message_info_flags (
                                folder->summary, (CamelMessageInfo *) mi,
                                server_flags, NULL);
                        changed = camel_ews_utils_update_follow_up_flags (item, (CamelMessageInfo *) mi) || 
changed;
+                       changed = camel_ews_utils_update_read_receipt_flags (item, (CamelMessageInfo *) mi, 
server_flags, FALSE) || changed;
 
                        if (changed)
                                camel_folder_change_info_change_uid (ci, mi->info.uid);
@@ -795,7 +830,7 @@ camel_ews_utils_sync_created_items (CamelEwsFolder *ews_folder,
                EEwsItemType item_type;
                const GSList *to, *cc;
                const gchar *msg_headers;
-               gboolean has_attachments, found_property;
+               gboolean has_attachments, found_property, message_requests_read_receipt = FALSE;
                guint32 server_flags;
 
                if (!item)
@@ -833,8 +868,11 @@ camel_ews_utils_sync_created_items (CamelEwsFolder *ews_folder,
                        camel_mime_parser_scan_from (parser, FALSE);
                        g_object_unref (stream);
 
-                       if (camel_mime_part_construct_from_parser_sync (part, parser, NULL, NULL))
+                       if (camel_mime_part_construct_from_parser_sync (part, parser, NULL, NULL)) {
                                mi = (CamelEwsMessageInfo *) camel_folder_summary_info_new_from_header 
(folder->summary, part->headers);
+                               if (camel_header_raw_find (&(part->headers), "Disposition-Notification-To", 
NULL))
+                                       message_requests_read_receipt = TRUE;
+                       }
 
                        g_object_unref (parser);
                        g_object_unref (part);
@@ -893,9 +931,9 @@ camel_ews_utils_sync_created_items (CamelEwsFolder *ews_folder,
                mi->server_flags = server_flags;
 
                camel_ews_utils_update_follow_up_flags (item, (CamelMessageInfo *) mi);
+               camel_ews_utils_update_read_receipt_flags (item, (CamelMessageInfo *) mi, server_flags, 
message_requests_read_receipt);
 
-               camel_folder_summary_add (
-                       folder->summary, (CamelMessageInfo *) mi);
+               camel_folder_summary_add (folder->summary, (CamelMessageInfo *) mi);
 
                /* camel_folder_summary_add() sets folder_flagged flag
                 * on the message info, but this is a fresh item downloaded
diff --git a/src/server/e-ews-item.c b/src/server/e-ews-item.c
index dde2cfa..23b5f81 100644
--- a/src/server/e-ews-item.c
+++ b/src/server/e-ews-item.c
@@ -554,15 +554,15 @@ parse_extended_property (EEwsItemPrivate *priv,
                        priv->mapi_icon_index = num_value;
                        break;
 
-               case 0x1081:
+               case 0x1081: /* PidTagLastVerbExecuted */
                        priv->mapi_last_verb_executed = num_value;
                        break;
 
-               case 0xe07:
+               case 0x0e07: /* PidTagMessageFlags */
                        priv->mapi_message_flags = num_value;
                        break;
 
-               case 0xe17:
+               case 0x0e17: /* PidTagMessageStatus */
                        priv->mapi_message_status = num_value;
                        break;
                }
@@ -1451,6 +1451,14 @@ e_ews_item_is_answered (EEwsItem *item,
        return TRUE;
 }
 
+guint32
+e_ews_item_get_message_flags (EEwsItem *item)
+{
+       g_return_val_if_fail (E_IS_EWS_ITEM (item), 0);
+
+       return item->priv->mapi_message_flags;
+}
+
 const GSList *
 e_ews_item_get_to_recipients (EEwsItem *item)
 {
@@ -1645,11 +1653,12 @@ e_ews_item_get_extended_property_as_boolean (EEwsItem *item,
        if (g_str_equal (value, "true"))
                return TRUE;
 
-       if (g_str_equal (value, "true"))
+       if (g_str_equal (value, "false"))
                return FALSE;
 
        if (found)
                *found = FALSE;
+
        return FALSE;
 }
 
diff --git a/src/server/e-ews-item.h b/src/server/e-ews-item.h
index e75fb7a..a7c2948 100644
--- a/src/server/e-ews-item.h
+++ b/src/server/e-ews-item.h
@@ -201,6 +201,7 @@ gboolean    e_ews_item_is_forwarded         (EEwsItem *item,
                                                 gboolean *is_forwarded);
 gboolean       e_ews_item_is_answered          (EEwsItem *item,
                                                 gboolean *is_answered);
+guint32                e_ews_item_get_message_flags    (EEwsItem *item);
 const GSList * e_ews_item_get_to_recipients    (EEwsItem *item);
 const GSList * e_ews_item_get_cc_recipients    (EEwsItem *item);
 const GSList * e_ews_item_get_bcc_recipients   (EEwsItem *item);
diff --git a/src/utils/ews-camel-common.c b/src/utils/ews-camel-common.c
index 768c3a7..508afe0 100644
--- a/src/utils/ews-camel-common.c
+++ b/src/utils/ews-camel-common.c
@@ -183,7 +183,7 @@ create_mime_message_cb (ESoapMessage *msg,
         * property Further crap is that Exchange 2007 assumes when it
         * sees this property that you're setting the value to 0
         * ... it never checks */
-       msgflag  = MAPI_MSGFLAG_READ; /* draft or sent is always read */
+       msgflag = MAPI_MSGFLAG_READ; /* draft or sent is always read */
        if ((message_camel_flags & CAMEL_MESSAGE_DRAFT) != 0)
                msgflag |= MAPI_MSGFLAG_UNSENT;
 


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