diff --git a/pontarius-xmpp.cabal b/pontarius-xmpp.cabal index 624aa13..af700b9 100644 --- a/pontarius-xmpp.cabal +++ b/pontarius-xmpp.cabal @@ -53,9 +53,11 @@ Library , data-default >=0.2 , stringprep >=0.1.3 Exposed-modules: Network.Xmpp - , Network.Xmpp.Bind - , Network.Xmpp.Concurrent , Network.Xmpp.IM + , Network.Xmpp.Basic + Other-modules: + Network.Xmpp.Bind + , Network.Xmpp.Concurrent , Network.Xmpp.IM.Message , Network.Xmpp.IM.Presence , Network.Xmpp.Marshal @@ -74,8 +76,7 @@ Library , Network.Xmpp.TLS , Network.Xmpp.Types , Network.Xmpp.Xep.ServiceDiscovery - Other-modules: - Network.Xmpp.Jid + , Network.Xmpp.Jid , Network.Xmpp.Concurrent.Types , Network.Xmpp.Concurrent.Channels.IQ , Network.Xmpp.Concurrent.Threads diff --git a/source/Network/Xmpp.hs b/source/Network/Xmpp.hs index 0c87fc8..d5f2ea7 100644 --- a/source/Network/Xmpp.hs +++ b/source/Network/Xmpp.hs @@ -1,7 +1,6 @@ -- | -- Module: $Header$ --- Description: A work in progress client implementation of RFC 6120 (XMPP: --- Core). +-- Description: RFC 6120 (XMPP: Core). -- License: Apache License 2.0 -- -- Maintainer: info@jonkri.com @@ -37,6 +36,9 @@ module Network.Xmpp , startTLS , simpleAuth , auth + , scramSha1 + , digestMd5 + , plain , closeConnection , endSession , setConnectionClosedHandler @@ -78,11 +80,10 @@ module Network.Xmpp -- or IQ stanza. , getStanzaChan -- ** Messages - -- | The /message/ stanza is a /push/ mechanism whereby one entity pushes - -- information to another entity, similar to the communications that occur in - -- a system such as email. - -- - -- + -- | The /message/ stanza is a /push/ mechanism whereby one entity + -- pushes information to another entity, similar to the communications that + -- occur in a system such as email. It is not to be confused with + -- /instant messaging/ which is handled in the 'Network.Xmpp.IM' module , Message(..) , MessageError(..) , MessageType(..) @@ -101,6 +102,7 @@ module Network.Xmpp -- for communication is signaled end-to-end by means of a dedicated -- communication primitive: the presence stanza. , Presence(..) + , PresenceType(..) , PresenceError(..) -- *** Creating , module Network.Xmpp.Presence @@ -147,10 +149,8 @@ module Network.Xmpp , exampleParams ) where -import Data.Text as Text +import Data.XML.Types (Element) -import Network -import qualified Network.TLS as TLS import Network.Xmpp.Bind import Network.Xmpp.Concurrent import Network.Xmpp.Concurrent.Channels @@ -158,100 +158,20 @@ import Network.Xmpp.Concurrent.Types import Network.Xmpp.Marshal import Network.Xmpp.Message import Network.Xmpp.Monad -import Network.Xmpp.Pickle import Network.Xmpp.Presence import Network.Xmpp.Sasl -import Network.Xmpp.Sasl.Mechanisms -import Network.Xmpp.Sasl.Types import Network.Xmpp.Session +-- import Network.Xmpp.Session import Network.Xmpp.Stream import Network.Xmpp.TLS import Network.Xmpp.Types -import Control.Monad.Error - --- | Connect to host with given address. -connect :: HostName -> PortID -> Text -> XmppConMonad (Either StreamError ()) -connect address port hostname = do - xmppRawConnect address port hostname - result <- xmppStartStream - case result of - Left e -> do - pushElement . pickleElem xpStreamError $ toError e - xmppCloseStreams - return () - Right () -> return () - return result - where - -- TODO: Descriptive texts in stream errors? - toError (StreamNotStreamElement _name) = - XmppStreamError StreamInvalidXml Nothing Nothing - toError (StreamInvalidStreamNamespace _ns) = - XmppStreamError StreamInvalidNamespace Nothing Nothing - toError (StreamInvalidStreamPrefix _prefix) = - XmppStreamError StreamBadNamespacePrefix Nothing Nothing - -- TODO: Catch remaining xmppStartStream errors. - toError (StreamWrongVersion _ver) = - XmppStreamError StreamUnsupportedVersion Nothing Nothing - toError (StreamWrongLangTag _) = - XmppStreamError StreamInvalidXml Nothing Nothing - toError StreamUnknownError = - XmppStreamError StreamBadFormat Nothing Nothing - - --- | Authenticate to the server using the first matching method and bind a --- resource. -auth :: [SaslHandler] - -> Maybe Text - -> XmppConMonad (Either AuthError Jid) -auth mechanisms resource = runErrorT $ do - ErrorT $ xmppSasl mechanisms - jid <- lift $ xmppBind resource - lift $ xmppStartSession - return jid - --- | Authenticate to the server with the given username and password --- and bind a resource. --- --- Prefers SCRAM-SHA1 over DIGEST-MD5. -simpleAuth :: Text.Text -- ^ The username - -> Text.Text -- ^ The password - -> Maybe Text -- ^ The desired resource or 'Nothing' to let the - -- server assign one - -> XmppConMonad (Either AuthError Jid) -simpleAuth username passwd resource = flip auth resource $ - [ -- TODO: scramSha1Plus - scramSha1 username Nothing passwd - , digestMd5 username Nothing passwd - ] - - --- | The quick and easy way to set up a connection to an XMPP server --- --- This will --- * connect to the host --- * secure the connection with TLS --- * authenticate to the server using either SCRAM-SHA1 (preferred) or --- Digest-MD5 --- * bind a resource --- * return the full JID you have been assigned --- --- Note that the server might assign a different resource even when we send --- a preference. -simpleConnect :: HostName -- ^ Host to connect to - -> PortID -- ^ Port to connec to - -> Text -- ^ Hostname of the server (to distinguish the XMPP - -- service) - -> Text -- ^ User name (authcid) - -> Text -- ^ Password - -> Maybe Text -- ^ Desired resource (or Nothing to let the server - -- decide) - -> XmppConMonad Jid -simpleConnect host port hostname username password resource = do - connect host port hostname - startTLS exampleParams - saslResponse <- simpleAuth username password resource - case saslResponse of - Right jid -> return jid - Left e -> error $ show e +-- -- Sends the session IQ set element and waits for an answer. Throws an error if +-- -- if an IQ error stanza is returned from the server. +-- startSession :: Session -> IO () +-- startSession session = do +-- answer <- sendIQ' Nothing Set Nothing sessionXML session +-- case answer of +-- IQResponseResult _ -> return () +-- e -> error $ show e diff --git a/source/Network/Xmpp/Concurrent.hs b/source/Network/Xmpp/Concurrent.hs index e11c5a7..4ac42aa 100644 --- a/source/Network/Xmpp/Concurrent.hs +++ b/source/Network/Xmpp/Concurrent.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Concurrent ( Session , module Network.Xmpp.Concurrent.Monad diff --git a/source/Network/Xmpp/Concurrent/Channels.hs b/source/Network/Xmpp/Concurrent/Channels.hs index 45afd4c..32d6ae9 100644 --- a/source/Network/Xmpp/Concurrent/Channels.hs +++ b/source/Network/Xmpp/Concurrent/Channels.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE OverloadedStrings #-} module Network.Xmpp.Concurrent.Channels ( module Network.Xmpp.Concurrent.Channels.Basic @@ -90,7 +91,7 @@ toChans messageC presenceC stanzaC iqHands sta = atomically $ do iqID (Right iq') = iqResultID iq' --- | Creates and initializes a new concurrent context. +-- | Creates and initializes a new Xmpp context. newContext :: IO Context newContext = do messageC <- newTChanIO diff --git a/source/Network/Xmpp/Concurrent/Channels/Basic.hs b/source/Network/Xmpp/Concurrent/Channels/Basic.hs index 4e1395d..287b089 100644 --- a/source/Network/Xmpp/Concurrent/Channels/Basic.hs +++ b/source/Network/Xmpp/Concurrent/Channels/Basic.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Concurrent.Channels.Basic where import Control.Concurrent.STM diff --git a/source/Network/Xmpp/Concurrent/Channels/IQ.hs b/source/Network/Xmpp/Concurrent/Channels/IQ.hs index 087b91e..c444296 100644 --- a/source/Network/Xmpp/Concurrent/Channels/IQ.hs +++ b/source/Network/Xmpp/Concurrent/Channels/IQ.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Concurrent.Channels.IQ where import Control.Concurrent (forkIO, threadDelay) diff --git a/source/Network/Xmpp/Concurrent/Channels/Message.hs b/source/Network/Xmpp/Concurrent/Channels/Message.hs index 58dbc6d..20d50b9 100644 --- a/source/Network/Xmpp/Concurrent/Channels/Message.hs +++ b/source/Network/Xmpp/Concurrent/Channels/Message.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Concurrent.Channels.Message where import Network.Xmpp.Concurrent.Channels.Types diff --git a/source/Network/Xmpp/Concurrent/Channels/Presence.hs b/source/Network/Xmpp/Concurrent/Channels/Presence.hs index 9c3d878..bf93ecb 100644 --- a/source/Network/Xmpp/Concurrent/Channels/Presence.hs +++ b/source/Network/Xmpp/Concurrent/Channels/Presence.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Concurrent.Channels.Presence where import Network.Xmpp.Concurrent.Channels.Types diff --git a/source/Network/Xmpp/Concurrent/Channels/Types.hs b/source/Network/Xmpp/Concurrent/Channels/Types.hs index fcf4ee7..d02025f 100644 --- a/source/Network/Xmpp/Concurrent/Channels/Types.hs +++ b/source/Network/Xmpp/Concurrent/Channels/Types.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Concurrent.Channels.Types where import Control.Concurrent.STM @@ -7,7 +8,7 @@ import Data.Text (Text) import Network.Xmpp.Concurrent.Types import Network.Xmpp.Types --- | Session with Channels +-- | An XMPP session context data Context = Context { session :: Session -- The original master channels that the reader puts stanzas diff --git a/source/Network/Xmpp/Concurrent/Monad.hs b/source/Network/Xmpp/Concurrent/Monad.hs index 96a1bc2..9046e6f 100644 --- a/source/Network/Xmpp/Concurrent/Monad.hs +++ b/source/Network/Xmpp/Concurrent/Monad.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE OverloadedStrings #-} module Network.Xmpp.Concurrent.Monad where diff --git a/source/Network/Xmpp/Concurrent/Threads.hs b/source/Network/Xmpp/Concurrent/Threads.hs index 4100588..64c7c2f 100644 --- a/source/Network/Xmpp/Concurrent/Threads.hs +++ b/source/Network/Xmpp/Concurrent/Threads.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} diff --git a/source/Network/Xmpp/IM.hs b/source/Network/Xmpp/IM.hs index 42c09cc..1f2a61f 100644 --- a/source/Network/Xmpp/IM.hs +++ b/source/Network/Xmpp/IM.hs @@ -1,5 +1,12 @@ module Network.Xmpp.IM - ( module Network.Xmpp.IM.Message + ( -- * Instant Messages + subject + , thread + , body + , newIM + , simpleIM + , answerIM + -- * Presence , module Network.Xmpp.IM.Presence ) where diff --git a/source/Network/Xmpp/IM/Message.hs b/source/Network/Xmpp/IM/Message.hs index 770e59c..2a76a3e 100644 --- a/source/Network/Xmpp/IM/Message.hs +++ b/source/Network/Xmpp/IM/Message.hs @@ -1,4 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} +{-# OPTIONS_HADDOCK hide #-} + module Network.Xmpp.IM.Message where @@ -89,8 +91,10 @@ newIM t i lang tp sbj thrd bdy payload = Message ++ [payload] } --- | Generate a simple instance message -simpleIM :: Jid -> Text -> Message +-- | Generate a simple message +simpleIM :: Jid -- ^ recipient + -> Text -- ^ body + -> Message simpleIM t bd = newIM t Nothing diff --git a/source/Network/Xmpp/IM/Presence.hs b/source/Network/Xmpp/IM/Presence.hs index a999647..c586a1f 100644 --- a/source/Network/Xmpp/IM/Presence.hs +++ b/source/Network/Xmpp/IM/Presence.hs @@ -1,3 +1,5 @@ +{-# OPTIONS_HADDOCK hide #-} + module Network.Xmpp.IM.Presence where import Data.Text(Text) diff --git a/source/Network/Xmpp/Message.hs b/source/Network/Xmpp/Message.hs index 0e14315..875421f 100644 --- a/source/Network/Xmpp/Message.hs +++ b/source/Network/Xmpp/Message.hs @@ -1,4 +1,6 @@ {-# LANGUAGE RecordWildCards #-} +{-# OPTIONS_HADDOCK hide #-} + module Network.Xmpp.Message ( Message(..) , MessageError(..) diff --git a/source/Network/Xmpp/Monad.hs b/source/Network/Xmpp/Monad.hs index a90e059..63503ba 100644 --- a/source/Network/Xmpp/Monad.hs +++ b/source/Network/Xmpp/Monad.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE OverloadedStrings #-} @@ -44,6 +45,7 @@ pushElement x = do sink <- gets sConPushBS liftIO . sink $ renderElement x +-- | Encode and send stanza pushStanza :: Stanza -> XmppConMonad Bool pushStanza = pushElement . pickleElem xpStanza @@ -93,7 +95,7 @@ pullPickle p = do Left e -> liftIO . Ex.throwIO $ StreamXMLError (show e) Right r -> return r --- Pulls a stanza (or stream error) from the stream. Throws an error on a stream +-- | Pulls a stanza (or stream error) from the stream. Throws an error on a stream -- error. pullStanza :: XmppConMonad Stanza pullStanza = do diff --git a/source/Network/Xmpp/Pickle.hs b/source/Network/Xmpp/Pickle.hs index 2286fea..e00e190 100644 --- a/source/Network/Xmpp/Pickle.hs +++ b/source/Network/Xmpp/Pickle.hs @@ -1,3 +1,5 @@ +{-# OPTIONS_HADDOCK hide #-} + {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TupleSections #-} diff --git a/source/Network/Xmpp/Sasl.hs b/source/Network/Xmpp/Sasl.hs index c2b31c2..5f79247 100644 --- a/source/Network/Xmpp/Sasl.hs +++ b/source/Network/Xmpp/Sasl.hs @@ -1,6 +1,12 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE NoMonomorphismRestriction, OverloadedStrings #-} -module Network.Xmpp.Sasl where +module Network.Xmpp.Sasl + ( xmppSasl + , digestMd5 + , scramSha1 + , plain + ) where import Control.Applicative import Control.Arrow (left) @@ -31,11 +37,11 @@ import Network.Xmpp.Pickle import qualified System.Random as Random import Network.Xmpp.Sasl.Types +import Network.Xmpp.Sasl.Mechanisms --- Uses the first supported mechanism to authenticate, if any. Updates the --- XmppConMonad state with non-password credentials and restarts the stream upon --- success. This computation wraps an ErrorT computation, which means that --- catchError can be used to catch any errors. +-- | Uses the first supported mechanism to authenticate, if any. Updates the +-- state with non-password credentials and restarts the stream upon +-- success. xmppSasl :: [SaslHandler] -- ^ Acceptable authentication mechanisms and their -- corresponding handlers -> XmppConMonad (Either AuthError ()) diff --git a/source/Network/Xmpp/Sasl/Common.hs b/source/Network/Xmpp/Sasl/Common.hs index 0adea45..23c3bb7 100644 --- a/source/Network/Xmpp/Sasl/Common.hs +++ b/source/Network/Xmpp/Sasl/Common.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE OverloadedStrings #-} diff --git a/source/Network/Xmpp/Sasl/Mechanisms.hs b/source/Network/Xmpp/Sasl/Mechanisms.hs index 674d6dd..f604381 100644 --- a/source/Network/Xmpp/Sasl/Mechanisms.hs +++ b/source/Network/Xmpp/Sasl/Mechanisms.hs @@ -1,6 +1,7 @@ +{-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Sasl.Mechanisms ( module Network.Xmpp.Sasl.Mechanisms.DigestMd5 - , module Network.Xmpp.Sasl.Mechanisms.Scram + , scramSha1 , module Network.Xmpp.Sasl.Mechanisms.Plain ) where diff --git a/source/Network/Xmpp/Sasl/Mechanisms/DigestMd5.hs b/source/Network/Xmpp/Sasl/Mechanisms/DigestMd5.hs index 31e68f8..d8b9a7d 100644 --- a/source/Network/Xmpp/Sasl/Mechanisms/DigestMd5.hs +++ b/source/Network/Xmpp/Sasl/Mechanisms/DigestMd5.hs @@ -1,6 +1,9 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE OverloadedStrings #-} -module Network.Xmpp.Sasl.Mechanisms.DigestMd5 where +module Network.Xmpp.Sasl.Mechanisms.DigestMd5 + ( digestMd5 + ) where import Control.Applicative import Control.Arrow (left) @@ -40,9 +43,9 @@ import Network.Xmpp.Sasl.Types -xmppDigestMd5 :: Text -- Authorization identity (authzid) - -> Maybe Text -- Authentication identity (authzid) - -> Text -- Password (authzid) +xmppDigestMd5 :: Text -- ^ Authentication identity (authzid or username) + -> Maybe Text -- ^ Authorization identity (authcid) + -> Text -- ^ Password (authzid) -> SaslM () xmppDigestMd5 authcid authzid password = do (ac, az, pw) <- prepCredentials authcid authzid password @@ -128,9 +131,9 @@ xmppDigestMd5 authcid authzid password = do ha2 = hash ["AUTHENTICATE", digestURI] in hash [ha1, nonce, nc, cnonce, qop, ha2] -digestMd5 :: Text -- Authorization identity (authzid) - -> Maybe Text -- Authentication identity (authzid) - -> Text -- Password (authzid) +digestMd5 :: Text -- ^ Authentication identity (authcid or username) + -> Maybe Text -- ^ Authorization identity (authzid) + -> Text -- ^ Password -> SaslHandler digestMd5 authcid authzid password = ( "DIGEST-MD5" , xmppDigestMd5 authcid authzid password diff --git a/source/Network/Xmpp/Sasl/Mechanisms/Plain.hs b/source/Network/Xmpp/Sasl/Mechanisms/Plain.hs index fcc1e20..8f1ed25 100644 --- a/source/Network/Xmpp/Sasl/Mechanisms/Plain.hs +++ b/source/Network/Xmpp/Sasl/Mechanisms/Plain.hs @@ -1,9 +1,12 @@ +{-# OPTIONS_HADDOCK hide #-} -- Implementation of the PLAIN Simple Authentication and Security Layer (SASL) -- Mechanism, http://tools.ietf.org/html/rfc4616. {-# LANGUAGE OverloadedStrings #-} -module Network.Xmpp.Sasl.Mechanisms.Plain where +module Network.Xmpp.Sasl.Mechanisms.Plain + ( plain + ) where import Control.Applicative import Control.Arrow (left) @@ -72,5 +75,8 @@ xmppPlain authcid authzid password = do where authzid' = maybe "" Text.encodeUtf8 authzid -plain :: Text.Text -> Maybe Text.Text -> Text.Text -> SaslHandler +plain :: Text.Text -- ^ authentication ID (username) + -> Maybe Text.Text -- ^ authorization ID + -> Text.Text -- ^ password + -> SaslHandler plain authcid authzid passwd = ("PLAIN", xmppPlain authcid authzid passwd) \ No newline at end of file diff --git a/source/Network/Xmpp/Sasl/Mechanisms/Scram.hs b/source/Network/Xmpp/Sasl/Mechanisms/Scram.hs index a949239..6cf809d 100644 --- a/source/Network/Xmpp/Sasl/Mechanisms/Scram.hs +++ b/source/Network/Xmpp/Sasl/Mechanisms/Scram.hs @@ -1,8 +1,10 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} -module Network.Xmpp.Sasl.Mechanisms.Scram where +module Network.Xmpp.Sasl.Mechanisms.Scram + where import Control.Applicative ((<$>)) import Control.Monad.Error @@ -153,7 +155,6 @@ scram hashToken authcid authzid password = do u1 = hmac str (salt +++ (BS.pack [0,0,0,1])) us = iterate (hmac str) u1 --- | 'scram' spezialised to the SHA-1 hash function, packaged as a SaslHandler scramSha1 :: Text.Text -- ^ username -> Maybe Text.Text -- ^ authorization ID -> Text.Text -- ^ password diff --git a/source/Network/Xmpp/Sasl/StringPrep.hs b/source/Network/Xmpp/Sasl/StringPrep.hs index 07442aa..cff48a6 100644 --- a/source/Network/Xmpp/Sasl/StringPrep.hs +++ b/source/Network/Xmpp/Sasl/StringPrep.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE OverloadedStrings #-} module Network.Xmpp.Sasl.StringPrep where diff --git a/source/Network/Xmpp/Sasl/Types.hs b/source/Network/Xmpp/Sasl/Types.hs index cc0351f..daa13ec 100644 --- a/source/Network/Xmpp/Sasl/Types.hs +++ b/source/Network/Xmpp/Sasl/Types.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Sasl.Types where import Control.Monad.Error diff --git a/source/Network/Xmpp/Session.hs b/source/Network/Xmpp/Session.hs index b6500f3..a282512 100644 --- a/source/Network/Xmpp/Session.hs +++ b/source/Network/Xmpp/Session.hs @@ -1,14 +1,88 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE OverloadedStrings #-} - module Network.Xmpp.Session where -import Data.XML.Pickle -import Data.XML.Types(Element) +import Control.Monad.Error +import Data.Text as Text +import Data.XML.Pickle +import Data.XML.Types(Element) +import qualified Network.TLS as TLS +import Network.Xmpp.Bind +import Network.Xmpp.Concurrent.Types +import Network.Xmpp.Marshal +import Network.Xmpp.Monad +import Network.Xmpp.Pickle +import Network.Xmpp.Sasl +import Network.Xmpp.Sasl.Mechanisms +import Network.Xmpp.Sasl.Types +import Network.Xmpp.Stream +import Network.Xmpp.Types +import Network +import Network.Xmpp.TLS + +-- | The quick and easy way to set up a connection to an XMPP server +-- +-- This will +-- +-- * connect to the host +-- +-- * secure the connection with TLS +-- +-- * authenticate to the server using either SCRAM-SHA1 (preferred) or +-- Digest-MD5 +-- +-- * bind a resource +-- +-- * return the full JID you have been assigned +-- +-- Note that the server might assign a different resource even when we send +-- a preference. +simpleConnect :: HostName -- ^ Host to connect to + -> PortID -- ^ Port to connec to + -> Text -- ^ Hostname of the server (to distinguish the XMPP + -- service) + -> Text -- ^ User name (authcid) + -> Text -- ^ Password + -> Maybe Text -- ^ Desired resource (or Nothing to let the server + -- decide) + -> XmppConMonad Jid +simpleConnect host port hostname username password resource = do + connect host port hostname + startTLS exampleParams + saslResponse <- simpleAuth username password resource + case saslResponse of + Right jid -> return jid + Left e -> error $ show e + + +-- | Connect to host with given address. +connect :: HostName -> PortID -> Text -> XmppConMonad (Either StreamError ()) +connect address port hostname = do + xmppRawConnect address port hostname + result <- xmppStartStream + case result of + Left e -> do + pushElement . pickleElem xpStreamError $ toError e + xmppCloseStreams + return () + Right () -> return () + return result + where + -- TODO: Descriptive texts in stream errors? + toError (StreamNotStreamElement _name) = + XmppStreamError StreamInvalidXml Nothing Nothing + toError (StreamInvalidStreamNamespace _ns) = + XmppStreamError StreamInvalidNamespace Nothing Nothing + toError (StreamInvalidStreamPrefix _prefix) = + XmppStreamError StreamBadNamespacePrefix Nothing Nothing + -- TODO: Catch remaining xmppStartStream errors. + toError (StreamWrongVersion _ver) = + XmppStreamError StreamUnsupportedVersion Nothing Nothing + toError (StreamWrongLangTag _) = + XmppStreamError StreamInvalidXml Nothing Nothing + toError StreamUnknownError = + XmppStreamError StreamBadFormat Nothing Nothing -import Network.Xmpp.Monad -import Network.Xmpp.Pickle -import Network.Xmpp.Types -import Network.Xmpp.Concurrent sessionXML :: Element sessionXML = pickleElem @@ -33,11 +107,28 @@ xmppStartSession = do Left e -> error $ show e Right _ -> return () --- -- Sends the session IQ set element and waits for an answer. Throws an error if --- -- if an IQ error stanza is returned from the server. --- startSession :: Session -> IO () --- startSession session = do --- answer <- sendIQ' Nothing Set Nothing sessionXML session --- case answer of --- IQResponseResult _ -> return () --- e -> error $ show e +-- | Authenticate to the server using the first matching method and bind a +-- resource. +auth :: [SaslHandler] + -> Maybe Text + -> XmppConMonad (Either AuthError Jid) +auth mechanisms resource = runErrorT $ do + ErrorT $ xmppSasl mechanisms + jid <- lift $ xmppBind resource + lift $ xmppStartSession + return jid + +-- | Authenticate to the server with the given username and password +-- and bind a resource. +-- +-- Prefers SCRAM-SHA1 over DIGEST-MD5. +simpleAuth :: Text.Text -- ^ The username + -> Text.Text -- ^ The password + -> Maybe Text -- ^ The desired resource or 'Nothing' to let the + -- server assign one + -> XmppConMonad (Either AuthError Jid) +simpleAuth username passwd resource = flip auth resource $ + [ -- TODO: scramSha1Plus + scramSha1 username Nothing passwd + , digestMd5 username Nothing passwd + ] diff --git a/source/Network/Xmpp/Stream.hs b/source/Network/Xmpp/Stream.hs index 6fb1dd6..888c2ad 100644 --- a/source/Network/Xmpp/Stream.hs +++ b/source/Network/Xmpp/Stream.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE NoMonomorphismRestriction, OverloadedStrings #-} {-# LANGUAGE TupleSections #-} diff --git a/source/Network/Xmpp/TLS.hs b/source/Network/Xmpp/TLS.hs index 7c1c2ec..c50aebf 100644 --- a/source/Network/Xmpp/TLS.hs +++ b/source/Network/Xmpp/TLS.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE OverloadedStrings #-} diff --git a/source/Network/Xmpp/Types.hs b/source/Network/Xmpp/Types.hs index 8d279e9..a357437 100644 --- a/source/Network/Xmpp/Types.hs +++ b/source/Network/Xmpp/Types.hs @@ -741,29 +741,36 @@ data XmppConnectionState deriving (Show, Eq, Typeable) data XmppConnection = XmppConnection - { sConSrc :: !(Source IO Event) - , sRawSrc :: !(Source IO BS.ByteString) - , sConPushBS :: !(BS.ByteString -> IO Bool) - , sConHandle :: !(Maybe Handle) - , sFeatures :: !ServerFeatures - , sConnectionState :: !XmppConnectionState - , sHostname :: !(Maybe Text) - , sJid :: !(Maybe Jid) - , sCloseConnection :: !(IO ()) - , sPreferredLang :: !(Maybe LangTag) - , sStreamLang :: !(Maybe LangTag) -- Will be a `Just' value + { sConSrc :: !(Source IO Event) -- ^ inbound connection + , sRawSrc :: !(Source IO BS.ByteString) -- ^ inbound + -- connection + , sConPushBS :: !(BS.ByteString -> IO Bool) -- ^ outbound + -- connection + , sConHandle :: !(Maybe Handle) -- ^ Handle for TLS + , sFeatures :: !ServerFeatures -- ^ Features the server + -- advertised + , sConnectionState :: !XmppConnectionState -- ^ State of connection + , sHostname :: !(Maybe Text) -- ^ Hostname of the server + , sJid :: !(Maybe Jid) -- ^ Our JID + , sCloseConnection :: !(IO ()) -- ^ necessary steps to cleanly + -- close the connection (send TLS + -- bye etc.) + , sPreferredLang :: !(Maybe LangTag) -- ^ Default language when + -- no explicit language + -- tag is set + , sStreamLang :: !(Maybe LangTag) -- ^ Will be a `Just' value -- once connected to the -- server. - , sStreamId :: !(Maybe Text) -- Stream ID as specified by + , sStreamId :: !(Maybe Text) -- ^ Stream ID as specified by -- the server. - , sToJid :: !(Maybe Jid) -- JID to include in the + , sToJid :: !(Maybe Jid) -- ^ JID to include in the -- stream element's `to' -- attribute when the -- connection is secured. See -- also below. - , sJidWhenPlain :: !Bool -- Whether or not to also include the + , sJidWhenPlain :: !Bool -- ^ Whether or not to also include the -- Jid when the connection is plain. - , sFrom :: !(Maybe Jid) -- From as specified by the + , sFrom :: !(Maybe Jid) -- ^ From as specified by the -- server in the stream -- element's `from' -- attribute. @@ -780,4 +787,4 @@ newtype XmppT m a = XmppT { runXmppT :: StateT XmppConnection m a } deriving (Mo type XmppConMonad a = StateT XmppConnection IO a -- Make XmppT derive the Monad and MonadIO instances. -deriving instance (Monad m, MonadIO m) => MonadState (XmppConnection) (XmppT m) \ No newline at end of file +deriving instance (Monad m, MonadIO m) => MonadState (XmppConnection) (XmppT m) diff --git a/source/Network/Xmpp/Xep/ServiceDiscovery.hs b/source/Network/Xmpp/Xep/ServiceDiscovery.hs index 1a6882d..d637107 100644 --- a/source/Network/Xmpp/Xep/ServiceDiscovery.hs +++ b/source/Network/Xmpp/Xep/ServiceDiscovery.hs @@ -1,3 +1,4 @@ +{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TupleSections #-}