-- This config acts as a sink that will discard all received mail
local kumo = require 'kumo'
package.path = 'assets/?.lua;' .. package.path
local utils = require 'policy-extras.policy_utils'

local SINK_DATA_FILE = os.getenv 'SINK_DATA'
  or '/opt/kumomta/etc/policy/responses.toml'

-- Resolve our hostname, then derive the docker network from that.
-- This assumes that the network is a /24 and that HOSTNAME is
-- injected by docker and resolves to the container IP on that network
local function resolve_docker_network()
  local MY_IPS = kumo.dns.lookup_addr(os.getenv 'HOSTNAME' or 'localhost')
  local DOCKER_NETWORK = string.match(MY_IPS[1], '^(.*)%.%d+$') .. '.0/24'
  return DOCKER_NETWORK
end

kumo.on('init', function()
  kumo.configure_accounting_db_path(os.tmpname())
  kumo.set_config_monitor_globs { SINK_DATA_FILE }
  local DOCKER_NETWORK = resolve_docker_network()
  local SINK_PORT = os.getenv 'SINK_PORT' or '25'
  kumo.start_esmtp_listener {
    listen = '0:' .. SINK_PORT,
    -- Explicitly an open relay, because we want to sink everything
    relay_hosts = { '0.0.0.0/0' },
    banner = 'This system will sink and discard all mail',
  }

  local SINK_HTTP = os.getenv 'SINK_HTTP' or '8000'
  kumo.start_http_listener {
    listen = '0.0.0.0:' .. SINK_HTTP,
    trusted_hosts = { '127.0.0.1', '::1', DOCKER_NETWORK },
  }

  -- Define spool locations
  -- This is unused by this config, but we are required to
  -- define a default spool location.

  local spool_dir = os.getenv 'SINK_SPOOL' or '/var/spool/kumomta'

  for _, name in ipairs { 'data', 'meta' } do
    kumo.define_spool {
      name = name,
      path = spool_dir .. '/' .. name,
    }
  end

  -- No logs are configured: we don't need them
end)

-- Load and parse the responses.toml data and resolve the configuration
-- for a given domain
local function load_data_for_domain(domain)
  local data = kumo.toml_load(SINK_DATA_FILE)
  local config = data.domain[domain] or data.default
  config.bounces = data.bounce[domain] or { { code = 550, msg = 'boing!' } }
  config.defers = data.defer[domain] or { { code = 451, msg = 'later!' } }
  return config
end

-- Cache the result of a load_data_for_domain call
local resolve_domain = kumo.memoize(load_data_for_domain, {
  name = 'response-data-cache',
  ttl = '1 hour',
  capacity = 100,
})

kumo.on('smtp_server_message_received', function(msg)
  local recipient = msg:recipient()

  -- Do any special responses requested by the client
  if string.find(recipient.user, 'tempfail') then
    kumo.reject(400, 'tempfail requested')
  end
  if string.find(recipient.user, 'permfail') then
    kumo.reject(500, 'permfail requested')
  end
  if utils.starts_with(recipient.user, '450-') then
    kumo.reject(450, 'you said ' .. recipient.user)
  end
  if utils.starts_with(recipient.user, '250-') then
    msg:set_meta('queue', 'null')
    return
  end

  -- Now any general bounce responses based on the toml file
  local domain = recipient.domain
  local config = resolve_domain(domain)

  local d100 = math.random(100)
  local selection = nil
  if d100 < config.bounce then
    selection = config.bounces
  elseif d100 < config.bounce + config.defer then
    selection = config.defers
  end

  if selection then
    local choice = selection[math.random(#selection)]
    kumo.reject(choice.code, choice.msg)
  end

  -- Finally, accept and discard any messages that haven't
  -- been rejected already
  msg:set_meta('queue', 'null')
end)

kumo.on('http_message_generated', function(msg)
  -- Accept and discard all messages
  msg:set_meta('queue', 'null')
end)
