Add weight parsing to DnsblSite.hs.
authorMichael Orlitzky <michael@orlitzky.com>
Sun, 5 Jul 2015 06:15:17 +0000 (02:15 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Sun, 5 Jul 2015 06:15:17 +0000 (02:15 -0400)
src/DnsblSite.hs

index df4437d23be1ba77ea16e0c601c9756f18353606..24d8c96e84b72b6368c30abd4c62fa0c076fd246 100644 (file)
@@ -1,18 +1,88 @@
 -- | This module contains the 'DnsblSite' data type representing one
---   blacklist with its associated return codes and multiplier. For example,
+--   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 multiplier is \"2".
+--   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
-newtype Multiplier = Multiplier Int
 
-data DnsblSite = DnsblSite Domain IPv4Pattern Multiplier
+data DnsblSite = DnsblSite Domain IPv4Pattern Weight
+