From 1dc60a340029e0f3ff51739467e687aafa129f44 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 27 Sep 2024 08:36:02 +0200 Subject: [PATCH] tests: add testcase for DESK-2104 References: DESK-2104, GXF-1819 --- include/gromox/mapitags.hpp | 9 ++++- tests/oxcmail_ie.cpp | 70 +++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/include/gromox/mapitags.hpp b/include/gromox/mapitags.hpp index 77510e118..4cb880584 100644 --- a/include/gromox/mapitags.hpp +++ b/include/gromox/mapitags.hpp @@ -1170,10 +1170,10 @@ enum { PidLidTaskFRecurring = 0x8126, /* PSETID_Appointment */ + PidLidSendMeetingAsIcal = 0x8200, PidLidAppointmentSequence = 0x8201, PidLidBusyStatus = 0x8205, PidLidLocation = 0x8208, - PidLidAppointmentReplyTime = 0x8220, PidLidAppointmentStartWhole = 0x820D, PidLidAppointmentEndWhole = 0x820E, PidLidAppointmentDuration = 0x8213, @@ -1181,16 +1181,21 @@ enum { PidLidAppointmentRecur = 0x8216, PidLidAppointmentStateFlags = 0x8217, PidLidResponseStatus = 0x8218, + PidLidAppointmentReplyTime = 0x8220, PidLidRecurring = 0x8223, /* this object is a recurring series */ PidLidIntendedBusyStatus = 0x8224, PidLidExceptionReplaceTime = 0x8228, PidLidFInvited = 0x8229, + PidLidAppointmentReplyName = 0x8230, PidLidRecurrenceType = 0x8231, PidLidRecurrencePattern = 0x8232, PidLidTimeZoneStruct = 0x8233, PidLidTimeZoneDescription = 0x8234, PidLidClipStart = 0x8235, PidLidClipEnd = 0x8236, + PidLidAllAttendeesString = 0x8238, + PidLidToAttendeesString = 0x823B, + PidLidCcAttendeesString = 0x823C, PidLidAppointmentProposedStartWhole = 0x8250, PidLidAppointmentProposedEndWhole = 0x8251, PidLidAppointmentCounterProposal = 0x8257, @@ -1211,9 +1216,11 @@ enum { PidLidReminderTime = 0x8502, PidLidReminderSet = 0x8503, PidLidPrivate = 0x8506, + PidLidSideEffects = 0x8510, PidLidSmartNoAttach = 0x8514, PidLidCommonStart = 0x8516, PidLidCommonEnd = 0x8517, + PidLidTaskMode = 0x8518, PidLidFlagRequest = 0x8530, PidLidMileage = 0x8534, // not in ms-oxprops PidLidBilling = 0x8535, diff --git a/tests/oxcmail_ie.cpp b/tests/oxcmail_ie.cpp index d9ed1dd3d..de9993b99 100644 --- a/tests/oxcmail_ie.cpp +++ b/tests/oxcmail_ie.cpp @@ -1,16 +1,25 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2024 grommunio GmbH // This file is part of Gromox. +#include #include #include #include #include +#include #include #include #include "../tools/staticnpmap.cpp" #undef assert #define assert(x) do { if (!(x)) { printf("%s failed\n", #x); return EXIT_FAILURE; } } while (false) +namespace { +struct ie_name_entry { + uint16_t proptag; + PROPERTY_NAME pn; +}; +} + using namespace gromox; using namespace gi_dump; using mptr = std::unique_ptr; @@ -137,6 +146,19 @@ static char data_5[] = "///2\r\n" "--0--\r\n"; +static BOOL ie_get_propids(const ie_name_entry *map, size_t mapsize, + const PROPNAME_ARRAY *pna, PROPID_ARRAY *idp) +{ + auto &id = *idp; + id.resize(pna->size()); + for (size_t i = 0; i < pna->size(); ++i) { + auto row = std::find_if(&map[0], &map[mapsize], + [&](const auto &r) -> bool { return r.pn == (*pna)[i]; }); + id[i] = row != &map[mapsize] ? row->proptag : 0; + } + return TRUE; +} + static int select_parts_1() { /* @@ -309,6 +331,53 @@ static int select_parts_5() return 0; } +static void ical_export_1() +{ + /* + * DESK-2104: Old Zarafa imports (which lack some TZ fields) shifted by + * one day in some MUA, attributed to DTSTART not containing any TZID + * but just UTC. + */ + const ie_name_entry ie_map[] = { + {0x809d, {MNID_ID, PSETID_Appointment, PidLidAppointmentStartWhole}}, + {0x809e, {MNID_ID, PSETID_Appointment, PidLidAppointmentEndWhole}}, + {0x80b8, {MNID_ID, PSETID_Appointment, PidLidTimeZoneStruct}}, + {0x80b9, {MNID_ID, PSETID_Appointment, PidLidTimeZoneDescription}}, + }; + auto get_propids = [&](const PROPNAME_ARRAY *a, PROPID_ARRAY *i) { + return ie_get_propids(ie_map, std::size(ie_map), a, i); + }; + static constexpr uint64_t v_time = 0x1dabd02f773da00; + const BINARY bin_48{48, {reinterpret_cast(deconst("\304\377\377\377\0\0\0\0\304\377\377\377\0\0\0\0\n\0\0\0\5\0\3\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\5\0\2\0\0\0\0\0\0\0"))}}; + const TAGGED_PROPVAL props[] = { + {PR_MESSAGE_CLASS, deconst("IPM.Appointment")}, + {PR_START_DATE, deconst(&v_time)}, + {PR_END_DATE, deconst(&v_time)}, + {0x809d0040, deconst(&v_time)}, + {0x809e0040, deconst(&v_time)}, + {0x80b80102, deconst(&bin_48)}, + {0x80b9001f, deconst("Europe/Vienna")}, + }; + const MESSAGE_CONTENT msgctnt = {{std::size(props), deconst(props)}}; + ical icalout; + fprintf(stderr, "=== ical_export_1\n"); + if (!oxcical_export(&msgctnt, icalout, "x500org", malloc, get_propids, nullptr)) { + fprintf(stderr, "oxcical_export failed\n"); + return; + } + std::string icstr; + if (icalout.serialize(icstr) != ecSuccess) { + fprintf(stderr, "ical_serialize failed\n"); + return; + } + constexpr char needle[] = "DTSTART;TZID=Europe/Vienna:20240612T215900"; + auto ptr = strstr(icstr.c_str(), needle); + if (ptr == nullptr) { + printf("%s\n", icstr.c_str()); + fprintf(stderr, "FAILED. Substrings Europe/215900 not found.\n"); + } +} + int main() { auto ee_get_user_ids = [](const char *, unsigned int *, unsigned int *, enum display_type *) -> BOOL { return false; }; @@ -324,5 +393,6 @@ int main() select_parts_3(); select_parts_4(); select_parts_5(); + ical_export_1(); return EXIT_SUCCESS; }