{-# LANGUAGE PatternGuards, BangPatterns, DeriveDataTypeable, OverloadedStrings, ScopedTypeVariables, TemplateHaskell #-} -- DeriveGeneric, StandaloneDeriving {- | Types and settings. Copyright (c) Don Stewart 2008-2009, Simon Michael 2009-2014 License: BSD3. -} module Base where import Control.Concurrent.STM (TChan) -- import Control.DeepSeq (NFData) import Control.Exception import Control.Monad.IO.Class (MonadIO, liftIO) -- import GHC.Generics import Data.Time () import Data.Time.Clock import Data.Typeable import Network.HTTP.Conduit (Manager) import System.Console.CmdArgs import System.IO (Handle) -- import Text.Feed.Types import Text.Printf (printf) progname = "rss2irc" version = "1.2" -- sync with rss2irc.cabal progversion = progname ++ " " ++ version :: String defport = 6667 defusername = progname defrealname = progname ++ " feed announcer" defuseragent :: String defuseragent = progversion definterval = 5 defidle = 0 defmaxitems = 5 maxmessagelength = 400 -- | Maximum size of each part of our irc announcements. -- The max announcement length will be the sum of these, plus typically 15 -- due to prettification, plus any length increase due to --replace. The -- defaults below should keep most announcements within maxmessagelength -- and all announcements within maxmessagelength * 2 or so. maxtitlelength = 100 maxdesclength = 300 maxauthorlength = 50 maxdatelength = 50 maxlinklength = 200 progname, version, progversion, defusername, defrealname :: String defport, definterval, defidle, defmaxitems, maxmessagelength, maxtitlelength, maxdesclength, maxauthorlength, maxdatelength, maxlinklength :: Int defopts :: Opts defopts = Opts { ident = defrealname &= typ "STR" &= help "set the bot's identity string (useful for contact info)" ,uagent = defuseragent &= typ "STR" &= help "set the bot's Http UserAgent string " ,delay = def &= help "wait for N minutes before starting (helps avoid mass joins)" ,interval = definterval &= name "i" &= help ("polling and announcing interval in minutes (default "++(show definterval)++")") ,cache_control = def &= explicit &= name "cache-control" &= typ "STR" &= help ("set a HTTP cache-control header when polling") ,idle = defidle &= help ("announce only when channel has been idle N minutes (default "++(show defidle)++")") ,max_items = defmaxitems &= help ("announce at most N items per interval (default "++(show defmaxitems)++")") ,recent = def &= name "r" &= help "announce up to N recent items at startup (default 0)" ,ignore_ids_and_times = def &= help "ignore feed item IDs and timestamps (use for feeds with bad ones)" ,allow_duplicates = def &= help "turn off duplicate announcement protection (enabled by default)" ,use_actions = def &= help "use CTCP ACTIONs instead of normal IRC messages" ,no_title = def &= help ("don't show item title (shown by default, up to "++(show maxtitlelength)++" chars)") ,author = def &= name "a" &= help ("show author (up to "++(show maxauthorlength)++" chars)") ,description = def &= name "d" &= help ("show description (up to "++(show maxdesclength)++" chars)") ,link_ = def &= help ("show link URL (up to "++(show maxlinklength)++" chars)") ,time = def &= help ("show timestamp (up to "++(show maxdatelength)++" chars)") ,email = def &= help "show email addresses (stripped by default)" ,html = def &= help "show HTML tags and entities (stripped by default)" ,replace = def &= typ "OLD/NEW" &= help "replace OLD with NEW (regexpr patterns)" ,num_iterations = def &= name "n" &= help "exit after N iterations" ,quiet = def &= help "silence normal console output" ,debug_irc = def &= help "log irc activity" ,debug_feed = def &= help "log feed items and polling stats" ,debug_xml = def &= help "log feed content" ,feed = def &= argPos 0 &= typ "FEEDURL" ,irc_address = def &= argPos 1 &= opt ("" :: String) &= typ "IRCSERVER[:PORT]/CHANNEL/NICK" } &= program progname &= groupname progname &= summary progversion data Opts = Opts { ident :: String ,uagent :: String ,delay :: Int ,interval :: Int ,cache_control :: String ,idle :: Int ,max_items :: Int ,recent :: Int ,ignore_ids_and_times :: Bool ,allow_duplicates :: Bool ,use_actions :: Bool ,no_title :: Bool ,author :: Bool ,description :: Bool ,link_ :: Bool ,time :: Bool ,email :: Bool ,html :: Bool ,replace :: [String] ,num_iterations :: (Maybe Int) ,quiet :: Bool ,debug_irc :: Bool ,debug_feed :: Bool ,debug_xml :: Bool ,feed :: String ,irc_address :: String } deriving (Show, Data, Typeable) data Reader = Reader { httpManager :: !(Maybe Manager) , iterationsleft :: !(Maybe Int) } deriving (Show) instance Show Manager where show = const "(Manager)" data Bot = Bot { socket :: !Handle -- ^ the bot's active IRC connection, or stdout indicating none , server :: !String -- ^ the IRC server's hostname or IP address, or "" indicating none , port :: !Int -- ^ the IRC server's port number , channel :: !String -- ^ the IRC channel to join , botnick :: !String -- ^ the bot's IRC nickname , announcequeue :: !(TChan String) -- ^ a shared queue of messages to be announced , batchindex :: !Int -- ^ how many announcements have been made in the current batch , lastmsgtime :: !UTCTime -- ^ the last time somebody spoke on the IRC channel } instance Show Bot where show Bot{socket=s,server=srv,port=p,channel=c,botnick=n,lastmsgtime=t} = printf "Bot{botnick=%s, socket=%s, server=%s, port=%d, channel=%s, lastmsgtime=%s}" n (show s) srv p c (show t) -- | rss2irc's application state, shared by all threads. data App = App {aOpts :: !Opts -- ^ initial command-line options ,aReader :: !Reader -- ^ the feed reader's state ,aBot :: !Bot -- ^ the irc bot's state } deriving (Show) type FeedAddress = String data FeedParseException = FeedParseException String deriving (Typeable) instance Exception FeedParseException instance Show FeedParseException where show (FeedParseException url) = printf "could not parse feed content from %s" url data IrcAddress = IrcAddress {ircaddrServer :: !String, ircaddrPort :: !(Maybe Int), ircaddrChannel :: !String, ircaddrNick :: !String } deriving (Show) data IrcException = IrcException String deriving (Typeable) instance Exception IrcException instance Show IrcException where show (IrcException msg) = printf "IRC error (%s)" msg -- deriving instance Generic Item -- instance NFData Item io :: MonadIO m => IO a -> m a io = liftIO