packages feed

hxmppc-0.2: hxmppc.hs

{-# LANGUAGE OverloadedStrings, TemplateHaskell, TypeOperators #-}
import Network.Protocol.XMPP (Message(..), MessageType(..), ReceivedStanza(..),
                              parseJID, getStanza, putStanza)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Network (PortID(..), PortNumber)
import System.Environment (getArgs)
import System.Exit (exitSuccess, exitFailure)
import System.IO (stderr)
import Control.Monad
import Control.Monad.IO.Class
import Data.Functor
import EasyXMPP
import Data.Record.Label
-- import Control.Arrow
import System.Console.GetOpt

data Settings = Settings { _user :: T.Text
                         , _pass :: T.Text
                         , _host :: String
                         , _port :: PortNumber
                         , _help :: Bool
                         }
$(mkLabels [''Settings])
type Flag = Settings -> Settings

defaultSettings :: Settings
defaultSettings = Settings { _user = ""
                           , _pass = ""
                           , _host = ""
                           , _port = 5222
                           , _help = False
                           }

options :: [OptDescr Flag]
options =
  [ Option "u" ["user"] (ReqArg (setL user . T.pack)             "USER") "Username (example: foo@jabber.org)"
  , Option "p" ["pass"] (ReqArg (setL pass . T.pack)             "PASS") "Password"
  , Option "h" ["host"] (ReqArg (setL host)                      "HOST") "Hostname (example: jabber.org)"
  , Option "P" ["port"] (ReqArg (setL port . fromInteger . read) "PORT") "Port"
  , Option "?" ["help"] (NoArg (setL help True))                         "Show this help message"
  ]

usage :: MonadIO m => T.Text -> m b
usage msg = liftIO $ T.hPutStrLn stderr msg' >> exitFailure
  where msg' = T.unlines [T.pack $ usageInfo "Usage: hxmppc [<option>*] <command>" options
                         ,"command ::= tell <destination-user> <message>*"
                         ,"          | wait"
                         ,""
                         ,msg
                         ]

main :: IO ()
main = do
  (flags, nonopts, errs) <- getOpt Permute options <$> getArgs
  let opts = foldr ($) defaultSettings flags
  when (not . null $ errs) $ usage (T.concat . map T.pack $ errs)
  when (getL help opts) $ usage ""
  when (T.null $ getL user opts) $ usage "Missing username"
  when (T.null $ getL pass opts) $ usage "Missing password"
  when (null   $ getL host opts) $ usage "Missing hostname"
  let Just botJID = parseJID (getL user opts)

  res <- runPersistentClient (botJID, getL pass opts) (getL host opts, PortNumber (getL port opts)) $ do
    case map T.pack nonopts of
      "tell" : args -> do
        case args of
          []  -> usage "`tell' expects a destination user and a message"
          [_] -> usage "`tell' expects a message as well"
          (to:msg) -> do
             toJID <- maybe (usage "`tell' bad format for destination user") return $ parseJID to
             putStanza $ mkMsg toJID (T.unwords msg)
             _ <- getStanza
             liftIO exitSuccess
      "wait" : args -> do
        case args of
          [] ->
            forever $ do
              message <- getStanza
              case message of
                ReceivedMessage msg | messageType msg /= MessageError ->
                  let text = maybe "" ((<>": "). T.pack . show) (messageFrom msg) <> extractMsg msg in
                  liftIO (T.putStrLn text >> exitSuccess)
                _ -> return ()
          _ -> usage "`wait' expects no arguments"
      [] -> usage $ "no command"
      cmd : _ -> usage $ "no such command " <> cmd
  case res of
    Left err -> usage $ "XMPP error:" <> T.pack (show err)
    Right _  -> return ()