From 70966b1e0af4f233419a68474d9fe8f587d80b25 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 7 Jul 2024 20:51:17 +0200 Subject: [PATCH 1/3] doc: mention -Y, -u in exm2eml manpage --- doc/gromox-exm2eml.8 | 11 +++++++++++ tools/exm2eml.cpp | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/gromox-exm2eml.8 b/doc/gromox-exm2eml.8 index e285cdc91..4d06a33a0 100644 --- a/doc/gromox-exm2eml.8 +++ b/doc/gromox-exm2eml.8 @@ -25,5 +25,16 @@ that particular folder. .PP An alternate way to get an EML representation is using grommunio-web's "Export as > EML file(s)" function from the context menu of a mail item. +.SH Options +.TP +\fB\-Y\fP \fIvalue\fP +If set to 1, allday events are emitted as so-called floating dates. +If set to 0 however, allday events are emitted as precise-time events. +.br +Default: 1 +.TP +\fB\-u\fP [\fIuser\fP]\fB@\fIdomin.example\fP +Source mail store from which to load the message from. For the public folder of +a domain, leave out the local part, i.e. use \fB@\fP\fIdomain.example\fP. .SH See also \fBgromox\fP(7), \fBgromox\-eml2mt\fP(8gx) diff --git a/tools/exm2eml.cpp b/tools/exm2eml.cpp index ddf3b5ace..59f445220 100644 --- a/tools/exm2eml.cpp +++ b/tools/exm2eml.cpp @@ -43,7 +43,7 @@ static unsigned int g_export_mode = EXPORT_MAIL; static int g_allday_mode = -1; static constexpr HXoption g_options_table[] = { {nullptr, 'Y', HXTYPE_INT, &g_allday_mode, nullptr, nullptr, 0, "Allday emission mode (default=-1, YMDHMS=0, YMD=1)"}, - {nullptr, 'u', HXTYPE_STRING, &g_username, nullptr, nullptr, 0, "Username of store to import to", "EMAILADDR"}, + {nullptr, 'u', HXTYPE_STRING, &g_username, nullptr, nullptr, 0, "Username of store to export from", "EMAILADDR"}, {"ical", 0, HXTYPE_VAL, &g_export_mode, nullptr, nullptr, EXPORT_ICAL, "Export as calendar object"}, {"mail", 0, HXTYPE_VAL, &g_export_mode, nullptr, nullptr, EXPORT_MAIL, "Export as RFC5322 mail"}, {"mt", 0, HXTYPE_VAL, &g_export_mode, nullptr, nullptr, EXPORT_GXMT, "Export as Gromox mailbox transfer format"}, From 10ca5c4d8147a9bd115ebfe156b2ba952e601c5a Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 7 Jul 2024 21:51:21 +0200 Subject: [PATCH 2/3] mt2exm: add -v option --- doc/gromox-exm2eml.8 | 5 +++++ doc/gromox-mt2exm.8 | 3 +++ tools/exm2eml.cpp | 6 ++++++ tools/genimport.cpp | 21 ++++++++++++++++----- tools/genimport.hpp | 3 ++- tools/mt2exm.cpp | 1 + 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/doc/gromox-exm2eml.8 b/doc/gromox-exm2eml.8 index 4d06a33a0..967a6a592 100644 --- a/doc/gromox-exm2eml.8 +++ b/doc/gromox-exm2eml.8 @@ -32,6 +32,11 @@ If set to 1, allday events are emitted as so-called floating dates. If set to 0 however, allday events are emitted as precise-time events. .br Default: 1 +\fB\-p\fP +Show properties in detail (enhances \fB\-t\fP). +.TP +\fB\-t\fP +Show a diagnostic tree view of the source data as it is being read. .TP \fB\-u\fP [\fIuser\fP]\fB@\fIdomin.example\fP Source mail store from which to load the message from. For the public folder of diff --git a/doc/gromox-mt2exm.8 b/doc/gromox-mt2exm.8 index f35e9fce6..4c8d012f3 100644 --- a/doc/gromox-mt2exm.8 +++ b/doc/gromox-mt2exm.8 @@ -49,6 +49,9 @@ Print folder/message summary as these items are processed. Target mail store which to import mails to. For the public folder of a domain, leave out the local part, i.e. use \fB@\fP\fIdomain.example\fP. .TP +\fB\-v\fP +Verbose mode: report individual FID/MIDs for newly created objects. +.TP \fB\-x\fP When importing an MT stream that does not request message splicing, mt2exm will raise an error if a to-be-created folder already exists. This behavior can be diff --git a/tools/exm2eml.cpp b/tools/exm2eml.cpp index 59f445220..2c0b60940 100644 --- a/tools/exm2eml.cpp +++ b/tools/exm2eml.cpp @@ -43,6 +43,8 @@ static unsigned int g_export_mode = EXPORT_MAIL; static int g_allday_mode = -1; static constexpr HXoption g_options_table[] = { {nullptr, 'Y', HXTYPE_INT, &g_allday_mode, nullptr, nullptr, 0, "Allday emission mode (default=-1, YMDHMS=0, YMD=1)"}, + {nullptr, 'p', HXTYPE_NONE, &g_show_props, nullptr, nullptr, 0, "Show properties in detail (if -t)"}, + {nullptr, 't', HXTYPE_NONE, &g_show_tree, nullptr, nullptr, 0, "Show tree-based analysis of the archive"}, {nullptr, 'u', HXTYPE_STRING, &g_username, nullptr, nullptr, 0, "Username of store to export from", "EMAILADDR"}, {"ical", 0, HXTYPE_VAL, &g_export_mode, nullptr, nullptr, EXPORT_ICAL, "Export as calendar object"}, {"mail", 0, HXTYPE_VAL, &g_export_mode, nullptr, nullptr, EXPORT_MAIL, "Export as RFC5322 mail"}, @@ -193,6 +195,10 @@ int main(int argc, char **argv) try return EXIT_FAILURE; } } + if (g_show_tree) { + fprintf(stderr, "Message 0\n"); + gi_dump_msgctnt(0, *ctnt); + } if (g_export_mode == EXPORT_MAIL) { if (!oxcmail_export(ctnt, false, oxcmail_body::plain_and_html, &imail, zalloc, cu_get_propids, diff --git a/tools/genimport.cpp b/tools/genimport.cpp index 374c803d9..5e69096ff 100644 --- a/tools/genimport.cpp +++ b/tools/genimport.cpp @@ -39,12 +39,14 @@ using namespace std::string_literals; using namespace gromox; +using LLU = unsigned long long; namespace exmdb_client = exmdb_client_remote; std::string g_dstuser; static std::string g_storedir_s; const char *g_storedir; -unsigned int g_user_id, g_show_tree, g_show_props, g_wet_run = 1, g_public_folder; +unsigned int g_user_id, g_show_tree, g_show_props, g_wet_run = 1; +unsigned int g_public_folder, g_verbose_create; static thread_local alloc_context g_alloc_mgr; static ec_error_t (*exmdb_local_rules_execute)(const char *, const char *, const char *, eid_t, eid_t, unsigned int); @@ -170,8 +172,7 @@ void gi_dump_folder_map(const gi_folder_map_t &map) fprintf(stderr, "\t# HierID (hex) -> Target name\n"); for (const auto &[nid, tgt] : map) fprintf(stderr, "\t%xh -> %s (%s %llxh)\n", nid, tgt.create_name.c_str(), - tgt.create ? "create under" : "splice into", - static_cast(tgt.fid_to)); + tgt.create ? "create under" : "splice into", LLU{tgt.fid_to}); } void gi_dump_name_map(const gi_name_map &map) @@ -372,6 +373,9 @@ int exm_create_folder(uint64_t parent_fld, TPROPVAL_ARRAY *props, bool o_excl, fprintf(stderr, "exm: Could not create folder \"%s\". " "Either it already existed or some there was some other unspecified problem.\n", dn); return -EEXIST; + } else if (g_verbose_create) { + fprintf(stderr, "exm: Created folder \"%s\" (fid=0x%llx)\n", dn, + LLU{rop_util_get_gc_value(*new_fld_id)}); } return 0; } @@ -382,8 +386,7 @@ int exm_permissions(eid_t fid, const std::vector &perms) return 0; if (!exmdb_client::update_folder_permission(g_storedir, fid, false, perms.size(), perms.data())) { - fprintf(stderr, "exm: update_folder_perm(%llxh) RPC failed\n", - static_cast(fid)); + fprintf(stderr, "exm: update_folder_perm(%llxh) RPC failed\n", LLU{fid}); return -EIO; } return 0; @@ -408,6 +411,10 @@ int exm_deliver_msg(const char *target, MESSAGE_CONTENT *ct, unsigned int mode) auto dm_status = static_cast(r32); switch (dm_status) { case deliver_message_result::result_ok: + if (g_verbose_create) + fprintf(stderr, "Created/delivered new message 0x%llx:0x%llx\n", + LLU{rop_util_get_gc_value(folder_id)}, + LLU{rop_util_get_gc_value(msg_id)}); break; case deliver_message_result::result_error: fprintf(stderr, "Message rejected - unspecified reason\n"); @@ -498,6 +505,10 @@ int exm_create_msg(uint64_t parent_fld, MESSAGE_CONTENT *ctnt) } else if (e_result != ecSuccess) { fprintf(stderr, "exm: write_message: %s\n", mapi_strerror(e_result)); return -EIO; + } else if (g_verbose_create) { + fprintf(stderr, "Created new message 0x%llx:0x%llx\n", + LLU{rop_util_get_gc_value(parent_fld)}, + LLU{rop_util_get_gc_value(msg_id)}); } return 0; } diff --git a/tools/genimport.hpp b/tools/genimport.hpp index b66611454..67a9658a4 100644 --- a/tools/genimport.hpp +++ b/tools/genimport.hpp @@ -88,7 +88,8 @@ enum { extern std::string g_dstuser; extern const char *g_storedir; -extern unsigned int g_user_id, g_show_tree, g_show_props, g_wet_run, g_public_folder; +extern unsigned int g_user_id, g_show_tree, g_show_props, g_wet_run; +extern unsigned int g_public_folder, g_verbose_create; extern void tree(unsigned int d); extern void tlog(const char *f, ...) __attribute__((format(printf, 1, 2))); diff --git a/tools/mt2exm.cpp b/tools/mt2exm.cpp index 347b13f77..9304547ca 100644 --- a/tools/mt2exm.cpp +++ b/tools/mt2exm.cpp @@ -60,6 +60,7 @@ static constexpr HXoption g_options_table[] = { {nullptr, 'p', HXTYPE_NONE, &g_show_props, nullptr, nullptr, 0, "Show properties in detail (if -t)"}, {nullptr, 't', HXTYPE_NONE, &g_show_tree, nullptr, nullptr, 0, "Show tree-based analysis of the archive"}, {nullptr, 'u', HXTYPE_STRING, &g_username, nullptr, nullptr, 0, "Username of store to import to", "EMAILADDR"}, + {nullptr, 'v', HXTYPE_NONE | HXOPT_INC, &g_verbose_create, nullptr, nullptr, 0, "Be more verbose"}, {nullptr, 'x', HXTYPE_VAL, &g_oexcl, nullptr, nullptr, 0, "Disable O_EXCL like behavior for non-spliced folders"}, {"repeat", 0, HXTYPE_UINT, &g_repeat_iter, {}, {}, 0, "For testing purposes, import each message N times", "N"}, {"skip-notif", 0, HXTYPE_NONE, &g_skip_notif, nullptr, nullptr, 0, "Skip emission of notifications (if -D)"}, From fe6a029d53ef3b6ecb4032298c0e0b540e3e374e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 7 Jul 2024 22:32:45 +0200 Subject: [PATCH 3/3] oxvcard: set PidLidEmail*AddressType on VCF import References: GXH-79, GXF-1300, GXF-1337 --- lib/mapi/oxvcard.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/mapi/oxvcard.cpp b/lib/mapi/oxvcard.cpp index bb36e2807..4b8a0917d 100644 --- a/lib/mapi/oxvcard.cpp +++ b/lib/mapi/oxvcard.cpp @@ -44,6 +44,7 @@ unsigned int g_oxvcard_pedantic; static constexpr uint32_t g_n_proptags[] = {PR_SURNAME, PR_GIVEN_NAME, PR_MIDDLE_NAME, PR_DISPLAY_NAME_PREFIX, PR_GENERATION}; +/* The 8000s numbers must match up with the order of the oxvcard_get_propids::bf array */ static constexpr uint32_t g_workaddr_proptags[] = {0x8000001F, 0x8001001F, 0x8002001F, 0x8003001F, 0x8004001F, 0x8005001F}; static constexpr uint32_t g_homeaddr_proptags[] = @@ -56,6 +57,8 @@ static constexpr uint32_t g_otheraddr_proptags[] = PR_OTHER_ADDRESS_POSTAL_CODE, PR_OTHER_ADDRESS_COUNTRY}; static constexpr uint32_t g_email_proptags[] = {0x8006001F, 0x8007001F, 0x8008001F}; +static constexpr uint32_t g_addrtype_proptags[] = + {0x8012001F, 0x8013001F, 0x8014001F}; static constexpr uint32_t g_im_proptag = 0x8009001F; static constexpr uint32_t g_categories_proptag = 0x800A101F; static constexpr uint32_t g_bcd_proptag = 0x800B0102; @@ -87,9 +90,10 @@ static BOOL oxvcard_check_compatible(const vcard *pvcard) static BOOL oxvcard_get_propids(PROPID_ARRAY *ppropids, GET_PROPIDS get_propids) { - PROPERTY_NAME bf[18]; + PROPERTY_NAME bf[21]; size_t start = 0, z = 0; - + + /* bf array must be ordered w.r.t. g_workaddr_proptags et al */ bf[z++].lid = PidLidWorkAddressPostOfficeBox; bf[z++].lid = PidLidWorkAddressStreet; bf[z++].lid = PidLidWorkAddressCity; @@ -126,6 +130,16 @@ static BOOL oxvcard_get_propids(PROPID_ARRAY *ppropids, bf[z].kind = MNID_STRING; bf[z++].pname = deconst("vcarduid"); + bf[z].guid = PSETID_ADDRESS; + bf[z].kind = MNID_ID; + bf[z++].lid = PidLidEmail1AddressType; + bf[z].guid = PSETID_ADDRESS; + bf[z].kind = MNID_ID; + bf[z++].lid = PidLidEmail2AddressType; + bf[z].guid = PSETID_ADDRESS; + bf[z].kind = MNID_ID; + bf[z++].lid = PidLidEmail3AddressType; + PROPNAME_ARRAY propnames; propnames.count = z; propnames.ppropname = bf; @@ -401,7 +415,8 @@ message_content *oxvcard_import(const vcard *pvcard, GET_PROPIDS get_propids) tr continue; if (mail_count > 2) continue; - if (pmsg->proplist.set(g_email_proptags[mail_count++], pstring) != 0) + if (pmsg->proplist.set(g_email_proptags[mail_count], pstring) != 0 || + pmsg->proplist.set(g_addrtype_proptags[mail_count++], "SMTP") != 0) return imp_null; } else if (strcasecmp(pvline_name, "TITLE") == 0) { auto pstring = pvline->get_first_subval();