import Data.Maybe (fromJust, isJust, isNothing)
import System.Console.GetOpt
+import System.Directory (doesFileExist)
import System.Environment (getArgs)
import Configuration (Cfg(..))
opt_help :: Bool,
opt_ignore_replies :: Bool,
opt_ignore_retweets :: Bool,
+ opt_sendmail_path :: FilePath,
opt_from :: Maybe String,
opt_to :: Maybe String,
opt_verbose :: Bool }
opt_help = False,
opt_ignore_replies = False,
opt_ignore_retweets = False,
+ opt_sendmail_path = "/usr/sbin/sendmail",
opt_from = Nothing,
opt_to = Nothing,
opt_verbose = False }
(ReqArg set_from "email_address")
"Send tweets FROM email_address.",
+ Option
+ ['s']["sendmail_path"]
+ (ReqArg set_sendmail_path "sendmail_path")
+ "Use sendmail_path to send mail",
+
Option
['i']["ignore-replies"]
(NoArg set_ignore_replies)
set_verbose opts =
return opts { opt_verbose = True }
+set_sendmail_path :: String -> Options -> IO Options
+set_sendmail_path arg opts = do
+ return opts { opt_sendmail_path = arg }
+
set_to :: String -> Options -> IO Options
set_to arg opts = do
return opts { opt_to = Just arg }
-- | The usage header.
usage :: String
-usage = "Usage: twat [-n heartbeat] [-t to_address] [-f from_address] <username1> [username2, [username3]...]"
+usage = "Usage: twat [-n heartbeat] [-t to_address] [-f from_address] [-s path-to-sendmail] <username1> [username2, [username3]...]"
-- | Was the help option passed?
then return ["\"heartbeat\" does not appear to be an integer."]
else return []
--- |Parse errors relating to the list of usernames.
+-- | Parse errors relating to the list of usernames.
username_errors :: IO [String]
username_errors = do
argv <- getArgs
else return []
--- |Parse errors relating to the "To" address.
+-- | Parse errors relating to the "To" address.
to_errors :: IO [String]
to_errors = do
toaddr <- parse_to_address
else return []
+-- | Errors for the sendmail path argument.
+sendmail_path_errors :: IO [String]
+sendmail_path_errors = do
+ sendmail <- parse_sendmail_path
+ exists <- doesFileExist sendmail
+ if (not exists)
+ then return ["sendmail path does not exist"]
+ else return []
+
+
-- | Parse errors relating to the "From" address.
from_errors :: IO [String]
from_errors = do
errs_username <- username_errors
errs_to <- to_errors
errs_from <- from_errors
+ errs_sendmail <- sendmail_path_errors
return $ map format_error (errors ++
errs_heartbeat ++
errs_username ++
+ errs_sendmail ++
errs_to ++
errs_from)
opts <- parse_options
return (opt_to opts)
+-- | What sendmail path was given on the command line?
+parse_sendmail_path :: IO FilePath
+parse_sendmail_path = do
+ opts <- parse_options
+ return (opt_sendmail_path opts)
+
-- | What "From" address was given on the command line?
parse_from_address :: IO (Maybe String)
parse_from_address = do
return Cfg { heartbeat = fromJust $ opt_heartbeat opts,
ignore_replies = opt_ignore_replies opts,
ignore_retweets = opt_ignore_retweets opts,
+ sendmail_path = opt_sendmail_path opts,
from_address = opt_from opts,
to_address = opt_to opts,
verbose = opt_verbose opts }
-- |Showing a message will print it in roughly RFC-compliant
-- form. This form is sufficient for handing the message off to
--- sendmail.
+-- sendmail (or compatible).
instance Show Message where
show m =
concat [ if (length (headers m) == 0) then "" else (intercalate "\n" (headers m)) ++ "\n",
-- |Takes a message as an argument, and passes it to the system's
--- sendmail binary.
-sendmail :: Message -> IO (String, String, ExitCode)
-sendmail message = do
+-- sendmail (or compatible) binary.
+sendmail :: FilePath -> Message -> IO (String, String, ExitCode)
+sendmail sendmail_path message = do
let sendmail_args = ["-f",
(from message)]
(inh, outh, errh, ph) <-
- runInteractiveProcess "/usr/bin/sendmail" sendmail_args Nothing Nothing
+ runInteractiveProcess sendmail_path sendmail_args Nothing Nothing
outm <- newEmptyMVar
outs <- hGetContents outh
-- | If the given Message is not Nothing, send a copy of it for every
-- Status in the list.
-send_messages :: Maybe Message -> [Status] -> IO ()
-send_messages maybe_message statuses =
+send_messages :: Cfg -> Maybe Message -> [Status] -> IO ()
+send_messages cfg maybe_message statuses =
case maybe_message of
Nothing -> return ()
Just message -> do
default_date <- rfc822_now
let mfs = message_from_status message (default_date)
let messages = map mfs statuses
- sendmail_results <- mapM sendmail messages
+ sendmail_results <- mapM sendmail' messages
_ <- mapM print_sendmail_result sendmail_results
return ()
-
-
+ where
+ sendmail' = sendmail (sendmail_path cfg)
-- | Display the number of skipped replies if ignore_replies is true
-- and verbose is enabled.
_ <- mapM (putStrLn . pretty_print) good_statuses
- send_messages maybe_message good_statuses
+ send_messages cfg maybe_message good_statuses
let new_latest_status_id = get_max_status_id new_statuses
do_recurse new_latest_status_id
-- | A debugging tool that will parse, print, and email a single
-- status (given by its id).
-twat_single_status :: Integer -> (Maybe Message) -> IO ()
-twat_single_status the_status_id maybe_message = do
+twat_single_status :: Cfg -> Integer -> (Maybe Message) -> IO ()
+twat_single_status cfg the_status_id maybe_message = do
xmldata <- get_status the_status_id
-- Parsing an empty result can blow up. Just pretend there are
Just message -> do
default_date <- rfc822_now
let messages = map (message_from_status message (default_date)) statuses
- sendmail_results <- mapM sendmail messages
+ sendmail_results <- mapM sendmail' messages
_ <- mapM print_sendmail_result sendmail_results
return ()
+ where
+ sendmail' = sendmail (sendmail_path cfg)
\ No newline at end of file