[evolution-ews] Bug #654950 - Contact doesn't fetch photo



commit 477ea341525bb5882d22dc836b1d73e27f9a6b9f
Author: Fabiano Fidêncio <fidencio redhat com>
Date:   Wed Apr 17 02:05:42 2013 +0200

    Bug #654950 - Contact doesn't fetch photo
    
    This operation is only supported for Exchange Server newer than 2010_SP2.
    Ideally we might could populate which item can be changed or not
    according with the server version, dinamically, but, for now, it is
    implemented in a different way by Evolution.

 src/addressbook/e-book-backend-ews.c |  432 +++++++++++++++++++++++++++++-----
 src/server/e-ews-connection.c        |  381 ++++++++++++++++++++++++++++--
 src/server/e-ews-connection.h        |   45 ++++
 src/server/e-ews-item.c              |   28 ++-
 src/server/e-ews-item.h              |    3 +
 5 files changed, 801 insertions(+), 88 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-ews.c b/src/addressbook/e-book-backend-ews.c
index 2361657..f595fb7 100644
--- a/src/addressbook/e-book-backend-ews.c
+++ b/src/addressbook/e-book-backend-ews.c
@@ -274,8 +274,11 @@ static const struct phone_field_mapping {
 };
 
 static void
-ebews_populate_uid (EContact *contact,
-                    EEwsItem *item)
+ebews_populate_uid (EBookBackendEws *ebews,
+                   EContact *contact,
+                    EEwsItem *item,
+                   GCancellable *cancellable,
+                   GError **error)
 {
        const EwsId *id;
 
@@ -287,8 +290,11 @@ ebews_populate_uid (EContact *contact,
 }
 
 static void
-ebews_populate_full_name (EContact *contact,
-                          EEwsItem *item)
+ebews_populate_full_name (EBookBackendEws *ebews,
+                         EContact *contact,
+                         EEwsItem *item,
+                         GCancellable *cancellable,
+                         GError **error)
 {
        const EwsCompleteName *cn;
 
@@ -298,8 +304,11 @@ ebews_populate_full_name (EContact *contact,
 }
 
 static void
-ebews_populate_nick_name (EContact *contact,
-                          EEwsItem *item)
+ebews_populate_nick_name (EBookBackendEws *ebews,
+                         EContact *contact,
+                         EEwsItem *item,
+                         GCancellable *cancellable,
+                         GError **error)
 {
        const EwsCompleteName *cn;
 
@@ -309,8 +318,11 @@ ebews_populate_nick_name (EContact *contact,
 }
 
 static void
-ebews_populate_birth_date (EContact *contact,
-                           EEwsItem *item)
+ebews_populate_birth_date (EBookBackendEws *ebews,
+                          EContact *contact,
+                          EEwsItem *item,
+                          GCancellable *cancellable,
+                          GError **error)
 {
        time_t bdate;
        GDate date;
@@ -332,8 +344,11 @@ ebews_populate_birth_date (EContact *contact,
 }
 
 static void
-ebews_populate_anniversary (EContact *contact,
-                            EEwsItem *item)
+ebews_populate_anniversary (EBookBackendEws *ebews,
+                           EContact *contact,
+                           EEwsItem *item,
+                           GCancellable *cancellable,
+                           GError **error)
 {
        time_t bdate;
        GDate date;
@@ -354,6 +369,88 @@ ebews_populate_anniversary (EContact *contact,
        }
 }
 
+static EContactPhoto *
+get_photo (EBookBackendEws *ebews,
+          EEwsItem *item,
+          GCancellable *cancellable,
+          GError **error)
+{
+       EContactPhoto *photo = NULL;
+       EEwsAttachmentInfo *info;
+       GSList *contact_item_ids = NULL, *new_items = NULL;
+       GSList *attachments = NULL,  *attachments_ids = NULL, *items = NULL;
+       const guchar *content;
+       const gchar *contact_photo_id;
+       const EwsId *id;
+       gsize len;
+
+       id = e_ews_item_get_id (item);
+       contact_item_ids = g_slist_prepend (contact_item_ids, g_strdup (id->id));
+       if (!e_ews_connection_get_photo_attachment_id_sync (
+                       ebews->priv->cnc,
+                       EWS_PRIORITY_MEDIUM,
+                       contact_item_ids,
+                       &new_items,
+                       cancellable,
+                       error))
+               goto exit;
+
+       contact_photo_id = e_ews_item_get_contact_photo_id (new_items->data);
+       if (!contact_photo_id)
+               goto exit;
+
+       attachments_ids = g_slist_prepend (attachments_ids, g_strdup (contact_photo_id));
+       items = e_ews_connection_get_attachments_sync (
+               ebews->priv->cnc,
+               EWS_PRIORITY_MEDIUM,
+               NULL,
+               attachments_ids,
+               NULL,
+               FALSE,
+               &attachments,
+               NULL,
+               NULL,
+               cancellable,
+               error);
+
+       if (!items)
+               goto exit;
+
+       info = attachments->data;
+       content = (guchar *) e_ews_attachment_info_get_inlined_data (info, &len);
+
+       photo = e_contact_photo_new ();
+       photo->type = E_CONTACT_PHOTO_TYPE_INLINED;
+       e_contact_photo_set_inlined (photo, content, len);
+
+exit:
+       g_slist_free_full (contact_item_ids, g_free);
+       g_slist_free_full (new_items, g_object_unref);
+       g_slist_free_full (attachments_ids, g_free);
+       g_slist_free_full (items, g_free);
+       g_slist_free_full (attachments, (GDestroyNotify) e_ews_attachment_info_free);
+
+       return photo;
+}
+
+static void
+ebews_populate_photo (EBookBackendEws *ebews,
+                     EContact *contact,
+                     EEwsItem *item,
+                     GCancellable *cancellable,
+                     GError **error)
+{
+       EContactPhoto *photo;
+
+       photo = get_photo (ebews, item, cancellable, error);
+       if (!photo) {
+               return;
+       }
+
+       e_contact_set (contact, E_CONTACT_PHOTO, photo);
+       e_contact_photo_free (photo);
+}
+
 static void
 set_phone_number (EContact *contact,
                   EContactField field,
@@ -368,8 +465,11 @@ set_phone_number (EContact *contact,
 }
 
 static void
-ebews_populate_phone_numbers (EContact *contact,
-                              EEwsItem *item)
+ebews_populate_phone_numbers (EBookBackendEws *ebews,
+                             EContact *contact,
+                             EEwsItem *item,
+                             GCancellable *cancellable,
+                             GError **error)
 {
        gint i;
 
@@ -410,8 +510,11 @@ set_address (EContact *contact,
 }
 
 static void
-ebews_populate_address (EContact *contact,
-                        EEwsItem *item)
+ebews_populate_address (EBookBackendEws *ebews,
+                       EContact *contact,
+                       EEwsItem *item,
+                       GCancellable *cancellable,
+                       GError **error)
 {
 
        set_address (contact, E_CONTACT_ADDRESS_WORK, item, "Business");
@@ -420,16 +523,22 @@ ebews_populate_address (EContact *contact,
 }
 
 static void
-ebews_populate_ims (EContact *contact,
-                    EEwsItem *item)
+ebews_populate_ims (EBookBackendEws *ebews,
+                   EContact *contact,
+                   EEwsItem *item,
+                   GCancellable *cancellable,
+                   GError **error)
 {
        /* TODO : The fields returned by server does not match with the EContact fields
         * for the IMS, handle it later */
 }
 
 static void
-ebews_populate_notes (EContact *contact,
-                      EEwsItem *item)
+ebews_populate_notes (EBookBackendEws *ebews,
+                     EContact *contact,
+                     EEwsItem *item,
+                     GCancellable *cancellable,
+                     GError **error)
 {
        const gchar *notes = e_ews_item_get_notes (item);
        if (!notes)
@@ -452,8 +561,11 @@ set_email_address (EContact *contact,
 }
 
 static void
-ebews_populate_emails (EContact *contact,
-                       EEwsItem *item)
+ebews_populate_emails (EBookBackendEws *ebews,
+                      EContact *contact,
+                      EEwsItem *item,
+                      GCancellable *cancellable,
+                      GError **errror)
 {
        set_email_address (contact, E_CONTACT_EMAIL_1, item, "EmailAddress1");
        set_email_address (contact, E_CONTACT_EMAIL_2, item, "EmailAddress2");
@@ -516,6 +628,13 @@ ebews_set_anniversary (ESoapMessage *message,
 
 }
 
+static void
+ebews_set_photo (ESoapMessage *message,
+                 EContact *contact)
+{
+
+}
+
 static gboolean
 add_entry (ESoapMessage *msg,
            EContact *contact,
@@ -678,9 +797,12 @@ convert_indexed_contact_property_to_updatexml (ESoapMessage *message,
 }
 
 static void
-ebews_set_full_name_changes (ESoapMessage *message,
-                             EContact *new,
-                             EContact *old)
+ebews_set_full_name_changes (EBookBackendEws *ebews,
+                            ESoapMessage *message,
+                            EContact *new,
+                            EContact *old,
+                            GCancellable *cancellable,
+                            GError **error)
 {
        EContactName *name, *old_name;
 
@@ -701,9 +823,12 @@ ebews_set_full_name_changes (ESoapMessage *message,
 }
 
 static void
-ebews_set_birth_date_changes (ESoapMessage *message,
-                              EContact *new,
-                              EContact *old)
+ebews_set_birth_date_changes (EBookBackendEws *ebews,
+                             ESoapMessage *message,
+                             EContact *new,
+                             EContact *old,
+                             GCancellable *cancellable,
+                             GError **error)
 {
        EContactDate *new_date, *old_date;
        gchar *birthday;
@@ -723,17 +848,144 @@ ebews_set_birth_date_changes (ESoapMessage *message,
 }
 
 static void
-ebews_set_anniversary_changes (ESoapMessage *message,
-                               EContact *new,
-                               EContact *old)
+ebews_set_anniversary_changes (EBookBackendEws *ebews,
+                              ESoapMessage *message,
+                              EContact *new,
+                              EContact *old,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+
+}
+
+static void
+set_photo (EBookBackendEws *ebews,
+          EContact *contact,
+          EContactPhoto *photo,
+          GCancellable *cancellable,
+          GError **error)
+{
+       EEwsAttachmentInfo *info;
+       EwsId *id;
+       GSList *files = NULL;
+       const guchar *data;
+       gsize len;
+
+       id = g_new0 (EwsId, 1);
+       id->id = e_contact_get (contact, E_CONTACT_UID);
+       id->change_key = e_contact_get (contact, E_CONTACT_REV);
+
+       data = e_contact_photo_get_inlined (photo, &len);
+
+       info = e_ews_attachment_info_new (E_EWS_ATTACHMENT_INFO_TYPE_INLINED);
+       e_ews_attachment_info_set_inlined_data (info, data, len);
+       e_ews_attachment_info_set_mime_type (info, "image/jpeg");
+       e_ews_attachment_info_set_filename (info, "ContactPicture.jpg");
+
+       files = g_slist_append (files, info);
+
+       e_ews_connection_create_photo_attachment_sync (
+                       ebews->priv->cnc,
+                       EWS_PRIORITY_MEDIUM,
+                       id,
+                       files,
+                       cancellable,
+                       error);
+
+       g_free (id->change_key);
+       g_free (id->id);
+       g_free (id);
+
+       g_slist_free_full (files, (GDestroyNotify) e_ews_attachment_info_free);
+}
+
+static gboolean
+photos_equal (EContactPhoto *old,
+               EContactPhoto *new)
+{
+       const guchar *old_content, *new_content;
+       gsize old_len, new_len;
+
+       if (!old && !new)
+               return TRUE;
+
+       if (!old || !new)
+               return FALSE;
+
+       old_content = e_contact_photo_get_inlined (old, &old_len);
+       new_content = e_contact_photo_get_inlined (new, &new_len);
+
+       if (old_len != new_len)
+               return FALSE;
+
+       if (memcmp (old_content, new_content, old_len) != 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+static void
+ebews_set_photo_changes (EBookBackendEws *ebews,
+                        ESoapMessage *message,
+                        EContact *new,
+                        EContact *old,
+                        GCancellable *cancellable,
+                        GError **error)
 {
+       EContactPhoto *old_photo, *new_photo;
+       GSList *contact_item_ids = NULL, *new_items = NULL, *attachments_ids = NULL, *deleted_attachments = 
NULL;
+       gchar *id = e_contact_get (old, E_CONTACT_UID);
+       const gchar *contact_photo_id;
+
+       old_photo = e_contact_get (old, E_CONTACT_PHOTO);
+       new_photo = e_contact_get (new, E_CONTACT_PHOTO);
 
+       if (photos_equal (old_photo, new_photo))
+               goto exit;
+
+       contact_item_ids = g_slist_append (contact_item_ids, id);
+       if (!e_ews_connection_get_photo_attachment_id_sync (
+                       ebews->priv->cnc,
+                       EWS_PRIORITY_MEDIUM,
+                       contact_item_ids,
+                       &new_items,
+                       cancellable,
+                       error))
+               goto exit;
+
+       contact_photo_id = e_ews_item_get_contact_photo_id (new_items->data);
+       if (contact_photo_id) {
+               attachments_ids = g_slist_prepend (attachments_ids, g_strdup (contact_photo_id));
+               deleted_attachments = e_ews_connection_delete_attachments_sync (
+                                       ebews->priv->cnc,
+                                       EWS_PRIORITY_MEDIUM,
+                                       attachments_ids,
+                                       cancellable,
+                                       error);
+
+               if (!deleted_attachments)
+                       goto exit;
+       }
+
+       if (new_photo)
+               set_photo (ebews, new, new_photo, cancellable, error);
+
+exit:
+       e_contact_photo_free (old_photo);
+       e_contact_photo_free (new_photo);
+       g_slist_free_full (contact_item_ids, g_free);
+       g_slist_free_full (new_items, g_object_unref);
+       g_slist_free_full (attachments_ids, g_free);
+       g_slist_free_full (deleted_attachments, g_free);
 }
 
 static void
-ebews_set_phone_number_changes (ESoapMessage *message,
-                                EContact *new,
-                                EContact *old)
+ebews_set_phone_number_changes (EBookBackendEws *ebews,
+                               ESoapMessage *message,
+                               EContact *new,
+                               EContact *old,
+                               GCancellable *cancellable,
+                               GError **error)
 {
        gint i;
        gchar *new_value, *old_value;
@@ -823,9 +1075,12 @@ compare_address (ESoapMessage *message,
 }
 
 static void
-ebews_set_address_changes (ESoapMessage *message,
-                           EContact *new,
-                           EContact *old)
+ebews_set_address_changes (EBookBackendEws *ebews,
+                          ESoapMessage *message,
+                          EContact *new,
+                          EContact *old,
+                          GCancellable *cancellable,
+                          GError **error)
 {
        compare_address (message, new, old, E_CONTACT_ADDRESS_WORK, "Business");
        compare_address (message, new, old, E_CONTACT_ADDRESS_HOME, "Home");
@@ -833,17 +1088,23 @@ ebews_set_address_changes (ESoapMessage *message,
 }
 
 static void
-ebews_set_im_changes (ESoapMessage *message,
-                      EContact *new,
-                      EContact *old)
+ebews_set_im_changes (EBookBackendEws *ebews,
+                     ESoapMessage *message,
+                     EContact *new,
+                     EContact *old,
+                     GCancellable *cancellable,
+                     GError **error)
 {
 
 }
 
 static void
-ebews_set_notes_changes (ESoapMessage *message,
-                         EContact *new,
-                         EContact *old)
+ebews_set_notes_changes (EBookBackendEws *ebews,
+                        ESoapMessage *message,
+                        EContact *new,
+                        EContact *old,
+                        GCancellable *cancellable,
+                        GError **error)
 {
        gchar *old_notes, *new_notes;
 
@@ -860,9 +1121,12 @@ ebews_set_notes_changes (ESoapMessage *message,
 }
 
 static void
-ebews_set_email_changes (ESoapMessage *message,
-                         EContact *new,
-                         EContact *old)
+ebews_set_email_changes (EBookBackendEws *ebews,
+                        ESoapMessage *message,
+                        EContact *new,
+                        EContact *old,
+                        GCancellable *cancellable,
+                        GError **error)
 {
        gchar *new_value, *old_value;
 
@@ -900,9 +1164,9 @@ static const struct field_element_mapping {
        const gchar *element_name;
        /* set function for simple string type values */
        const gchar * (*get_simple_prop_func) (EEwsItem *item);
-       void (*populate_contact_func)(EContact *contact, EEwsItem *item);
+       void (*populate_contact_func)(EBookBackendEws *ebews, EContact *contact, EEwsItem *item, GCancellable 
*cancellable, GError **error);
        void (*set_value_in_soap_message) (ESoapMessage *message, EContact *contact);
-       void (*set_changes) (ESoapMessage *message, EContact *new, EContact *old);
+       void (*set_changes) (EBookBackendEws *ebews, ESoapMessage *message, EContact *new, EContact *old, 
GCancellable *cancellable, GError **error);
 
 } mappings[] = {
        /* The order should be maintained for create contacts to work */
@@ -930,6 +1194,7 @@ static const struct field_element_mapping {
        { E_CONTACT_SPOUSE, ELEMENT_TYPE_SIMPLE, "SpouseName", e_ews_item_get_spouse_name},
        { E_CONTACT_FAMILY_NAME, ELEMENT_TYPE_SIMPLE, "Surname", e_ews_item_get_surname},
        { E_CONTACT_BIRTH_DATE, ELEMENT_TYPE_COMPLEX, "WeddingAnniversary", NULL,  
ebews_populate_anniversary, ebews_set_anniversary, ebews_set_anniversary_changes },
+       { E_CONTACT_PHOTO, ELEMENT_TYPE_COMPLEX, "Photo", NULL,  ebews_populate_photo, ebews_set_photo, 
ebews_set_photo_changes },
 
        /* Should take of uid and changekey (REV) */
        { E_CONTACT_UID, ELEMENT_TYPE_COMPLEX, "ItemId", NULL,  ebews_populate_uid, ebews_set_item_id},
@@ -940,6 +1205,7 @@ typedef struct {
        EDataBook *book;
        EContact *contact;
        guint32 opid;
+       GCancellable *cancellable;
 } EwsCreateContact;
 
 static void
@@ -992,6 +1258,7 @@ ews_create_contact_cb (GObject *object,
 
        if (error == NULL) {
                EEwsItem *item = (EEwsItem *) items->data;
+               EContactPhoto *photo;
 
                /* set item id */
                item_id = e_ews_item_get_id ((EEwsItem *) items->data);
@@ -1008,6 +1275,17 @@ ews_create_contact_cb (GObject *object,
                        g_slist_free (contacts);
                }
 
+               /*
+                * The contact photo is basically an attachment with a special name.
+                * Considering this, we only can set the contact photo after create the contact itself.
+                * Then we are able to attach the picture to the "Contact Item".
+                */
+               photo = e_contact_get (create_contact->contact, E_CONTACT_PHOTO);
+               if (photo) {
+                       set_photo (ebews, create_contact->contact, photo, create_contact->cancellable, 
&error);
+                       e_contact_photo_free (photo);
+               }
+
                g_object_unref (item);
                g_slist_free (items);
        }
@@ -1020,6 +1298,7 @@ ews_create_contact_cb (GObject *object,
        /* free memory allocated for create_contact & unref contained objects */
        g_object_unref (create_contact->ebews);
        g_object_unref (create_contact->contact);
+       g_object_unref (create_contact->cancellable);
        g_free (create_contact);
        g_clear_error (&error);
 }
@@ -1084,6 +1363,7 @@ e_book_backend_ews_create_contacts (EBookBackend *backend,
        create_contact->book = g_object_ref (book);
        create_contact->opid = opid;
        create_contact->contact = g_object_ref (contact);
+       create_contact->cancellable = g_object_ref (cancellable);
 
        fid = e_ews_folder_id_new (priv->folder_id, NULL, FALSE);
 
@@ -1206,6 +1486,7 @@ typedef struct {
        EContact *new_contact;
        EContact *old_contact;
        guint32 opid;
+       GCancellable *cancellable;
 } EwsModifyContact;
 
 static void
@@ -1230,18 +1511,27 @@ ews_modify_contact_cb (GObject *object,
        g_return_if_fail (priv->summary != NULL);
 
        if (error == NULL) {
-               EEwsItem *item = (EEwsItem *) items->data;
+               if (items != NULL) {
+                       EEwsItem *item = (EEwsItem *) items->data;
 
-               /* set item id */
-               item_id = e_ews_item_get_id ((EEwsItem *) items->data);
+                       /* set item id */
+                       item_id = e_ews_item_get_id (item);
+
+                       e_contact_set (modify_contact->new_contact, E_CONTACT_UID, item_id->id);
+                       e_contact_set (modify_contact->new_contact, E_CONTACT_REV, item_id->change_key);
 
-               e_contact_set (modify_contact->new_contact, E_CONTACT_UID, item_id->id);
-               e_contact_set (modify_contact->new_contact, E_CONTACT_REV, item_id->change_key);
+                       g_object_unref (item);
+               }
 
                id = e_contact_get (modify_contact->old_contact, E_CONTACT_UID);
 
                e_book_backend_sqlitedb_remove_contact (priv->summary, priv->folder_id, id, &error);
-               e_book_backend_sqlitedb_new_contact (ebews->priv->summary, ebews->priv->folder_id, 
modify_contact->new_contact, TRUE, &error);
+               e_book_backend_sqlitedb_new_contact (
+                               ebews->priv->summary,
+                               ebews->priv->folder_id,
+                               modify_contact->new_contact,
+                               TRUE,
+                               &error);
 
                if (error == NULL) {
                        GSList *new_contacts;
@@ -1251,7 +1541,6 @@ ews_modify_contact_cb (GObject *object,
                        g_slist_free (new_contacts);
                }
 
-               g_object_unref (item);
                g_slist_free (items);
        }
 
@@ -1265,6 +1554,7 @@ ews_modify_contact_cb (GObject *object,
        g_object_unref (modify_contact->ebews);
        g_object_unref (modify_contact->new_contact);
        g_object_unref (modify_contact->old_contact);
+       g_object_unref (modify_contact->cancellable);
        g_free (modify_contact);
        g_clear_error (&error);
 }
@@ -1279,6 +1569,7 @@ convert_contact_to_updatexml (ESoapMessage *msg,
        EContact *new_contact = modify_contact->new_contact;
        gchar *value = NULL, *old_value = NULL;
        gint i, element_type;
+       GError *error = NULL;
 
        id = g_new0 (EwsId, 1);
        id->id = e_contact_get (old_contact, E_CONTACT_UID);
@@ -1304,7 +1595,20 @@ convert_contact_to_updatexml (ESoapMessage *msg,
                } else if (element_type == ELEMENT_TYPE_COMPLEX) {
                        if (mappings[i].field_id == E_CONTACT_UID)
                                continue;
-                       mappings[i].set_changes (msg, new_contact, old_contact);
+                       mappings[i].set_changes (
+                                       modify_contact->ebews, msg,
+                                       new_contact, old_contact,
+                                       modify_contact->cancellable,
+                                       &error);
+
+                       if (error != NULL) {
+                               e_data_book_respond_modify_contacts (
+                                               modify_contact->book,
+                                               modify_contact->opid,
+                                               EDB_ERROR_EX (OTHER_ERROR, error->message),
+                                               NULL);
+                               g_clear_error (&error);
+                       }
                }
        }
 
@@ -1390,6 +1694,8 @@ e_book_backend_ews_modify_contacts (EBookBackend *backend,
        modify_contact->opid = opid;
        modify_contact->old_contact = g_object_ref (old_contact);
        modify_contact->new_contact = g_object_ref (contact);
+       modify_contact->cancellable = g_object_ref (cancellable);
+
        e_ews_connection_update_items (
                priv->cnc, EWS_PRIORITY_MEDIUM,
                "AlwaysOverwrite", "SendAndSaveCopy",
@@ -2062,6 +2368,7 @@ static void
 ebews_store_contact_items (EBookBackendEws *ebews,
                            GSList *new_items,
                            gboolean distribution_list,
+                          GCancellable *cancellable,
                            GError **error)
 {
        EBookBackendEwsPrivate *priv;
@@ -2094,7 +2401,7 @@ ebews_store_contact_items (EBookBackendEws *ebews,
                                        if (val != NULL)
                                                e_contact_set (contact, mappings[i].field_id, val);
                                } else
-                                       mappings[i].populate_contact_func (contact, item);
+                                       mappings[i].populate_contact_func (ebews, contact, item, cancellable, 
error);
                        }
                } else {
                        /* store display_name, fileas, item id */       
@@ -2111,8 +2418,11 @@ ebews_store_contact_items (EBookBackendEws *ebews,
 }
 
 static void
-ebews_get_vcards_list (GSList *new_items,
-                       GSList **vcards)
+ebews_get_vcards_list (EBookBackendEws *ebews,
+                      GSList *new_items,
+                       GSList **vcards,
+                      GCancellable *cancellable,
+                      GError **error)
 {
        GSList *l;
 
@@ -2137,7 +2447,7 @@ ebews_get_vcards_list (GSList *new_items,
                                if (val != NULL)
                                        e_contact_set (contact, mappings[i].field_id, val);
                        } else
-                               mappings[i].populate_contact_func (contact, item);
+                               mappings[i].populate_contact_func (ebews, contact, item, cancellable, error);
                }
                vcard_string = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
                *vcards = g_slist_append (*vcards, g_strdup(vcard_string));
@@ -2289,14 +2599,15 @@ ebews_fetch_items (EBookBackendEws *ebews,
                        contact_item_ids, "Default", CONTACT_ITEM_PROPS,
                        FALSE, NULL, E_EWS_BODY_TYPE_TEXT, &new_items, NULL, NULL,
                        cancellable, error);
+
        if (*error)
                goto cleanup;
 
        if (new_items) {
                if (store_to_cache)
-                       ebews_store_contact_items (ebews, new_items, FALSE, error);
+                       ebews_store_contact_items (ebews, new_items, FALSE, cancellable, error);
                else
-                       ebews_get_vcards_list (new_items, vcards);
+                       ebews_get_vcards_list (ebews, new_items, vcards, cancellable, error);
        }
        new_items = NULL;
 
@@ -2931,6 +3242,7 @@ e_book_backend_ews_get_backend_property (EBookBackend *backend,
                        e_contact_field_name (E_CONTACT_ADDRESS_OTHER),
                        e_contact_field_name (E_CONTACT_BIRTH_DATE),
                        e_contact_field_name (E_CONTACT_NOTE),
+                       e_contact_field_name (E_CONTACT_PHOTO),
                        NULL);
 
                g_string_free (buffer, TRUE);
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index 71923da..d4bd9e9 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -36,6 +36,11 @@
 #include <libical/ical.h>
 #include <libedataserver/libedataserver.h>
 
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/tree.h>
+
 #include "e-ews-connection.h"
 #include "e-ews-message.h"
 #include "e-ews-item-change.h"
@@ -109,6 +114,7 @@ struct _EwsAsyncData {
        gint total_items;
        const gchar *directory;
        GSList *items;
+       EwsPhotoAttachmentInfo *photo;
        gchar *sync_state;
        gboolean includes_last_item;
        EwsDelegateDeliver deliver_to;
@@ -904,29 +910,11 @@ ews_handle_items_param (ESoapParameter *subparam,
 }
 
 static void
-get_items_response_cb (ESoapResponse *response,
-                       GSimpleAsyncResult *simple)
+handle_get_items_response_cb (EwsAsyncData *async_data, ESoapParameter *param)
 {
-       EwsAsyncData *async_data;
-       ESoapParameter *param;
        ESoapParameter *subparam;
        GError *error = NULL;
 
-       async_data = g_simple_async_result_get_op_res_gpointer (simple);
-
-       param = e_soap_response_get_first_parameter_by_name (
-               response, "ResponseMessages", &error);
-
-       /* Sanity check */
-       g_return_if_fail (
-               (param != NULL && error == NULL) ||
-               (param == NULL && error != NULL));
-
-       if (error != NULL) {
-               g_simple_async_result_take_error (simple, error);
-               return;
-       }
-
        subparam = e_soap_parameter_get_first_child (param);
 
        while (subparam != NULL) {
@@ -950,6 +938,32 @@ get_items_response_cb (ESoapResponse *response,
 }
 
 static void
+get_items_response_cb (ESoapResponse *response,
+                       GSimpleAsyncResult *simple)
+{
+       EwsAsyncData *async_data;
+       ESoapParameter *param;
+       GError *error = NULL;
+
+       async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+       param = e_soap_response_get_first_parameter_by_name (
+               response, "ResponseMessages", &error);
+
+       /* Sanity check */
+       g_return_if_fail (
+               (param != NULL && error == NULL) ||
+               (param == NULL && error != NULL));
+
+       if (error != NULL) {
+               g_simple_async_result_take_error (simple, error);
+               return;
+       }
+
+       handle_get_items_response_cb (async_data, param);
+}
+
+static void
 ews_handle_resolution_set_param (ESoapParameter *subparam,
                                  EwsAsyncData *async_data)
 {
@@ -4065,6 +4079,86 @@ e_ews_connection_delete_item_sync (EEwsConnection *cnc,
        return success;
 }
 
+static xmlXPathObjectPtr
+xpath_eval (xmlXPathContextPtr ctx,
+           const gchar *format,
+           ...)
+{
+       xmlXPathObjectPtr result;
+       va_list args;
+       gchar *expr;
+
+       if (ctx == NULL)
+               return NULL;
+
+       va_start (args, format);
+       expr = g_strdup_vprintf (format, args);
+       va_end (args);
+
+       result = xmlXPathEvalExpression ((xmlChar *) expr, ctx);
+       g_free (expr);
+
+       if (result == NULL)
+               return NULL;
+
+       if (result->type == XPATH_NODESET && xmlXPathNodeSetIsEmpty (result->nodesetval)) {
+               xmlXPathFreeObject (result);
+               return NULL;
+       }
+
+       return result;
+}
+
+static gboolean
+element_has_child (ESoapMessage *message,
+                  const gchar *path)
+{
+       xmlDocPtr doc;
+       xmlXPathContextPtr xpctx;
+       xmlXPathObjectPtr result;
+       xmlNodeSetPtr nodeset;
+       xmlNodePtr node;
+       gboolean ret = FALSE;
+
+       doc = e_soap_message_get_xml_doc (message);
+       xpctx = xmlXPathNewContext (doc);
+
+       xmlXPathRegisterNs (
+                       xpctx,
+                       (xmlChar *) "s",
+                       (xmlChar *) "http://schemas.xmlsoap.org/soap/envelope/";);
+
+       xmlXPathRegisterNs (
+                       xpctx,
+                       (xmlChar *) "m",
+                       (xmlChar *) "http://schemas.microsoft.com/exchange/services/2006/messages";);
+
+       xmlXPathRegisterNs (
+                       xpctx,
+                       (xmlChar *) "t",
+                       (xmlChar *) "http://schemas.microsoft.com/exchange/services/2006/types";);
+
+       result = xpath_eval (xpctx, path);
+
+       if (result == NULL)
+               goto exit;
+
+       if (!xmlXPathNodeSetGetLength (result->nodesetval))
+               goto exit;
+
+       nodeset = result->nodesetval;
+       node = nodeset->nodeTab[0];
+       if (!node->children)
+               goto exit;
+
+       ret = TRUE;
+
+exit:
+       xmlXPathFreeObject (result);
+       xmlXPathFreeContext (xpctx);
+       return ret;
+}
+
 void
 e_ews_connection_update_items (EEwsConnection *cnc,
                                gint pri,
@@ -4124,9 +4218,18 @@ e_ews_connection_update_items (EEwsConnection *cnc,
        g_simple_async_result_set_op_res_gpointer (
                simple, async_data, (GDestroyNotify) async_data_free);
 
-       e_ews_connection_queue_request (
-               cnc, msg, get_items_response_cb,
-               pri, cancellable, simple);
+       /*
+        * We need to check for both namespaces, because, the message is being wrote without use the types
+        * namespace. Maybe it is wrong, but the server doesn't complain about that. But this is the reason
+        * for the first check. The second one, is related to "how it should be" accord with EWS 
specifications.
+        */
+       if (!element_has_child (msg, "/s:Envelope/s:Body/m:UpdateItem/m:ItemChanges/ItemChange/Updates") &&
+               !element_has_child (msg, 
"/s:Envelope/s:Body/m:UpdateItem/m:ItemChanges/t:ItemChange/t:Updates"))
+               g_simple_async_result_complete_in_idle (simple);
+       else
+               e_ews_connection_queue_request (
+                       cnc, msg, get_items_response_cb,
+                       pri, cancellable, simple);
 
        g_object_unref (simple);
 }
@@ -5638,6 +5741,7 @@ create_attachments_response_cb (ESoapResponse *response,
 static gboolean
 e_ews_connection_attach_file (ESoapMessage *msg,
                               EEwsAttachmentInfo *info,
+                             gboolean contact_photo,
                              GError **error)
 {
        EEwsAttachmentInfoType type = e_ews_attachment_info_get_type (info);
@@ -5690,11 +5794,11 @@ e_ews_connection_attach_file (ESoapMessage *msg,
        e_soap_message_start_element (msg, "FileAttachment", NULL, NULL);
 
        e_ews_message_write_string_parameter (msg, "Name", NULL, filename);
-
+       if (contact_photo)
+               e_ews_message_write_string_parameter (msg, "IsContactPhoto", NULL, "true");
        e_soap_message_start_element (msg, "Content", NULL, NULL);
        e_soap_message_write_base64 (msg, content, length);
        e_soap_message_end_element (msg); /* "Content" */
-
        e_soap_message_end_element (msg); /* "FileAttachment" */
 
        g_free (filename);
@@ -5740,7 +5844,7 @@ e_ews_connection_create_attachments (EEwsConnection *cnc,
        e_soap_message_start_element (msg, "Attachments", "messages", NULL);
 
        for (l = files; l != NULL; l = g_slist_next (l))
-               if (!e_ews_connection_attach_file (msg, l->data, &local_error)) {
+               if (!e_ews_connection_attach_file (msg, l->data, FALSE, &local_error)) {
                        if (local_error != NULL)
                                g_simple_async_result_take_error (simple, local_error);
                        g_simple_async_result_complete_in_idle (simple);
@@ -5998,7 +6102,11 @@ ews_handle_attachments_param (ESoapParameter *param,
                        info = e_ews_item_dump_mime_content (item, async_data->directory);
 
                } else if (!g_ascii_strcasecmp (name, "FileAttachment")) {
-                       info = e_ews_dump_file_attachment_from_soap_parameter (subparam, 
async_data->directory, async_data->sync_state, &attach_id);
+                       info = e_ews_dump_file_attachment_from_soap_parameter (
+                                       subparam,
+                                       async_data->directory,
+                                       async_data->sync_state,
+                                       &attach_id);
                }
 
                if (info && attach_id) {
@@ -6177,6 +6285,227 @@ e_ews_connection_get_attachments_sync (EEwsConnection *cnc,
        return attachments_ids;
 }
 
+void
+e_ews_connection_get_photo_attachment_id (EEwsConnection *cnc,
+                                         gint pri,
+                                         const GSList *ids,
+                                         GCancellable *cancellable,
+                                         GAsyncReadyCallback callback,
+                                         gpointer user_data)
+{
+       ESoapMessage *msg;
+       GSimpleAsyncResult *simple;
+       EwsAsyncData *async_data;
+       const GSList *l;
+
+       g_return_if_fail (cnc != NULL);
+
+       msg = e_ews_message_new_with_header (cnc->priv->uri, cnc->priv->impersonate_user, "GetItem", NULL, 
NULL, EWS_EXCHANGE_2010_SP2);
+
+       e_soap_message_start_element (msg, "ItemShape", "messages", NULL);
+       e_ews_message_write_string_parameter (msg, "BaseShape", NULL, "IdOnly");
+       e_ews_message_write_string_parameter (msg, "IncludeMimeContent", NULL, "false");
+       e_soap_message_start_element (msg, "AdditionalProperties", NULL, NULL);
+       e_ews_message_write_string_parameter_with_attribute (msg, "FieldURI", NULL, NULL, "FieldURI", 
"item:Attachments");
+       e_soap_message_end_element (msg);
+       e_soap_message_end_element (msg);
+
+       e_soap_message_start_element (msg, "ItemIds", "messages", NULL);
+
+       for (l = ids; l != NULL; l = g_slist_next (l))
+               e_ews_message_write_string_parameter_with_attribute (msg, "ItemId", NULL, NULL, "Id", 
l->data);
+
+       e_soap_message_end_element (msg);
+
+       e_ews_message_write_footer (msg);
+
+       simple = g_simple_async_result_new (
+               G_OBJECT (cnc), callback, user_data,
+               e_ews_connection_get_photo_attachment_id);
+
+       async_data = g_new0 (EwsAsyncData, 1);
+       g_simple_async_result_set_op_res_gpointer (
+               simple, async_data, (GDestroyNotify) async_data_free);
+
+       e_ews_connection_queue_request (
+               cnc, msg, get_items_response_cb,
+               pri, cancellable, simple);
+
+       g_object_unref (simple);
+}
+
+gboolean
+e_ews_connection_get_photo_attachment_id_finish (EEwsConnection *cnc,
+                                                GAsyncResult *result,
+                                                GSList **items,
+                                                GError **error)
+{
+       GSimpleAsyncResult *simple;
+       EwsAsyncData *async_data;
+
+       g_return_val_if_fail (cnc != NULL, FALSE);
+       g_return_val_if_fail (
+               g_simple_async_result_is_valid (
+               result, G_OBJECT (cnc), e_ews_connection_get_photo_attachment_id),
+               FALSE);
+
+       simple = G_SIMPLE_ASYNC_RESULT (result);
+       async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+       if (g_simple_async_result_propagate_error (simple, error))
+               return FALSE;
+
+       if (!async_data->items) {
+               g_set_error_literal (error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ITEMNOTFOUND, _("No 
items found"));
+               return FALSE;
+       }
+
+       *items = async_data->items;
+
+       return TRUE;
+}
+
+gboolean
+e_ews_connection_get_photo_attachment_id_sync (EEwsConnection *cnc,
+                                              gint pri,
+                                              const GSList *ids,
+                                              GSList **items,
+                                              GCancellable *cancellable,
+                                              GError **error)
+{
+       EAsyncClosure *closure;
+       GAsyncResult *result;
+       gboolean success;
+
+       g_return_val_if_fail (cnc != NULL, FALSE);
+
+       closure = e_async_closure_new ();
+
+       e_ews_connection_get_photo_attachment_id (
+               cnc, pri, ids, cancellable,
+               e_async_closure_callback, closure);
+
+       result = e_async_closure_wait (closure);
+
+       success = e_ews_connection_get_photo_attachment_id_finish (
+               cnc, result, items, error);
+
+       e_async_closure_free (closure);
+
+       return success;
+}
+
+void
+e_ews_connection_create_photo_attachment (EEwsConnection *cnc,
+                                         gint pri,
+                                         const EwsId *parent,
+                                         const GSList *files,
+                                         GCancellable *cancellable,
+                                         GAsyncReadyCallback callback,
+                                         gpointer user_data)
+{
+       ESoapMessage *msg;
+       GSimpleAsyncResult *simple;
+       const GSList *l;
+       EwsAsyncData *async_data;
+       GError *local_error = NULL;
+
+       g_return_if_fail (cnc != NULL);
+
+       simple = g_simple_async_result_new (
+               G_OBJECT (cnc), callback, user_data,
+               e_ews_connection_create_photo_attachment);
+
+       async_data = g_new0 (EwsAsyncData, 1);
+       g_simple_async_result_set_op_res_gpointer (
+               simple, async_data, (GDestroyNotify) async_data_free);
+
+       msg = e_ews_message_new_with_header (cnc->priv->uri, cnc->priv->impersonate_user, "CreateAttachment", 
NULL, NULL, EWS_EXCHANGE_2010_SP2);
+
+       e_soap_message_start_element (msg, "ParentItemId", "messages", NULL);
+       e_soap_message_add_attribute (msg, "Id", parent->id, NULL, NULL);
+       if (parent->change_key)
+               e_soap_message_add_attribute (msg, "ChangeKey", parent->change_key, NULL, NULL);
+       e_soap_message_end_element (msg);
+
+       /* start interation over all items to get the attachemnts */
+       e_soap_message_start_element (msg, "Attachments", "messages", NULL);
+
+       for (l = files; l != NULL; l = g_slist_next (l))
+               if (!e_ews_connection_attach_file (msg, l->data, TRUE, &local_error)) {
+                       if (local_error != NULL)
+                               g_simple_async_result_take_error (simple, local_error);
+                       g_simple_async_result_complete_in_idle (simple);
+                       g_object_unref (simple);
+
+                       return;
+               }
+
+       e_soap_message_end_element (msg); /* "Attachments" */
+
+       e_ews_message_write_footer (msg);
+
+       e_ews_connection_queue_request (
+               cnc, msg, create_attachments_response_cb,
+               pri, cancellable, simple);
+
+       g_object_unref (simple);
+}
+
+GSList *
+e_ews_connection_create_photo_attachment_finish (EEwsConnection *cnc,
+                                                GAsyncResult *result,
+                                                GError **error)
+{
+       GSimpleAsyncResult *simple;
+       EwsAsyncData *async_data;
+       GSList *ids;
+
+       g_return_val_if_fail (cnc != NULL, NULL);
+       g_return_val_if_fail (
+               g_simple_async_result_is_valid (
+               result, G_OBJECT (cnc), e_ews_connection_create_photo_attachment),
+               NULL);
+
+       simple = G_SIMPLE_ASYNC_RESULT (result);
+       async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+       if (g_simple_async_result_propagate_error (simple, error))
+               return NULL;
+
+       ids = async_data->items;
+       return ids;
+}
+
+GSList *
+e_ews_connection_create_photo_attachment_sync (EEwsConnection *cnc,
+                                              gint pri,
+                                              const EwsId *parent,
+                                              const GSList *files,
+                                              GCancellable *cancellable,
+                                              GError **error)
+{
+       EAsyncClosure *closure;
+       GAsyncResult *result;
+       GSList *ids;
+
+       g_return_val_if_fail (cnc != NULL, NULL);
+
+       closure = e_async_closure_new ();
+
+       e_ews_connection_create_photo_attachment (
+               cnc, pri, parent, files, cancellable,
+               e_async_closure_callback, closure);
+
+       result = e_async_closure_wait (closure);
+
+       ids = e_ews_connection_create_photo_attachment_finish (cnc, result, error);
+
+       e_async_closure_free (closure);
+
+       return ids;
+}
+
 static void
 ews_handle_free_busy_view (ESoapParameter *param,
                            EwsAsyncData *async_data)
diff --git a/src/server/e-ews-connection.h b/src/server/e-ews-connection.h
index 86874eb..3ecac5c 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -199,6 +199,11 @@ typedef struct {
        gpointer field_uri;
 } EwsSortOrder;
 
+typedef struct {
+       gchar *id;
+       gsize len;
+} EwsPhotoAttachmentInfo;
+
 void           ews_oal_free                    (EwsOAL *oal);
 void           ews_oal_details_free            (EwsOALDetails *details);
 
@@ -321,6 +326,46 @@ gboolean   e_ews_connection_find_folder_items_sync
                                                 GCancellable *cancellable,
                                                 GError **error);
 
+void           e_ews_connection_get_photo_attachment_id
+                                               (EEwsConnection *cnc,
+                                                gint pri,
+                                                const GSList *ids,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_ews_connection_get_photo_attachment_id_finish
+                                               (EEwsConnection *cnc,
+                                                GAsyncResult *result,
+                                                GSList **items,
+                                                GError **error);
+gboolean       e_ews_connection_get_photo_attachment_id_sync
+                                               (EEwsConnection *cnc,
+                                                gint pri,
+                                                const GSList *ids,
+                                                GSList **items,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+void           e_ews_connection_create_photo_attachment
+                                               (EEwsConnection *cnc,
+                                                gint pri,
+                                                const EwsId *parent,
+                                                const GSList *files,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+GSList *       e_ews_connection_create_photo_attachment_finish
+                                               (EEwsConnection *cnc,
+                                                GAsyncResult *result,
+                                                GError **error);
+GSList *       e_ews_connection_create_photo_attachment_sync
+                                               (EEwsConnection *cnc,
+                                                gint pri,
+                                                const EwsId *parent,
+                                                const GSList *files,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
 void           e_ews_connection_get_items      (EEwsConnection *cnc,
                                                 gint pri,
                                                 const GSList *ids,
diff --git a/src/server/e-ews-item.c b/src/server/e-ews-item.c
index 538b965..fe9a798 100644
--- a/src/server/e-ews-item.c
+++ b/src/server/e-ews-item.c
@@ -178,6 +178,7 @@ struct _EEwsItemPrivate {
 
        gchar *uid;
        gchar *timezone;
+       gchar *contact_photo_id;
 
        GSList *to_recipients;
        GSList *cc_recipients;
@@ -254,6 +255,9 @@ e_ews_item_dispose (GObject *object)
        g_free (priv->timezone);
        priv->timezone = NULL;
 
+       g_free (priv->contact_photo_id);
+       priv->contact_photo_id = NULL;
+
        if (priv->to_recipients) {
                g_slist_foreach (priv->to_recipients, (GFunc) e_ews_mailbox_free, NULL);
                g_slist_free (priv->to_recipients);
@@ -288,7 +292,6 @@ e_ews_item_dispose (GObject *object)
                g_slist_foreach (priv->attendees, (GFunc) ews_item_free_attendee, NULL);
                g_slist_free (priv->attendees);
                priv->attendees = NULL;
-
        }
 
        if (priv->calendar_item_accept_id) {
@@ -594,10 +597,23 @@ process_attachments_list (EEwsItemPrivate *priv,
        GSList *list = NULL;
 
        for (subparam = e_soap_parameter_get_first_child (param); subparam != NULL; subparam = 
e_soap_parameter_get_next_child (subparam)) {
+               gchar *id;
 
                subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "AttachmentId");
+               id = e_soap_parameter_get_property (subparam1, "Id");
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "IsContactPhoto");
+               if (subparam1) {
+                       gchar *value = e_soap_parameter_get_string_value (subparam1);
+                       if (g_strcmp0 (value, "true") == 0) {
+                               priv->contact_photo_id = id;
+                               g_free (value);
+                               continue;
+                       }
+                       g_free (value);
+               }
 
-               list = g_slist_append (list, e_soap_parameter_get_property (subparam1, "Id"));
+               list = g_slist_append (list, id);
        }
 
        priv->attachments_list = list;
@@ -1995,6 +2011,14 @@ e_ews_item_get_tzid (EEwsItem *item)
        return item->priv->timezone;
 }
 
+const gchar *
+e_ews_item_get_contact_photo_id (EEwsItem *item)
+{
+       g_return_val_if_fail (E_IS_EWS_ITEM (item), NULL);
+
+       return item->priv->contact_photo_id;
+}
+
 EwsResolveContact *
 e_ews_item_resolve_contact_from_soap_param (ESoapParameter *param)
 {
diff --git a/src/server/e-ews-item.h b/src/server/e-ews-item.h
index 220c517..2f3d26a 100644
--- a/src/server/e-ews-item.h
+++ b/src/server/e-ews-item.h
@@ -223,6 +223,7 @@ const GSList *      e_ews_item_get_modified_occurrences
 gchar *                e_ews_embed_attachment_id_in_uri (const gchar *olduri, const gchar *attach_id);
 GSList *       e_ews_item_get_attachments_ids
                                                (EEwsItem *item);
+
 EEwsAttachmentInfo *
 e_ews_dump_file_attachment_from_soap_parameter (ESoapParameter *param, const gchar *cache, const gchar 
*comp_uid, gchar **attach_id);
 
@@ -308,6 +309,8 @@ gboolean    e_ews_item_task_has_complete_date
                                                (EEwsItem * item,
                                                 gboolean * has_date);
 const gchar *  e_ews_item_get_tzid             (EEwsItem *item);
+const gchar *  e_ews_item_get_contact_photo_id (EEwsItem *item);
+
 
 /* Folder Permissions */
 EEwsPermission *e_ews_permission_new           (EEwsPermissionUserType user_type,



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