module DNS (
MxSetMap,
+ NormalDomain,
mx_set_map,
- normalize_string_domain )
+ normalize_string )
where
import qualified Data.ByteString.Char8 as BS ( pack, unpack )
normalize,
withResolver )
--- | A map from domain names (represented as 'String's) to sets of
--- mail exchanger names (also represented as 'String's).
+-- | A type-safe wrapper around a domain name (represented as a
+-- string) that ensures we've created it by calling
+-- 'normalize_string'. This prevents us from making
+-- comparisons on un-normalized 'Domain's or 'String's.
+--
+newtype NormalDomain =
+ NormalDomain String
+ deriving ( Eq, Ord, Show )
+
+
+-- | A set of mail exchanger names, represented as 'String's. The use
+-- of 'NormalDomain' prevents us from constructing a set of names
+-- that aren't normalized first.
--
-type MxSetMap = Map String MxSet
+type MxSet = Set NormalDomain
--- | A set of mail exchanger names, represented as 'String's.
-type MxSet = Set String
+
+-- | A map from domain names (represented as 'String's) to sets of
+-- mail exchanger names (also represented as 'String's). The use of
+-- 'NormalDomain' in the key prevents us from using keys that aren't
+-- normalized; this is important because we'll be using them for
+-- lookups and want e.g. \"foo.com\" and \"FOO.com\" to look up the
+-- same MX records.
+--
+type MxSetMap = Map NormalDomain MxSet
-- | Normalize a domain name string by converting to a 'Domain',
--
-- ==== __Examples__
--
--- >>> normalize_string_domain "ExAMplE.com"
--- "example.com."
+-- >>> normalize_string "ExAMplE.com"
+-- NormalDomain "example.com."
--
-normalize_string_domain :: String -> String
-normalize_string_domain = BS.unpack . normalize . BS.pack
+normalize_string :: String -> NormalDomain
+normalize_string = NormalDomain . BS.unpack . normalize . BS.pack
-- | Retrieve all MX records for the given domain. This is somewhat
-- domain name in the first component and a set of its mail
-- exchangers (as strings) in the second component.
--
- make_pair :: Domain -> IO (String, Set String)
+ make_pair :: Domain -> IO (NormalDomain, Set NormalDomain)
make_pair domain = do
-- Lookup the @domain@'s MX records.
mx_list <- lookup_mxs domain
- -- Now convert the MX records *back* to strings.
- let string_mx_list = map BS.unpack mx_list
+ -- Now convert the MX records *back* to strings, and then to
+ -- NormalDomains
+ let normal_mx_list = map (normalize_string . BS.unpack) mx_list
+
+ -- Convert the list into a set...
+ let normal_mx_set = Set.fromList normal_mx_list
- -- Convert the list into a set
- let string_mx_set = Set.fromList string_mx_list
+ -- The lookup key.
+ let normal_domain = normalize_string $ BS.unpack domain
-- Finally, construct the pair and return it.
- return (BS.unpack domain, string_mx_set)
+ return (normal_domain, normal_mx_set)