diff -Nru evolution-data-server-3.44.0/CMakeLists.txt evolution-data-server-3.44.4/CMakeLists.txt --- evolution-data-server-3.44.0/CMakeLists.txt 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/CMakeLists.txt 2022-08-05 07:45:35.000000000 +0000 @@ -4,7 +4,7 @@ cmake_policy(VERSION 3.1) project(evolution-data-server - VERSION 3.44.0 + VERSION 3.44.4 LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 14) set(PROJECT_BUGREPORT "https://gitlab.gnome.org/GNOME/evolution-data-server/issues/") diff -Nru evolution-data-server-3.44.0/debian/changelog evolution-data-server-3.44.4/debian/changelog --- evolution-data-server-3.44.0/debian/changelog 2022-03-20 01:45:47.000000000 +0000 +++ evolution-data-server-3.44.4/debian/changelog 2023-06-19 18:23:37.000000000 +0000 @@ -1,3 +1,39 @@ +evolution-data-server (3.44.4-0ubuntu1.1) jammy-security; urgency=medium + + * No-change rebuild in the -security pocket. + + -- Marc Deslauriers Mon, 19 Jun 2023 14:23:37 -0400 + +evolution-data-server (3.44.4-0ubuntu1) jammy; urgency=medium + + * New upstream release (LP: #1980545) + + -- Nathan Pratta Teodosio Wed, 06 Jul 2022 10:46:37 -0300 + +evolution-data-server (3.44.2-0ubuntu1) jammy; urgency=medium + + * New upstream release (LP: #1976371) + + -- Nathan Pratta Teodosio Tue, 31 May 2022 09:55:46 -0300 + +evolution-data-server (3.44.1-0ubuntu2) jammy; urgency=medium + + * Don't build with libgweather4 + + -- Jeremy Bicha Mon, 09 May 2022 19:16:50 -0400 + +evolution-data-server (3.44.1-0ubuntu1) jammy; urgency=medium + + * New upstream release (LP: #1969934) + + -- Jeremy Bicha Thu, 28 Apr 2022 07:34:04 -0400 + +evolution-data-server (3.44.0-3) unstable; urgency=medium + + * Build with libgweather4 + + -- Jeremy Bicha Mon, 28 Mar 2022 11:24:11 -0400 + evolution-data-server (3.44.0-2) unstable; urgency=medium * debian/rules: Fix dh_fixperms override (Closes: #1004484, #1006603) diff -Nru evolution-data-server-3.44.0/debian/control evolution-data-server-3.44.4/debian/control --- evolution-data-server-3.44.0/debian/control 2022-03-20 01:45:47.000000000 +0000 +++ evolution-data-server-3.44.4/debian/control 2023-06-19 18:23:37.000000000 +0000 @@ -5,8 +5,9 @@ Source: evolution-data-server Section: gnome Priority: optional -Maintainer: Debian GNOME Maintainers -Uploaders: Iain Lane , Jeremy Bicha , Laurent Bigonville +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian GNOME Maintainers +Uploaders: Iain Lane , Jeremy Bicha , Laurent Bigonville Build-Depends: cmake, debhelper-compat (= 13), dh-sequence-gir, @@ -47,8 +48,10 @@ Rules-Requires-Root: binary-targets Standards-Version: 4.5.0 Homepage: https://wiki.gnome.org/Apps/Evolution -Vcs-Git: https://salsa.debian.org/gnome-team/evolution-data-server.git -Vcs-Browser: https://salsa.debian.org/gnome-team/evolution-data-server +XS-Debian-Vcs-Git: https://salsa.debian.org/gnome-team/evolution-data-server.git +XS-Debian-Vcs-Browser: https://salsa.debian.org/gnome-team/evolution-data-server +Vcs-Git: https://salsa.debian.org/gnome-team/evolution-data-server.git -b ubuntu/jammy +Vcs-Browser: https://salsa.debian.org/gnome-team/evolution-data-server/tree/ubuntu/jammy Package: evolution-data-server Architecture: any diff -Nru evolution-data-server-3.44.0/debian/control.in evolution-data-server-3.44.4/debian/control.in --- evolution-data-server-3.44.0/debian/control.in 2022-03-20 01:45:47.000000000 +0000 +++ evolution-data-server-3.44.4/debian/control.in 2022-07-06 13:46:37.000000000 +0000 @@ -1,7 +1,8 @@ Source: evolution-data-server Section: gnome Priority: optional -Maintainer: Debian GNOME Maintainers +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian GNOME Maintainers Uploaders: @GNOME_TEAM@ Build-Depends: cmake, debhelper-compat (= 13), @@ -43,8 +44,10 @@ Rules-Requires-Root: binary-targets Standards-Version: 4.5.0 Homepage: https://wiki.gnome.org/Apps/Evolution -Vcs-Git: https://salsa.debian.org/gnome-team/evolution-data-server.git -Vcs-Browser: https://salsa.debian.org/gnome-team/evolution-data-server +XS-Debian-Vcs-Git: https://salsa.debian.org/gnome-team/evolution-data-server.git +XS-Debian-Vcs-Browser: https://salsa.debian.org/gnome-team/evolution-data-server +Vcs-Git: https://salsa.debian.org/gnome-team/evolution-data-server.git -b ubuntu/jammy +Vcs-Browser: https://salsa.debian.org/gnome-team/evolution-data-server/tree/ubuntu/jammy Package: evolution-data-server Architecture: any diff -Nru evolution-data-server-3.44.0/debian/gbp.conf evolution-data-server-3.44.4/debian/gbp.conf --- evolution-data-server-3.44.0/debian/gbp.conf 2022-03-20 01:45:47.000000000 +0000 +++ evolution-data-server-3.44.4/debian/gbp.conf 2022-07-06 13:46:37.000000000 +0000 @@ -1,6 +1,7 @@ [DEFAULT] pristine-tar = True -debian-branch = debian/master +debian-branch = ubuntu/jammy +debian-tag = ubuntu/%(version)s upstream-branch = upstream/latest [buildpackage] diff -Nru evolution-data-server-3.44.0/debian/watch evolution-data-server-3.44.4/debian/watch --- evolution-data-server-3.44.0/debian/watch 2022-03-20 01:45:47.000000000 +0000 +++ evolution-data-server-3.44.4/debian/watch 2022-07-06 13:46:37.000000000 +0000 @@ -1,4 +1,4 @@ version=4 -opts="searchmode=plain, uversionmangle=s/\.(alpha|beta|rc)/~$1/" \ +opts="searchmode=plain, uversionmangle=s/\.(alpha|beta|rc)/~$1/, downloadurlmangle=s|cache.json||" \ https://download.gnome.org/sources/@PACKAGE@/cache.json \ [\d.]+[02468]/@PACKAGE@-([\d.]+)@ARCHIVE_EXT@ diff -Nru evolution-data-server-3.44.0/NEWS evolution-data-server-3.44.4/NEWS --- evolution-data-server-3.44.0/NEWS 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/NEWS 2022-08-05 07:45:35.000000000 +0000 @@ -1,3 +1,54 @@ +Evolution-Data-Server 3.44.4 2022-08-05 +--------------------------------------- + +Bug Fixes: + I#407 - IMAPx: Unsubscribed folder always removed from the UI + +Miscellaneous: + ESoupAuthBearer: Check for token expiration in e_soup_auth_bearer_is_authenticated() + ESoupSession: Avoid downgrade of Bearer (OAuth2) auth for authentication + Check for non-zero value passed to g_flags_get_first_value() + alarm-notify: Use themed icon instead of file icon for notifications + +Evolution-Data-Server 3.44.3 2022-07-01 +--------------------------------------- + +Bug Fixes: + I#350 - LDAP: Conditionally use 'description' as Note + I#391 - Tests fail with libphonenumber 8.12.49 + I#392 - Sanitize IPv6 proxy address before passing it to WebKitGTK + I#393 - Calendar: Correct UNTIL recurrence with midnight start + I#396 - Camel: Read message ID-s with multiple `@` + +Miscellaneous: + Disable hardware acceleration for WebKitGTK + ESource: Reconnect signal handlers when the D-Bus 'source' interface changes + +Evolution-Data-Server 3.44.2 2022-05-27 +--------------------------------------- + +Bug Fixes: + I#359 - CalDAV: Crash on calendar update + I#386 - e-webdav-discover: Fails to find Radicale calendars within collection account + I#388 - Google OAuth out-of-band (oob) flow will be deprecated + I#389 - IMAPx: Fails to create folder with NIL folder hierarchy delimiter + evo-I#1348 - WebDAVCollectionBackend: Removes sources on server error + +Miscellaneous: + ERemindersWidget: Allow width shrink for small screens + Fix few memory leaks discovered by Coverity scan + GOA module: Prevent ESource removal on D-Bus reconnect or registry reload + +Evolution-Data-Server 3.44.1 2022-04-22 +--------------------------------------- + +Bug Fixes: + I#380 - CalDAV: Free / Busy not working with Nextcloud + I#381 - EWebDAVSession: Correct extract of href from Location header + +Miscellaneous: + ESoupAuthBearer: Implement two more SoupAuth virtual methods + Evolution-Data-Server 3.44.0 2022-03-18 --------------------------------------- diff -Nru evolution-data-server-3.44.0/src/addressbook/backends/ldap/e-book-backend-ldap.c evolution-data-server-3.44.4/src/addressbook/backends/ldap/e-book-backend-ldap.c --- evolution-data-server-3.44.0/src/addressbook/backends/ldap/e-book-backend-ldap.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/addressbook/backends/ldap/e-book-backend-ldap.c 2022-08-05 07:45:35.000000000 +0000 @@ -262,6 +262,8 @@ #define PROP_TYPE_GROUP (1 << 6) #define PROP_TYPE_CONTACT (1 << 7) /* is ignored for contact lists */ #define PROP_TYPE_FORCE_BINARY (1 << 8) /* to force ";binary" in attribute name */ +#define PROP_WITH_EVOSCHEME (1 << 9) +#define PROP_WITHOUT_EVOSCHEME (1 << 10) gint prop_type; /* the remaining items are only used for the TYPE_COMPLEX props */ @@ -287,6 +289,8 @@ #define GROUP_PROP(fid,a,ctor,ber,cmp) {fid, a, PROP_TYPE_GROUP, ctor, ber, cmp} #define ADDRESS_STRING_PROP(fid,a, ctor) {fid, a, PROP_TYPE_COMPLEX, ctor} #define CONTACT_STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING | PROP_TYPE_CONTACT} +#define CONTACT_STRING_PROP_WITH_EVOSCHEME(fid,a) {fid, a, PROP_TYPE_STRING | PROP_TYPE_CONTACT | PROP_WITH_EVOSCHEME} +#define CONTACT_STRING_PROP_WITHOUT_EVOSCHEME(fid,a) {fid, a, PROP_TYPE_STRING | PROP_TYPE_CONTACT | PROP_WITHOUT_EVOSCHEME} #define CALENTRY_CONTACT_STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING | PROP_TYPE_CONTACT | PROP_CALENTRY} /* name fields */ @@ -361,7 +365,8 @@ /* map nickname to displayName */ CONTACT_STRING_PROP (E_CONTACT_NICKNAME, "displayName"), E_STRING_PROP (E_CONTACT_SPOUSE, "spouseName"), - E_STRING_PROP (E_CONTACT_NOTE, "note"), + CONTACT_STRING_PROP_WITH_EVOSCHEME (E_CONTACT_NOTE, "note"), + CONTACT_STRING_PROP_WITHOUT_EVOSCHEME (E_CONTACT_NOTE, "description"), E_COMPLEX_PROP (E_CONTACT_ANNIVERSARY, "anniversary", anniversary_populate, anniversary_ber, anniversary_compare), E_COMPLEX_PROP (E_CONTACT_BIRTH_DATE, "birthDate", birthday_populate, birthday_ber, birthday_compare), E_STRING_PROP (E_CONTACT_MAILER, "mailer"), @@ -1300,6 +1305,13 @@ if (is_list) continue; } + + if (((prop_info[i].prop_type & PROP_WITHOUT_EVOSCHEME) != 0 && + bl->priv->evolutionPersonSupported) || + ((prop_info[i].prop_type & PROP_WITH_EVOSCHEME) != 0 && + !bl->priv->evolutionPersonSupported)) + continue; + if ((prop_info[i].prop_type & PROP_CALENTRY) != 0) { if (!bl->priv->calEntrySupported) continue; @@ -2841,7 +2853,7 @@ const gchar *ldap_attr) { gint phone_ids[2] = { E_CONTACT_PHONE_HOME, E_CONTACT_PHONE_HOME_2 }; - const gchar *phone1, *phone2; + gchar *phone1, *phone2; gint i; for (i = 0; i < 2; i++) { @@ -2854,6 +2866,9 @@ else equal = (!!phone1 == !!phone2); + g_free (phone1); + g_free (phone2); + if (!equal) return equal; } @@ -2914,7 +2929,7 @@ const gchar *ldap_attr) { gint phone_ids[2] = { E_CONTACT_PHONE_BUSINESS, E_CONTACT_PHONE_BUSINESS_2 }; - const gchar *phone1, *phone2; + gchar *phone1, *phone2; gint i; for (i = 0; i < 2; i++) { @@ -2927,6 +2942,9 @@ else equal = (!!phone1 == !!phone2); + g_free (phone1); + g_free (phone2); + if (!equal) return equal; } @@ -3868,6 +3886,11 @@ !(prop_info[i].prop_type & PROP_WRITE_ONLY) && (ldap_data->bl->priv->evolutionPersonSupported || !(prop_info[i].prop_type & PROP_EVOLVE)) && + (!(prop_info[i].prop_type & (PROP_WITH_EVOSCHEME | PROP_WITHOUT_EVOSCHEME)) || + ((prop_info[i].prop_type & PROP_WITHOUT_EVOSCHEME) != 0 && + !ldap_data->bl->priv->evolutionPersonSupported) || + ((prop_info[i].prop_type & PROP_WITH_EVOSCHEME) != 0 && + ldap_data->bl->priv->evolutionPersonSupported)) && (ldap_data->bl->priv->calEntrySupported || !(prop_info[i].prop_type & PROP_CALENTRY))) { g_string_append_c (big_query, '('); @@ -4067,6 +4090,11 @@ if (!(prop_info[i].prop_type & PROP_WRITE_ONLY) && (ldap_data->bl->priv->evolutionPersonSupported || !(prop_info[i].prop_type & PROP_EVOLVE)) && + (!(prop_info[i].prop_type & (PROP_WITH_EVOSCHEME | PROP_WITHOUT_EVOSCHEME)) || + ((prop_info[i].prop_type & PROP_WITHOUT_EVOSCHEME) != 0 && + !ldap_data->bl->priv->evolutionPersonSupported) || + ((prop_info[i].prop_type & PROP_WITH_EVOSCHEME) != 0 && + ldap_data->bl->priv->evolutionPersonSupported)) && (ldap_data->bl->priv->calEntrySupported || !(prop_info[i].prop_type & PROP_CALENTRY))) { g_string_append_c (big_query, '('); @@ -4186,6 +4214,11 @@ if (!strcmp (query_prop, e_contact_field_name (prop_info[i].field_id))) { if ((evolution_person_supported || !(prop_info[i].prop_type & PROP_EVOLVE)) && + (!(prop_info[i].prop_type & (PROP_WITH_EVOSCHEME | PROP_WITHOUT_EVOSCHEME)) || + ((prop_info[i].prop_type & PROP_WITHOUT_EVOSCHEME) != 0 && + !evolution_person_supported) || + ((prop_info[i].prop_type & PROP_WITH_EVOSCHEME) != 0 && + evolution_person_supported)) && (calentry_supported || !(prop_info[i].prop_type & PROP_CALENTRY))) { return prop_info[i].ldap_attr; @@ -4262,7 +4295,12 @@ } else { for (i = 0; i < G_N_ELEMENTS (prop_info); i++) { - if (!g_ascii_strcasecmp (attr, prop_info[i].ldap_attr)) { + if (!g_ascii_strcasecmp (attr, prop_info[i].ldap_attr) && + (!(prop_info[i].prop_type & (PROP_WITH_EVOSCHEME | PROP_WITHOUT_EVOSCHEME)) || + ((prop_info[i].prop_type & PROP_WITHOUT_EVOSCHEME) != 0 && + !bl->priv->evolutionPersonSupported) || + ((prop_info[i].prop_type & PROP_WITH_EVOSCHEME) != 0 && + bl->priv->evolutionPersonSupported))) { info = &prop_info[i]; break; } diff -Nru evolution-data-server-3.44.0/src/calendar/backends/caldav/e-cal-backend-caldav.c evolution-data-server-3.44.4/src/calendar/backends/caldav/e-cal-backend-caldav.c --- evolution-data-server-3.44.0/src/calendar/backends/caldav/e-cal-backend-caldav.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/calendar/backends/caldav/e-cal-backend-caldav.c 2022-08-05 07:45:35.000000000 +0000 @@ -199,7 +199,8 @@ soup_uri = e_source_webdav_dup_soup_uri (webdav_extension); cbdav->priv->calendar_schedule = e_cal_backend_get_kind (E_CAL_BACKEND (cbdav)) != I_CAL_VJOURNAL_COMPONENT && - capabilities && g_hash_table_contains (capabilities, E_WEBDAV_CAPABILITY_CALENDAR_SCHEDULE); + (!capabilities || g_hash_table_contains (capabilities, E_WEBDAV_CAPABILITY_CALENDAR_AUTO_SCHEDULE) || + g_hash_table_contains (capabilities, E_WEBDAV_CAPABILITY_CALENDAR_SCHEDULE)); calendar_access = capabilities && g_hash_table_contains (capabilities, E_WEBDAV_CAPABILITY_CALENDAR_ACCESS); if (calendar_access) { @@ -544,7 +545,8 @@ link = *in_link; while (link && left_to_go > 0) { - ECalMetaBackendInfo *nfo = link->data; + GSList *nfo_link = link; + ECalMetaBackendInfo *nfo = nfo_link->data; link = g_slist_next (link); if (!link) { @@ -634,7 +636,7 @@ else e_cal_meta_backend_info_free (nfo); - link->data = NULL; + nfo_link->data = NULL; g_clear_error (&local_error); continue; } else if (local_error) { @@ -2211,7 +2213,9 @@ const GSList *link; GError *local_error = NULL; - if (ecb_caldav_get_free_busy_from_schedule_outbox_sync (cbdav, users, start, end, out_freebusy, cancellable, &local_error)) { + /* Finish only if found anything, otherwise re-check with the principals */ + if (ecb_caldav_get_free_busy_from_schedule_outbox_sync (cbdav, users, start, end, out_freebusy, cancellable, &local_error) && + out_freebusy && *out_freebusy) { g_clear_object (&webdav); return; } diff -Nru evolution-data-server-3.44.0/src/calendar/libecal/e-cal-client.c evolution-data-server-3.44.4/src/calendar/libecal/e-cal-client.c --- evolution-data-server-3.44.0/src/calendar/libecal/e-cal-client.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/calendar/libecal/e-cal-client.c 2022-08-05 07:45:35.000000000 +0000 @@ -5187,13 +5187,13 @@ mod_flags = g_string_new (NULL); flags_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE); - flags_value = g_flags_get_first_value (flags_class, mod); - while (flags_value != NULL) { + for (flags_value = g_flags_get_first_value (flags_class, mod); + flags_value && mod; + flags_value = g_flags_get_first_value (flags_class, mod)) { if (mod_flags->len > 0) g_string_append_c (mod_flags, ':'); g_string_append (mod_flags, flags_value->value_nick); mod &= ~flags_value->value; - flags_value = g_flags_get_first_value (flags_class, mod); } strv = g_new0 (gchar *, g_slist_length (icalcomps) + 1); @@ -5549,13 +5549,13 @@ mod_flags = g_string_new (NULL); flags_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE); - flags_value = g_flags_get_first_value (flags_class, mod); - while (flags_value != NULL) { + for (flags_value = g_flags_get_first_value (flags_class, mod); + flags_value && mod; + flags_value = g_flags_get_first_value (flags_class, mod)) { if (mod_flags->len > 0) g_string_append_c (mod_flags, ':'); g_string_append (mod_flags, flags_value->value_nick); mod &= ~flags_value->value; - flags_value = g_flags_get_first_value (flags_class, mod); } g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); diff -Nru evolution-data-server-3.44.0/src/calendar/libecal/e-cal-recur.c evolution-data-server-3.44.4/src/calendar/libecal/e-cal-recur.c --- evolution-data-server-3.44.0/src/calendar/libecal/e-cal-recur.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/calendar/libecal/e-cal-recur.c 2022-08-05 07:45:35.000000000 +0000 @@ -529,11 +529,6 @@ if (rrule_until && !i_cal_time_is_null_time (rrule_until) && i_cal_time_is_date (rrule_until) && !i_cal_time_is_date (dtstart)) { i_cal_time_adjust (rrule_until, 1, 0, 0, 0); - i_cal_time_set_is_date (rrule_until, FALSE); - i_cal_time_set_time (rrule_until, 0, 0, 0); - - if (!i_cal_time_get_timezone (rrule_until) && !i_cal_time_is_utc (rrule_until)) - i_cal_time_set_timezone (rrule_until, dtstart_zone); } if (rrule_until && !i_cal_time_is_null_time (rrule_until)) @@ -676,11 +671,6 @@ if (exrule_until && !i_cal_time_is_null_time (exrule_until) && i_cal_time_is_date (exrule_until) && !i_cal_time_is_date (dtstart)) { i_cal_time_adjust (exrule_until, 1, 0, 0, 0); - i_cal_time_set_is_date (exrule_until, FALSE); - i_cal_time_set_time (exrule_until, 0, 0, 0); - - if (!i_cal_time_get_timezone (exrule_until) && !i_cal_time_is_utc (exrule_until)) - i_cal_time_set_timezone (exrule_until, dtstart_zone); } if (exrule_until && !i_cal_time_is_null_time (exrule_until)) diff -Nru evolution-data-server-3.44.0/src/camel/camel-mime-utils.c evolution-data-server-3.44.4/src/camel/camel-mime-utils.c --- evolution-data-server-3.44.0/src/camel/camel-mime-utils.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/camel/camel-mime-utils.c 2022-08-05 07:45:35.000000000 +0000 @@ -2706,7 +2706,7 @@ w (g_warning ("Invalid address spec: %s", *in)); } } - if (*inptr == '@') { + while (*inptr == '@') { inptr++; g_string_append_c (addr, '@'); word = header_decode_domain (&inptr); @@ -2716,8 +2716,6 @@ } else { w (g_warning ("Invalid address, missing domain: %s", *in)); } - } else { - w (g_warning ("Invalid addr-spec, missing @: %s", *in)); } } else { w (g_warning ("invalid addr-spec, no local part")); @@ -3216,7 +3214,9 @@ } static void -header_references_decode_single (const gchar **in, GSList **list) +header_references_decode_single (const gchar **in, + gboolean *had_valid_value, + GSList **list) { const gchar *inptr = *in; GString *accum_word = NULL; @@ -3227,30 +3227,33 @@ if (*inptr == '<') { id = header_msgid_decode_internal (&inptr); if (id) { + *had_valid_value = TRUE; *list = g_slist_prepend (*list, id); break; } } else { word = header_decode_word (&inptr); if (word) { - /* To support broken clients, which do not enclose message IDs into angle brackets, as - required in the RFC 2822: https://tools.ietf.org/html/rfc2822#section-3.6.4 */ - if (!*inptr || camel_mime_is_lwsp (*inptr)) { - if (accum_word) { - g_string_append (accum_word, word); - *list = g_slist_prepend (*list, g_string_free (accum_word, FALSE)); - accum_word = NULL; + if (!*had_valid_value) { + /* To support broken clients, which do not enclose message IDs into angle brackets, as + required in the RFC 2822: https://tools.ietf.org/html/rfc2822#section-3.6.4 */ + if (!*inptr || camel_mime_is_lwsp (*inptr)) { + if (accum_word) { + g_string_append (accum_word, word); + *list = g_slist_prepend (*list, g_string_free (accum_word, FALSE)); + accum_word = NULL; + } else { + *list = g_slist_prepend (*list, word); + word = NULL; + } } else { - *list = g_slist_prepend (*list, word); - word = NULL; - } - } else { - if (accum_word) - g_string_append (accum_word, word); - else - accum_word = g_string_new (word); + if (accum_word) + g_string_append (accum_word, word); + else + accum_word = g_string_new (word); - g_string_append_c (accum_word, *inptr); + g_string_append_c (accum_word, *inptr); + } } g_free (word); } else if (*inptr != '\0') @@ -3276,12 +3279,13 @@ camel_header_references_decode (const gchar *in) { GSList *refs = NULL; + gboolean had_valid_value = FALSE; if (in == NULL || in[0] == '\0') return NULL; while (*in) - header_references_decode_single (&in, &refs); + header_references_decode_single (&in, &had_valid_value, &refs); return refs; } diff -Nru evolution-data-server-3.44.0/src/camel/providers/imapx/camel-imapx-store.c evolution-data-server-3.44.4/src/camel/providers/imapx/camel-imapx-store.c --- evolution-data-server-3.44.0/src/camel/providers/imapx/camel-imapx-store.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/camel/providers/imapx/camel-imapx-store.c 2022-08-05 07:45:35.000000000 +0000 @@ -2317,6 +2317,16 @@ goto exit; separator = camel_imapx_mailbox_get_separator (parent_mailbox); + + /* NIL separator means flat structure, where subfolders cannot be created */ + if (!separator) { + g_object_unref (parent_mailbox); + /* Cannot set error here, like in the development version, due to untranslated + string, thus let it create the folder in the top level. Evolution throws + an error about "folder not found" due to using the path with the parent folder. */ + goto check_namespace; + } + parent_mailbox_name = camel_imapx_mailbox_get_name (parent_mailbox); mailbox_name = g_strdup_printf ( @@ -2355,7 +2365,7 @@ check_separator: - if (strchr (folder_name, separator) != NULL) { + if (separator && strchr (folder_name, separator) != NULL) { g_set_error ( error, CAMEL_FOLDER_ERROR, CAMEL_FOLDER_ERROR_INVALID_PATH, @@ -3167,12 +3177,20 @@ success = camel_imapx_conn_manager_unsubscribe_mailbox_sync (conn_man, mailbox, cancellable, error); if (success) { - CamelFolderInfo *fi; + CamelSettings *settings; - fi = imapx_store_build_folder_info ( - CAMEL_IMAPX_STORE (subscribable), folder_name, 0); - camel_subscribable_folder_unsubscribed (subscribable, fi); - camel_folder_info_free (fi); + settings = camel_service_ref_settings (CAMEL_SERVICE (imapx_store)); + + /* Notify about unsubscribed folder only if showing subscribed folders only */ + if (camel_imapx_settings_get_use_subscriptions (CAMEL_IMAPX_SETTINGS (settings))) { + CamelFolderInfo *fi; + + fi = imapx_store_build_folder_info (imapx_store, folder_name, 0); + camel_subscribable_folder_unsubscribed (subscribable, fi); + camel_folder_info_free (fi); + } + + g_clear_object (&settings); } exit: diff -Nru evolution-data-server-3.44.0/src/camel/providers/nntp/camel-nntp-store.c evolution-data-server-3.44.4/src/camel/providers/nntp/camel-nntp-store.c --- evolution-data-server-3.44.0/src/camel/providers/nntp/camel-nntp-store.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/camel/providers/nntp/camel-nntp-store.c 2022-08-05 07:45:35.000000000 +0000 @@ -1442,6 +1442,9 @@ /* return back the .ev-store-summary file, it's saved in user_data_dir */ if (g_rename (ucd_ev_store_summary, udd_ev_store_summary) == -1) g_debug ("%s: Failed to return back '%s' to '%s': %s", G_STRFUNC, ucd_ev_store_summary, udd_ev_store_summary, g_strerror (errno)); + + g_free (udd_ev_store_summary); + g_free (ucd_ev_store_summary); } } diff -Nru evolution-data-server-3.44.0/src/camel/tests/misc/test1.c evolution-data-server-3.44.4/src/camel/tests/misc/test1.c --- evolution-data-server-3.44.0/src/camel/tests/misc/test1.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/camel/tests/misc/test1.c 2022-08-05 07:45:35.000000000 +0000 @@ -36,6 +36,11 @@ { "test@camel.host", "test.groupwise@bug.novell", "test@camel.host" } }, { " << test.groupwise@bug.novell>@novell> <@novell>", { "test.groupwise@bug.novell", "test@camel.host", "test.groupwise@bug.novell" } }, + { "", { "test@camel@host" } }, /* broken clients with multiple '@' */ + { "test@camel.host", { "test@camel.host" } }, /* broken clients without <> */ + { "test@camel@host", { "test@camel@host" } }, /* broken clients without <> */ + { " ", /* mix of good and broken values */ + { "t.e.s.t@c.a.m.e.l", "test.1.2.3@camel.1.2.3@host.3.2.1", "test@camel" } }, }; gint @@ -55,7 +60,9 @@ list = camel_header_references_decode (test1[i].header); for (j = 0; test1[i].values[j]; j++) { check_msg (list != NULL, "didn't find all references"); - check (strcmp (test1[i].values[j], list->data) == 0); + check_msg (string_equal (test1[i].values[j], list->data), + "returned ID '%s' doesn't match expected '%s'", + (const gchar *) list->data, test1[i].values[j]); list = g_slist_next (list); } check_msg (list == NULL, "found more references than should have"); diff -Nru evolution-data-server-3.44.0/src/libebackend/e-webdav-collection-backend.c evolution-data-server-3.44.4/src/libebackend/e-webdav-collection-backend.c --- evolution-data-server-3.44.0/src/libebackend/e-webdav-collection-backend.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libebackend/e-webdav-collection-backend.c 2022-08-05 07:45:35.000000000 +0000 @@ -57,6 +57,19 @@ g_hash_table_insert (known_sources, rid, uid); } +static gboolean +webdav_collection_debug_enabled (void) +{ + static gint enabled = -1; + + if (enabled == -1) { + const gchar *envval = g_getenv ("WEBDAV_DEBUG"); + enabled = envval && *envval && g_strcmp0 (envval, "0") != 0 ? 1 : 0; + } + + return enabled == 1; +} + typedef struct _RemoveSourcesData { ESourceRegistryServer *server; EWebDAVCollectionBackend *webdav_backend; @@ -75,8 +88,13 @@ source = e_source_registry_server_ref_source (rsd->server, uid); if (source) { - if (!e_webdav_collection_backend_is_custom_source (rsd->webdav_backend, source)) + if (!e_webdav_collection_backend_is_custom_source (rsd->webdav_backend, source)) { + if (webdav_collection_debug_enabled ()) { + e_util_debug_print ("WEBDAV", " %p: Going to remove previously known source '%s' (%s)\n", rsd->webdav_backend, + e_source_get_display_name (source), e_source_get_uid (source)); + } e_source_remove_sync (source, NULL, NULL); + } g_object_unref (source); } @@ -571,6 +589,9 @@ g_list_foreach (sources, webdav_collection_add_uid_to_hashtable, known_sources); g_list_free_full (sources, g_object_unref); + if (webdav_collection_debug_enabled ()) + e_util_debug_print ("WEBDAV", "%p: This is '%s' (%s)\n", webdav_backend, e_source_get_display_name (source), e_source_get_uid (source)); + server = e_collection_backend_ref_server (collection); if (e_source_collection_get_calendar_enabled (collection_extension) && calendar_url && @@ -589,9 +610,13 @@ webdav_collection_process_discovered_sources (collection, discovered_sources, known_sources, source_types, G_N_ELEMENTS (source_types)); + if (webdav_collection_debug_enabled ()) + e_util_debug_print ("WEBDAV", "%p: Received %u calendars from '%s'\n", webdav_backend, g_slist_length (discovered_sources), calendar_url); + e_webdav_discover_free_discovered_sources (discovered_sources); discovered_sources = NULL; any_success = TRUE; + /* Prevent lost of already known calendars when the discover failed */ } else if (local_error) { RemoveSourceTypesData rstd; @@ -599,6 +624,17 @@ rstd.calendars = TRUE; g_hash_table_foreach_remove (known_sources, webdav_collection_remove_source_types_cb, &rstd); + + if (webdav_collection_debug_enabled () && + (!credentials_empty || ( + !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) && + !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)))) + e_util_debug_print ("WEBDAV", "%p: Failed to get calendars from '%s': %s\n", webdav_backend, calendar_url, local_error->message); + } else if (e_source_collection_get_calendar_enabled (collection_extension) && calendar_url) { + if (webdav_collection_debug_enabled ()) { + e_util_debug_print ("WEBDAV", "%p: Failed to get calendars from '%s': %s\n", webdav_backend, calendar_url, + g_cancellable_is_cancelled (cancellable) ? "Is cancelled" : "Unknown error"); + } } if (!local_error && e_source_collection_get_contacts_enabled (collection_extension) && contacts_url && @@ -612,16 +648,31 @@ webdav_collection_process_discovered_sources (collection, discovered_sources, known_sources, source_types, G_N_ELEMENTS (source_types)); + if (webdav_collection_debug_enabled ()) + e_util_debug_print ("WEBDAV", "%p: Received %u books from '%s'\n", webdav_backend, g_slist_length (discovered_sources), contacts_url); + e_webdav_discover_free_discovered_sources (discovered_sources); discovered_sources = NULL; any_success = TRUE; - } else if (any_success && local_error) { + /* Prevent lost of already known address books when the discover failed */ + } else if (local_error) { RemoveSourceTypesData rstd; rstd.server = server; rstd.calendars = FALSE; g_hash_table_foreach_remove (known_sources, webdav_collection_remove_source_types_cb, &rstd); + + if (webdav_collection_debug_enabled () && + (!credentials_empty || ( + !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) && + !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)))) + e_util_debug_print ("WEBDAV", "%p: Failed to get books from '%s': %s\n", webdav_backend, contacts_url, local_error->message); + } else if (e_source_collection_get_contacts_enabled (collection_extension) && contacts_url) { + if (webdav_collection_debug_enabled ()) { + e_util_debug_print ("WEBDAV", "%p: Failed to get books from '%s': %s\n", webdav_backend, contacts_url, + g_cancellable_is_cancelled (cancellable) ? "Is cancelled" : "Unknown error"); + } } if (any_success && server && !g_cancellable_is_cancelled (cancellable)) { @@ -630,6 +681,11 @@ rsd.server = server; rsd.webdav_backend = webdav_backend; + if (webdav_collection_debug_enabled () && g_hash_table_size (known_sources)) { + e_util_debug_print ("WEBDAV", "%p: Have %u leftover previously known sources\n", webdav_backend, + g_hash_table_size (known_sources)); + } + g_hash_table_foreach (known_sources, webdav_collection_remove_unknown_sources_cb, &rsd); g_clear_error (&local_error); diff -Nru evolution-data-server-3.44.0/src/libedataserver/e-oauth2-service-google.c evolution-data-server-3.44.4/src/libedataserver/e-oauth2-service-google.c --- evolution-data-server-3.44.0/src/libedataserver/e-oauth2-service-google.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libedataserver/e-oauth2-service-google.c 2022-08-05 07:45:35.000000000 +0000 @@ -24,6 +24,7 @@ #include "e-oauth2-service-google.h" /* https://developers.google.com/identity/protocols/OAuth2InstalledApp */ +/* https://developers.google.com/identity/protocols/oauth2/native-app */ /* Forward Declarations */ static void e_oauth2_service_google_oauth2_service_init (EOAuth2ServiceInterface *iface); @@ -120,14 +121,60 @@ eos_google_get_authentication_uri (EOAuth2Service *service, ESource *source) { - return "https://accounts.google.com/o/oauth2/auth"; + return "https://accounts.google.com/o/oauth2/v2/auth"; } static const gchar * eos_google_get_refresh_uri (EOAuth2Service *service, ESource *source) { - return "https://www.googleapis.com/oauth2/v3/token"; + return "https://oauth2.googleapis.com/token"; +} + +static const gchar * +eos_google_get_redirect_uri (EOAuth2Service *service, + ESource *source) +{ + G_LOCK_DEFINE_STATIC (redirect_uri); + const gchar *key_name = "oauth2-google-redirect-uri"; + gchar *value; + + G_LOCK (redirect_uri); + + value = g_object_get_data (G_OBJECT (service), key_name); + if (!value) { + const gchar *client_id = eos_google_get_client_id (service, source); + + if (client_id) { + GPtrArray *array; + gchar **strv; + gchar *joinstr; + guint ii; + + strv = g_strsplit (client_id, ".", -1); + array = g_ptr_array_new (); + + for (ii = 0; strv[ii]; ii++) { + g_ptr_array_insert (array, 0, strv[ii]); + } + + g_ptr_array_add (array, NULL); + + joinstr = g_strjoinv (".", (gchar **) array->pdata); + /* Use reverse-DNS of the client ID with the below path */ + value = g_strconcat (joinstr, ":/oauth2redirect", NULL); + + g_ptr_array_free (array, TRUE); + g_strfreev (strv); + g_free (joinstr); + + g_object_set_data_full (G_OBJECT (service), key_name, value, g_free); + } + } + + G_UNLOCK (redirect_uri); + + return value; } static void @@ -189,13 +236,13 @@ params = soup_form_decode (query); if (params) { - const gchar *response; + const gchar *code; - response = g_hash_table_lookup (params, "response"); - if (response && g_ascii_strncasecmp (response, "code=", 5) == 0) { - *out_authorization_code = g_strdup (response + 5); + code = g_hash_table_lookup (params, "code"); + if (code && *code) { + *out_authorization_code = g_strdup (code); known = TRUE; - } else if (response && g_ascii_strncasecmp (response, "error", 5) == 0) { + } else if (g_hash_table_lookup (params, "error")) { known = TRUE; } @@ -223,6 +270,7 @@ iface->get_client_secret = eos_google_get_client_secret; iface->get_authentication_uri = eos_google_get_authentication_uri; iface->get_refresh_uri = eos_google_get_refresh_uri; + iface->get_redirect_uri = eos_google_get_redirect_uri; iface->prepare_authentication_uri_query = eos_google_prepare_authentication_uri_query; iface->extract_authorization_code = eos_google_extract_authorization_code; } diff -Nru evolution-data-server-3.44.0/src/libedataserver/e-soup-auth-bearer.c evolution-data-server-3.44.4/src/libedataserver/e-soup-auth-bearer.c --- evolution-data-server-3.44.0/src/libedataserver/e-soup-auth-bearer.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libedataserver/e-soup-auth-bearer.c 2022-08-05 07:45:35.000000000 +0000 @@ -120,7 +120,8 @@ g_mutex_lock (&bearer->priv->property_lock); - authenticated = (bearer->priv->access_token != NULL); + authenticated = (bearer->priv->access_token != NULL) && + !e_soup_auth_bearer_is_expired_locked (bearer); g_mutex_unlock (&bearer->priv->property_lock); @@ -145,6 +146,20 @@ return res; } +static gboolean +e_soup_auth_bearer_can_authenticate (SoupAuth *auth) +{ + return FALSE; +} + +static void +e_soup_auth_bearer_authenticate (SoupAuth *auth, + const gchar *username, + const gchar *password) +{ + /* Not applicable here */ +} + static void e_soup_auth_bearer_class_init (ESoupAuthBearerClass *class) { @@ -164,6 +179,8 @@ auth_class->get_protection_space = e_soup_auth_bearer_get_protection_space; auth_class->is_authenticated = e_soup_auth_bearer_is_authenticated; auth_class->get_authorization = e_soup_auth_bearer_get_authorization; + auth_class->can_authenticate = e_soup_auth_bearer_can_authenticate; + auth_class->authenticate = e_soup_auth_bearer_authenticate; } static void @@ -197,6 +214,7 @@ { gboolean was_authenticated; gboolean now_authenticated; + gboolean changed; g_return_if_fail (E_IS_SOUP_AUTH_BEARER (bearer)); @@ -204,13 +222,12 @@ g_mutex_lock (&bearer->priv->property_lock); - if (g_strcmp0 (bearer->priv->access_token, access_token) == 0) { - g_mutex_unlock (&bearer->priv->property_lock); - return; - } + changed = g_strcmp0 (bearer->priv->access_token, access_token) != 0; - g_free (bearer->priv->access_token); - bearer->priv->access_token = g_strdup (access_token); + if (changed) { + g_free (bearer->priv->access_token); + bearer->priv->access_token = g_strdup (access_token); + } if (expires_in_seconds > 0) bearer->priv->expiry = time (NULL) + expires_in_seconds - 5; @@ -219,12 +236,12 @@ g_mutex_unlock (&bearer->priv->property_lock); - now_authenticated = soup_auth_is_authenticated (SOUP_AUTH (bearer)); + if (changed) { + now_authenticated = soup_auth_is_authenticated (SOUP_AUTH (bearer)); - if (was_authenticated != now_authenticated) - g_object_notify ( - G_OBJECT (bearer), - SOUP_AUTH_IS_AUTHENTICATED); + if (was_authenticated != now_authenticated) + g_object_notify (G_OBJECT (bearer), "is-authenticated"); + } } /** diff -Nru evolution-data-server-3.44.0/src/libedataserver/e-soup-session.c evolution-data-server-3.44.4/src/libedataserver/e-soup-session.c --- evolution-data-server-3.44.0/src/libedataserver/e-soup-session.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libedataserver/e-soup-session.c 2022-08-05 07:45:35.000000000 +0000 @@ -331,14 +331,19 @@ session = E_SOUP_SESSION (soup_session); + g_mutex_lock (&session->priv->property_lock); if (E_IS_SOUP_AUTH_BEARER (auth)) { g_object_ref (auth); g_warn_if_fail ((gpointer) session->priv->using_bearer_auth == (gpointer) auth); g_clear_object (&session->priv->using_bearer_auth); session->priv->using_bearer_auth = E_SOUP_AUTH_BEARER (auth); + } else if (session->priv->using_bearer_auth) { + /* This can mean the bearer auth expired, then a Basic auth is used by the libsoup; + that's not meant to be done here, thus fail early. */ + g_mutex_unlock (&session->priv->property_lock); + return; } - g_mutex_lock (&session->priv->property_lock); if (retrying && !session->priv->auth_prefilled) { g_mutex_unlock (&session->priv->property_lock); return; diff -Nru evolution-data-server-3.44.0/src/libedataserver/e-source.c evolution-data-server-3.44.4/src/libedataserver/e-source.c --- evolution-data-server-3.44.0/src/libedataserver/e-source.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libedataserver/e-source.c 2022-08-05 07:45:35.000000000 +0000 @@ -1042,6 +1042,20 @@ return FALSE; } +static void source_connect_dbus_source (ESource *source); + +static void +e_source_dbus_object_notify_source_cb (GObject *dbus_object, + GParamSpec *param, + gpointer user_data) +{ + ESource *source = user_data; + + g_return_if_fail (E_IS_SOURCE (source)); + + source_connect_dbus_source (source); +} + static void source_set_dbus_object (ESource *source, EDBusObject *dbus_object) @@ -1053,7 +1067,10 @@ g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object)); g_return_if_fail (source->priv->dbus_object == NULL); - source->priv->dbus_object = g_object_ref (dbus_object); + source->priv->dbus_object = G_DBUS_OBJECT (g_object_ref (dbus_object)); + + g_signal_connect_object (source->priv->dbus_object, "notify::source", + G_CALLBACK (e_source_dbus_object_notify_source_cb), source, 0); } static void @@ -1231,14 +1248,13 @@ dbus_source = e_dbus_object_get_source (dbus_object); if (dbus_source != NULL) { - g_signal_handlers_disconnect_matched ( - dbus_source, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); + g_signal_handlers_disconnect_by_data (dbus_source, object); g_object_unref (dbus_source); } - g_object_unref (priv->dbus_object); - priv->dbus_object = NULL; + g_signal_handlers_disconnect_by_data (priv->dbus_object, object); + + g_clear_object (&priv->dbus_object); } g_mutex_unlock (&priv->property_lock); @@ -2014,6 +2030,11 @@ dbus_source = e_dbus_object_get_source (dbus_object); g_return_if_fail (E_DBUS_IS_SOURCE (dbus_source)); + g_signal_handlers_disconnect_by_func (dbus_source, source_notify_dbus_data_cb, source); + g_signal_handlers_disconnect_by_func (dbus_source, source_notify_dbus_connection_status_cb, source); + g_signal_handlers_disconnect_by_func (dbus_source, source_dbus_credentials_required_cb, source); + g_signal_handlers_disconnect_by_func (dbus_source, source_dbus_authenticate_cb, source); + g_signal_connect_object ( dbus_source, "notify::data", G_CALLBACK (source_notify_dbus_data_cb), source, 0); @@ -2504,14 +2525,21 @@ dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (source->priv->dbus_object)); if (dbus_source) { - g_signal_handlers_disconnect_by_data (dbus_source, source), + g_signal_handlers_disconnect_by_data (dbus_source, source); g_object_unref (dbus_source); } + + g_signal_handlers_disconnect_by_func (source->priv->dbus_object, e_source_dbus_object_notify_source_cb, source); } g_clear_object (&source->priv->dbus_object); source->priv->dbus_object = dbus_object; + if (source->priv->dbus_object) { + g_signal_connect_object (source->priv->dbus_object, "notify::source", + G_CALLBACK (e_source_dbus_object_notify_source_cb), source, 0); + } + g_mutex_unlock (&source->priv->property_lock); source_connect_dbus_source (source); @@ -4594,7 +4622,7 @@ flags_class = g_type_class_ref (G_TYPE_TLS_CERTIFICATE_FLAGS); for (flags_value = g_flags_get_first_value (flags_class, certificate_errors); - flags_value; + flags_value && certificate_errors; flags_value = g_flags_get_first_value (flags_class, certificate_errors)) { if (certificate_errors_str->len) g_string_append_c (certificate_errors_str, ':'); diff -Nru evolution-data-server-3.44.0/src/libedataserver/e-webdav-discover.c evolution-data-server-3.44.4/src/libedataserver/e-webdav-discover.c --- evolution-data-server-3.44.0/src/libedataserver/e-webdav-discover.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libedataserver/e-webdav-discover.c 2022-08-05 07:45:35.000000000 +0000 @@ -45,15 +45,18 @@ static gboolean e_webdav_discovery_already_discovered (const gchar *href, - const GSList *discovered_sources) + const GSList *discovered_sources, + guint32 href_supports) { GSList *link; for (link = (GSList *) discovered_sources; link; link = g_slist_next (link)) { EWebDAVDiscoveredSource *discovered = link->data; - if (discovered && g_strcmp0 (href, discovered->href) == 0) + if (discovered && g_strcmp0 (href, discovered->href) == 0) { + discovered->supports |= href_supports; return TRUE; + } } return FALSE; @@ -82,7 +85,8 @@ continue; if (e_webdav_discovery_already_discovered (resource->href, - resource->kind == E_WEBDAV_RESOURCE_KIND_ADDRESSBOOK ? wdd->addressbooks : wdd->calendars)) + resource->kind == E_WEBDAV_RESOURCE_KIND_ADDRESSBOOK ? wdd->addressbooks : wdd->calendars, + resource->supports)) continue; discovered = g_slice_new0 (EWebDAVDiscoveredSource); @@ -105,6 +109,45 @@ } } +typedef enum { + COVERED_LOOKUP = 1 << 0, + COVERED_ADDRESSBOOK = 1 << 1, + COVERED_CALENDAR = 1 << 2 +} ECoveredMark; + +static void +e_webdav_discover_mark_covered (GHashTable *covered_hrefs, + const gchar *href, + ECoveredMark mark) +{ + gint value; + + if (!covered_hrefs || !href || !*href) + return; + + value = GPOINTER_TO_INT (g_hash_table_lookup (covered_hrefs, href)); + + if ((value & mark) != mark) { + value |= mark; + g_hash_table_insert (covered_hrefs, g_strdup (href), GINT_TO_POINTER (value)); + } +} + +static gboolean +e_webdav_discover_is_covered (GHashTable *covered_hrefs, + const gchar *href, + ECoveredMark mark) +{ + gint value; + + if (!covered_hrefs || !href || !*href) + return FALSE; + + value = GPOINTER_TO_INT (g_hash_table_lookup (covered_hrefs, href)); + + return (value & mark) == mark; +} + static gboolean e_webdav_discover_propfind_uri_sync (EWebDAVSession *webdav, WebDAVDiscoverData *wdd, @@ -145,7 +188,7 @@ full_href = e_webdav_session_ensure_full_uri (webdav, request_uri, (const gchar *) home_set_href); - if (full_href && *full_href && GPOINTER_TO_INT (g_hash_table_contains (wdd->covered_hrefs, full_href)) != 2 && + if (full_href && *full_href && !e_webdav_discover_is_covered (wdd->covered_hrefs, full_href, COVERED_ADDRESSBOOK) && e_webdav_session_list_sync (webdav, full_href, E_WEBDAV_DEPTH_THIS_AND_CHILDREN, E_WEBDAV_LIST_ONLY_ADDRESSBOOK | E_WEBDAV_LIST_ALL, &resources, wdd->cancellable, &local_error)) { @@ -154,7 +197,7 @@ } if (full_href && *full_href) - g_hash_table_insert (wdd->covered_hrefs, g_strdup (full_href), GINT_TO_POINTER (2)); + e_webdav_discover_mark_covered (wdd->covered_hrefs, full_href, COVERED_ADDRESSBOOK); if (local_error && wdd->error && !*wdd->error) g_propagate_error (wdd->error, local_error); @@ -181,7 +224,7 @@ full_href = e_webdav_session_ensure_full_uri (webdav, request_uri, (const gchar *) home_set_href); - if (full_href && *full_href && GPOINTER_TO_INT (g_hash_table_contains (wdd->covered_hrefs, full_href)) != 2 && + if (full_href && *full_href && !e_webdav_discover_is_covered (wdd->covered_hrefs, full_href, COVERED_CALENDAR) && e_webdav_session_list_sync (webdav, full_href, E_WEBDAV_DEPTH_THIS_AND_CHILDREN, E_WEBDAV_LIST_ONLY_CALENDAR | E_WEBDAV_LIST_ALL, &resources, wdd->cancellable, &local_error)) { @@ -190,7 +233,7 @@ } if (full_href && *full_href) - g_hash_table_insert (wdd->covered_hrefs, g_strdup (full_href), GINT_TO_POINTER (2)); + e_webdav_discover_mark_covered (wdd->covered_hrefs, full_href, COVERED_CALENDAR); if (local_error && wdd->error && !*wdd->error) g_propagate_error (wdd->error, local_error); @@ -262,10 +305,11 @@ is_addressbook = e_xml_find_child (node, E_WEBDAV_NS_CARDDAV, "addressbook") != NULL; if (is_calendar || is_addressbook) { + gint covered_mark = (is_addressbook ? COVERED_ADDRESSBOOK : 0) | (is_calendar ? COVERED_CALENDAR : 0); GSList *resources = NULL; GError *local_error = NULL; - if (GPOINTER_TO_INT (g_hash_table_contains (wdd->covered_hrefs, href)) != 2 && + if (!e_webdav_discover_is_covered (wdd->covered_hrefs, href, covered_mark) && !g_cancellable_is_cancelled (wdd->cancellable) && e_webdav_session_list_sync (webdav, href, E_WEBDAV_DEPTH_THIS, (is_calendar ? E_WEBDAV_LIST_ONLY_CALENDAR : 0) | (is_addressbook ? E_WEBDAV_LIST_ONLY_ADDRESSBOOK : 0) | E_WEBDAV_LIST_ALL, @@ -274,7 +318,7 @@ g_slist_free_full (resources, e_webdav_resource_free); } - g_hash_table_insert (wdd->covered_hrefs, g_strdup (href), GINT_TO_POINTER (2)); + e_webdav_discover_mark_covered (wdd->covered_hrefs, href, covered_mark); if (local_error && wdd->error && !*wdd->error) g_propagate_error (wdd->error, local_error); @@ -285,7 +329,7 @@ if (((wdd->only_supports & (~CUSTOM_SUPPORTS_FLAGS)) == E_WEBDAV_DISCOVER_SUPPORTS_NONE || (wdd->only_supports & E_WEBDAV_DISCOVER_SUPPORTS_WEBDAV_NOTES) != 0) && (g_str_has_suffix (href, "/Notes") || g_str_has_suffix (href, "/Notes/")) && - !e_webdav_discovery_already_discovered (href, wdd->calendars) && + !e_webdav_discovery_already_discovered (href, wdd->calendars, 0) && e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_DAV, "resourcetype", E_WEBDAV_NS_DAV, "collection", NULL, NULL)) { GSList *resources = NULL; @@ -299,7 +343,7 @@ g_slist_free_full (resources, e_webdav_resource_free); - g_hash_table_insert (wdd->covered_hrefs, g_strdup (href), GINT_TO_POINTER (2)); + e_webdav_discover_mark_covered (wdd->covered_hrefs, href, COVERED_CALENDAR); } return TRUE; @@ -319,10 +363,10 @@ g_return_val_if_fail (wdd != NULL, FALSE); g_return_val_if_fail (uri && *uri, FALSE); - if (g_hash_table_contains (wdd->covered_hrefs, uri)) + if (e_webdav_discover_is_covered (wdd->covered_hrefs, uri, COVERED_LOOKUP)) return TRUE; - g_hash_table_insert (wdd->covered_hrefs, g_strdup (uri), GINT_TO_POINTER (1)); + e_webdav_discover_mark_covered (wdd->covered_hrefs, uri, COVERED_LOOKUP); xml = e_xml_document_new (E_WEBDAV_NS_DAV, "propfind"); g_return_val_if_fail (xml != NULL, FALSE); diff -Nru evolution-data-server-3.44.0/src/libedataserver/e-webdav-session.c evolution-data-server-3.44.4/src/libedataserver/e-webdav-session.c --- evolution-data-server-3.44.0/src/libedataserver/e-webdav-session.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libedataserver/e-webdav-session.c 2022-08-05 07:45:35.000000000 +0000 @@ -2018,16 +2018,14 @@ header = soup_message_headers_get_list (message->response_headers, "Location"); if (header) { - gchar *file = strrchr (header, '/'); + SoupURI *uri; - if (file) { - gchar *decoded; + uri = soup_uri_new_with_base (soup_message_get_uri (message), header); + if (uri && uri->host) + *out_href = soup_uri_to_string (uri, FALSE); - decoded = soup_uri_decode (file + 1); - *out_href = soup_uri_encode (decoded ? decoded : (file + 1), NULL); - - g_free (decoded); - } + if (uri) + soup_uri_free (uri); } if (!*out_href) @@ -3461,57 +3459,62 @@ } static guint32 -e_webdav_session_extract_supports (xmlNodePtr prop_node) +e_webdav_session_extract_supports (xmlNodePtr prop_node, + EWebDAVResourceKind kind) { - xmlNodePtr calendar_components; guint32 supports = E_WEBDAV_RESOURCE_SUPPORTS_NONE; g_return_val_if_fail (prop_node != NULL, E_WEBDAV_RESOURCE_SUPPORTS_NONE); - if (e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_DAV, "resourcetype", E_WEBDAV_NS_CARDDAV, "addressbook", NULL, NULL)) + if (kind == E_WEBDAV_RESOURCE_KIND_ADDRESSBOOK && + e_xml_find_in_hierarchy (prop_node, E_WEBDAV_NS_DAV, "resourcetype", E_WEBDAV_NS_CARDDAV, "addressbook", NULL, NULL)) supports = supports | E_WEBDAV_RESOURCE_SUPPORTS_CONTACTS; - calendar_components = e_xml_find_child (prop_node, E_WEBDAV_NS_CALDAV, "supported-calendar-component-set"); + if (kind == E_WEBDAV_RESOURCE_KIND_CALENDAR) { + xmlNodePtr calendar_components; + + calendar_components = e_xml_find_child (prop_node, E_WEBDAV_NS_CALDAV, "supported-calendar-component-set"); - if (calendar_components) { - xmlNodePtr node; - gint found_comps = 0; - - for (node = calendar_components->children; node; node = xmlNextElementSibling (node)) { - if (e_xml_is_element_name (node, E_WEBDAV_NS_CALDAV, "comp")) { - xmlChar *name; - - found_comps++; - - name = xmlGetProp (node, (const xmlChar *) "name"); - - if (!name) - continue; - - if (g_ascii_strcasecmp ((const gchar *) name, "VEVENT") == 0) - supports |= E_WEBDAV_RESOURCE_SUPPORTS_EVENTS; - else if (g_ascii_strcasecmp ((const gchar *) name, "VJOURNAL") == 0) - supports |= E_WEBDAV_RESOURCE_SUPPORTS_MEMOS; - else if (g_ascii_strcasecmp ((const gchar *) name, "VTODO") == 0) - supports |= E_WEBDAV_RESOURCE_SUPPORTS_TASKS; - else if (g_ascii_strcasecmp ((const gchar *) name, "VFREEBUSY") == 0) - supports |= E_WEBDAV_RESOURCE_SUPPORTS_FREEBUSY; - else if (g_ascii_strcasecmp ((const gchar *) name, "VTIMEZONE") == 0) - supports |= E_WEBDAV_RESOURCE_SUPPORTS_TIMEZONE; + if (calendar_components) { + xmlNodePtr node; + gint found_comps = 0; + + for (node = calendar_components->children; node; node = xmlNextElementSibling (node)) { + if (e_xml_is_element_name (node, E_WEBDAV_NS_CALDAV, "comp")) { + xmlChar *name; + + found_comps++; + + name = xmlGetProp (node, (const xmlChar *) "name"); + + if (!name) + continue; + + if (g_ascii_strcasecmp ((const gchar *) name, "VEVENT") == 0) + supports |= E_WEBDAV_RESOURCE_SUPPORTS_EVENTS; + else if (g_ascii_strcasecmp ((const gchar *) name, "VJOURNAL") == 0) + supports |= E_WEBDAV_RESOURCE_SUPPORTS_MEMOS; + else if (g_ascii_strcasecmp ((const gchar *) name, "VTODO") == 0) + supports |= E_WEBDAV_RESOURCE_SUPPORTS_TASKS; + else if (g_ascii_strcasecmp ((const gchar *) name, "VFREEBUSY") == 0) + supports |= E_WEBDAV_RESOURCE_SUPPORTS_FREEBUSY; + else if (g_ascii_strcasecmp ((const gchar *) name, "VTIMEZONE") == 0) + supports |= E_WEBDAV_RESOURCE_SUPPORTS_TIMEZONE; - xmlFree (name); + xmlFree (name); + } } - } - if (!found_comps) { - /* If the property is not present, assume all component - * types are supported. (RFC 4791, Section 5.2.3) */ - supports = supports | - E_WEBDAV_RESOURCE_SUPPORTS_EVENTS | - E_WEBDAV_RESOURCE_SUPPORTS_MEMOS | - E_WEBDAV_RESOURCE_SUPPORTS_TASKS | - E_WEBDAV_RESOURCE_SUPPORTS_FREEBUSY | - E_WEBDAV_RESOURCE_SUPPORTS_TIMEZONE; + if (!found_comps) { + /* If the property is not present, assume all component + * types are supported. (RFC 4791, Section 5.2.3) */ + supports = supports | + E_WEBDAV_RESOURCE_SUPPORTS_EVENTS | + E_WEBDAV_RESOURCE_SUPPORTS_MEMOS | + E_WEBDAV_RESOURCE_SUPPORTS_TASKS | + E_WEBDAV_RESOURCE_SUPPORTS_FREEBUSY | + E_WEBDAV_RESOURCE_SUPPORTS_TIMEZONE; + } } } @@ -3674,7 +3677,7 @@ source_href = e_webdav_session_util_maybe_dequote (g_strdup ((const gchar *) x_source_href)); } - supports = e_webdav_session_extract_supports (prop_node); + supports = e_webdav_session_extract_supports (prop_node, kind); etag = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_DAV, "getetag", E_WEBDAV_NS_CALENDARSERVER, "getctag"); display_name = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_DAV, "displayname", NULL, NULL); content_type = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_DAV, "getcontenttype", NULL, NULL); diff -Nru evolution-data-server-3.44.0/src/libedataserverui/e-credentials-prompter-impl-oauth2.c evolution-data-server-3.44.4/src/libedataserverui/e-credentials-prompter-impl-oauth2.c --- evolution-data-server-3.44.0/src/libedataserverui/e-credentials-prompter-impl-oauth2.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libedataserverui/e-credentials-prompter-impl-oauth2.c 2022-08-05 07:45:35.000000000 +0000 @@ -561,6 +561,24 @@ g_free (display_name); } +static gchar * +credentials_prompter_impl_oauth2_sanitize_host (gchar *host) +{ + if (!host || !*host) + return host; + + if (*host == '[' && strchr (host, ':')) { + gint len = strlen (host); + + if (len > 2 && host[len - 1] == ']') { + memmove (host, host + 1, len - 2); + host[len - 2] = '\0'; + } + } + + return host; +} + static void credentials_prompter_impl_oauth2_set_proxy (WebKitWebContext *web_context, ESourceRegistry *registry, @@ -604,7 +622,7 @@ case E_PROXY_METHOD_MANUAL: ignore_hosts = e_source_proxy_dup_ignore_hosts (proxy); - tmp = e_source_proxy_dup_socks_host (proxy); + tmp = credentials_prompter_impl_oauth2_sanitize_host (e_source_proxy_dup_socks_host (proxy)); if (tmp && *tmp) { suri = soup_uri_new (NULL); soup_uri_set_scheme (suri, "socks"); @@ -623,7 +641,7 @@ } g_free (tmp); - tmp = e_source_proxy_dup_http_host (proxy); + tmp = credentials_prompter_impl_oauth2_sanitize_host (e_source_proxy_dup_http_host (proxy)); if (tmp && *tmp) { suri = soup_uri_new (NULL); soup_uri_set_scheme (suri, SOUP_URI_SCHEME_HTTP); @@ -650,7 +668,7 @@ } g_free (tmp); - tmp = e_source_proxy_dup_https_host (proxy); + tmp = credentials_prompter_impl_oauth2_sanitize_host (e_source_proxy_dup_https_host (proxy)); if (tmp && *tmp) { suri = soup_uri_new (NULL); soup_uri_set_scheme (suri, SOUP_URI_SCHEME_HTTP); @@ -856,6 +874,7 @@ "enable-page-cache", FALSE, "enable-plugins", FALSE, "media-playback-allows-inline", FALSE, + "hardware-acceleration-policy", WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER, NULL); web_context = webkit_web_context_new (); diff -Nru evolution-data-server-3.44.0/src/libedataserverui/e-reminders-widget.c evolution-data-server-3.44.4/src/libedataserverui/e-reminders-widget.c --- evolution-data-server-3.44.0/src/libedataserverui/e-reminders-widget.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/libedataserverui/e-reminders-widget.c 2022-08-05 07:45:35.000000000 +0000 @@ -1547,7 +1547,9 @@ GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkWidget *widget; - GtkBox *box; + GtkCssProvider *css_provider; + GtkFlowBox *flow_box; + GError *error = NULL; /* Chain up to parent's method. */ G_OBJECT_CLASS (e_reminders_widget_parent_class)->constructed (object); @@ -1652,27 +1654,44 @@ reminders_widget_fill_snooze_combo (reminders, g_settings_get_int (reminders->priv->settings, "notify-last-snooze-minutes")); - box = GTK_BOX (gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL)); - g_object_set (G_OBJECT (box), - "halign", GTK_ALIGN_END, - "hexpand", TRUE, - "valign", GTK_ALIGN_CENTER, - "vexpand", FALSE, - "margin-top", 4, + flow_box = GTK_FLOW_BOX (gtk_flow_box_new ()); + g_object_set (G_OBJECT (flow_box), + "homogeneous", FALSE, + "selection-mode", GTK_SELECTION_NONE, + "column-spacing", 1, + "row-spacing", 1, NULL); widget = gtk_label_new (""); + gtk_widget_set_margin_start (widget, 8); - gtk_box_pack_start (box, reminders->priv->snooze_combo, FALSE, FALSE, 0); - gtk_box_pack_start (box, reminders->priv->snooze_button, FALSE, FALSE, 0); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - gtk_box_pack_start (box, reminders->priv->dismiss_button, FALSE, FALSE, 0); - gtk_box_pack_start (box, reminders->priv->dismiss_all_button, FALSE, FALSE, 0); - - gtk_button_box_set_child_non_homogeneous (GTK_BUTTON_BOX (box), reminders->priv->snooze_combo, TRUE); - gtk_button_box_set_child_non_homogeneous (GTK_BUTTON_BOX (box), widget, TRUE); + gtk_flow_box_insert (flow_box, reminders->priv->snooze_combo, -1); + gtk_flow_box_insert (flow_box, reminders->priv->snooze_button, -1); + gtk_flow_box_insert (flow_box, widget, -1); + gtk_flow_box_insert (flow_box, reminders->priv->dismiss_button, -1); + gtk_flow_box_insert (flow_box, reminders->priv->dismiss_all_button, -1); + + gtk_grid_attach (GTK_GRID (reminders), GTK_WIDGET (flow_box), 0, 1, 1, 1); + + css_provider = gtk_css_provider_new (); + + if (gtk_css_provider_load_from_data (css_provider, "flowboxchild { padding: 0px; }", -1, &error)) { + GtkFlowBoxChild *child; + guint ii = 0; + + while (child = gtk_flow_box_get_child_at_index (flow_box, ii), child) { + gtk_style_context_add_provider ( + gtk_widget_get_style_context (GTK_WIDGET (child)), + GTK_STYLE_PROVIDER (css_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + ii++; + } + } else { + g_warning ("%s: Failed to parse CSS: %s", G_STRFUNC, error ? error->message : "Unknown error"); + } - gtk_grid_attach (GTK_GRID (reminders), GTK_WIDGET (box), 0, 1, 1, 1); + g_clear_object (&css_provider); + g_clear_error (&error); gtk_widget_show_all (GTK_WIDGET (reminders)); diff -Nru evolution-data-server-3.44.0/src/modules/gnome-online-accounts/module-gnome-online-accounts.c evolution-data-server-3.44.4/src/modules/gnome-online-accounts/module-gnome-online-accounts.c --- evolution-data-server-3.44.0/src/modules/gnome-online-accounts/module-gnome-online-accounts.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/modules/gnome-online-accounts/module-gnome-online-accounts.c 2022-08-05 07:45:35.000000000 +0000 @@ -1154,11 +1154,14 @@ e_goa_debug_printf ("Found %d existing sources\n", g_list_length (list)); + g_hash_table_remove_all (extension->goa_to_eds); + for (link = list; link != NULL; link = g_list_next (link)) { ESource *source; ESourceGoa *goa_ext; const gchar *account_id; const gchar *source_uid; + const gchar *existing_source_uid; GList *match; source = E_SOURCE (link->data); @@ -1173,14 +1176,20 @@ continue; } - if (g_hash_table_lookup (extension->goa_to_eds, account_id)) { - e_goa_debug_printf ("Source '%s' references account '%s' which is already used by other source\n", - source_uid, account_id); - - /* There are more ESource-s referencing the same GOA account; - delete the later. */ - g_queue_push_tail (&trash, source); - continue; + existing_source_uid = g_hash_table_lookup (extension->goa_to_eds, account_id); + if (existing_source_uid) { + if (g_strcmp0 (source_uid, existing_source_uid) == 0) { + e_goa_debug_printf ("Already know the source '%s' references account '%s'\n", + source_uid, account_id); + } else { + e_goa_debug_printf ("Source '%s' references account '%s' which is already used by source '%s'\n", + source_uid, account_id, existing_source_uid); + + /* There are more ESource-s referencing the same GOA account; + delete the later. */ + g_queue_push_tail (&trash, source); + continue; + } } /* Verify the GOA account still exists. */ diff -Nru evolution-data-server-3.44.0/src/services/evolution-alarm-notify/e-alarm-notify.c evolution-data-server-3.44.4/src/services/evolution-alarm-notify/e-alarm-notify.c --- evolution-data-server-3.44.0/src/services/evolution-alarm-notify/e-alarm-notify.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/src/services/evolution-alarm-notify/e-alarm-notify.c 2022-08-05 07:45:35.000000000 +0000 @@ -325,33 +325,16 @@ if (!g_hash_table_contains (an->priv->notification_ids, notif_id)) { GNotification *notification; - GtkIconInfo *icon_info; + GIcon *icon; gchar *detailed_action; notification = g_notification_new (_("Reminders")); g_notification_set_body (notification, description); - icon_info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (), "appointment-soon", 48, 0); - if (icon_info) { - const gchar *filename; - - filename = gtk_icon_info_get_filename (icon_info); - if (filename && *filename) { - GFile *file; - GIcon *icon; - - file = g_file_new_for_path (filename); - icon = g_file_icon_new (file); - - if (icon) { - g_notification_set_icon (notification, icon); - g_object_unref (icon); - } - - g_object_unref (file); - } - - gtk_icon_info_free (icon_info); + icon = g_themed_icon_new ("appointment-soon"); + if (icon) { + g_notification_set_icon (notification, icon); + g_object_unref (icon); } detailed_action = g_action_print_detailed_name ("app.show-reminders", NULL); diff -Nru evolution-data-server-3.44.0/tests/libecal/test-cal-recur.c evolution-data-server-3.44.4/tests/libecal/test-cal-recur.c --- evolution-data-server-3.44.0/tests/libecal/test-cal-recur.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/tests/libecal/test-cal-recur.c 2022-08-05 07:45:35.000000000 +0000 @@ -363,6 +363,151 @@ } } +static ICalComponent * +create_component_midnight (const gchar *tz_location) +{ + const gchar *comp_str = + "BEGIN:VEVENT\r\n" + "SUMMARY:recurs\r\n" + "UID:recurs-id\r\n" + "DTSTART%s:20190107T000000%s\r\n" + "DTEND%s:20190107T003000%s\r\n" + "DTSTAMP:20190101T050000Z\r\n" + "CREATED:20190101T050000Z\r\n" + "LAST-MODIFIED:20190101T050000Z\r\n" + "RRULE:FREQ=DAILY;UNTIL=20190109\r\n" + "END:VEVENT\r\n"; + gchar *tzref = NULL, tzsuffix[2] = { 0, 0 }; + gchar *str; + ICalComponent *icomp; + ICalTimezone *zone = NULL; + ICalTime *itt; + + if (tz_location) { + if (g_ascii_strcasecmp (tz_location, "UTC") == 0) { + tzsuffix[0] = 'Z'; + zone = i_cal_timezone_get_utc_timezone (); + } else { + const gchar *tzid; + + zone = i_cal_timezone_get_builtin_timezone (tz_location); + g_assert_nonnull (zone); + + tzid = i_cal_timezone_get_tzid (zone); + g_assert_nonnull (tzid); + + tzref = g_strconcat (";TZID=", tzid, NULL); + } + } + + str = g_strdup_printf (comp_str, tzref ? tzref : "", tzsuffix, tzref ? tzref : "", tzsuffix); + icomp = i_cal_component_new_from_string (str); + g_assert_nonnull (icomp); + + g_free (tzref); + g_free (str); + + itt = i_cal_component_get_dtstart (icomp); + g_assert_nonnull (itt); + g_assert_true (i_cal_time_get_timezone (itt) == zone); + g_object_unref (itt); + + itt = i_cal_component_get_dtend (icomp); + g_assert_nonnull (itt); + g_assert_true (i_cal_time_get_timezone (itt) == zone); + g_object_unref (itt); + + return icomp; +} + +static void +setup_cal_midnight (ECalClient *cal_client, + const gchar *tz_location) +{ + ICalComponent *icomp; + gboolean success; + gchar *uid = NULL; + GError *error = NULL; + + icomp = create_component_midnight (tz_location); + + if (!e_cal_client_remove_object_sync (cal_client, i_cal_component_get_uid (icomp), NULL, E_CAL_OBJ_MOD_ALL, E_CAL_OPERATION_FLAG_NONE, NULL, &error)) { + g_assert_error (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND); + g_clear_error (&error); + } else { + g_assert_no_error (error); + } + + success = e_cal_client_create_object_sync (cal_client, icomp, E_CAL_OPERATION_FLAG_NONE, &uid, NULL, &error); + g_assert_no_error (error); + g_assert_true (success); + g_assert_nonnull (uid); + + g_object_unref (icomp); + g_free (uid); +} + +static gboolean +recur_instance_midnight_cb (ICalComponent *icomp, + ICalTime *instance_start, + ICalTime *instance_end, + gpointer user_data, + GCancellable *cancellable, + GError **error) +{ + GSList **listp = user_data; + + *listp = g_slist_append (*listp, i_cal_time_as_ical_string (instance_start)); + + return TRUE; +} + +static void +test_recur_midnight_for_zone (ECalClient *client, + const gchar *tz_location) +{ + ICalTime *start, *end; + GSList *list = NULL, *last; + + setup_cal_midnight (client, tz_location); + + start = i_cal_time_new_from_string ("20190101T000000Z"); + end = i_cal_time_new_from_string ("20190131T000000Z"); + + e_cal_client_generate_instances_sync (client, + i_cal_time_as_timet (start), + i_cal_time_as_timet (end), + NULL, /* GCancellable * */ + recur_instance_midnight_cb, &list); + + last = g_slist_last (list); + g_assert_nonnull (last); + if (g_ascii_strcasecmp (tz_location, "UTC") == 0) + g_assert_cmpstr (last->data, ==, "20190109T000000Z"); + else + g_assert_cmpstr (last->data, ==, "20190109T000000"); + g_assert_cmpint (g_slist_length (list), ==, 3); + + g_slist_free_full (list, g_free); + g_clear_object (&start); + g_clear_object (&end); +} + +static void +test_recur_midnight (ETestServerFixture *fixture, + gconstpointer user_data) +{ + ECalClient *client; + + client = E_TEST_SERVER_UTILS_SERVICE (fixture, ECalClient); + + e_cal_client_set_default_timezone (client, i_cal_timezone_get_builtin_timezone ("UTC")); + + test_recur_midnight_for_zone (client, "UTC"); + test_recur_midnight_for_zone (client, "America/New_York"); + test_recur_midnight_for_zone (client, "Europe/Berlin"); +} + static void test_recur_client (ETestServerFixture *fixture, gconstpointer user_data) @@ -623,6 +768,13 @@ e_test_server_utils_setup, test_recur_duration, e_test_server_utils_teardown); + g_test_add ( + "/ECalRecur/Midnight", + ETestServerFixture, + &test_closure, + e_test_server_utils_setup, + test_recur_midnight, + e_test_server_utils_teardown); return e_test_server_utils_run (argc, argv); } diff -Nru evolution-data-server-3.44.0/tests/libedata-book/test-book-cache-cursor-change-locale.c evolution-data-server-3.44.4/tests/libedata-book/test-book-cache-cursor-change-locale.c --- evolution-data-server-3.44.0/tests/libedata-book/test-book-cache-cursor-change-locale.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/tests/libedata-book/test-book-cache-cursor-change-locale.c 2022-08-05 07:45:35.000000000 +0000 @@ -69,7 +69,7 @@ tcu_step_test_add_assertion (data, 5, 17, 16, 18, 10, 14); tcu_step_test_add_assertion (data, 5, 12, 13, 9, 19, 20); - tcu_step_test_change_locale (data, "fr_CA.UTF-8", 0); + tcu_step_test_change_locale (data, "fr_CA.UTF-8", -1); tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6); tcu_step_test_add_assertion (data, 5, 4, 3, 7, 8, 15); tcu_step_test_add_assertion (data, 5, 17, 16, 18, 10, 14); diff -Nru evolution-data-server-3.44.0/tests/libedata-book/test-sqlite-cursor-change-locale.c evolution-data-server-3.44.4/tests/libedata-book/test-sqlite-cursor-change-locale.c --- evolution-data-server-3.44.0/tests/libedata-book/test-sqlite-cursor-change-locale.c 2022-03-18 06:56:43.000000000 +0000 +++ evolution-data-server-3.44.4/tests/libedata-book/test-sqlite-cursor-change-locale.c 2022-08-05 07:45:35.000000000 +0000 @@ -72,7 +72,7 @@ step_test_add_assertion (data, 5, 17, 16, 18, 10, 14); step_test_add_assertion (data, 5, 12, 13, 9, 19, 20); - step_test_change_locale (data, "fr_CA.UTF-8", 0); + step_test_change_locale (data, "fr_CA.UTF-8", -1); step_test_add_assertion (data, 5, 11, 1, 2, 5, 6); step_test_add_assertion (data, 5, 4, 3, 7, 8, 15); step_test_add_assertion (data, 5, 17, 16, 18, 10, 14);