aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-04-20 17:50:24 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-04-20 17:50:24 +0100
commite87e3b9f9d3ac720e27063143a49d43d35019637 (patch)
tree5adf761f66e8bce678018480355f2fb324867b12
parentfaeb2b01cc97a2051404b207133df2f14bc64c7a (diff)
downloadrspamd-e87e3b9f9d3ac720e27063143a49d43d35019637.tar.gz
rspamd-e87e3b9f9d3ac720e27063143a49d43d35019637.zip
Support tags replacement used in SA.
-rw-r--r--src/plugins/lua/spamassassin.lua134
1 files changed, 129 insertions, 5 deletions
diff --git a/src/plugins/lua/spamassassin.lua b/src/plugins/lua/spamassassin.lua
index 56369c0f3..be7bed344 100644
--- a/src/plugins/lua/spamassassin.lua
+++ b/src/plugins/lua/spamassassin.lua
@@ -40,6 +40,7 @@ local _ = require "fun"
local known_plugins = {
'Mail::SpamAssassin::Plugin::FreeMail',
'Mail::SpamAssassin::Plugin::HeaderEval',
+ 'Mail::SpamAssassin::Plugin::ReplaceTags'
}
-- Internal variables
@@ -48,6 +49,13 @@ local atoms = {}
local metas = {}
local freemail_domains = {}
local freemail_trie
+local replace = {
+ tags = {},
+ pre = {},
+ inter = {},
+ post = {},
+ rules = {}
+}
local section = rspamd_config:get_key("spamassassin")
-- Minimum score to treat symbols as meta
@@ -254,6 +262,10 @@ local function maybe_parse_sa_function(line)
return nil
end
+local function words_to_re(words, start)
+ return table.concat(_.totable(_.drop_n(start, words)), " ");
+end
+
local function process_tflags(rule, flags)
_.each(function(flag)
if flag == 'publish' then
@@ -266,6 +278,11 @@ local function process_tflags(rule, flags)
end, _.drop_n(1, flags))
end
+local function process_replace(words, tbl)
+ local re = words_to_re(words, 2)
+ tbl[words[2]] = re
+end
+
local function process_sa_conf(f)
local cur_rule = {}
local valid_rule = false
@@ -290,10 +307,6 @@ local function process_sa_conf(f)
valid_rule = false
end
- local function words_to_re(words, start)
- return table.concat(_.totable(_.drop_n(start, words)), " ");
- end
-
local skip_to_endif = false
for l in f:lines() do
(function ()
@@ -334,7 +347,7 @@ local function process_sa_conf(f)
if valid_rule then
insert_cur_rule()
end
- if slash and words[4] and (words[4] == '=~' or words[4] == '!~') then
+ if words[4] and (words[4] == '=~' or words[4] == '!~') then
cur_rule['type'] = 'header'
cur_rule['symbol'] = words[2]
@@ -429,6 +442,17 @@ local function process_sa_conf(f)
end, _.drop_n(1, words))
elseif words[1] == 'tflags' then
process_tflags(cur_rule, words)
+ elseif words[1] == 'replace_tag' then
+ process_replace(words, replace['tags'])
+ elseif words[1] == 'replace_pre' then
+ process_replace(words, replace['pre'])
+ elseif words[1] == 'replace_inter' then
+ process_replace(words, replace['inter'])
+ elseif words[1] == 'replace_post' then
+ process_replace(words, replace['post'])
+ elseif words[1] == 'replace_rules' then
+ _.each(function(r) table.insert(replace['rules'], r) end,
+ _.drop_n(1, words))
end
end)()
end
@@ -489,6 +513,106 @@ local function sa_regexp_match(data, re, raw, rule)
return res
end
+local function apply_replacements(str)
+ local pre = ""
+ local post = ""
+ local inter = ""
+
+ local function check_specific_tag(prefix, s, tbl)
+ local replacement = nil
+ local ret = s
+ _.each(function(n, t)
+ local ns,matches = string.gsub(s, string.format("<%s%s>", prefix, n), "")
+ if matches > 0 then
+ replacement = t
+ ret = ns
+ end
+ end, tbl)
+
+ return ret,replacement
+ end
+
+ local repl
+ str,repl = check_specific_tag("pre ", str, replace['pre'])
+ if repl then
+ pre = repl
+ end
+ str,repl = check_specific_tag("inter ", str, replace['inter'])
+ if repl then
+ inter = repl
+ end
+ str,repl = check_specific_tag("post ", str, replace['post'])
+ if repl then
+ post = repl
+ end
+
+ -- XXX: ugly hack
+ if inter then
+ str = string.gsub(str, "><", string.format(">%s<", inter))
+ end
+
+ local function replace_all_tags(s)
+ local str, matches
+ str = s
+ _.each(function(n, t)
+ str,matches = string.gsub(str, string.format("<%s>", n),
+ string.format("%s%s%s", pre, t, post))
+ end, replace['tags'])
+
+ return str
+ end
+
+ local s = replace_all_tags(str)
+
+
+ if str ~= s then
+ return true,s
+ end
+
+ return false,str
+end
+
+-- Replace rule tags
+local ntags = {}
+local function rec_replace_tags(tag, tagv)
+ if ntags[tag] then return ntags[tag] end
+ _.each(function(n, t)
+ if n ~= tag then
+ local s,matches = string.gsub(tagv, string.format("<%s>", n), t)
+ if matches > 0 then
+ ntags[tag] = rec_replace_tags(tag, s)
+ end
+ end
+ end, replace['tags'])
+
+ if not ntags[tag] then ntags[tag] = tagv end
+ return ntags[tag]
+end
+_.each(function(n, t)
+ rec_replace_tags(n, t)
+end, replace['tags'])
+_.each(function(n, t)
+ replace['tags'][n] = t
+end, ntags)
+
+_.each(function(r)
+ local rule = rules[r]
+
+ if rule['re_expr'] and rule['re'] then
+ local res,nexpr = apply_replacements(rule['re_expr'])
+ if res then
+ local nre = rspamd_regexp.create_cached(nexpr)
+ if not nre then
+ rspamd_logger.errx('cannot apply replacement for rule %1', r)
+ else
+ rspamd_logger.debugx('replace %1 -> %2', r, nexpr)
+ rule['re'] = nre
+ rule['re_expr'] = nexpr
+ end
+ end
+ end
+end, replace['rules'])
+
-- Header rules
_.each(function(k, r)
local f = function(task)