diff --git a/SOURCES/evolution-ews-3.28.5-birthday-date.patch b/SOURCES/evolution-ews-3.28.5-birthday-date.patch new file mode 100644 index 0000000..751d0ee --- /dev/null +++ b/SOURCES/evolution-ews-3.28.5-birthday-date.patch @@ -0,0 +1,262 @@ +diff -up evolution-ews-3.28.5/src/addressbook/CMakeLists.txt.birthday-date evolution-ews-3.28.5/src/addressbook/CMakeLists.txt +--- evolution-ews-3.28.5/src/addressbook/CMakeLists.txt.birthday-date 2018-07-30 16:01:00.000000000 +0200 ++++ evolution-ews-3.28.5/src/addressbook/CMakeLists.txt 2019-10-23 14:13:13.158137514 +0200 +@@ -45,6 +45,7 @@ target_compile_options(ebookbackendews P + ${LIBEBOOK_CFLAGS} + ${LIBEDATABOOK_CFLAGS} + ${LIBEDATASERVER_CFLAGS} ++ ${LIBICAL_CFLAGS} + ${MSPACK_CFLAGS} + ${SOUP_CFLAGS} + ) +@@ -60,6 +61,7 @@ target_include_directories(ebookbackende + ${LIBEBOOK_INCLUDE_DIRS} + ${LIBEDATABOOK_INCLUDE_DIRS} + ${LIBEDATASERVER_INCLUDE_DIRS} ++ ${LIBICAL_INCLUDE_DIRS} + ${MSPACK_INCLUDE_DIRS} + ${SOUP_INCLUDE_DIRS} + ) +@@ -70,6 +72,7 @@ target_link_libraries(ebookbackendews + ${LIBEBOOK_LDFLAGS} + ${LIBEDATABOOK_LDFLAGS} + ${LIBEDATASERVER_LDFLAGS} ++ ${LIBICAL_LDFLAGS} + ${MATH_LDFLAGS} + ${MSPACK_LDFLAGS} + ${SOUP_LDFLAGS} +diff -up evolution-ews-3.28.5/src/addressbook/e-book-backend-ews.c.birthday-date evolution-ews-3.28.5/src/addressbook/e-book-backend-ews.c +--- evolution-ews-3.28.5/src/addressbook/e-book-backend-ews.c.birthday-date 2019-10-23 14:04:31.100144733 +0200 ++++ evolution-ews-3.28.5/src/addressbook/e-book-backend-ews.c 2019-10-23 14:15:41.719135459 +0200 +@@ -37,6 +37,8 @@ + #include + #include + ++#include ++ + #include + + #include "server/e-ews-item-change.h" +@@ -268,29 +270,36 @@ ebews_populate_nick_name (EBookBackendEw + } + + static void ++ebews_populate_date_value (EBookBackendEws *bbews, ++ EContact *contact, ++ EContactField field, ++ time_t value) ++{ ++ if (value > (time_t) 0) { ++ struct icaltimetype itt; ++ ++ itt = icaltime_from_timet_with_zone (value, TRUE, icaltimezone_get_utc_timezone ()); ++ ++ if (icaltime_is_valid_time (itt) && !icaltime_is_null_time (itt)) { ++ EContactDate edate = { 0 }; ++ ++ edate.year = itt.year; ++ edate.month = itt.month; ++ edate.day = itt.day; ++ ++ e_contact_set (contact, field, &edate); ++ } ++ } ++} ++ ++static void + ebews_populate_birth_date (EBookBackendEws *bbews, + EContact *contact, + EEwsItem *item, + GCancellable *cancellable, + GError **error) + { +- time_t bdate; +- GDate date; +- EContactDate edate; +- +- bdate = e_ews_item_get_birthday (item); +- +- if (bdate) { +- g_date_clear (&date, 1); +- g_date_set_time_t (&date, bdate); +- +- edate.year = date.year; +- edate.month = date.month; +- edate.day = date.day; +- +- if (g_date_valid (&date)) +- e_contact_set (contact, E_CONTACT_BIRTH_DATE, &edate); +- } ++ ebews_populate_date_value (bbews, contact, E_CONTACT_BIRTH_DATE, e_ews_item_get_birthday (item)); + } + + static void +@@ -300,23 +309,7 @@ ebews_populate_anniversary (EBookBackend + GCancellable *cancellable, + GError **error) + { +- time_t bdate; +- GDate date; +- EContactDate edate; +- +- bdate = e_ews_item_get_wedding_anniversary (item); +- +- if (bdate) { +- g_date_clear (&date, 1); +- g_date_set_time_t (&date, bdate); +- +- edate.year = date.year; +- edate.month = date.month; +- edate.day = date.day; +- +- if (g_date_valid (&date)) +- e_contact_set (contact, E_CONTACT_ANNIVERSARY, &edate); +- } ++ ebews_populate_date_value (bbews, contact, E_CONTACT_ANNIVERSARY, e_ews_item_get_wedding_anniversary (item)); + } + + static EContactPhoto * +@@ -600,34 +593,41 @@ ebews_set_full_name (ESoapMessage *msg, + e_contact_name_free (name); + } + +-/* TODO Set birth and anniversary dates */ + static void +-ebews_set_birth_date (ESoapMessage *message, +- EContact *contact) ++ebews_set_date_value (ESoapMessage *message, ++ EContact *contact, ++ EContactField field, ++ const gchar *element_name) + { + EContactDate *date; +- gchar *birthday; ++ gchar *value; + +- date = e_contact_get (contact, E_CONTACT_BIRTH_DATE); ++ date = e_contact_get (contact, field); + + if (!date) + return; + +- birthday = g_strdup_printf ( +- "%04d-%02d-%02dT00:00:00", ++ value = g_strdup_printf ("%04d-%02d-%02dT00:00:00Z", + date->year, date->month, date->day); + +- e_ews_message_write_string_parameter (message, "Birthday", NULL, birthday); ++ e_ews_message_write_string_parameter (message, element_name, NULL, value); + +- g_free (birthday); ++ e_contact_date_free (date); ++ g_free (value); ++} + ++static void ++ebews_set_birth_date (ESoapMessage *message, ++ EContact *contact) ++{ ++ ebews_set_date_value (message, contact, E_CONTACT_BIRTH_DATE, "Birthday"); + } + + static void + ebews_set_anniversary (ESoapMessage *message, + EContact *contact) + { +- ++ ebews_set_date_value (message, contact, E_CONTACT_ANNIVERSARY, "WeddingAnniversary"); + } + + static void +@@ -838,30 +838,33 @@ ebews_set_full_name_changes (EBookBacken + } + + static void +-ebews_set_birth_date_changes (EBookBackendEws *bbews, +- ESoapMessage *message, ++ebews_set_date_value_changes (ESoapMessage *message, + EContact *new, + EContact *old, +- gchar **out_new_change_key, +- GCancellable *cancellable, +- GError **error) ++ EContactField field, ++ const gchar *element_name) + { + EContactDate *new_date, *old_date; +- gchar *birthday; + + if (!message) + return; + +- new_date = e_contact_get (new, E_CONTACT_BIRTH_DATE); +- old_date = e_contact_get (old, E_CONTACT_BIRTH_DATE); ++ new_date = e_contact_get (new, field); ++ old_date = e_contact_get (old, field); + + if (!e_contact_date_equal (new_date, old_date)) { +- birthday = g_strdup_printf ( +- "%04d-%02d-%02dT00:00:00", +- new_date->year, new_date->month, new_date->day); ++ if (new_date) { ++ gchar *value; ++ ++ value = g_strdup_printf ("%04d-%02d-%02dT00:00:00Z", ++ new_date->year, new_date->month, new_date->day); ++ ++ convert_contact_property_to_updatexml (message, element_name, value, "contacts", NULL, NULL); + +- convert_contact_property_to_updatexml (message, "Birthday", birthday, "contacts", NULL, NULL); +- g_free (birthday); ++ g_free (value); ++ } else { ++ e_ews_message_add_delete_item_field (message, element_name, "contacts"); ++ } + } + + e_contact_date_free (new_date); +@@ -869,6 +872,18 @@ ebews_set_birth_date_changes (EBookBacke + } + + static void ++ebews_set_birth_date_changes (EBookBackendEws *bbews, ++ ESoapMessage *message, ++ EContact *new, ++ EContact *old, ++ gchar **out_new_change_key, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ ebews_set_date_value_changes (message, new, old, E_CONTACT_BIRTH_DATE, "Birthday"); ++} ++ ++static void + ebews_set_anniversary_changes (EBookBackendEws *bbews, + ESoapMessage *message, + EContact *new, +@@ -877,7 +892,7 @@ ebews_set_anniversary_changes (EBookBack + GCancellable *cancellable, + GError **error) + { +- ++ ebews_set_date_value_changes (message, new, old, E_CONTACT_ANNIVERSARY, "WeddingAnniversary"); + } + + static void +@@ -1373,7 +1388,7 @@ static const struct field_element_mappin + { 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_GIVEN_NAME, ELEMENT_TYPE_COMPLEX, "GivenName", NULL, ebews_populate_givenname, ebews_set_givenname, ebews_set_givenname_changes}, +- { E_CONTACT_BIRTH_DATE, ELEMENT_TYPE_COMPLEX, "WeddingAnniversary", NULL, ebews_populate_anniversary, ebews_set_anniversary, ebews_set_anniversary_changes }, ++ { E_CONTACT_ANNIVERSARY, 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) */ +@@ -3515,6 +3530,7 @@ ebb_ews_get_backend_property (EBookBacke + e_contact_field_name (E_CONTACT_ADDRESS_WORK), + e_contact_field_name (E_CONTACT_ADDRESS_HOME), + e_contact_field_name (E_CONTACT_ADDRESS_OTHER), ++ e_contact_field_name (E_CONTACT_ANNIVERSARY), + e_contact_field_name (E_CONTACT_BIRTH_DATE), + e_contact_field_name (E_CONTACT_NOTE), + e_contact_field_name (E_CONTACT_PHOTO), diff --git a/SOURCES/evolution-ews-3.28.5-save-only-if-organizer.patch b/SOURCES/evolution-ews-3.28.5-save-only-if-organizer.patch new file mode 100644 index 0000000..5085cff --- /dev/null +++ b/SOURCES/evolution-ews-3.28.5-save-only-if-organizer.patch @@ -0,0 +1,75 @@ +diff -up evolution-ews-3.28.5/src/calendar/e-cal-backend-ews.c.save-only-if-organizer evolution-ews-3.28.5/src/calendar/e-cal-backend-ews.c +--- evolution-ews-3.28.5/src/calendar/e-cal-backend-ews.c.save-only-if-organizer 2019-11-13 07:44:37.295278517 +0100 ++++ evolution-ews-3.28.5/src/calendar/e-cal-backend-ews.c 2019-11-13 07:55:27.656269523 +0100 +@@ -147,6 +147,41 @@ ecb_ews_get_collection_settings (ECalBac + return CAMEL_EWS_SETTINGS (settings); + } + ++static GHashTable * ++ecb_ews_get_mail_aliases (ECalBackendEws *cbews) ++{ ++ ESource *source; ++ ESourceRegistry *registry; ++ GHashTable *aliases = NULL; ++ GList *identities, *link; ++ const gchar *parent_uid; ++ ++ source = e_backend_get_source (E_BACKEND (cbews)); ++ parent_uid = e_source_get_parent (source); ++ ++ if (!parent_uid || !*parent_uid) ++ return NULL; ++ ++ registry = e_cal_backend_get_registry (E_CAL_BACKEND (cbews)); ++ identities = e_source_registry_list_enabled (registry, E_SOURCE_EXTENSION_MAIL_IDENTITY); ++ ++ for (link = identities; link; link = g_list_next (link)) { ++ ESource *mail_identity = link->data; ++ ++ if (g_strcmp0 (parent_uid, e_source_get_parent (mail_identity)) == 0) { ++ ESourceMailIdentity *extension; ++ ++ extension = e_source_get_extension (mail_identity, E_SOURCE_EXTENSION_MAIL_IDENTITY); ++ aliases = e_source_mail_identity_get_aliases_as_hash_table (extension); ++ break; ++ } ++ } ++ ++ g_list_free_full (identities, g_object_unref); ++ ++ return aliases; ++} ++ + static void + ecb_ews_convert_error_to_edc_error (GError **perror) + { +@@ -1350,6 +1385,18 @@ ecb_ews_is_organizer (ECalBackendEws *cb + is_organizer = user_email && g_ascii_strcasecmp (email, user_email) == 0; + + g_free (user_email); ++ ++ if (!is_organizer) { ++ GHashTable *aliases; ++ ++ aliases = ecb_ews_get_mail_aliases (cbews); ++ ++ if (aliases) { ++ is_organizer = g_hash_table_contains (aliases, email); ++ ++ g_hash_table_unref (aliases); ++ } ++ } + } + + return is_organizer; +@@ -2595,6 +2642,10 @@ ecb_ews_save_component_sync (ECalMetaBac + g_slist_free_full (existing, g_object_unref); + g_slist_free_full (changed_instances, change_data_free); + g_slist_free_full (removed_instances, g_object_unref); ++ } else if (e_cal_component_has_organizer (master) && ++ !ecb_ews_is_organizer (cbews, master)) { ++ success = FALSE; ++ g_propagate_error (error, EDC_ERROR_EX (PermissionDenied, _("Cannot create meetings organized by other users in an Exchange Web Services calendar."))); + } else { + GHashTable *removed_indexes; + EwsCalendarConvertData convert_data = { 0 }; diff --git a/SOURCES/evolution-ews-3.28.5-sync-category-list.patch b/SOURCES/evolution-ews-3.28.5-sync-category-list.patch new file mode 100644 index 0000000..12cc76f --- /dev/null +++ b/SOURCES/evolution-ews-3.28.5-sync-category-list.patch @@ -0,0 +1,1168 @@ +diff -up evolution-ews-3.28.5/src/camel/camel-ews-store.c.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-store.c +--- evolution-ews-3.28.5/src/camel/camel-ews-store.c.sync-category-list 2019-10-24 09:39:08.336278207 +0200 ++++ evolution-ews-3.28.5/src/camel/camel-ews-store.c 2019-10-24 09:39:08.341278207 +0200 +@@ -673,6 +673,43 @@ ews_update_has_ooo_set (CamelSession *se + g_clear_object (&oof_settings); + } + ++static void ++ews_exchange_server_categories_cb (CamelSession *session, ++ GCancellable *cancellable, ++ gpointer user_data, ++ GError **error) ++{ ++ CamelEwsStore *ews_store = user_data; ++ EEwsConnection *cnc; ++ EwsFolderId fid = { 0 }; ++ gchar *properties = NULL; ++ GError *local_error = NULL; ++ ++ cnc = camel_ews_store_ref_connection (ews_store); ++ if (!cnc) ++ return; ++ ++ fid.id = (gchar *) "calendar"; ++ fid.is_distinguished_id = TRUE; ++ ++ if (e_ews_connection_get_user_configuration_sync (cnc, G_PRIORITY_DEFAULT, &fid, "CategoryList", ++ E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA, &properties, cancellable, &local_error) && properties) { ++ guchar *data; ++ gsize data_len = 0; ++ ++ data = g_base64_decode (properties, &data_len); ++ ++ if (data && data_len > 0) ++ camel_ews_utils_merge_category_list (ews_store, data, data_len); ++ ++ g_free (data); ++ } ++ ++ g_clear_error (&local_error); ++ g_clear_object (&cnc); ++ g_free (properties); ++} ++ + struct ScheduleUpdateData + { + GCancellable *cancellable; +@@ -1252,6 +1289,12 @@ ews_connect_sync (CamelService *service, + g_object_ref (ews_store), + g_object_unref); + ++ camel_session_submit_job ( ++ session, _("Look up Exchange server categories"), ++ ews_exchange_server_categories_cb, ++ g_object_ref (ews_store), ++ g_object_unref); ++ + if (!priv->updates_cancellable) + priv->updates_cancellable = g_cancellable_new (); + +@@ -2377,6 +2420,17 @@ ews_get_folder_info_sync (CamelStore *st + ews_store = (CamelEwsStore *) store; + priv = ews_store->priv; + ++ if ((flags & CAMEL_STORE_FOLDER_INFO_REFRESH) != 0 && ++ camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) { ++ CamelSession *session; ++ ++ session = camel_service_ref_session (CAMEL_SERVICE (ews_store)); ++ if (session) { ++ ews_exchange_server_categories_cb (session, cancellable, ews_store, NULL); ++ g_object_unref (session); ++ } ++ } ++ + if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0) { + gboolean includes_last_folder = TRUE; + GSList *folders = NULL, *to_check = NULL; +diff -up evolution-ews-3.28.5/src/camel/camel-ews-store-summary.c.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-store-summary.c +--- evolution-ews-3.28.5/src/camel/camel-ews-store-summary.c.sync-category-list 2018-07-30 16:01:00.000000000 +0200 ++++ evolution-ews-3.28.5/src/camel/camel-ews-store-summary.c 2019-10-24 09:39:08.341278207 +0200 +@@ -31,6 +31,7 @@ + #define S_UNLOCK(x) (g_rec_mutex_unlock(&(x)->priv->s_lock)) + + #define STORE_GROUP_NAME "##storepriv" ++#define CATEGORIES_KEY "Categories" + #define CURRENT_SUMMARY_VERSION 3 + + struct _CamelEwsStoreSummaryPrivate { +@@ -1047,3 +1048,159 @@ camel_ews_store_summary_has_folder (Came + + return ret; + } ++ ++static gchar * ++camel_ews_category_to_string (const CamelEwsCategory *cat) ++{ ++ gchar *guid, *name, *color_def = NULL, *str; ++ ++ g_return_val_if_fail (cat != NULL, NULL); ++ ++ guid = g_uri_escape_string (cat->guid, NULL, TRUE); ++ name = g_uri_escape_string (cat->name, NULL, TRUE); ++ ++ if (cat->color_def) ++ color_def = g_uri_escape_string (cat->color_def, NULL, TRUE); ++ ++ str = g_strconcat ( ++ guid ? guid : "", "\t", ++ name ? name : "", "\t", ++ color_def ? color_def : "", ++ NULL); ++ ++ g_free (guid); ++ g_free (name); ++ g_free (color_def); ++ ++ return str; ++} ++ ++static CamelEwsCategory * ++camel_ews_category_from_string (const gchar *str) ++{ ++ CamelEwsCategory *cat; ++ gchar **strv, *guid, *name, *color_def; ++ ++ g_return_val_if_fail (str != NULL, NULL); ++ ++ strv = g_strsplit (str, "\t", -1); ++ if (!strv || !strv[0] || !strv[1]) { ++ g_strfreev (strv); ++ return NULL; ++ } ++ ++ guid = g_uri_unescape_string (strv[0], NULL); ++ name = g_uri_unescape_string (strv[1], NULL); ++ color_def = (strv[2] && strv[2][0]) ? g_uri_unescape_string (strv[2], NULL) : NULL; ++ ++ cat = camel_ews_category_new (guid, name, color_def); ++ ++ g_free (guid); ++ g_free (name); ++ g_free (color_def); ++ g_strfreev (strv); ++ ++ return cat; ++} ++ ++GHashTable * /* gchar *guid ~> CamelEwsCategory * */ ++camel_ews_store_summary_get_categories (CamelEwsStoreSummary *ews_summary) ++{ ++ GHashTable *categories; ++ gchar **strv; ++ g_return_val_if_fail (CAMEL_IS_EWS_STORE_SUMMARY (ews_summary), NULL); ++ ++ S_LOCK (ews_summary); ++ ++ strv = g_key_file_get_string_list (ews_summary->priv->key_file, STORE_GROUP_NAME, CATEGORIES_KEY, NULL, NULL); ++ ++ S_UNLOCK (ews_summary); ++ ++ categories = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, camel_ews_category_free); ++ ++ if (strv) { ++ gint ii; ++ ++ for (ii = 0; strv[ii]; ii++) { ++ CamelEwsCategory *cat; ++ ++ cat = camel_ews_category_from_string (strv[ii]); ++ if (cat) ++ g_hash_table_insert (categories, cat->guid, cat); ++ } ++ ++ g_strfreev (strv); ++ } ++ ++ return categories; ++} ++ ++void ++camel_ews_store_summary_set_categories (CamelEwsStoreSummary *ews_summary, ++ GHashTable *categories) /* gchar *guid ~> CamelEwsCategory * */ ++{ ++ GPtrArray *array; ++ GHashTableIter iter; ++ gpointer value; ++ ++ g_return_if_fail (CAMEL_IS_EWS_STORE_SUMMARY (ews_summary)); ++ g_return_if_fail (categories != NULL); ++ ++ array = g_ptr_array_new_full (g_hash_table_size (categories), g_free); ++ ++ g_hash_table_iter_init (&iter, categories); ++ while (g_hash_table_iter_next (&iter, NULL, &value)) { ++ CamelEwsCategory *cat = value; ++ ++ if (cat) { ++ gchar *str; ++ ++ str = camel_ews_category_to_string (cat); ++ ++ if (str) ++ g_ptr_array_add (array, str); ++ } ++ } ++ ++ S_LOCK (ews_summary); ++ ++ g_key_file_set_string_list (ews_summary->priv->key_file, STORE_GROUP_NAME, CATEGORIES_KEY, ++ (const gchar * const *) array->pdata, array->len); ++ ++ ews_summary->priv->dirty = TRUE; ++ ++ S_UNLOCK (ews_summary); ++ ++ g_ptr_array_free (array, TRUE); ++} ++ ++CamelEwsCategory * ++camel_ews_category_new (const gchar *guid, ++ const gchar *name, ++ const gchar *color_def) ++{ ++ CamelEwsCategory *cat; ++ ++ g_return_val_if_fail (guid != NULL, NULL); ++ g_return_val_if_fail (name != NULL, NULL); ++ ++ cat = g_new0 (CamelEwsCategory, 1); ++ cat->guid = g_strdup (guid); ++ cat->name = g_strdup (name); ++ cat->color_def = g_strdup (color_def); ++ ++ return cat; ++} ++ ++void ++camel_ews_category_free (gpointer ptr) ++{ ++ CamelEwsCategory *cat = ptr; ++ ++ if (cat) { ++ g_free (cat->guid); ++ g_free (cat->name); ++ g_free (cat->color_def); ++ g_free (cat); ++ } ++} +diff -up evolution-ews-3.28.5/src/camel/camel-ews-store-summary.h.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-store-summary.h +--- evolution-ews-3.28.5/src/camel/camel-ews-store-summary.h.sync-category-list 2018-07-30 16:01:00.000000000 +0200 ++++ evolution-ews-3.28.5/src/camel/camel-ews-store-summary.h 2019-10-24 09:39:08.341278207 +0200 +@@ -50,6 +50,12 @@ + + G_BEGIN_DECLS + ++typedef struct _CamelEwsCategory { ++ gchar *guid; ++ gchar *name; ++ gchar *color_def; ++} CamelEwsCategory; ++ + typedef struct _CamelEwsStoreSummary CamelEwsStoreSummary; + typedef struct _CamelEwsStoreSummaryClass CamelEwsStoreSummaryClass; + typedef struct _CamelEwsStoreSummaryPrivate CamelEwsStoreSummaryPrivate; +@@ -215,6 +221,17 @@ gchar * camel_ews_store_summary_get_fol + gboolean camel_ews_store_summary_has_folder + (CamelEwsStoreSummary *ews_summary, + const gchar *id); ++GHashTable * camel_ews_store_summary_get_categories /* gchar *guid ~> CamelEwsCategory * */ ++ (CamelEwsStoreSummary *ews_summary); ++void camel_ews_store_summary_set_categories ++ (CamelEwsStoreSummary *ews_summary, ++ GHashTable *categories); /* gchar *guid ~> CamelEwsCategory * */ ++ ++CamelEwsCategory * ++ camel_ews_category_new (const gchar *guid, ++ const gchar *name, ++ const gchar *color_def); ++void camel_ews_category_free (gpointer ptr); /* CamelEwsCategory * */ + + G_END_DECLS + +diff -up evolution-ews-3.28.5/src/camel/camel-ews-utils.c.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-utils.c +--- evolution-ews-3.28.5/src/camel/camel-ews-utils.c.sync-category-list 2018-07-30 16:01:00.000000000 +0200 ++++ evolution-ews-3.28.5/src/camel/camel-ews-utils.c 2019-10-24 09:39:08.341278207 +0200 +@@ -29,6 +29,7 @@ + #include + + #include ++#include + + #include "server/camel-ews-settings.h" + #include "server/e-ews-camel-common.h" +@@ -381,6 +382,43 @@ camel_ews_utils_sync_deleted_items (Came + } + + static const gchar * ++ews_utils_outlook_color_index_to_color_def (gint color_index) ++{ ++ const gchar *colors_array[] = { ++ "#ff1a36", /* Red */ ++ "#ff8c00", /* Orange */ ++ "#f4b10b", /* Peach */ ++ "#fff100", /* Yellow */ ++ "#009e48", /* Green */ ++ "#00b294", /* Teal */ ++ "#89933f", /* Olive */ ++ "#00bcf2", /* Blue */ ++ "#8e69df", /* Purple */ ++ "#f30092", /* Maroon */ ++ "#6c7e9a", /* Steel */ ++ "#425066", /* DarkSteel */ ++ "#969696", /* Gray */ ++ "#525552", /* DarkGray */ ++ "#282828", /* Black */ ++ "#a00023", /* DarkRed */ ++ "#c45502", /* DarkOrange */ ++ "#af7000", /* DarkPeach */ ++ "#b59b02", /* DarkYellow */ ++ "#176002", /* DarkGreen */ ++ "#00725c", /* DarkTeal */ ++ "#5c6022", /* DarkOlive */ ++ "#036393", /* DarkBlue */ ++ "#422f8e", /* DarkPurple */ ++ "#960269" /* DarkMaroon */ ++ }; ++ ++ if (color_index >= 0 && color_index < G_N_ELEMENTS (colors_array)) ++ return colors_array[color_index]; ++ ++ return NULL; ++} ++ ++static const gchar * + ews_utils_rename_label (const gchar *cat, + gboolean from_cat) + { +@@ -422,6 +460,58 @@ ews_utils_is_system_user_flag (const gch + g_str_equal (name, "$has-cal"); + } + ++/* From Exchange name (which allows spaces) to evolution-name */ ++static gchar * ++camel_ews_utils_encode_category_name (const gchar *name) ++{ ++ if (name && strchr (name, ' ')) { ++ GString *str; ++ ++ str = g_string_sized_new (strlen (name) + 16); ++ ++ while (*name) { ++ if (*name == '_') ++ g_string_append_c (str, '_'); ++ ++ g_string_append_c (str, *name == ' ' ? '_' : *name); ++ ++ name++; ++ } ++ ++ return g_string_free (str, FALSE); ++ } ++ ++ return g_strdup (name); ++} ++ ++/* From evolution-name to Exchange name (which allows spaces) */ ++static gchar * ++camel_ews_utils_decode_category_name (const gchar *flag) ++{ ++ if (flag && strchr (flag, '_')) { ++ GString *str = g_string_sized_new (strlen (flag)); ++ ++ while (*flag) { ++ if (*flag == '_') { ++ if (flag[1] == '_') { ++ g_string_append_c (str, '_'); ++ flag++; ++ } else { ++ g_string_append_c (str, ' '); ++ } ++ } else { ++ g_string_append_c (str, *flag); ++ } ++ ++ flag++; ++ } ++ ++ return g_string_free (str, FALSE); ++ } ++ ++ return g_strdup (flag); ++} ++ + /* free with g_slist_free_full (flags, g_free); + the lists' members are values for the String xml element. */ + GSList * +@@ -441,6 +531,7 @@ ews_utils_gather_server_user_flags (ESoa + * array of strings */ + for (ii = 0; ii < len; ii++) { + const gchar *n = ews_utils_rename_label (camel_named_flags_get (user_flags, ii), FALSE); ++ + if (*n == '\0') + continue; + +@@ -449,26 +540,7 @@ ews_utils_gather_server_user_flags (ESoa + if (ews_utils_is_system_user_flag (n)) + continue; + +- if (strchr (n, '_')) { +- GString *str = g_string_sized_new (strlen (n)); +- +- while (*n) { +- if (*n == '_') { +- if (n[1] == '_') +- g_string_append_c (str, '_'); +- else +- g_string_append_c (str, ' '); +- } else { +- g_string_append_c (str, *n); +- } +- +- n++; +- } +- +- out_user_flags = g_slist_prepend (out_user_flags, g_string_free (str, FALSE)); +- } else { +- out_user_flags = g_slist_prepend (out_user_flags, g_strdup (n)); +- } ++ out_user_flags = g_slist_prepend (out_user_flags, camel_ews_utils_decode_category_name (n)); + } + + camel_message_info_property_unlock (mi); +@@ -512,33 +584,17 @@ ews_utils_merge_server_user_flags (EEwsI + + /* now transfer over all the categories */ + for (p = e_ews_item_get_categories (item); p; p = p->next) { +- const gchar *flag = ews_utils_rename_label (p->data, 1); +- gchar *underscored = NULL; ++ const gchar *name = ews_utils_rename_label (p->data, 1); ++ gchar *flag; + +- if (!flag || !*flag) ++ if (!name || !*name) + continue; + +- if (strchr (flag, ' ')) { +- GString *str; +- +- str = g_string_sized_new (strlen (flag) + 16); +- +- while (*flag) { +- if (*flag == '_') +- g_string_append_c (str, '_'); +- +- g_string_append_c (str, *flag == ' ' ? '_' : *flag); +- +- flag++; +- } +- +- underscored = g_string_free (str, FALSE); +- flag = underscored; +- } ++ flag = camel_ews_utils_encode_category_name (name); + + camel_message_info_set_user_flag (mi, flag, TRUE); + +- g_free (underscored); ++ g_free (flag); + } + + camel_message_info_thaw_notifications (mi); +@@ -1281,3 +1337,279 @@ camel_ews_utils_ref_corresponding_source + + return source; + } ++ ++static gboolean ++ews_util_equal_label_tag_cb (gconstpointer ptr1, ++ gconstpointer ptr2) ++{ ++ const gchar *evo_label_def = ptr1; ++ const gchar *tag = ptr2; ++ const gchar *pos; ++ ++ if (!evo_label_def || !tag || !*tag) ++ return FALSE; ++ ++ pos = g_strrstr (evo_label_def, tag); ++ ++ return pos > evo_label_def && pos[-1] == '|' && !pos[strlen (tag)]; ++} ++ ++static gboolean ++ews_utils_find_in_ptr_array (GPtrArray *haystack, ++ gconstpointer needle, ++ GEqualFunc equal_func, ++ guint *out_index) ++{ ++ guint ii; ++ ++ if (!haystack) ++ return FALSE; ++ ++ if (!equal_func) ++ equal_func = g_direct_equal; ++ ++ for (ii = 0; ii < haystack->len; ii++) { ++ if (equal_func (haystack->pdata[ii], needle)) { ++ if (out_index) ++ *out_index = ii; ++ ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/* Returns whether had been done any changes */ ++static gboolean ++ews_utils_save_category_changes (GHashTable *old_categories, /* gchar *guid ~> CamelEwsCategory * */ ++ GHashTable *new_categories) /* gchar *guid ~> CamelEwsCategory * */ ++{ ++ GHashTableIter iter; ++ GSettings *settings; ++ GPtrArray *evo_labels; /* gchar * (encoded label definition) */ ++ gchar **strv; ++ gint ii; ++ gpointer value; ++ gboolean changed = FALSE; ++ ++ if (!old_categories || !new_categories) ++ return new_categories != NULL; ++ ++ evo_labels = g_ptr_array_new_full (5, g_free); ++ ++ settings = e_util_ref_settings ("org.gnome.evolution.mail"); ++ strv = g_settings_get_strv (settings, "labels"); ++ ++ for (ii = 0; strv && strv[ii]; ii++) { ++ g_ptr_array_add (evo_labels, g_strdup (strv[ii])); ++ } ++ ++ g_strfreev (strv); ++ ++ g_hash_table_iter_init (&iter, new_categories); ++ while (g_hash_table_iter_next (&iter, NULL, &value)) { ++ CamelEwsCategory *new_cat = value, *old_cat; ++ gchar *tag = NULL; ++ ++ if (!new_cat) ++ continue; ++ ++ old_cat = g_hash_table_lookup (old_categories, new_cat->guid); ++ if (old_cat) { ++ if (g_strcmp0 (old_cat->name, new_cat->name) != 0 || ++ g_strcmp0 (old_cat->color_def, new_cat->color_def) != 0) { ++ /* Old category changed name or color */ ++ tag = camel_ews_utils_encode_category_name (new_cat->name); ++ } ++ } else { ++ /* This is a new category */ ++ tag = camel_ews_utils_encode_category_name (new_cat->name); ++ } ++ ++ if (tag && *tag) { ++ guint index = (guint) -1; ++ gchar *label_def; ++ ++ changed = TRUE; ++ ++ /* Sanitize value */ ++ for (ii = 0; tag[ii]; ii++) { ++ if (tag[ii] == '|') ++ tag[ii] = '-'; ++ } ++ ++ if (old_cat && g_strcmp0 (old_cat->name, new_cat->name) != 0) { ++ gchar *old_tag = camel_ews_utils_encode_category_name (old_cat->name); ++ ++ if (old_tag && *old_tag) { ++ if (!ews_utils_find_in_ptr_array (evo_labels, old_tag, ews_util_equal_label_tag_cb, &index)) ++ index = (guint) -1; ++ } ++ ++ g_free (old_tag); ++ } ++ ++ for (ii = 0; new_cat->name[ii]; ii++) { ++ if (new_cat->name[ii] == '|') ++ new_cat->name[ii] = '-'; ++ } ++ ++ if (index == (guint) -1 && ++ !ews_utils_find_in_ptr_array (evo_labels, tag, ews_util_equal_label_tag_cb, &index)) ++ index = (guint) -1; ++ ++ label_def = g_strconcat (new_cat->name, "|", new_cat->color_def ? new_cat->color_def : "#FF0000", "|", tag, NULL); ++ ++ if (index == (guint) -1 || index >= (gint) evo_labels->len) { ++ g_ptr_array_add (evo_labels, label_def); ++ } else { ++ g_free (evo_labels->pdata[index]); ++ evo_labels->pdata[index] = label_def; ++ } ++ } ++ ++ g_hash_table_remove (old_categories, new_cat->guid); ++ ++ g_free (tag); ++ } ++ ++ if (g_hash_table_size (old_categories) > 0) { ++ /* Some categories had been removed */ ++ changed = TRUE; ++ ++ g_hash_table_iter_init (&iter, old_categories); ++ while (g_hash_table_iter_next (&iter, NULL, &value)) { ++ CamelEwsCategory *old_cat = value; ++ gchar *old_tag; ++ guint index; ++ ++ if (!old_cat) ++ continue; ++ ++ old_tag = camel_ews_utils_encode_category_name (old_cat->name); ++ ++ for (ii = 0; old_tag && old_tag[ii]; ii++) { ++ if (old_tag[ii] == '|') ++ old_tag[ii] = '-'; ++ } ++ ++ if (old_tag && ++ ews_utils_find_in_ptr_array (evo_labels, old_tag, ews_util_equal_label_tag_cb, &index)) ++ g_ptr_array_remove_index (evo_labels, index); ++ ++ g_free (old_tag); ++ } ++ } ++ ++ if (changed) { ++ /* NULL-terminated array of strings */ ++ g_ptr_array_add (evo_labels, NULL); ++ ++ g_settings_set_strv (settings, "labels", (const gchar * const *) evo_labels->pdata); ++ } ++ ++ g_ptr_array_free (evo_labels, TRUE); ++ g_object_unref (settings); ++ ++ return changed; ++} ++ ++void ++camel_ews_utils_merge_category_list (CamelEwsStore *ews_store, ++ const guchar *xml_data, ++ gsize xml_data_len) ++{ ++ xmlDocPtr doc; ++ xmlXPathContextPtr xpath_ctx; ++ ++ g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store)); ++ g_return_if_fail (xml_data != NULL); ++ ++ doc = e_xml_parse_data (xml_data, xml_data_len); ++ if (!doc) ++ return; ++ ++ xpath_ctx = e_xml_new_xpath_context_with_namespaces (doc, "C", "CategoryList.xsd", NULL); ++ ++ if (xpath_ctx) { ++ xmlXPathObjectPtr xpath_obj_categories; ++ ++ xpath_obj_categories = e_xml_xpath_eval (xpath_ctx, "%s", "/C:categories/C:category"); ++ ++ if (xpath_obj_categories) { ++ GHashTable *old_categories, *new_categories; ++ gint response_index, response_length; ++ ++ new_categories = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, camel_ews_category_free); ++ ++ response_length = xmlXPathNodeSetGetLength (xpath_obj_categories->nodesetval); ++ ++ for (response_index = 0; response_index < response_length; response_index++) { ++ xmlXPathObjectPtr xpath_obj_category; ++ ++ xpath_obj_category = e_xml_xpath_eval (xpath_ctx, ++ "/C:categories/C:category[%d]", ++ response_index + 1); ++ ++ if (xpath_obj_category) { ++ gchar *name; ++ ++ name = e_xml_xpath_eval_as_string (xpath_ctx, "/C:categories/C:category[%d]/@name", response_index + 1); ++ ++ if (name && ews_utils_rename_label (name, 1) == name) { ++ const gchar *color_def = NULL; ++ gchar *color, *guid; ++ gint color_index = -1; ++ ++ color = e_xml_xpath_eval_as_string (xpath_ctx, "/C:categories/C:category[%d]/@color", response_index + 1); ++ if (color) { ++ gchar *endptr = NULL; ++ ++ color_index = (gint) g_ascii_strtoll (color, &endptr, 10); ++ ++ if (endptr == color) ++ color_index = -1; ++ } ++ ++ g_free (color); ++ ++ if (color_index >= 0) ++ color_def = ews_utils_outlook_color_index_to_color_def (color_index); ++ ++ guid = e_xml_xpath_eval_as_string (xpath_ctx, "/C:categories/C:category[%d]/@guid", response_index + 1); ++ ++ if (guid && *guid) { ++ CamelEwsCategory *cat; ++ ++ cat = camel_ews_category_new (guid, name, color_def); ++ if (cat) ++ g_hash_table_insert (new_categories, cat->guid, cat); ++ } ++ ++ g_free (guid); ++ } ++ ++ g_free (name); ++ xmlXPathFreeObject (xpath_obj_category); ++ } ++ } ++ ++ xmlXPathFreeObject (xpath_obj_categories); ++ ++ old_categories = camel_ews_store_summary_get_categories (ews_store->summary); ++ ++ if (ews_utils_save_category_changes (old_categories, new_categories)) { ++ camel_ews_store_summary_set_categories (ews_store->summary, new_categories); ++ camel_ews_store_summary_save (ews_store->summary, NULL); ++ } ++ ++ g_hash_table_destroy (new_categories); ++ g_hash_table_destroy (old_categories); ++ } ++ } ++ ++ if (xpath_ctx) ++ xmlXPathFreeContext (xpath_ctx); ++ xmlFreeDoc (doc); ++} +diff -up evolution-ews-3.28.5/src/camel/camel-ews-utils.h.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-utils.h +--- evolution-ews-3.28.5/src/camel/camel-ews-utils.h.sync-category-list 2018-07-30 16:01:00.000000000 +0200 ++++ evolution-ews-3.28.5/src/camel/camel-ews-utils.h 2019-10-24 09:39:08.341278207 +0200 +@@ -94,6 +94,10 @@ CamelMessageInfo * /* (transfer full) */ + EEwsConnection *cnc, + EEwsItem *item, + GCancellable *cancellable); ++void camel_ews_utils_merge_category_list ++ (CamelEwsStore *ews_store, ++ const guchar *xml_data, ++ gsize xml_data_len); + + G_END_DECLS + +diff -up evolution-ews-3.28.5/src/server/e-ews-connection.c.sync-category-list evolution-ews-3.28.5/src/server/e-ews-connection.c +--- evolution-ews-3.28.5/src/server/e-ews-connection.c.sync-category-list 2019-10-24 09:39:08.339278207 +0200 ++++ evolution-ews-3.28.5/src/server/e-ews-connection.c 2019-10-24 09:46:14.667272312 +0200 +@@ -155,7 +155,7 @@ struct _EwsAsyncData { + EwsDelegateDeliver deliver_to; + EEwsFolderType folder_type; + EEwsConnection *cnc; +- gchar *user_photo; /* base64-encoded, as GetUserPhoto result */ ++ gchar *custom_data; /* Can be re-used by operations, will be freed with g_free() */ + }; + + struct _EwsNode { +@@ -200,7 +200,7 @@ ews_connection_error_quark (void) + static void + async_data_free (EwsAsyncData *async_data) + { +- g_free (async_data->user_photo); ++ g_free (async_data->custom_data); + g_free (async_data); + } + +@@ -10830,10 +10830,10 @@ get_user_photo_response_cb (ESoapRespons + return; + } + +- async_data->user_photo = e_soap_parameter_get_string_value (param); +- if (async_data->user_photo && !*async_data->user_photo) { +- g_free (async_data->user_photo); +- async_data->user_photo = NULL; ++ async_data->custom_data = e_soap_parameter_get_string_value (param); ++ if (async_data->custom_data && !*async_data->custom_data) { ++ g_free (async_data->custom_data); ++ async_data->custom_data = NULL; + } + } + +@@ -10918,11 +10918,11 @@ e_ews_connection_get_user_photo_finish ( + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + +- if (!async_data->user_photo) ++ if (!async_data->custom_data) + return FALSE; + +- *out_picture_data = async_data->user_photo; +- async_data->user_photo = NULL; ++ *out_picture_data = async_data->custom_data; ++ async_data->custom_data = NULL; + + return TRUE; + } +@@ -10953,5 +10953,256 @@ e_ews_connection_get_user_photo_sync (EE + + e_async_closure_free (closure); + ++ return success; ++} ++ ++static void ++get_user_configuration_response_cb (ESoapResponse *response, ++ GSimpleAsyncResult *simple) ++{ ++ EwsAsyncData *async_data; ++ ESoapParameter *param, *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); ++ ++ if (param) { ++ param = e_soap_parameter_get_first_child_by_name (param, "GetUserConfigurationResponseMessage"); ++ if (!param) { ++ g_set_error (&error, ++ SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, ++ "Missing <%s> in SOAP response", "GetUserConfigurationResponseMessage"); ++ } ++ } ++ ++ if (param) { ++ param = e_soap_parameter_get_first_child_by_name (param, "UserConfiguration"); ++ if (!param) { ++ g_set_error (&error, ++ SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, ++ "Missing <%s> in SOAP response", "UserConfiguration"); ++ } ++ } ++ ++ /* 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_by_name (param, "ItemId"); ++ if (subparam) { ++ gchar *id, *changekey; ++ ++ id = e_soap_parameter_get_property (subparam, "Id"); ++ changekey = e_soap_parameter_get_property (subparam, "ChangeKey"); ++ ++ /* Encoded as: Id + "\n" + ChangeKey */ ++ async_data->custom_data = g_strconcat (id ? id : "", "\n", changekey, NULL); ++ ++ g_free (changekey); ++ g_free (id); ++ } ++ ++ if (!subparam) { ++ subparam = e_soap_parameter_get_first_child_by_name (param, "Dictionary"); ++ if (subparam) ++ async_data->custom_data = e_soap_response_dump_parameter (response, subparam); ++ } ++ ++ if (!subparam) { ++ subparam = e_soap_parameter_get_first_child_by_name (param, "XmlData"); ++ if (subparam) { ++ async_data->custom_data = e_soap_parameter_get_string_value (subparam); ++ } ++ } ++ ++ if (!subparam) { ++ subparam = e_soap_parameter_get_first_child_by_name (param, "BinaryData"); ++ if (subparam) { ++ async_data->custom_data = e_soap_parameter_get_string_value (subparam); ++ } ++ } ++ ++ if (async_data->custom_data && !*async_data->custom_data) { ++ g_free (async_data->custom_data); ++ async_data->custom_data = NULL; ++ } ++} ++ ++static void ++e_ews_folder_id_append_to_msg (ESoapMessage *msg, ++ const gchar *email, ++ const EwsFolderId *fid) ++{ ++ g_return_if_fail (msg != NULL); ++ g_return_if_fail (fid != NULL); ++ ++ if (fid->is_distinguished_id) ++ e_soap_message_start_element (msg, "DistinguishedFolderId", NULL, NULL); ++ else ++ e_soap_message_start_element (msg, "FolderId", NULL, NULL); ++ ++ e_soap_message_add_attribute (msg, "Id", fid->id, NULL, NULL); ++ if (fid->change_key) ++ e_soap_message_add_attribute (msg, "ChangeKey", fid->change_key, NULL, NULL); ++ ++ if (fid->is_distinguished_id && email) { ++ e_soap_message_start_element (msg, "Mailbox", NULL, NULL); ++ e_ews_message_write_string_parameter (msg, "EmailAddress", NULL, email); ++ e_soap_message_end_element (msg); ++ } ++ ++ e_soap_message_end_element (msg); ++} ++ ++void ++e_ews_connection_get_user_configuration (EEwsConnection *cnc, ++ gint pri, ++ const EwsFolderId *fid, ++ const gchar *config_name, ++ EEwsUserConfigurationProperties props, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ ESoapMessage *msg; ++ GSimpleAsyncResult *simple; ++ EwsAsyncData *async_data; ++ EwsFolderId local_fid; ++ ++ g_return_if_fail (cnc != NULL); ++ g_return_if_fail (cnc->priv != NULL); ++ g_return_if_fail (fid != NULL); ++ g_return_if_fail (config_name != NULL); ++ ++ simple = g_simple_async_result_new (G_OBJECT (cnc), callback, user_data, e_ews_connection_get_user_configuration); ++ async_data = g_new0 (EwsAsyncData, 1); ++ g_simple_async_result_set_op_res_gpointer (simple, async_data, (GDestroyNotify) async_data_free); ++ ++ /* EWS server version earlier than 2010 doesn't support it. */ ++ if (!e_ews_connection_satisfies_server_version (cnc, E_EWS_EXCHANGE_2010)) { ++ g_simple_async_result_complete_in_idle (simple); ++ g_object_unref (simple); ++ return; ++ } ++ ++ local_fid = *fid; ++ local_fid.change_key = NULL; ++ ++ msg = e_ews_message_new_with_header ( ++ cnc->priv->settings, ++ cnc->priv->uri, ++ cnc->priv->impersonate_user, ++ "GetUserConfiguration", ++ NULL, ++ NULL, ++ cnc->priv->version, ++ E_EWS_EXCHANGE_2010, ++ FALSE, ++ TRUE); ++ ++ e_soap_message_start_element (msg, "UserConfigurationName", "messages", NULL); ++ e_soap_message_add_attribute (msg, "Name", config_name, NULL, NULL); ++ ++ e_ews_folder_id_append_to_msg (msg, cnc->priv->email, &local_fid); ++ ++ e_soap_message_end_element (msg); /* UserConfigurationName */ ++ ++ e_soap_message_start_element (msg, "UserConfigurationProperties", "messages", NULL); ++ ++ switch (props) { ++ case E_EWS_USER_CONFIGURATION_PROPERTIES_ID: ++ e_soap_message_write_string (msg, "Id"); ++ break; ++ case E_EWS_USER_CONFIGURATION_PROPERTIES_DICTIONARY: ++ e_soap_message_write_string (msg, "Dictionary"); ++ break; ++ case E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA: ++ e_soap_message_write_string (msg, "XmlData"); ++ break; ++ case E_EWS_USER_CONFIGURATION_PROPERTIES_BINARYDATA: ++ e_soap_message_write_string (msg, "BinaryData"); ++ break; ++ /* case E_EWS_USER_CONFIGURATION_PROPERTIES_ALL: ++ e_soap_message_write_string (msg, "All"); ++ break; */ ++ default: ++ e_soap_message_write_string (msg, "Unknown"); ++ break; ++ } ++ ++ e_soap_message_end_element (msg); /* UserConfigurationProperties */ ++ ++ e_ews_message_write_footer (msg); ++ ++ e_ews_connection_queue_request (cnc, msg, get_user_configuration_response_cb, pri, cancellable, simple); ++ ++ g_object_unref (simple); ++} ++ ++gboolean ++e_ews_connection_get_user_configuration_finish (EEwsConnection *cnc, ++ GAsyncResult *result, ++ gchar **out_properties, ++ 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_user_configuration), ++ FALSE); ++ g_return_val_if_fail (out_properties != NULL, 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->custom_data) ++ return FALSE; ++ ++ *out_properties = async_data->custom_data; ++ async_data->custom_data = NULL; ++ ++ return TRUE; ++} ++ ++gboolean ++e_ews_connection_get_user_configuration_sync (EEwsConnection *cnc, ++ gint pri, ++ const EwsFolderId *fid, ++ const gchar *config_name, ++ EEwsUserConfigurationProperties props, ++ gchar **out_properties, ++ 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_user_configuration ( ++ cnc, pri, fid, config_name, props, cancellable, e_async_closure_callback, closure); ++ ++ result = e_async_closure_wait (closure); ++ ++ success = e_ews_connection_get_user_configuration_finish (cnc, result, out_properties, error); ++ ++ e_async_closure_free (closure); ++ + return success; + } +diff -up evolution-ews-3.28.5/src/server/e-ews-connection.h.sync-category-list evolution-ews-3.28.5/src/server/e-ews-connection.h +--- evolution-ews-3.28.5/src/server/e-ews-connection.h.sync-category-list 2019-10-24 09:39:08.339278207 +0200 ++++ evolution-ews-3.28.5/src/server/e-ews-connection.h 2019-10-24 09:39:08.342278207 +0200 +@@ -132,6 +132,15 @@ typedef enum { + E_EWS_SIZE_REQUESTED_648X648 = 648 + } EEwsSizeRequested; + ++typedef enum { ++ E_EWS_USER_CONFIGURATION_PROPERTIES_UNKNOWN = -1, ++ E_EWS_USER_CONFIGURATION_PROPERTIES_ID, ++ E_EWS_USER_CONFIGURATION_PROPERTIES_DICTIONARY, ++ E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA, ++ E_EWS_USER_CONFIGURATION_PROPERTIES_BINARYDATA /*, ++ E_EWS_USER_CONFIGURATION_PROPERTIES_ALL - skip it, be specific */ ++} EEwsUserConfigurationProperties; ++ + typedef struct { + gchar *id; + gchar *dn; +@@ -1377,6 +1386,29 @@ gboolean e_ews_connection_get_user_photo + gchar **out_picture_data, /* base64-encoded */ + GCancellable *cancellable, + GError **error); ++void e_ews_connection_get_user_configuration ++ (EEwsConnection *cnc, ++ gint pri, ++ const EwsFolderId *fid, ++ const gchar *config_name, ++ EEwsUserConfigurationProperties props, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++gboolean e_ews_connection_get_user_configuration_finish ++ (EEwsConnection *cnc, ++ GAsyncResult *result, ++ gchar **out_properties, ++ GError **error); ++gboolean e_ews_connection_get_user_configuration_sync ++ (EEwsConnection *cnc, ++ gint pri, ++ const EwsFolderId *fid, ++ const gchar *config_name, ++ EEwsUserConfigurationProperties props, ++ gchar **out_properties, ++ GCancellable *cancellable, ++ GError **error); + + G_END_DECLS + +diff -up evolution-ews-3.28.5/src/server/e-soap-response.c.sync-category-list evolution-ews-3.28.5/src/server/e-soap-response.c +--- evolution-ews-3.28.5/src/server/e-soap-response.c.sync-category-list 2018-07-30 16:01:00.000000000 +0200 ++++ evolution-ews-3.28.5/src/server/e-soap-response.c 2019-10-24 09:39:08.342278207 +0200 +@@ -685,3 +685,29 @@ e_soap_response_dump_response (ESoapResp + + return ret; + } ++ ++gchar * ++e_soap_response_dump_parameter (ESoapResponse *response, ++ ESoapParameter *param) ++{ ++ xmlBuffer *buffer; ++ gint len; ++ gchar *data; ++ ++ g_return_val_if_fail (E_IS_SOAP_RESPONSE (response), NULL); ++ g_return_val_if_fail (param != NULL, NULL); ++ ++ buffer = xmlBufferCreate (); ++ len = xmlNodeDump (buffer, response->priv->xmldoc, param, 0, 0); ++ ++ if (len <= 0) { ++ xmlBufferFree (buffer); ++ return NULL; ++ } ++ ++ data = g_strndup ((const gchar *) buffer->content, len); ++ ++ xmlBufferFree (buffer); ++ ++ return data; ++} +diff -up evolution-ews-3.28.5/src/server/e-soap-response.h.sync-category-list evolution-ews-3.28.5/src/server/e-soap-response.h +--- evolution-ews-3.28.5/src/server/e-soap-response.h.sync-category-list 2018-07-30 16:01:00.000000000 +0200 ++++ evolution-ews-3.28.5/src/server/e-soap-response.h 2019-10-24 09:39:08.343278207 +0200 +@@ -101,6 +101,8 @@ ESoapParameter * + const gchar *name); + gint e_soap_response_dump_response (ESoapResponse *response, + FILE *buffer); ++gchar * e_soap_response_dump_parameter (ESoapResponse *response, ++ ESoapParameter *param); + + G_END_DECLS + diff --git a/SPECS/evolution-ews.spec b/SPECS/evolution-ews.spec index a51d79a..2f90244 100644 --- a/SPECS/evolution-ews.spec +++ b/SPECS/evolution-ews.spec @@ -2,7 +2,7 @@ Name: evolution-ews Version: 3.28.5 -Release: 5%{?dist} +Release: 9%{?dist} Group: Applications/Productivity Summary: Evolution extension for Exchange Web Services License: LGPLv2 @@ -31,6 +31,15 @@ Patch06: evolution-ews-3.28.5-double-collection-backend-populate.patch # RH bug #1696761 Patch07: evolution-ews-3.28.5-cve-2019-3890.patch +# RH bug #1741091 +Patch08: evolution-ews-3.28.5-birthday-date.patch + +# RH bug #1764818 +Patch09: evolution-ews-3.28.5-sync-category-list.patch + +# RH bug #1765005 +Patch10: evolution-ews-3.28.5-save-only-if-organizer.patch + Requires: evolution >= %{eds_evo_version} Requires: evolution-data-server >= %{eds_evo_version} Requires: %{name}-langpacks = %{version}-%{release} @@ -77,6 +86,9 @@ This package contains translations for %{name}. %patch05 -p1 -b .meeting-with-attachment %patch06 -p1 -b .double-collection-backend-populate %patch07 -p1 -b .cve-2019-3890 +%patch08 -p1 -b .birthday-date +%patch09 -p1 -b .sync-category-list +%patch10 -p1 -b .save-only-if-organizer %build @@ -117,6 +129,19 @@ make install DESTDIR=$RPM_BUILD_ROOT %files langpacks -f _build/%{name}.lang %changelog +* Wed Nov 13 2019 Milan Crha - 3.28.5-9 +- Remove patch for RH bug #1765005 (Reject creating meetings organized by other users) + +* Tue Oct 29 2019 Milan Crha - 3.28.5-8 +- Remove patch for RH bug #1765005 (Send meeting change notifications only if being the organizer) + +* Thu Oct 24 2019 Milan Crha - 3.28.5-7 +- Add patch for RH bug #1764818 (Sync CategoryList with mail Labels) +- Add patch for RH bug #1765005 (Send meeting change notifications only if being the organizer) + +* Wed Oct 23 2019 Milan Crha - 3.28.5-6 +- Add patch for RH bug #1741091 (Birthday date of Contact depends on system timezone) + * Mon May 27 2019 Milan Crha - 3.28.5-5 - Rebuild with added gating