From 57819446d5026c5ec7a6566ae4a34ad6a2fe74d7 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 18 Dec 2018 15:09:20 +0000 Subject: [PATCH] [Feature] Rspamadm: Allow to append footers to plain messages --- lualib/rspamadm/mime.lua | 79 ++++++++++++++++++++++++++++++++++---- src/libmime/content_type.h | 4 +- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/lualib/rspamadm/mime.lua b/lualib/rspamadm/mime.lua index 07fc982a7..fa6cc1ee0 100644 --- a/lualib/rspamadm/mime.lua +++ b/lualib/rspamadm/mime.lua @@ -603,19 +603,27 @@ local function modify_handler(opts) return content end - local function do_append_footer(task, part, footer) + local function do_append_footer(task, part, footer, is_multipart) local newline_s = newline(task) local tp = part:get_text() local ct = 'text/plain' + local cte = 'quoted-printable' if tp:is_html() then ct = 'text/html' end - io.write(string.format('Content-Type: %s; charset=utf-8%s'.. - 'Content-Transfer-Encoding: quoted-printable%s%s', - ct, newline_s, newline_s, newline_s)) - io.flush() + if part:get_cte() == '7bit' then + cte = '7bit' + end + + if is_multipart then + io.write(string.format('Content-Type: %s; charset=utf-8%s'.. + 'Content-Transfer-Encoding: %s%s%s', + ct, newline_s, cte, newline_s, newline_s)) + io.flush() + end + local content = tostring(tp:get_content('raw_utf') or '') local double_nline = newline_s .. newline_s local nlen = #double_nline @@ -626,12 +634,15 @@ local function modify_handler(opts) footer) rspamd_util.encode_qp(content, 80, task:get_newlines_type()):save_in_file(1) + io.write(double_nline) else - rspamd_util.encode_qp(content .. footer, + content = content .. footer + rspamd_util.encode_qp(content, 80, task:get_newlines_type()):save_in_file(1) + io.write(double_nline) end - io.write(double_nline) + end local text_footer, html_footer @@ -647,17 +658,63 @@ local function modify_handler(opts) for _,fname in ipairs(opts.file) do local task = load_task(opts, fname) local newline_s = newline(task) + local need_rewrite_ct = false + local parsed_ct + local seen_cte = false local function process_headers_cb(name, hdr) + for _,h in ipairs(opts['remove_header']) do if name:match(h) then return end end + if need_rewrite_ct then + if name:lower() == 'content-type' then + local nct = string.format('%s: %s/%s; charset=utf-8%s', + 'Content-Type', parsed_ct.type, parsed_ct.subtype, newline_s) + io.write(nct) + return + elseif name:lower() == 'content-transfer-encoding' then + seen_cte = true + io.write(string.format('%s: %s%s', + 'Content-Transfer-Encoding', 'quoted-printable', newline_s)) + return + end + end + io.write(hdr.raw) end + if html_footer or text_footer then + -- We need to take extra care about content-type and cte + local ct = task:get_header('Content-Type') + if ct then + ct = rspamd_util.parse_content_type(ct, task:get_mempool()) + end + + if ct then + if ct.type and ct.type == 'text' then + if ct.subtype then + if html_footer and (ct.subtype == 'html' or ct.subtype == 'htm') then + need_rewrite_ct = true + elseif text_footer and ct.subtype == 'plain' then + need_rewrite_ct = true + end + else + if text_footer then + need_rewrite_ct = true + end + end + + parsed_ct = ct + end + else + -- XXX: Write some content type based on magic? + end + end + task:headers_foreach(process_headers_cb, {full = true}) for _,h in ipairs(opts['add_header']) do @@ -670,6 +727,11 @@ local function modify_handler(opts) end end + if not seen_cte and need_rewrite_ct then + io.write(string.format('%s: %s%s', + 'Content-Transfer-Encoding', 'quoted-printable', newline_s)) + end + -- End of headers io.write(newline_s) @@ -754,7 +816,8 @@ local function modify_handler(opts) io.flush() if append_footer and not skip_footer then - do_append_footer(task, part, append_footer) + do_append_footer(task, part, append_footer, + parent and parent:is_multipart()) else part:get_raw_headers():save_in_file(1) io.write(newline_s) diff --git a/src/libmime/content_type.h b/src/libmime/content_type.h index c4dc5896e..554aad6a1 100644 --- a/src/libmime/content_type.h +++ b/src/libmime/content_type.h @@ -51,7 +51,7 @@ struct rspamd_content_type { GHashTable *attrs; /* Can be empty */ }; -enum rspamd_contetn_disposition_type { +enum rspamd_content_disposition_type { RSPAMD_CT_UNKNOWN = 0, RSPAMD_CT_INLINE = 1, RSPAMD_CT_ATTACHMENT = 2, @@ -59,7 +59,7 @@ enum rspamd_contetn_disposition_type { struct rspamd_content_disposition { gchar *lc_data; - enum rspamd_contetn_disposition_type type; + enum rspamd_content_disposition_type type; rspamd_ftok_t filename; GHashTable *attrs; /* Can be empty */ }; -- 2.39.5