# -*- ruby -*-

configuration = @configuration
trust = Object.new
trust.instance_eval do
  @configuration = configuration
end

class << trust
  def clear
    @envelope_from_domains = []
  end

  def add_envelope_from_domain(domain_matcher=Proc.new)
    @envelope_from_domains << domain_matcher
  end

  def trusted_envelope_from_domain?(envelope_from)
    user, domain = parse_envelope_from(envelope_from)
    return false if domain.nil?
    match?(@envelope_from_domains, normalize_domain(domain))
  end

  def load_envelope_from_domains(path)
    resolved_paths = @configuration.resolve_path(path)
    resolved_paths.each do |resolved_path|
      parse_envelope_from_domain_list_file(resolved_path)
    end
  end

  private
  def normalize_domain(domain)
    domain.downcase
  end

  def match?(list, host)
    list.any? do |matcher|
      if matcher.respond_to?(:call)
        matcher.call(host)
      else
        matcher === host
      end
    end
  end

  def parse_envelope_from(envelope_from)
    user = domain = nil
    if /\A<(.+?)@(.+?)>\z/ =~ envelope_from
      user = $1
      domain = $2
    end
    [user, domain]
  end

  def parse_envelope_from_domain_list_file(path)
    File.open(path) do |file|
      file.each_line do |line|
        case line
        when /^\s*#/, /^\s*$/
          # comment or empty line
        when /^\s*\/(.+)\/\s*$/
          add_envelope_from_domain(Regexp.new($1, Regexp::IGNORECASE))
        else
          add_envelope_from_domain(normalize_domain(line.strip))
        end
      end
    end
  end
end

trust.clear

singleton_class = class << self; self; end
singleton_class.send(:define_method, :trust) do
  trust
end

trust.add_envelope_from_domain("gmail.com")
trust.add_envelope_from_domain("hotmail.com")
trust.add_envelope_from_domain("msn.com")
trust.add_envelope_from_domain("yahoo.co.jp")
trust.add_envelope_from_domain("softbank.ne.jp")
trust.add_envelope_from_domain("ezweb.ne.jp")
trust.add_envelope_from_domain("docomo.ne.jp")
trust.add_envelope_from_domain("clear-code.com")

define_applicable_condition("Trust") do |condition|
  condition.description = "Set {trusted_*}=yes macros for trusted session"

  condition.define_envelope_from_stopper do |context, from|
    if trust.trusted_envelope_from_domain?(from)
      context["trusted_domain"] = "yes"
    end
    false
  end
end
