// Is a sender on a blocklist? An address asked of several lists at once with each return code
// named, IPv6 by its nibbles, a domain, a list's refusal kept apart from a listing, and a list that
// never answers not holding up the rest.
//
//   DNSBL_SERVER=127.0.0.1 quillo run dnsbl.qwe      then open http://localhost:8080/ip?address=127.0.0.2, /ip6, /domain and /trouble
//
// DNSBL_SERVER is your own resolver (ip or ip:port). Spamhaus refuses public resolvers such as
// 8.8.8.8, which is what `error` then says.

use "dnsbl.qwer"

route GET /ip ? { address: str = "127.0.0.2" } {
    let r = dnsbl_check_ip(address, {})
    if is_err(r) { reply 400 r.error }
    { listed: r.listed, hits: r.hits, score: r.score, codes: map(filter(r.lists, (l) => l.listed), (l) => l.codes) }
}

route GET /clean = dnsbl_check_ip("127.0.0.1", {})?

route GET /reverse = {
    v4: dnsbl_reverse("192.0.2.99")?,
    v6: dnsbl_reverse("2001:db8::1")?,
    bad: dnsbl_reverse("not.an.ip").error,
}

route GET /ip6 {
    let r = dnsbl_check_ip("::ffff:7f00:2", { lists: ["zen.spamhaus.org", "bl.spamcop.net"] })?
    { hits: r.hits, skipped: r.lists[1].skipped, code: r.lists[0].codes[0].meaning }
}

route GET /domain {
    let r = dnsbl_check_domain("Bad-Domain.TEST.", {})?
    {
        subject: r.subject,
        hits: r.hits,
        meanings: map(filter(r.lists, (l) => l.listed), (l) => l.codes[0].meaning),
        clean: dnsbl_check_domain("good-domain.test", {})?.listed,
        not_domain: dnsbl_check_domain("127.0.0.2", {}).error,
        idn: dnsbl_check_domain("bücher.example", {}).error,
    }
}

// A list of our own with weights and words, one that refuses, one that fails, one that says
// nothing, and a long reason sent over TCP since it did not fit in UDP.
route GET /trouble {
    let lists = [
        { zone: "own.example", weight: 2.5, codes: { "127.0.0.9": "seen in our own trap" } },
        "public.example",
        "broken.example",
        "silent.example",
        "zen.spamhaus.org",
    ]
    let r = dnsbl_check_ip("127.0.0.2", { lists, timeout_ms: 200, tries: 2 })?
    { score: r.score, errors: r.errors, own: r.lists[0], broken: r.lists[2].error, silent: contains(r.lists[3].error, "no answer"), reason_length: len(r.lists[4].reason) }
}

route GET /names = {
    known: len(dnsbl_known_lists()),
    xbl: dnsbl_code_name("zen.spamhaus.org", "127.0.0.4"),
    pbl: dnsbl_code_name("zen.spamhaus.org", "127.0.0.11"),
    phish: dnsbl_code_name("dbl.spamhaus.org", "127.0.1.4"),
    surbl: dnsbl_code_name("multi.surbl.org", "127.0.0.24"),
    uribl: dnsbl_code_name("multi.uribl.com", "127.0.0.14"),
    public: dnsbl_code_name("zen.spamhaus.org", "127.255.255.254"),
}
