]> source.dussan.org Git - rspamd.git/commitdiff
[Minor] Rework rmilter headers internal functions 1354/head
authorAndrew Lewis <nerf@judo.za.org>
Fri, 20 Jan 2017 09:30:36 +0000 (11:30 +0200)
committerAndrew Lewis <nerf@judo.za.org>
Fri, 20 Jan 2017 09:30:36 +0000 (11:30 +0200)
src/plugins/lua/rmilter_headers.lua

index d8083ea7029ce0d7f5c132d5f81834a18ad4a03f..86acaf9507f585f5240dbf607ff4a229ad10e7c1 100644 (file)
@@ -82,246 +82,236 @@ local settings = {
 }
 
 local active_routines = {}
-local routines = {}
+local custom_routines = {}
 
-routines['x-spamd-bar'] = function(task, common_meta)
-  local common, add, remove = {}, {}, {}
-  if not common_meta['metric_score'] then
-    common['metric_score'] = task:get_metric_score('default')
-    common_meta['metric_score'] = common['metric_score']
-  end
-  local score = common_meta['metric_score'][1]
-  local spambar
-  if score <= -1 then
-    spambar = string.rep(settings.routines['x-spamd-bar'].negative, score*-1)
-  elseif score >= 1 then
-    spambar = string.rep(settings.routines['x-spamd-bar'].positive, score)
-  else
-    spambar = settings.routines['x-spamd-bar'].neutral
-  end
-  if settings.routines['x-spamd-bar'].remove then
-    remove[settings.routines['x-spamd-bar'].header] = settings.routines['x-spamd-bar'].remove
-  end
-  if spambar ~= '' then
-    add[settings.routines['x-spamd-bar'].header] = spambar
-  end
-  return nil, add, remove, common
-end
+local function rmilter_headers(task)
 
-routines['x-spam-level'] = function(task, common_meta)
-  local common, add, remove = {}, {}, {}
-  if not common_meta['metric_score'] then
-    common['metric_score'] = task:get_metric_score('default')
-    common_meta['metric_score'] = common['metric_score']
-  end
-  local score = common_meta['metric_score'][1]
-  if score < 1 then
-    return nil, {}, {}, common
-  end
-  if settings.routines['x-spam-level'].remove then
-    remove[settings.routines['x-spam-level'].header] = settings.routines['x-spam-level'].remove
-  end
-  add[settings.routines['x-spam-level'].header] = string.rep(settings.routines['x-spam-level'].char, score)
-  return nil, add, remove, common
-end
+  local routines, common, add, remove = {}, {}, {}, {}
 
-routines['spam-header'] = function(task, common_meta)
-  local common, add, remove = {}, {}, {}
-  if not common_meta['metric_action'] then
-    common['metric_action'] = task:get_metric_action('default')
-    common_meta['metric_action'] = common['metric_action']
-  end
-  if settings.routines['spam-header'].remove then
-    remove[settings.routines['spam-header'].header] = settings.routines['spam-header'].remove
-  end
-  local action = common_meta['metric_action']
-  if action ~= 'no action' and action ~= 'greylist' then
-    add[settings.routines['spam-header'].header] = settings.routines['spam-header'].value
+  routines['x-spamd-bar'] = function()
+    if not common['metric_score'] then
+      common['metric_score'] = task:get_metric_score('default')
+    end
+    local score = common['metric_score'][1]
+    local spambar
+    if score <= -1 then
+      spambar = string.rep(settings.routines['x-spamd-bar'].negative, score*-1)
+    elseif score >= 1 then
+      spambar = string.rep(settings.routines['x-spamd-bar'].positive, score)
+    else
+      spambar = settings.routines['x-spamd-bar'].neutral
+    end
+    if settings.routines['x-spamd-bar'].remove then
+      remove[settings.routines['x-spamd-bar'].header] = settings.routines['x-spamd-bar'].remove
+    end
+    if spambar ~= '' then
+      add[settings.routines['x-spamd-bar'].header] = spambar
+    end
   end
-  return nil, add, remove, common
-end
 
-routines['x-virus'] = function(task, common_meta)
-  local add, remove = {}, {}
-  local common = {symbols = {}}
-  if not common_meta.symbols then
-    common_meta.symbols = {}
+  routines['x-spam-level'] = function()
+    if not common['metric_score'] then
+      common['metric_score'] = task:get_metric_score('default')
+    end
+    local score = common['metric_score'][1]
+    if score < 1 then
+      return nil, {}, {}
+    end
+    if settings.routines['x-spam-level'].remove then
+      remove[settings.routines['x-spam-level'].header] = settings.routines['x-spam-level'].remove
+    end
+    add[settings.routines['x-spam-level'].header] = string.rep(settings.routines['x-spam-level'].char, score)
   end
-  if settings.routines['x-virus'].remove then
-    remove[settings.routines['x-virus'].header] = settings.routines['x-virus'].remove
+
+  routines['spam-header'] = function()
+    if not common['metric_action'] then
+      common['metric_action'] = task:get_metric_action('default')
+    end
+    if settings.routines['spam-header'].remove then
+      remove[settings.routines['spam-header'].header] = settings.routines['spam-header'].remove
+    end
+    local action = common['metric_action']
+    if action ~= 'no action' and action ~= 'greylist' then
+      add[settings.routines['spam-header'].header] = settings.routines['spam-header'].value
+    end
   end
-  local virii = {}
-  for _, sym in ipairs(settings.routines['x-virus'].symbols) do
-    if not (common_meta.symbols[sym] == false) then
-      local s = task:get_symbol(sym)
-      if not s then
-        common_meta.symbols[sym] = false
-        common[sym] = false
-      else
-        common_meta.symbols[sym] = s
-        common[sym] = s
-        if (((s or E)[1] or E).options or E)[1] then
-          table.insert(virii, s[1].options[1])
-        else
-          table.insert(virii, 'unknown')
-        end
+
+  routines['x-virus'] = function()
+    if not common.symbols then
+      common.symbols = {}
+    end
+    if settings.routines['x-virus'].remove then
+      remove[settings.routines['x-virus'].header] = settings.routines['x-virus'].remove
+    end
+    local virii = {}
+    for _, sym in ipairs(settings.routines['x-virus'].symbols) do
+      if not (common.symbols[sym] == false) then
+       local s = task:get_symbol(sym)
+       if not s then
+         common.symbols[sym] = false
+       else
+         common.symbols[sym] = s
+         if (((s or E)[1] or E).options or E)[1] then
+           table.insert(virii, s[1].options[1])
+         else
+           table.insert(virii, 'unknown')
+         end
+       end
       end
     end
+    if #virii > 0 then
+      add[settings.routines['x-virus'].header] = table.concat(virii, ',')
+    end
   end
-  if #virii > 0 then
-    add[settings.routines['x-virus'].header] = table.concat(virii, ',')
-  end
-  return nil, add, remove, common
-end
 
-routines['x-spam-status'] = function(task, common_meta)
-  local common, add, remove = {}, {}, {}
-  if not common_meta['metric_score'] then
-    common['metric_score'] = task:get_metric_score('default')
-    common_meta['metric_score'] = common['metric_score']
-  end
-  if not common_meta['metric_action'] then
-    common['metric_action'] = task:get_metric_action('default')
-    common_meta['metric_action'] = common['metric_action']
-  end
-  local score = common_meta['metric_score'][1]
-  local action = common_meta['metric_action']
-  local is_spam
-  local spamstatus
-  if action ~= 'no action' and action ~= 'greylist' then
-    is_spam = 'Yes'
-  else
-    is_spam = 'No'
-  end
-  spamstatus = is_spam .. ', score=' .. string.format('%.2f', score)
-  if settings.routines['x-spam-status'].remove then
-    remove[settings.routines['x-spam-status'].header] = settings.routines['x-spam-status'].remove
+  routines['x-spam-status'] = function()
+    if not common['metric_score'] then
+      common['metric_score'] = task:get_metric_score('default')
+    end
+    if not common['metric_action'] then
+      common['metric_action'] = task:get_metric_action('default')
+    end
+    local score = common['metric_score'][1]
+    local action = common['metric_action']
+    local is_spam
+    local spamstatus
+    if action ~= 'no action' and action ~= 'greylist' then
+      is_spam = 'Yes'
+    else
+      is_spam = 'No'
+    end
+    spamstatus = is_spam .. ', score=' .. string.format('%.2f', score)
+    if settings.routines['x-spam-status'].remove then
+      remove[settings.routines['x-spam-status'].header] = settings.routines['x-spam-status'].remove
+    end
+    add[settings.routines['x-spam-status'].header] = spamstatus
   end
-  add[settings.routines['x-spam-status'].header] = spamstatus
-  return nil, add, remove, common
-end
 
-routines['authentication-results'] = function(task, common_meta)
-  local add, remove, auth_results, hdr_parts = {}, {}, {}, {}
-  local common = {symbols = {}}
-  local auth_types = {
-    dkim = settings.routines['authentication-results'].dkim_symbols,
-    dmarc = settings.routines['authentication-results'].dmarc_symbols,
-    spf = settings.routines['authentication-results'].spf_symbols,
-  }
-  if not common_meta.symbols then common_meta.symbols = {} end
-  for auth_type, symbols in pairs(auth_types) do
-    for key, sym in pairs(symbols) do
-      if not (common_meta.symbols[sym] == false) then
-        local s = task:get_symbol(sym)
-        if not s then
-          common_meta.symbols[sym] = false
-          common.symbols[sym] = false
-        else
-          common_meta.symbols[sym] = s
-          common.symbols[sym] = s
-          if not auth_results[auth_type] then
-            auth_results[auth_type] = {key}
-          else
-            table.insert(auth_results[auth_type], key)
-          end
-          if auth_type ~= 'dkim' then
-            break
-          end
-        end
+  routines['authentication-results'] = function()
+    local auth_results, hdr_parts = {}, {}
+    if not common.symbols then
+      common.symbols = {}
+    end
+    local auth_types = {
+      dkim = settings.routines['authentication-results'].dkim_symbols,
+      dmarc = settings.routines['authentication-results'].dmarc_symbols,
+      spf = settings.routines['authentication-results'].spf_symbols,
+    }
+    for auth_type, symbols in pairs(auth_types) do
+      for key, sym in pairs(symbols) do
+       if not (common.symbols[sym] == false) then
+         local s = task:get_symbol(sym)
+         if not s then
+           common.symbols[sym] = false
+         else
+           common.symbols[sym] = s
+           if not auth_results[auth_type] then
+             auth_results[auth_type] = {key}
+           else
+             table.insert(auth_results[auth_type], key)
+           end
+           if auth_type ~= 'dkim' then
+             break
+           end
+         end
+       end
       end
     end
+    if settings.routines['authentication-results'].remove then
+      remove[settings.routines['authentication-results'].header] = settings.routines['authentication-results'].remove
+    end
+    for auth_type, keys in pairs(auth_results) do
+      for _, key in ipairs(keys) do
+       local hdr = ''
+       if auth_type == 'dmarc' and key ~= 'none' then
+         hdr = hdr .. 'dmarc='
+         if key == 'reject' or key == 'quarantine' or key == 'softfail' then
+           hdr = hdr .. 'fail'
+         else
+           hdr = hdr .. key
+         end
+         if key == 'pass' then
+           hdr = hdr .. ' policy=' .. common.symbols[auth_types['dmarc'][key]][1]['options'][2]
+           hdr = hdr .. ' header.from=' .. common.symbols[auth_types['dmarc'][key]][1]['options'][1]
+         elseif key ~= 'none' then
+           local t = rspamd_str_split(common.symbols[auth_types['dmarc'][key]][1]['options'][1], ' : ')
+           local dom = t[1]
+           local rsn = t[2]
+           hdr = hdr .. ' reason="' .. rsn .. '"'
+           hdr = hdr .. ' header.from=' .. dom
+           if key == 'softfail' then
+             hdr = hdr .. ' policy=none'
+           else
+             hdr = hdr .. ' policy=' .. key
+           end
+         end
+         table.insert(hdr_parts, hdr)
+       elseif auth_type == 'dkim' and key ~= 'none' then
+         if common.symbols[auth_types['dkim'][key]][1] then
+           for _, v in ipairs(common.symbols[auth_types['dkim'][key]][1]['options']) do
+             hdr = hdr .. auth_type .. '=' .. key .. ' header.d=' .. v
+             table.insert(hdr_parts, hdr)
+           end
+         end
+       elseif auth_type == 'spf' and key ~= 'none' then
+         hdr = hdr .. auth_type .. '=' .. key
+         local smtp_from = task:get_from('smtp')
+         if smtp_from['addr'] ~= '' and smtp_from['addr'] ~= nil then
+           hdr = hdr .. ' smtp.mailfrom=' .. smtp_from['addr']
+         else
+           local helo = task:get_helo()
+           if helo then
+             hdr = hdr .. ' smtp.helo=' .. task:get_helo()
+           end
+         end
+         table.insert(hdr_parts, hdr)
+       end
+      end
+    end
+    if #hdr_parts > 0 then
+      add[settings.routines['authentication-results'].header] = table.concat(hdr_parts, '; ')
+    end
   end
-  if settings.routines['authentication-results'].remove then
-    remove[settings.routines['authentication-results'].header] = settings.routines['authentication-results'].remove
-  end
-  for auth_type, keys in pairs(auth_results) do
-    for _, key in ipairs(keys) do
-      local hdr = ''
-      if auth_type == 'dmarc' and key ~= 'none' then
-        hdr = hdr .. 'dmarc='
-        if key == 'reject' or key == 'quarantine' or key == 'softfail' then
-          hdr = hdr .. 'fail'
-        else
-          hdr = hdr .. key
-        end
-        if key == 'pass' then
-          hdr = hdr .. ' policy=' .. common_meta.symbols[auth_types['dmarc'][key]][1]['options'][2]
-          hdr = hdr .. ' header.from=' .. common_meta.symbols[auth_types['dmarc'][key]][1]['options'][1]
-        elseif key ~= 'none' then
-          local t = rspamd_str_split(common_meta.symbols[auth_types['dmarc'][key]][1]['options'][1], ' : ')
-          local dom = t[1]
-          local rsn = t[2]
-          hdr = hdr .. ' reason="' .. rsn .. '"'
-          hdr = hdr .. ' header.from=' .. dom
-          if key == 'softfail' then
-            hdr = hdr .. ' policy=none'
-          else
-            hdr = hdr .. ' policy=' .. key
-          end
+
+  for _, n in ipairs(active_routines) do
+    local ok, err
+    if custom_routines[n] then
+      local to_add, to_remove, common_in
+      ok, err, to_add, to_remove, common_in = pcall(custom_routines[n], task, common)
+      if ok then
+        for k, v in pairs(to_add) do
+          add[k] = v
         end
-        table.insert(hdr_parts, hdr)
-      elseif auth_type == 'dkim' and key ~= 'none' then
-        if common_meta.symbols[auth_types['dkim'][key]][1] then
-          for _, v in ipairs(common_meta.symbols[auth_types['dkim'][key]][1]['options']) do
-            hdr = hdr .. auth_type .. '=' .. key .. ' header.d=' .. v
-            table.insert(hdr_parts, hdr)
-          end
+        for k, v in pairs(to_remove) do
+          add[k] = v
         end
-      elseif auth_type == 'spf' and key ~= 'none' then
-        hdr = hdr .. auth_type .. '=' .. key
-        local smtp_from = task:get_from('smtp')
-        if smtp_from['addr'] ~= '' and smtp_from['addr'] ~= nil then
-          hdr = hdr .. ' smtp.mailfrom=' .. smtp_from['addr']
-        else
-          local helo = task:get_helo()
-          if helo then
-            hdr = hdr .. ' smtp.helo=' .. task:get_helo()
+        for k, v in pairs(common_in) do
+          if type(v) == 'table' then
+            if not common[k] then
+              common[k] = {}
+            end
+            for kk, vv in pairs(v) do
+              common[k][kk] = vv
+            end
+          else
+            common[k] = v
           end
         end
-        table.insert(hdr_parts, hdr)
       end
+    else
+      ok, err = pcall(routines[n])
     end
-  end
-  if #hdr_parts > 0 then
-    add[settings.routines['authentication-results'].header] = table.concat(hdr_parts, '; ')
-  end
-  return nil, add, remove, common
-end
-
-local function rmilter_headers(task)
-  local common_meta, to_add, to_remove = {}, {}, {}
-  for n, f in pairs(active_routines) do
-    local ok, err, add, remove, common = pcall(routines[f], task, common_meta)
     if not ok then
       logger.errx(task, 'call to %s failed: %s', n, err)
-    else
-      for k, v in pairs(add) do
-        to_add[k] = v
-      end
-      for k, v in pairs(remove) do
-        to_remove[k] = v
-      end
-      for k, v in pairs(common) do
-        if type(v) == 'table' then
-          if not common_meta[k] then
-            common_meta[k] = {}
-          end
-          for sk, sv in pairs(v) do
-            common_meta[k][sk] = sv
-          end
-        else
-          common_meta[k] = v
-        end
-      end
     end
   end
-  if not next(to_add) then to_add = nil end
-  if not next(to_remove) then to_remove = nil end
-  if to_add or to_remove then
+
+  if not next(add) then add = nil end
+  if not next(remove) then remove = nil end
+  if add or remove then
     task:set_rmilter_reply({
-      add_headers = to_add,
-      remove_headers = to_remove
+      add_headers = add,
+      remove_headers = remove
     })
   end
 end
@@ -338,29 +328,30 @@ end
 if type(opts['custom']) == 'table' then
   for k, v in pairs(opts['custom']) do
     local f, err = load(v)
-    if err then
+    if not f then
       logger.errx(rspamd_config, 'could not load "%s": %s', k, err)
     else
-      routines[k] = f
+      custom_routines[k] = f()
     end
   end
 end
 for _, s in ipairs(opts['use']) do
-  if not routines[s] then
-    logger.errx(rspamd_config, 'routine "%s" does not exist', s)
-  else
+  if (opts.routines and opts.routines[s]) or custom_routines[s] then
     table.insert(active_routines, s)
     if (opts.routines and opts.routines[s]) then
       for k, v in pairs(opts.routines[s]) do
         settings.routines[s][k] = v
       end
     end
+  else
+    logger.errx(rspamd_config, 'routine "%s" does not exist', s)
   end
 end
 if (#active_routines < 1) then
   logger.errx(rspamd_config, 'no active routines')
   return
 end
+logger.infox(rspamd_config, 'active routines [%s]', table.concat(active_routines, ','))
 rspamd_config:register_symbol({
   name = 'RMILTER_HEADERS',
   type = 'postfilter',