From 031638c08a4ce9d7ea156ead71cb8ef02e23fa81 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 9 Jun 2013 15:17:00 -0400 Subject: [PATCH] Use a hyphen instead of an underscore in the program name. Add a new -a parameter, to accept an 'A' record in addition to the MX required by default. Update the man page with the new option. --- doc/man1/email-validator.1 | 14 ++++++++++++-- email-validator.cabal | 2 +- makefile | 2 +- src/CommandLine.hs | 10 ++++++++-- src/Main.hs | 28 +++++++++++++++++++++++----- 5 files changed, 45 insertions(+), 11 deletions(-) diff --git a/doc/man1/email-validator.1 b/doc/man1/email-validator.1 index 3e56741..5fd7d10 100644 --- a/doc/man1/email-validator.1 +++ b/doc/man1/email-validator.1 @@ -5,7 +5,7 @@ email-validator \- Perform basic syntax and deliverability checks on email addre .SH SYNOPSIS -\fBemail-validator\fR [\fB\-h\fR] [\fB-i \fIFILE\fR] [\fB-o \fIFILE\fR] \fI\fR +\fBemail-validator\fR [\fB\-ha\fR] [\fB-i \fIFILE\fR] [\fB-o \fIFILE\fR] \fI\fR .SH INPUT @@ -33,10 +33,20 @@ A regular expression is used to check for invalid characters and syntax. .IP \[bu] We confirm the existence of a MX record for the domain part of the -address. +address. This is not required; in fact many domains accept mail via +an 'A' record for e.g. example.com which is used in lieu of an MX +record. This behavior can be controlled via the \fR\-a\fR flag. + +.P +These checks are performed in parallel using the number of available +threads. .SH OPTIONS +.IP \fB\-\-accept-a\fR,\ \fB\-a\fR +Accept an 'A' record for the domain instead of requiring an MX record +(the default). + .IP \fB\-\-input\fR,\ \fB\-i\fR Specify the input file containing a list of email addresses, rather than using stdin (the default). diff --git a/email-validator.cabal b/email-validator.cabal index 7ccf0f0..e080aa1 100644 --- a/email-validator.cabal +++ b/email-validator.cabal @@ -15,7 +15,7 @@ description: Perform basic syntax and deliverability checks on email addresses. -executable email_validator +executable email-validator build-depends: base == 4.*, bytestring == 0.10.*, diff --git a/makefile b/makefile index 7dd4524..2681fc3 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -BIN = dist/build/email_validator/email_validator +BIN = dist/build/email-validator/email-validator TESTSUITE_BIN = dist/build/testsuite/testsuite .PHONY : test dist hlint diff --git a/src/CommandLine.hs b/src/CommandLine.hs index 1088f2a..a7507df 100644 --- a/src/CommandLine.hs +++ b/src/CommandLine.hs @@ -17,7 +17,8 @@ import ExitCodes -- We optionally accept input/output files to use instead of -- stdin/stdout. -data Args = Args { input_file :: Maybe FilePath, +data Args = Args { accept_a :: Bool, + input_file :: Maybe FilePath, output_file :: Maybe FilePath } deriving (Show, Data, Typeable) @@ -30,6 +31,10 @@ program_name = "email-validator" my_summary :: String my_summary = program_name ++ "-" ++ (showVersion version) +accept_a_help :: String +accept_a_help = + "Accept an 'A' record for the domain instead of requiring an MX record." + input_file_help :: String input_file_help = "Path to the input file (default: stdin), one email address per line" @@ -41,7 +46,8 @@ output_file_help = arg_spec :: Mode (CmdArgs Args) arg_spec = cmdArgsMode $ - Args { input_file = def &= typFile &= help input_file_help, + Args { accept_a = def &= help accept_a_help, + input_file = def &= typFile &= help input_file_help, output_file = def &= typFile &= help output_file_help } &= program program_name &= summary my_summary diff --git a/src/Main.hs b/src/Main.hs index 9b22f5c..fc1b1b1 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -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 ( @@ -60,17 +60,35 @@ validate_mx resolver domain _ -> return True +-- | 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) + 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) @@ -112,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 -- 2.43.2