1 -- | This module contains the 'DnsblSite' data type representing one
2 -- blacklist with its associated return codes and weight. For example,
3 -- in Postfix's main.cf you might have,
5 -- postscreen_dnsbl_sites = bl.mailspike.net=127.0.0.[2;10;11]*2, ...
7 -- Here, the 'Domain' is \"bl.mailspike.net\", the return code
8 -- pattern is \"127.0.0.[2;10;11]\", and the weight is \"2".
25 import Text.Parsec.String ( Parser )
26 import Text.Read ( readMaybe )
29 import IPv4Pattern ( IPv4Pattern )
31 newtype Weight = Weight Int deriving (Eq, Show)
33 -- | Parse the weight multiplier at the end of a dnsbl_site.
37 -- >>> import Text.Parsec ( parseTest )
39 -- Negative, zero, and positive integers are all supported:
41 -- >>> parseTest weight "*-5"
44 -- >>> parseTest weight "*0"
47 -- >>> parseTest weight "*17"
50 -- A bare asterisk doesn't work:
52 -- >>> parseTest weight "*"
53 -- parse error at (line 1, column 2):
54 -- unexpected end of input
55 -- expecting "-", "+" or digit
57 -- If the weight is empty, it defaults to @1@:
59 -- >>> parseTest weight ""
62 -- But the default is only used if the weight is really empty,
63 -- not if parsing simply fails:
65 -- >>> parseTest weight "*hello"
66 -- parse error at (line 1, column 2):
68 -- expecting "-", "+" or digit
70 weight :: Parser Weight
71 weight = try parse_weight <|> (eof >> return (Weight 1))
75 sign <- (char '-') <|> (option '+' (char '+'))
77 case ( readMaybe w :: Maybe Int ) of
78 -- If "many1 digit" gives us a list of digits, we should be able
79 -- to convert that to an Int! It will overflow rather than fail
80 -- if the input is too big/small, so it should really always
82 Nothing -> unexpected "weight: readMaybe failed on a sequence of digits!"
83 Just k -> return $ Weight (if sign == '-' then negate k else k)
85 newtype Domain = Domain String
87 data DnsblSite = DnsblSite Domain IPv4Pattern Weight