import Configuration (Cfg(..))
-- | A record containing values for all available options.
-data Options = Options { opt_heartbeat :: Maybe Int,
+data Options = Options { opt_consumer_key :: Maybe String,
+ opt_consumer_secret :: Maybe String,
+ opt_access_token :: Maybe String,
+ opt_access_secret :: Maybe String,
+ opt_heartbeat :: Maybe Int,
opt_help :: Bool,
opt_ignore_replies :: Bool,
opt_ignore_retweets :: Bool,
-- | Constructs an instance of Options, with each of its members set
-- to default values.
default_options :: Options
-default_options = Options { opt_heartbeat = Just 600,
+default_options = Options { opt_access_token = Nothing,
+ opt_access_secret = Nothing,
+ opt_consumer_key = Nothing,
+ opt_consumer_secret = Nothing,
+ opt_heartbeat = Just 600,
opt_help = False,
opt_ignore_replies = False,
opt_ignore_retweets = False,
options :: [OptDescr (Options -> IO Options)]
options =
[ Option
- ['h']["help"]
+ [] ["consumer_key"]
+ (ReqArg set_consumer_key "consumer_key")
+ "Your Twitter API consumer key.",
+
+ Option
+ [] ["consumer_secret"]
+ (ReqArg set_consumer_secret "consumer_secret")
+ "Your Twitter API consumer secret.",
+
+ Option
+ [] ["access_token"]
+ (ReqArg set_access_token "access_token")
+ "Your Twitter API access token.",
+
+ Option
+ [] ["access_secret"]
+ (ReqArg set_access_secret "access_secret")
+ "Your Twitter API access secret.",
+
+ Option
+ ['h'] ["help"]
(NoArg set_help)
"Prints this help message.",
Option
- ['n']["heartbeat"]
+ ['n'] ["heartbeat"]
(ReqArg set_heartbeat "heartbeat")
"How many seconds to wait between polling.",
Option
- ['t']["to"]
+ ['t'] ["to"]
(ReqArg set_to "email_address")
"Send tweets TO email_address.",
Option
- ['f']["from"]
+ ['f'] ["from"]
(ReqArg set_from "email_address")
"Send tweets FROM email_address.",
Option
- ['s']["sendmail_path"]
+ ['s'] ["sendmail_path"]
(ReqArg set_sendmail_path "sendmail_path")
"Use sendmail_path to send mail",
Option
- ['i']["ignore-replies"]
+ ['i'] ["ignore-replies"]
(NoArg set_ignore_replies)
"Ignore replies.",
Option
- ['I']["ignore-retweets"]
+ ['I'] ["ignore-retweets"]
(NoArg set_ignore_retweets)
"Ignore retweets.",
Option
- ['v']["verbose"]
+ ['v'] ["verbose"]
(NoArg set_verbose)
"Be verbose about stuff."
]
[(n,_)] -> Just n
_ -> Nothing
+set_consumer_key :: String -> Options -> IO Options
+set_consumer_key arg opts = do
+ return opts { opt_consumer_key = Just arg }
+
+set_consumer_secret :: String -> Options -> IO Options
+set_consumer_secret arg opts = do
+ return opts { opt_consumer_secret = Just arg }
+
+set_access_token :: String -> Options -> IO Options
+set_access_token arg opts = do
+ return opts { opt_access_token = Just arg }
+
+set_access_secret :: String -> Options -> IO Options
+set_access_secret arg opts = do
+ return opts { opt_access_secret = Just arg }
+
set_heartbeat :: String -> Options -> IO Options
set_heartbeat arg opts = do
let new_heartbeat = parse_int arg
-- | The usage header.
usage :: String
-usage = "Usage: twat [-n heartbeat] [-t to_address] [-f from_address] [-s path-to-sendmail] <username1> [username2, [username3]...]"
+usage = "Usage: twat --consumer_key=<key> --consumer_secret=<secret> --access_token=<key> --access_secret=<secret> [-n heartbeat] [-t to_address] [-f from_address] [-s path-to-sendmail] <username1> [username2, [username3]...]"
-- | Was the help option passed?
get_cfg :: IO Cfg
get_cfg = do
opts <- parse_options
- return Cfg { heartbeat = fromJust $ opt_heartbeat opts,
+ return Cfg { consumer_key = fromJust $ opt_consumer_key opts,
+ consumer_secret = fromJust $ opt_consumer_secret opts,
+ access_token = fromJust $ opt_access_token opts,
+ access_secret = fromJust $ opt_access_secret opts,
+ heartbeat = fromJust $ opt_heartbeat opts,
ignore_replies = opt_ignore_replies opts,
ignore_retweets = opt_ignore_retweets opts,
sendmail_path = opt_sendmail_path opts,
recurse :: Cfg -> String -> Integer -> (Maybe Message) -> IO ()
recurse cfg username latest_status_id maybe_message = do
thread_sleep (heartbeat cfg)
- timeline <- get_user_new_statuses username latest_status_id
+ timeline <- get_user_new_statuses cfg username latest_status_id
-- FIXME
let Just new_statuses = decode timeline :: Maybe Timeline
-- | Try continually to download username's timeline, and determine the
-- latest status id to be posted once we have done so.
-get_latest_status_id :: Int -> String -> IO Integer
-get_latest_status_id delay username = do
- timeline <- get_user_timeline username
+get_latest_status_id :: Cfg -> String -> IO Integer
+get_latest_status_id cfg username = do
+ let delay = heartbeat cfg
+ timeline <- get_user_timeline cfg username
let Just initial_timeline = decode timeline :: Maybe Timeline
case (length initial_timeline) of
-- If the HTTP part barfs, try again after a while.
putStrLn ("Couldn't retrieve " ++ username ++ "'s timeline. Retrying...")
thread_sleep delay
- get_latest_status_id delay username
+ get_latest_status_id cfg username
_ -> return (get_max_status_id initial_timeline)
-- should be emailed.
run_twat :: Cfg -> Maybe Message -> String -> IO ()
run_twat cfg msg username = do
- latest_status_id <- get_latest_status_id (heartbeat cfg) username
+ latest_status_id <- get_latest_status_id cfg username
recurse cfg username latest_status_id msg
return ()
-- And a Cfg object.
cfg <- get_cfg
-
+
-- If we have both a "To" and "From" address, we'll create a
-- message object to be passed to all of our threads.
let message = construct_message cfg
newOAuth,
signOAuth)
+import Configuration
+
-- |The API URL of username's timeline.
--
-- See,
"&since_id=" ++ (show last_status_id) ]
-get_status :: Integer -> IO B.ByteString
-get_status status_id = do
+get_status :: Cfg -> Integer -> IO B.ByteString
+get_status cfg status_id = do
let uri = status_url status_id
- http_get uri
+ http_get cfg uri
-- | Return's username's timeline.
-get_user_timeline :: String -> IO B.ByteString
-get_user_timeline username = do
+get_user_timeline :: Cfg -> String -> IO B.ByteString
+get_user_timeline cfg username = do
let uri = user_timeline_url username
- http_get uri
+ http_get cfg uri
-- | Returns the JSON representing all of username's statuses that are
-- newer than last_status_id.
-get_user_new_statuses :: String -> Integer -> IO B.ByteString
-get_user_new_statuses username last_status_id = do
+get_user_new_statuses :: Cfg -> String -> Integer -> IO B.ByteString
+get_user_new_statuses cfg username last_status_id = do
let uri = user_new_statuses_url username last_status_id
- http_get uri
+ http_get cfg uri
-- | Retrieve a URL, or crash.
-http_get :: String -> IO B.ByteString
-http_get url = do
+http_get :: Cfg -> String -> IO B.ByteString
+http_get cfg url = do
manager <- newManager def
request <- parseUrl url
responseBody response C.$$+- sinkLbs
where
- consumer_key = BC.pack ""
- consumer_secret = BC.pack ""
- access_token = BC.pack ""
- access_secret = BC.pack ""
+ consumer_key' = BC.pack (consumer_key cfg)
+ consumer_secret' = BC.pack (consumer_secret cfg)
+ access_token' = BC.pack (access_token cfg)
+ access_secret' = BC.pack (access_secret cfg)
oauth :: OAuth
oauth = newOAuth {
- oauthConsumerKey = consumer_key,
- oauthConsumerSecret = consumer_secret
+ oauthConsumerKey = consumer_key',
+ oauthConsumerSecret = consumer_secret'
}
credential :: Credential
- credential = newCredential access_token access_secret
+ credential = newCredential access_token' access_secret'