[evolution-ews] Bug #654950 - Contact doesn't fetch photo
- From: Fabiano Fidêncio <ffidencio src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews] Bug #654950 - Contact doesn't fetch photo
- Date: Mon, 29 Apr 2013 23:16:33 +0000 (UTC)
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]