Complete 32-bit Trixie compatibility fixes

This commit is contained in:
Mario Fetka
2026-07-19 18:25:32 +02:00
parent 825b31b203
commit f7baf37515
7 changed files with 71 additions and 15 deletions
+4 -4
View File
@@ -20,15 +20,15 @@
# ****************************************************************************/
find_path(GMime_INCLUDE_DIR NAMES gmime/gmime.h
PATH_SUFFIXES gmime-2.6 gmime-2.4 gmime-2.2 gmime-2.0 gmime)
find_library(GMime_LIBRARY NAMES gmime-2.6 gmime-2.4 gmime-2.2 gmime-2.0 gmime)
PATH_SUFFIXES gmime-3.0 gmime-2.6 gmime-2.4 gmime-2.2 gmime-2.0 gmime)
find_library(GMime_LIBRARY NAMES gmime-3.0 gmime-2.6 gmime-2.4 gmime-2.2 gmime-2.0 gmime)
if(GMime_INCLUDE_DIR AND EXISTS "${GMime_INCLUDE_DIR}/gmime/gmime-version.h")
file(STRINGS "${GMime_INCLUDE_DIR}/gmime/gmime-version.h"
_GMime_VERSION_LINES
REGEX "^#define GMIME_(MAJOR|MINOR|MICRO)_VERSION[ \t]+\\([0-9]+\\)")
REGEX "^#define GMIME_(MAJOR|MINOR|MICRO)_VERSION[ \t]+\\([0-9]+U?\\)")
foreach(_component MAJOR MINOR MICRO)
string(REGEX MATCH "GMIME_${_component}_VERSION[ \t]+\\(([0-9]+)\\)"
string(REGEX MATCH "GMIME_${_component}_VERSION[ \t]+\\(([0-9]+)U?\\)"
_GMime_VERSION_MATCH "${_GMime_VERSION_LINES}")
set(_GMime_VERSION_${_component} "${CMAKE_MATCH_1}")
endforeach()
+12 -8
View File
@@ -240,14 +240,14 @@ SendRFC822Address(ImapSession *session, char *Address, char *Answer)
return(STATUS_ABORT);
}
static void
MakeRFC822Header(char *Header, unsigned long *HSize)
static size_t
MakeRFC822Header(char *Header, size_t headerSize)
{
char *NL, *ptr, *ptr2, *start=Header;
BOOL StripLine, KeepGoing=TRUE;
ptr=Header;
Header[*HSize]='\0';
Header[headerSize]='\0';
while (KeepGoing) {
StripLine=FALSE;
NL=strchr(ptr,0x0a);
@@ -286,7 +286,7 @@ MakeRFC822Header(char *Header, unsigned long *HSize)
KeepGoing=FALSE;
}
}
*HSize=strlen(Header);
return strlen(Header);
}
__inline static char *
@@ -3328,16 +3328,20 @@ GetMessageHeader(ImapSession *session, FetchStruct *FetchRequest)
size_t count;
/* Request the header */
if (NMAPSendCommandF(session->store.conn, "READ %" PRIx64 " 0 %lu\r\n", FetchRequest->message->guid, FetchRequest->message->headerSize) != -1) {
if (NMAPSendCommandF(session->store.conn, "READ %" PRIx64 " 0 %" PRIu64 "\r\n", FetchRequest->message->guid, FetchRequest->message->headerSize) != -1) {
if ((ccode = NMAPReadPropertyValueLength(session->store.conn, "nmap.document", &count)) == 2001) {
FetchRequest->message->headerSize = (long)count;
if (count > INT_MAX) {
return STATUS_FETCH_LIMIT;
}
FetchRequest->message->headerSize = count;
FetchRequest->messageDetail.header = MemMalloc(FetchRequest->message->headerSize + 1);
if (FetchRequest->messageDetail.header) {
if ((ccode = NMAPReadCount(session->store.conn, FetchRequest->messageDetail.header, FetchRequest->message->headerSize)) > 0) {
if ((unsigned long)ccode == FetchRequest->message->headerSize) {
if ((size_t)ccode == count) {
if (NMAPReadCrLf(session->store.conn) == 2) {
FetchRequest->messageDetail.header[FetchRequest->message->headerSize] = '\0';
MakeRFC822Header(FetchRequest->messageDetail.header, &FetchRequest->message->headerSize);
FetchRequest->message->headerSize = MakeRFC822Header(
FetchRequest->messageDetail.header, count);
return(0);
}
}
+13 -1
View File
@@ -108,9 +108,17 @@ StoreProcessIncomingMail(StoreClient *client,
stream = g_mime_stream_fs_new(fd);
parser = g_mime_parser_new_with_stream(stream);
#if GMIME_MAJOR_VERSION >= 3
g_mime_parser_set_format(parser, GMIME_FORMAT_MESSAGE);
#else
g_mime_parser_set_scan_from (parser, FALSE);
#endif
g_object_unref(stream);
#if GMIME_MAJOR_VERSION >= 3
message = g_mime_parser_construct_message(parser, NULL);
#else
message = g_mime_parser_construct_message(parser);
#endif
g_object_unref(parser);
if (message == NULL) {
@@ -143,7 +151,7 @@ StoreProcessIncomingMail(StoreClient *client,
// treat message ID specially because we want to invent one if it
// doesn't already exist.
message_id = message->message_id;
message_id = g_mime_message_get_message_id(message);
if (!message_id) {
snprintf(generated_message_id, sizeof(generated_message_id),
"%u." GUID_FMT "@%s", document->time_created,
@@ -154,7 +162,11 @@ StoreProcessIncomingMail(StoreClient *client,
message_id);
ConnWrite(cpipe, outstr, outstr_size);
#if GMIME_MAJOR_VERSION >= 3
header_str = g_mime_object_get_headers(GMIME_OBJECT(message), NULL);
#else
header_str = g_mime_object_get_headers(GMIME_OBJECT(message));
#endif
if (header_str != NULL) {
snprintf(prop, XPL_MAX_PATH, FMT_UINT64_DEC, (uint64_t)strlen(header_str));
+4
View File
@@ -344,7 +344,11 @@ _XplServiceMain(int argc, char *argv[])
}
// initialize the mail parsing code
#if GMIME_MAJOR_VERSION >= 3
g_mime_init();
#else
g_mime_init(0);
#endif
// create lock pool
StoreInitializeFairLocks();
+3
View File
@@ -367,6 +367,8 @@ BongoSieveEvaluate(const char *script, size_t script_length,
mu_static_memory_stream_create(&stream, message, message_length) != 0 ||
mu_message_create(&mail, NULL) != 0 ||
mu_message_set_stream(mail, stream, NULL) != 0) goto finish;
/* mu_message_set_stream() transfers ownership of this reference. */
stream = NULL;
mu_sieve_set_data(machine, &context);
if (!install_bongo_actions(machine) ||
mu_sieve_compile_text(machine, normalized, normalized_length, &origin) != 0) goto finish;
@@ -396,6 +398,7 @@ finish:
mu_message_unref(mail);
mail = NULL;
}
/* Only failures before mu_message_set_stream() leave stream owned here. */
if (stream) mu_stream_unref(stream);
if (machine) mu_sieve_machine_destroy(&machine);
free(normalized);
+24 -2
View File
@@ -50,6 +50,27 @@ DATA_IMAGE = re.compile(
r"^data:image/(?:png|jpeg|gif|webp);base64,[A-Za-z0-9+/=\r\n]+$",
re.IGNORECASE)
MAX_DATA_IMAGE_URL = 350000
SAFE_STYLE_VALUE = re.compile(r"^[A-Za-z0-9 #(),.%+/'\"_-]+$")
def _sanitize_style(value):
"""Keep a conservative subset of inline CSS on HTML mail."""
declarations = []
for declaration in value.split(";"):
if not declaration.strip() or ":" not in declaration:
continue
name, css_value = declaration.split(":", 1)
name = name.strip().casefold()
css_value = css_value.strip()
if name not in ALLOWED_STYLE_PROPERTIES:
continue
if not css_value or not SAFE_STYLE_VALUE.fullmatch(css_value):
continue
lowered = css_value.casefold()
if "url(" in lowered or "expression(" in lowered:
continue
declarations.append("{}:{}".format(name, css_value))
return ";".join(declarations) or None
def sanitize_html(html, cleaner=None):
@@ -59,6 +80,8 @@ def sanitize_html(html, cleaner=None):
remote_images = []
def filter_attribute(tag, attribute, value):
if attribute == "style":
return _sanitize_style(value)
if attribute == "src" and tag == "img":
scheme = urlsplit(value).scheme.casefold()
if scheme in ("http", "https"):
@@ -87,6 +110,5 @@ def sanitize_html(html, cleaner=None):
"embed", "form", "svg", "math", "meta", "link"},
attributes=ALLOWED_ATTRIBUTES, attribute_filter=filter_attribute,
link_rel="noopener noreferrer nofollow",
url_schemes={"http", "https", "mailto", "cid", "data", "bongo-remote"},
filter_style_properties=ALLOWED_STYLE_PROPERTIES)
url_schemes={"http", "https", "mailto", "cid", "data", "bongo-remote"})
return {"html": sanitized, "remote_images": remote_images}
+11
View File
@@ -60,11 +60,22 @@ class HtmlMailTests(unittest.TestCase):
self.assertNotIn("alert", output)
self.assertNotIn("position", output)
self.assertNotIn("background-image", output)
self.assertIn('style="color:red"', output)
self.assertIn('src="cid:logo"', output)
self.assertIn('src="bongo-remote:0"', output)
self.assertEqual(result["remote_images"],
["https://tracker.example/pixel"])
def test_style_filter_rejects_obfuscated_and_active_values(self):
result = sanitize_html(
'<p style="color:e\\78pression(alert(1));'
'background-color:url(https://tracker.example/pixel);'
'font-weight:bold">safe</p>')
output = result["html"]
self.assertNotIn("expression", output)
self.assertNotIn("url", output)
self.assertIn("font-weight:bold", output)
if __name__ == "__main__":
unittest.main()