{-# LANGUAGE OverloadedStrings #-} -- | -- Module : Network.IRC.Client -- Copyright : (c) 2016 Michael Walker -- License : MIT -- Maintainer : Michael Walker -- Stability : experimental -- Portability : OverloadedStrings -- -- A simple IRC client library. Typical usage will be of this form: -- -- > run :: ByteString -> Int -> Text -> IO () -- > run host port nick = do -- > conn <- connect host port 1 -- > let cfg = defaultIRCConf nick -- > let cfg' = cfg { _eventHandlers = yourCustomEventHandlers : _eventHandlers cfg } -- > start conn cfg' -- -- You shouldn't really need to tweak anything other than the event -- handlers, as everything has been designed to be as simple as -- possible. module Network.IRC.Client ( -- * Initialisation connect , connectWithTLS , connectWithTLSConfig , connectWithTLSVerify , start , start' , startStateful -- * Logging , Origin (..) , connect' , connectWithTLS' , connectWithTLSConfig' , connectWithTLSVerify' , stdoutLogger , fileLogger , noopLogger -- * Interaction , send , sendBS , disconnect -- * Defaults , defaultIRCConf , defaultOnConnect , defaultOnDisconnect , defaultEventHandlers -- * Types , module Network.IRC.Client.Types -- * Utilities , module Network.IRC.Client.Utils , C.rawMessage , C.toByteString ) where import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Trans.Reader (runReaderT) import Data.ByteString (ByteString) import qualified Data.Conduit.Network.TLS as TLS import Data.Text (Text) import Data.Time.Clock (NominalDiffTime) import qualified Data.X509 as X import qualified Data.X509.CertificateStore as X import qualified Data.X509.Validation as X import qualified Network.Connection as TLS (TLSSettings(..)) import Network.IRC.Client.Handlers import Network.IRC.Client.Internal import Network.IRC.Client.Types import Network.IRC.Client.Utils import qualified Network.IRC.Conduit as C import qualified Network.TLS as TLS -- * Connecting to an IRC network -- | Connect to a server without TLS. connect :: MonadIO m => ByteString -- ^ The hostname -> Int -- ^ The port -> NominalDiffTime -- ^ The flood cooldown -> m (ConnectionConfig s) connect = connect' noopLogger -- | Connect to a server with TLS. connectWithTLS :: MonadIO m => ByteString -- ^ The hostname -> Int -- ^ The port -> NominalDiffTime -- ^ The flood cooldown -> m (ConnectionConfig s) connectWithTLS = connectWithTLS' noopLogger -- | Connect to a server with TLS using the given TLS config. connectWithTLSConfig :: MonadIO m => TLS.TLSClientConfig -- ^ The TLS config -> NominalDiffTime -- ^ The flood cooldown -> m (ConnectionConfig s) connectWithTLSConfig = connectWithTLSConfig' noopLogger -- | Connect to a server with TLS using the given certificate -- verifier. connectWithTLSVerify :: MonadIO m => (X.CertificateStore -> TLS.ValidationCache -> X.ServiceID -> X.CertificateChain -> IO [X.FailedReason]) -- ^ The certificate verifier. Returns an empty list if the cert is -- good. -> ByteString -- ^ The hostname -> Int -- ^ The port -> NominalDiffTime -- ^ The flood cooldown -> m (ConnectionConfig s) connectWithTLSVerify = connectWithTLSVerify' noopLogger -- | Connect to a server without TLS, with the provided logging -- function. connect' :: MonadIO m => (Origin -> ByteString -> IO ()) -- ^ The message logger -> ByteString -- ^ The hostname -> Int -- ^ The port -> NominalDiffTime -- ^ The flood cooldown -> m (ConnectionConfig s) connect' lg host port = connectInternal (C.ircClient port host) defaultOnConnect defaultOnDisconnect lg host port -- | Connect to a server with TLS, with the provided logging function. connectWithTLS' :: MonadIO m => (Origin -> ByteString -> IO ()) -- ^ The message logger -> ByteString -- ^ The hostname -> Int -- ^ The port -> NominalDiffTime -- ^ The flood cooldown -> m (ConnectionConfig s) connectWithTLS' lg host port = connectInternal (C.ircTLSClient port host) defaultOnConnect defaultOnDisconnect lg host port -- | Connect to a server with TLS using the given TLS config, with the -- provided logging function. connectWithTLSConfig' :: MonadIO m => (Origin -> ByteString -> IO ()) -- ^ The message logger -> TLS.TLSClientConfig -- ^ The TLS config -> NominalDiffTime -- ^ The flood cooldown -> m (ConnectionConfig s) connectWithTLSConfig' lg cfg = connectInternal (C.ircTLSClient' cfg) defaultOnConnect defaultOnDisconnect lg host port where host = TLS.tlsClientHost cfg port = TLS.tlsClientPort cfg -- | Connect to a server with TLS using the given certificate -- verifier, with the provided logging function. connectWithTLSVerify' :: MonadIO m => (Origin -> ByteString -> IO ()) -- ^ The message logger -> (X.CertificateStore -> TLS.ValidationCache -> X.ServiceID -> X.CertificateChain -> IO [X.FailedReason]) -- ^ The certificate verifier. Returns an empty list if the cert is -- good. -> ByteString -- ^ The hostname -> Int -- ^ The port -> NominalDiffTime -- ^ The flood cooldown -> m (ConnectionConfig s) connectWithTLSVerify' lg verifier host port = connectInternal (C.ircTLSClient' cfg) defaultOnConnect defaultOnDisconnect lg host port where cfg = let cfg0 = C.defaultTLSConfig port host -- this is a partial pattern match, but because I'm the -- author of irc-conduit I can do this. TLS.TLSSettings cTLSSettings = TLS.tlsClientTLSSettings cfg0 cHooks = TLS.clientHooks cTLSSettings in cfg0 { TLS.tlsClientTLSSettings = TLS.TLSSettings cTLSSettings { TLS.clientHooks = cHooks { TLS.onServerCertificate = verifier } } } -- * Starting -- | Run the event loop for a server, receiving messages and handing -- them off to handlers as appropriate. Messages will be logged to -- stdout. start :: MonadIO m => ConnectionConfig () -> InstanceConfig () -> m () start cconf iconf = startStateful cconf iconf () -- | like 'start' but for clients with state. startStateful :: MonadIO m => ConnectionConfig s -> InstanceConfig s -> s -> m () startStateful cconf iconf ustate = newIRCState cconf iconf ustate >>= start' -- | Like 'start', but use the provided initial state. start' :: MonadIO m => IRCState s -> m () start' = liftIO . runReaderT runner -- * Default configuration -- | Construct a default IRC configuration from a nick defaultIRCConf :: Text -> InstanceConfig s defaultIRCConf n = InstanceConfig { _nick = n , _username = n , _realname = n , _password = Nothing , _channels = [] , _ctcpVer = "irc-client-0.4.4" , _eventHandlers = defaultEventHandlers , _ignore = [] }