X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=src%2FMain.hs;h=fc1b1b18eba02c44d549de693cc8f3d65fd6ea1e;hb=031638c08a4ce9d7ea156ead71cb8ef02e23fa81;hp=293f953ac8b82a5952d759ee85c1a07dab13ca61;hpb=8096b134a33ace33ea23368353c011e9f68549c7;p=email-validator.git diff --git a/src/Main.hs b/src/Main.hs index 293f953..fc1b1b1 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -5,7 +5,7 @@ module Main where import Control.Concurrent.ParallelIO.Global (parallel, stopGlobalPool) -import Control.Monad (when) +import Control.Monad (unless) import qualified Data.ByteString as BS import qualified Data.ByteString.UTF8 as BSU import Network.DNS ( @@ -15,7 +15,7 @@ import Network.DNS ( defaultResolvConf, makeResolvSeed, withResolver) -import Network.DNS.Lookup (lookupMX) +import Network.DNS.Lookup (lookupA, lookupMX) import System.Directory (doesFileExist) import System.Exit (exitWith, ExitCode(..)) import System.IO ( @@ -26,12 +26,12 @@ import System.IO ( openFile, stdin, stdout) -import Text.Regex.PCRE.Light (compile, match, utf8) + import CommandLine (Args(..), apply_args) +import EmailAddress import ExitCodes (exit_input_file_doesnt_exist) -type Address = BSU.ByteString -- | Resolver parameters. We increase the default timeout from 3 to 5 -- seconds. @@ -59,57 +59,37 @@ validate_mx resolver domain Nothing -> return False _ -> return True --- | Split an address into local/domain parts. -parts :: Address -> (BSU.ByteString, BSU.ByteString) -parts address = bytestring_split address '@' --- | Check that the lengths of the local/domain parts are within spec. -validate_length :: Address -> Bool -validate_length address = - (BSU.length localpart <= 64) && (BSU.length domain <= 255) - where - (localpart, domain) = parts address - --- | Validate an email address against a simple regex. This should --- catch common addresses but disallows a lot of (legal) weird stuff. -validate_regex :: Address -> Bool -validate_regex address = - case matches of - Nothing -> False - _ -> True - where - regex_str = "(\\w+)([\\w\\-\\.]*)@(([0-9a-zA-Z\\-]+\\.)+)[a-zA-Z]{2,4}" - regex_bs = BSU.fromString regex_str - regex = compile regex_bs [utf8] - matches = match regex address [] - --- | Validate the syntax of an email address by checking its length --- and validating it against a simple regex. -validate_syntax :: Address -> Bool -validate_syntax address = - (validate_length address) && (validate_regex address) - --- | Split a 'ByteString' @s@ at the first occurrence of @character@. -bytestring_split :: BSU.ByteString -> Char -> (BSU.ByteString, BSU.ByteString) -bytestring_split s character = - (before, after) - where - break_func = (== character) - (before, rest) = BSU.break break_func s - after = BS.tail rest +-- | Check whether the given domain has a valid A record. +validate_a :: Resolver -> Domain -> IO Bool +validate_a resolver domain + | domain `elem` common_domains = return True + | otherwise = do + result <- lookupA resolver domain + case result of + Nothing -> return False + _ -> return True -- | Validate an email address by doing some simple syntax checks and -- (if those fail) an MX lookup. We don't count an A record as a mail -- exchanger. -validate :: Resolver -> Address -> IO (Address, Bool) -validate resolver address = do +validate :: Resolver -> Bool -> Address -> IO (Address, Bool) +validate resolver accept_a address = do let valid_syntax = validate_syntax address if valid_syntax then do let (_,domain) = parts address mx_result <- validate_mx resolver domain - return (address, mx_result) - else do + if mx_result + then return (address, True) + else + if accept_a + then do + a_result <- validate_a resolver domain + return (address, a_result) + else + return (address, False) + else return (address, False) @@ -132,7 +112,7 @@ main = do Nothing -> BS.hGetContents stdin Just path -> do is_file <- doesFileExist path - when (not is_file) $ do + unless is_file $ exitWith (ExitFailure exit_input_file_doesnt_exist) BS.readFile path @@ -150,7 +130,7 @@ main = do rs <- makeResolvSeed resolv_conf withResolver rs $ \resolver -> do -- Construst a list of [IO (Address, Bool)] - let actions = map (validate resolver) nonempty_addresses + let actions = map (validate resolver accept_a) nonempty_addresses -- And compute them in parallel. results <- parallel actions stopGlobalPool