Add the Twitter API oAuth stuff to the configuration and command line.
authorMichael Orlitzky <michael@orlitzky.com>
Tue, 9 Jul 2013 16:55:32 +0000 (12:55 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Tue, 9 Jul 2013 16:55:32 +0000 (12:55 -0400)
src/CommandLine.hs
src/Configuration.hs
src/Main.hs
src/Twitter/Http.hs

index 699de08f0abfff26cbc5b98698e75b417516b518..39ff5b2ecd76ae3f394977d66fcfdb36333bc79a 100644 (file)
@@ -17,7 +17,11 @@ import System.Environment (getArgs)
 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,
@@ -30,7 +34,11 @@ data Options = Options { opt_heartbeat :: Maybe Int,
 -- | 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,
@@ -51,42 +59,62 @@ default_options = Options { opt_heartbeat = Just 600,
 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."
   ]
@@ -100,6 +128,22 @@ parse_int s =
     [(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
@@ -136,7 +180,7 @@ set_from arg opts = do
 
 -- | 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?
@@ -275,7 +319,11 @@ parse_usernames = do
 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,
index e83dc29c8616e755048cb4c39d0461da750c1766..5e84368b6853a4d85c1a293f0fd44b484ff4f4a3 100644 (file)
@@ -6,7 +6,11 @@ module Configuration (
 )
 where
 
-data Cfg = Cfg { heartbeat :: Int,
+data Cfg = Cfg { consumer_key :: String,
+                 consumer_secret :: String,
+                 access_token :: String,
+                 access_secret :: String,
+                 heartbeat :: Int,
                  ignore_replies :: Bool,
                  ignore_retweets :: Bool,
                  sendmail_path :: String,
index bf99fe853fd2e947a5e1508cb8eeb9ddf92d835f..8c81555c60075952980b48198d3ee1f38ab5ec7e 100644 (file)
@@ -104,7 +104,7 @@ filter_statuses cfg ss =
 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
@@ -137,9 +137,10 @@ recurse cfg username latest_status_id maybe_message = do
 
 -- | 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
@@ -147,7 +148,7 @@ get_latest_status_id delay username = do
       -- 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)
 
 
@@ -159,7 +160,7 @@ get_latest_status_id delay username = do
 --   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 ()
 
@@ -205,7 +206,7 @@ main = do
 
   -- 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
index c8b8e470b5d0f9cfafdaea0df39b89fbf26f495a..6d055b90f0da7444568670f39586ab6fbc790a87 100644 (file)
@@ -13,6 +13,8 @@ import Web.Authenticate.OAuth (
   newOAuth,
   signOAuth)
 
+import Configuration
+
 -- |The API URL of username's timeline.
 --
 -- See,
@@ -47,30 +49,30 @@ user_new_statuses_url username last_status_id =
            "&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
 
@@ -80,16 +82,16 @@ http_get url = do
     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'