]> gitweb.michael.orlitzky.com - dead/harbl.git/blob - src/DnsblSite.hs
Add Pretty instances for Lists and pairs.
[dead/harbl.git] / src / DnsblSite.hs
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,
4 --
5 -- postscreen_dnsbl_sites = bl.mailspike.net=127.0.0.[2;10;11]*2, ...
6 --
7 -- Here, the blacklist (a 'UserDomain') is \"bl.mailspike.net\", the
8 -- return code pattern is \"127.0.0.[2;10;11]\", and the weight is
9 -- \"2".
10 --
11 module DnsblSite ()
12 where
13
14 import Text.Parsec (
15 ParseError,
16 (<|>),
17 char,
18 digit,
19 eof,
20 many1,
21 option,
22 parse,
23 string,
24 try,
25 unexpected )
26 import Text.Parsec.String ( Parser )
27 import Text.Read ( readMaybe )
28
29 import Domain ( UserDomain )
30 import IPv4Pattern ( IPv4Pattern )
31
32 newtype Weight = Weight Int deriving (Eq, Show)
33
34 -- | Parse the weight multiplier at the end of a dnsbl_site.
35 --
36 -- ==== _Examples_
37 --
38 -- >>> import Text.Parsec ( parseTest )
39 --
40 -- Negative, zero, and positive integers are all supported:
41 --
42 -- >>> parseTest weight "*-5"
43 -- Weight (-5)
44 --
45 -- >>> parseTest weight "*0"
46 -- Weight 0
47 --
48 -- >>> parseTest weight "*17"
49 -- Weight 17
50 --
51 -- A bare asterisk doesn't work:
52 --
53 -- >>> parseTest weight "*"
54 -- parse error at (line 1, column 2):
55 -- unexpected end of input
56 -- expecting "-", "+" or digit
57 --
58 -- If the weight is empty, it defaults to @1@:
59 --
60 -- >>> parseTest weight ""
61 -- Weight 1
62 --
63 -- But the default is only used if the weight is really empty,
64 -- not if parsing simply fails:
65 --
66 -- >>> parseTest weight "*hello"
67 -- parse error at (line 1, column 2):
68 -- unexpected "h"
69 -- expecting "-", "+" or digit
70 --
71 weight :: Parser Weight
72 weight = try parse_weight <|> (eof >> return (Weight 1))
73 where
74 parse_weight = do
75 _ <- char '*'
76 sign <- (char '-') <|> (option '+' (char '+'))
77 w <- many1 digit
78 case ( readMaybe w :: Maybe Int ) of
79 -- If "many1 digit" gives us a list of digits, we should be able
80 -- to convert that to an Int! It will overflow rather than fail
81 -- if the input is too big/small, so it should really always
82 -- succeed.
83 Nothing -> unexpected "weight: readMaybe failed on a sequence of digits!"
84 Just k -> return $ Weight (if sign == '-' then negate k else k)
85
86
87 data DnsblSite = DnsblSite UserDomain IPv4Pattern Weight