-- | This module contains the 'DnsblSite' data type representing one -- blacklist with its associated return codes and weight. For example, -- in Postfix's main.cf you might have, -- -- postscreen_dnsbl_sites = bl.mailspike.net=127.0.0.[2;10;11]*2, ... -- -- Here, the 'Domain' is \"bl.mailspike.net\", the return code -- pattern is \"127.0.0.[2;10;11]\", and the weight is \"2". -- module DnsblSite where import Text.Parsec ( ParseError, (<|>), char, digit, eof, many1, option, parse, string, try, unexpected ) import Text.Parsec.String ( Parser ) import Text.Read ( readMaybe ) import IPv4Pattern ( IPv4Pattern ) newtype Weight = Weight Int deriving (Eq, Show) -- | Parse the weight multiplier at the end of a dnsbl_site. -- -- ==== _Examples_ -- -- >>> import Text.Parsec ( parseTest ) -- -- Negative, zero, and positive integers are all supported: -- -- >>> parseTest weight "*-5" -- Weight (-5) -- -- >>> parseTest weight "*0" -- Weight 0 -- -- >>> parseTest weight "*17" -- Weight 17 -- -- A bare asterisk doesn't work: -- -- >>> parseTest weight "*" -- parse error at (line 1, column 2): -- unexpected end of input -- expecting "-", "+" or digit -- -- If the weight is empty, it defaults to @1@: -- -- >>> parseTest weight "" -- Weight 1 -- -- But the default is only used if the weight is really empty, -- not if parsing simply fails: -- -- >>> parseTest weight "*hello" -- parse error at (line 1, column 2): -- unexpected "h" -- expecting "-", "+" or digit -- weight :: Parser Weight weight = try parse_weight <|> (eof >> return (Weight 1)) where parse_weight = do _ <- char '*' sign <- (char '-') <|> (option '+' (char '+')) w <- many1 digit case ( readMaybe w :: Maybe Int ) of -- If "many1 digit" gives us a list of digits, we should be able -- to convert that to an Int! It will overflow rather than fail -- if the input is too big/small, so it should really always -- succeed. Nothing -> unexpected "weight: readMaybe failed on a sequence of digits!" Just k -> return $ Weight (if sign == '-' then negate k else k) newtype Domain = Domain String data DnsblSite = DnsblSite Domain IPv4Pattern Weight