|
|
|
|
@ -32,21 +32,23 @@ import Text.XML.Stream.Elements
@@ -32,21 +32,23 @@ import Text.XML.Stream.Elements
|
|
|
|
|
import Text.XML.Stream.Parse as XP |
|
|
|
|
import Text.XML.Unresolved(InvalidEventStream(..)) |
|
|
|
|
|
|
|
|
|
pushN :: Element -> XMPPConMonad Bool |
|
|
|
|
pushN x = do |
|
|
|
|
pushElement :: Element -> XMPPConMonad Bool |
|
|
|
|
pushElement x = do |
|
|
|
|
sink <- gets sConPushBS |
|
|
|
|
liftIO . sink $ renderElement x |
|
|
|
|
|
|
|
|
|
push :: Stanza -> XMPPConMonad Bool |
|
|
|
|
push = pushN . pickleElem xpStanza |
|
|
|
|
pushStanza :: Stanza -> XMPPConMonad Bool |
|
|
|
|
pushStanza = pushElement . pickleElem xpStanza |
|
|
|
|
|
|
|
|
|
pushOpen :: Element -> XMPPConMonad Bool |
|
|
|
|
pushOpen e = do |
|
|
|
|
pushOpenElement :: Element -> XMPPConMonad Bool |
|
|
|
|
pushOpenElement e = do |
|
|
|
|
sink <- gets sConPushBS |
|
|
|
|
liftIO . sink $ renderOpenElement e |
|
|
|
|
|
|
|
|
|
pullSink :: Sink Event IO b -> XMPPConMonad b |
|
|
|
|
pullSink snk = do |
|
|
|
|
-- `Connect-and-resumes' the given sink to the connection source, and pulls a |
|
|
|
|
-- `b' value. |
|
|
|
|
pullToSink :: Sink Event IO b -> XMPPConMonad b |
|
|
|
|
pullToSink snk = do |
|
|
|
|
source <- gets sConSrc |
|
|
|
|
(_, r) <- lift $ source $$+ snk |
|
|
|
|
return r |
|
|
|
|
@ -54,14 +56,14 @@ pullSink snk = do
@@ -54,14 +56,14 @@ pullSink snk = do
|
|
|
|
|
pullElement :: XMPPConMonad Element |
|
|
|
|
pullElement = do |
|
|
|
|
Ex.catch (do |
|
|
|
|
e <- pullSink (elements =$ CL.head) |
|
|
|
|
e <- pullToSink (elements =$ CL.head) |
|
|
|
|
case e of |
|
|
|
|
Nothing -> liftIO $ Ex.throwIO StreamConnectionError |
|
|
|
|
Just r -> return r |
|
|
|
|
) |
|
|
|
|
(\(InvalidEventStream s) -> liftIO . Ex.throwIO $ StreamXMLError s) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Pulls an element and unpickles it. |
|
|
|
|
pullPickle :: PU [Node] a -> XMPPConMonad a |
|
|
|
|
pullPickle p = do |
|
|
|
|
res <- unpickleElem p <$> pullElement |
|
|
|
|
@ -69,27 +71,30 @@ pullPickle p = do
@@ -69,27 +71,30 @@ pullPickle p = do
|
|
|
|
|
Left e -> liftIO . Ex.throwIO $ StreamXMLError e |
|
|
|
|
Right r -> return r |
|
|
|
|
|
|
|
|
|
-- Pulls a stanza from the stream. Throws an error on failure. |
|
|
|
|
pullStanza :: XMPPConMonad Stanza |
|
|
|
|
pullStanza = do |
|
|
|
|
res <- pullPickle xpStreamEntity |
|
|
|
|
res <- pullPickle xpStreamStanza |
|
|
|
|
case res of |
|
|
|
|
Left e -> liftIO . Ex.throwIO $ StreamError e |
|
|
|
|
Right r -> return r |
|
|
|
|
|
|
|
|
|
catchPush p = Ex.catch (p >> return True) |
|
|
|
|
-- Performs the given IO operation, catches any errors and re-throws everything |
|
|
|
|
-- except the `ResourceVanished' error. |
|
|
|
|
catchPush :: IO () -> IO Bool |
|
|
|
|
catchPush p = Ex.catch |
|
|
|
|
(p >> return True) |
|
|
|
|
(\e -> case GIE.ioe_type e of |
|
|
|
|
GIE.ResourceVanished -> return False |
|
|
|
|
_ -> Ex.throwIO e |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
zeroSource :: Source IO output |
|
|
|
|
zeroSource = liftIO . Ex.throwIO $ StreamConnectionError |
|
|
|
|
|
|
|
|
|
-- XmppConnection state used when there is no connection. |
|
|
|
|
xmppNoConnection :: XmppConnection |
|
|
|
|
xmppNoConnection = XmppConnection |
|
|
|
|
{ sConSrc = zeroSource |
|
|
|
|
, sRawSrc = zeroSource |
|
|
|
|
, sConPushBS = \_ -> return False |
|
|
|
|
, sConPushBS = \_ -> return False -- Nothing has been sent. |
|
|
|
|
, sConHandle = Nothing |
|
|
|
|
, sFeatures = SF Nothing [] [] |
|
|
|
|
, sConnectionState = XmppConnectionClosed |
|
|
|
|
@ -98,7 +103,12 @@ xmppNoConnection = XmppConnection
@@ -98,7 +103,12 @@ xmppNoConnection = XmppConnection
|
|
|
|
|
, sResource = Nothing |
|
|
|
|
, sCloseConnection = return () |
|
|
|
|
} |
|
|
|
|
where |
|
|
|
|
zeroSource :: Source IO output |
|
|
|
|
zeroSource = liftIO . Ex.throwIO $ StreamConnectionError |
|
|
|
|
|
|
|
|
|
-- Connects to the given hostname on port 5222 (TODO: Make this dynamic) and |
|
|
|
|
-- updates the XMPPConMonad XmppConnection state. |
|
|
|
|
xmppRawConnect :: HostName -> Text -> XMPPConMonad () |
|
|
|
|
xmppRawConnect host hostname = do |
|
|
|
|
uname <- gets sUsername |
|
|
|
|
@ -110,7 +120,7 @@ xmppRawConnect host hostname = do
@@ -110,7 +120,7 @@ xmppRawConnect host hostname = do
|
|
|
|
|
src <- liftIO . bufferSource $ raw $= XP.parseBytes def |
|
|
|
|
let st = XmppConnection |
|
|
|
|
src |
|
|
|
|
(raw) |
|
|
|
|
raw |
|
|
|
|
(catchPush . BS.hPut con) |
|
|
|
|
(Just con) |
|
|
|
|
(SF Nothing [] []) |
|
|
|
|
@ -121,28 +131,34 @@ xmppRawConnect host hostname = do
@@ -121,28 +131,34 @@ xmppRawConnect host hostname = do
|
|
|
|
|
(hClose con) |
|
|
|
|
put st |
|
|
|
|
|
|
|
|
|
-- Execute a XMPPConMonad computation. |
|
|
|
|
xmppNewSession :: XMPPConMonad a -> IO (a, XmppConnection) |
|
|
|
|
xmppNewSession action = do |
|
|
|
|
runStateT action xmppNoConnection |
|
|
|
|
xmppNewSession action = runStateT action xmppNoConnection |
|
|
|
|
|
|
|
|
|
-- Closes the connection and updates the XMPPConMonad XmppConnection state. |
|
|
|
|
xmppKillConnection :: XMPPConMonad () |
|
|
|
|
xmppKillConnection = do |
|
|
|
|
cc <- gets sCloseConnection |
|
|
|
|
void . liftIO $ (Ex.try cc :: IO (Either Ex.SomeException ())) |
|
|
|
|
put xmppNoConnection |
|
|
|
|
|
|
|
|
|
xmppSendIQ' :: StanzaId -> Maybe JID -> IQRequestType |
|
|
|
|
-> Maybe LangTag -> Element |
|
|
|
|
-- Sends an IQ request and waits for the response. If the response ID does not |
|
|
|
|
-- match the outgoing ID, an error is thrown. |
|
|
|
|
xmppSendIQ' :: StanzaId |
|
|
|
|
-> Maybe JID |
|
|
|
|
-> IQRequestType |
|
|
|
|
-> Maybe LangTag |
|
|
|
|
-> Element |
|
|
|
|
-> XMPPConMonad (Either IQError IQResult) |
|
|
|
|
xmppSendIQ' iqID to tp lang body = do |
|
|
|
|
push . IQRequestS $ IQRequest iqID Nothing to lang tp body |
|
|
|
|
pushStanza . IQRequestS $ IQRequest iqID Nothing to lang tp body |
|
|
|
|
res <- pullPickle $ xpEither xpIQError xpIQResult |
|
|
|
|
case res of |
|
|
|
|
Left e -> return $ Left e |
|
|
|
|
Right iq' -> do |
|
|
|
|
unless (iqID == iqResultID iq') . liftIO . Ex.throwIO $ |
|
|
|
|
unless |
|
|
|
|
(iqID == iqResultID iq') . liftIO . Ex.throwIO $ |
|
|
|
|
StreamXMLError |
|
|
|
|
("In xmppSendIQ' IDs don't match: " ++ show iqID ++ |
|
|
|
|
" /= " ++ show (iqResultID iq') ++ " .") |
|
|
|
|
("In xmppSendIQ' IDs don't match: " ++ show iqID ++ " /= " ++ |
|
|
|
|
show (iqResultID iq') ++ " .") |
|
|
|
|
return $ Right iq' |
|
|
|
|
|
|
|
|
|
|