commit 5781944: [Feature] Rspamadm: Allow to append footers to plain messages

Vsevolod Stakhov vsevolod at highsecure.ru
Thu Dec 27 18:28:11 UTC 2018


Author: Vsevolod Stakhov
Date: 2018-12-18 15:09:20 +0000
URL: https://github.com/rspamd/rspamd/commit/57819446d5026c5ec7a6566ae4a34ad6a2fe74d7

[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 */
 };


More information about the Commits mailing list