Skip to content

Commit 1925901

Browse files
committed
Merge branch 'prime'
2 parents 80551d1 + 17ca866 commit 1925901

File tree

15 files changed

+142
-99
lines changed

15 files changed

+142
-99
lines changed

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
AC_INIT([gromox], [2.42])
1+
AC_INIT([gromox], [2.43])
22
AC_CONFIG_AUX_DIR([build-aux])
33
AC_CONFIG_MACRO_DIR([build-aux])
44
AC_PREFIX_DEFAULT([/usr])

doc/changelog.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
Gromox 2.43 (2025-03-06)
2+
========================
3+
4+
Fixes:
5+
6+
* imap: reduce memory footprint when FETCHing messages
7+
* imap: resolve shutdown ordering crash
8+
* exmdb: upgrade 0-length PR_ENTRYIDs to fake 1 byte to soothe Outlook Cached
9+
Mode syncer
10+
* ews: heed MAPI proptype semantics and interpret 0xffffffff as a signed int
11+
when serializing to XML (-1 rather than 4294967295)
12+
* gab: resolve out-of-bounds access in dntomid
13+
14+
Enhancements:
15+
16+
* oxm2mt: support embedded messages
17+
* oxm2mt: add option to extract just an attachment embedded message
18+
* eml2mt: add option to extract just an attachment embedded message
19+
* mysql_adaptor: add TLS connection config directives
20+
21+
Behavioral changes:
22+
23+
* exmdb: launch threads in more rapid succession when there is job queue
24+
contention
25+
26+
127
Gromox 2.42 (2025-02-19)
228
========================
329

doc/exchange_nsp.4gx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Default: \fI3000\fP
1919
.TP
2020
\fBnsp_trace\fP
2121
Level 1: Log entry into and exit out of NSP functions, with their parameter
22-
values. Log data dumps of select calls. Level 2: Dump more data.
22+
values to stderr (not http_log_file!). Log data dumps of select calls. Level 2:
23+
Dump more data.
2324
.br
2425
Default: \fI0\fP
2526
.TP

doc/midb.8gx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ Default: \fI30minutes\fP
6767
.TP
6868
\fBmidb_cmd_debug\fP
6969
Log every incoming MIDB command and the return code of the operation in a
70-
minimal fashion to stderr. Level 1 emits commands with a failure return code,
71-
level 2 emits all commands.
70+
minimal fashion to stderr (not midb_log_file!). Level 1 emits commands with a
71+
failure return code, level 2 emits all commands. Logs are written to stderr
72+
only.
7273
.br
7374
Default: \fI0\fP
7475
.TP

doc/pop3.8gx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ Default: (unset)
117117
.TP
118118
\fBpop3_cmd_debug\fP
119119
Log every incoming POP3 command and the return code of the operation in a
120-
minimal fashion to stderr. Level 1 emits commands that have failed execution,
121-
level 2 emits all commands.
120+
minimal fashion to stderr (not pop3_log_file!). Level 1 emits commands that
121+
have failed execution, level 2 emits all commands.
122122
.br
123123
Default: \fI0\fP
124124
.TP

exch/http/pdu_processor.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,15 +1522,15 @@ static uint32_t pdu_processor_apply_async_id()
15221522
if (g_async_hash.size() >= 2 * ctx_num) {
15231523
as_hold.unlock();
15241524
delete pasync_node;
1525-
fprintf(stderr, "E-2045: g_async_hash reached maximum fill level (influenced by http.cfg:context_num,connection_ratio)\n");
1525+
mlog(LV_ERR, "E-2045: g_async_hash reached maximum fill level (influenced by http.cfg:context_num,connection_ratio)\n");
15261526
return 0;
15271527
}
15281528
try {
15291529
g_async_hash.emplace(async_id, nullptr);
15301530
} catch (const std::bad_alloc &) {
15311531
as_hold.unlock();
15321532
delete pasync_node;
1533-
fprintf(stderr, "E-2044: ENOMEM\n");
1533+
mlog(LV_ERR, "E-2044: ENOMEM\n");
15341534
return 0;
15351535
}
15361536
pasync_node->async_id = async_id;

exch/oab.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ http_status OabPlugin::proc(int ctx_id, const void *content, uint64_t len) try
6767
return wr;
6868
return write_response(ctx_id, response, strlen(response));
6969
} catch (const std::bad_alloc &) {
70-
fprintf(stderr, "E-2092: ENOMEM\n");
70+
mlog(LV_ERR, "E-2092: ENOMEM\n");
7171
return http_status::none;
7272
}
7373

exch/oxdisco.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ http_status OxdiscoPlugin::proc(int ctx_id, const void *content, uint64_t len) t
355355
mlog(LV_DEBUG, "[oxdisco] send redirect response");
356356
return resp(ctx_id, auth_info.username, email, ars);
357357
} catch (const std::bad_alloc &) {
358-
fprintf(stderr, "E-1700: ENOMEM\n");
358+
mlog(LV_ERR, "E-1700: ENOMEM\n");
359359
return die(ctx_id, server_error_code, server_error_msg);
360360
}
361361

include/gromox/mjson.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ struct GX_EXPORT mjson_io {
1515
using c_iter = decltype(m_cache)::const_iterator;
1616

1717
bool exists(const std::string &path) const;
18-
c_iter find(const std::string &path);
18+
const std::string *get_full(const std::string &path) const;
19+
std::optional<std::string> get_substr(const std::string &path, size_t of, size_t ln) const;
20+
ssize_t get_size(const std::string &path) const;
1921
void place(const std::string &path, std::string &&ctnt);
2022
void clear() { m_cache.clear(); }
2123
bool valid(c_iter it) const { return it != m_cache.cend(); }
2224
bool invalid(c_iter it) const { return it == m_cache.cend(); }
23-
static std::string substr(c_iter it, size_t of, size_t ln);
2425
};
2526

2627
struct GX_EXPORT MJSON_MIME {

lib/email/mjson.cpp

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-FileCopyrightText: 2020–2025 grommunio GmbH
33
// This file is part of Gromox.
44
#include <cerrno>
5+
#include <climits>
56
#include <cstdio>
67
#include <cstring>
78
#include <fcntl.h>
@@ -63,29 +64,35 @@ bool mjson_io::exists(const std::string &path) const
6364
return m_cache.find(path) != m_cache.cend();
6465
}
6566

66-
mjson_io::c_iter mjson_io::find(const std::string &path)
67+
void mjson_io::place(const std::string &path, std::string &&content)
68+
{
69+
m_cache[path] = std::move(content);
70+
}
71+
72+
const std::string *mjson_io::get_full(const std::string &path) const
6773
{
6874
auto iter = m_cache.find(path);
69-
if (iter != m_cache.cend())
70-
return iter;
71-
/*
72-
* Not finding the element is not an error; asking for `BODY[2.1.3]`
73-
* will iteratively look for /2.1.3.dgt, /2.1.dgt, /2.dgt.
74-
*/
75-
return m_cache.cend();
75+
return iter != m_cache.end() ? &iter->second : nullptr;
7676
}
7777

78-
void mjson_io::place(const std::string &path, std::string &&content)
78+
ssize_t mjson_io::get_size(const std::string &path) const
7979
{
80-
m_cache[path] = std::move(content);
80+
auto str = get_full(path);
81+
if (str == nullptr)
82+
return -1;
83+
if (str->size() >= SSIZE_MAX)
84+
return SSIZE_MAX;
85+
return str->size();
8186
}
8287

83-
std::string mjson_io::substr(mjson_io::c_iter it, size_t of, size_t len)
88+
std::optional<std::string> mjson_io::get_substr(const std::string &path,
89+
size_t of, size_t len) const
8490
{
85-
const auto &str = it->second;
86-
if (of <= str.size())
87-
return str.substr(of, len);
88-
return {};
91+
std::optional<std::string> r;
92+
auto str = get_full(path);
93+
if (str == nullptr || of > str->size())
94+
return r;
95+
return r.emplace(str->substr(of, len));
8996
}
9097

9198
bool MJSON_MIME::contains_none_type() const
@@ -364,10 +371,8 @@ static int mjson_fetch_mime_structure(mjson_io &io, const MJSON_MIME *pmime,
364371
temp_path = storage_path + "/"s + pmime->get_id();
365372
else
366373
temp_path = storage_path + "/"s + msg_filename + "." + pmime->get_id();
367-
auto fd = io.find(temp_path);
368-
buf += io.valid(fd) ?
369-
" " + std::to_string(fd->second.size()) :
370-
" NIL";
374+
ssize_t z = io.get_size(temp_path);
375+
buf += z >= 0 ? " " + std::to_string(z) : " NIL";
371376
} else {
372377
buf += " " + std::to_string(pmime->length);
373378
}
@@ -386,11 +391,11 @@ static int mjson_fetch_mime_structure(mjson_io &io, const MJSON_MIME *pmime,
386391
temp_path = storage_path + "/"s + msg_filename +
387392
"." + pmime->get_id() + ".dgt";
388393

389-
auto fd = io.find(temp_path);
390-
if (io.invalid(fd))
394+
auto eml_content = io.get_full(temp_path);
395+
if (eml_content == nullptr)
391396
goto RFC822_FAILURE;
392397
Json::Value digest;
393-
if (!json_from_str(fd->second, digest))
398+
if (!json_from_str(*eml_content, digest))
394399
goto RFC822_FAILURE;
395400
MJSON temp_mjson;
396401
if (!temp_mjson.load_from_json(digest))
@@ -559,15 +564,15 @@ static void mjson_enum_build(const MJSON_MIME *pmime, BUILD_PARAM *pbuild) { try
559564
dgt_path = msg_path + ".dgt";
560565
}
561566

562-
auto iter = pbuild->io.find(temp_path);
563-
if (pbuild->io.invalid(iter)) {
567+
auto eml_content = pbuild->io.get_substr(temp_path, pmime->get_content_offset(),
568+
pmime->get_content_length());
569+
if (!eml_content.has_value()) {
564570
pbuild->build_result = FALSE;
565571
return;
566572
}
567-
568-
auto eml = mjson_io::substr(iter, pmime->get_content_offset(), pmime->get_content_length());
573+
std::string eml;
569574
if (pmime->encoding_is_b()) {
570-
eml = base64_decode(eml);
575+
eml = base64_decode(*std::move(eml_content));
571576
} else if (pmime->encoding_is_q()) {
572577
std::string qpout;
573578
qpout.resize(eml.size());
@@ -665,12 +670,12 @@ BOOL MJSON::rfc822_get(mjson_io &io, MJSON *pjson, const char *storage_path,
665670
char dgt_path[256];
666671
snprintf(dgt_path, std::size(dgt_path), "%s/%s/%s.dgt", storage_path,
667672
pjson_base->get_mail_filename(), mjson_id);
668-
auto fd = io.find(dgt_path);
669-
if (io.invalid(fd))
673+
auto eml_content = io.get_full(dgt_path);
674+
if (eml_content == nullptr)
670675
continue;
671676
pjson->clear();
672677
Json::Value digest;
673-
if (!json_from_str(fd->second, digest) ||
678+
if (!json_from_str(*eml_content, digest) ||
674679
!pjson->load_from_json(digest))
675680
return false;
676681
pjson->path = temp_path;

0 commit comments

Comments
 (0)