summaryrefslogtreecommitdiff
path: root/Presence/XMPPServer.hs
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2014-02-21 13:13:40 -0500
committerjoe <joe@jerkface.net>2014-02-21 13:13:40 -0500
commitacad0d6ef22cbb75cdc4163c5163306a994cd792 (patch)
treea5d441398ec131b7a9d3c485c220ac59b7c2b1b4 /Presence/XMPPServer.hs
parentac3702dd365691cc9abf37248633f00f1e06cb12 (diff)
pidgin hack, error message in simulated chat.
Diffstat (limited to 'Presence/XMPPServer.hs')
-rw-r--r--Presence/XMPPServer.hs405
1 files changed, 368 insertions, 37 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs
index d41e06cb..bd4c56c4 100644
--- a/Presence/XMPPServer.hs
+++ b/Presence/XMPPServer.hs
@@ -1,6 +1,7 @@
1{-# LANGUAGE CPP #-} 1{-# LANGUAGE CPP #-}
2{-# LANGUAGE OverloadedStrings #-} 2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE RankNTypes #-} 3{-# LANGUAGE RankNTypes #-}
4{-# LANGUAGE FlexibleInstances #-} -- instance for TChan Event
4module XMPPServer 5module XMPPServer
5 ( xmppServer 6 ( xmppServer
6 , ConnectionKey(..) 7 , ConnectionKey(..)
@@ -49,7 +50,7 @@ import Data.Maybe
49import Data.Monoid ( (<>) ) 50import Data.Monoid ( (<>) )
50import Data.Text (Text) 51import Data.Text (Text)
51import qualified Data.Text as Text (pack,unpack) 52import qualified Data.Text as Text (pack,unpack)
52import Data.Char (toUpper) 53import Data.Char (toUpper,chr,ord)
53import Data.Map (Map) 54import Data.Map (Map)
54import qualified Data.Map as Map 55import qualified Data.Map as Map
55import Data.Set (Set, (\\) ) 56import Data.Set (Set, (\\) )
@@ -112,6 +113,9 @@ data RosterEventType
112 | RejectSubscriber 113 | RejectSubscriber
113 deriving (Show,Read,Ord,Eq,Enum) 114 deriving (Show,Read,Ord,Eq,Enum)
114 115
116data ClientHack = SimulatedChatErrors
117 deriving (Show,Read,Ord,Eq,Enum)
118
115data StanzaType 119data StanzaType
116 = Unrecognized 120 = Unrecognized
117 | Ping 121 | Ping
@@ -125,7 +129,7 @@ data StanzaType
125 | RosterEvent { rosterEventType :: RosterEventType 129 | RosterEvent { rosterEventType :: RosterEventType
126 , rosterUser :: Text 130 , rosterUser :: Text
127 , rosterContact :: Text } 131 , rosterContact :: Text }
128 | Error 132 | Error StanzaError XML.Event
129 | PresenceStatus { presenceShow :: JabberShow 133 | PresenceStatus { presenceShow :: JabberShow
130 , presencePriority :: Maybe Int8 134 , presencePriority :: Maybe Int8
131 , presenceStatus :: [(Lang,Text)] 135 , presenceStatus :: [(Lang,Text)]
@@ -137,7 +141,11 @@ data StanzaType
137 | Message { msgThread :: Maybe MessageThread 141 | Message { msgThread :: Maybe MessageThread
138 , msgLangMap :: [(Lang,LangSpecificMessage)] 142 , msgLangMap :: [(Lang,LangSpecificMessage)]
139 } 143 }
140 deriving Show 144 | NotifyClientVersion { versionName :: Text
145 , versionVersion :: Text }
146 | InternalEnableHack ClientHack
147 | InternalCacheId Text
148 deriving (Show,Eq)
141 149
142data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey (TChan Stanza) 150data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey (TChan Stanza)
143 151
@@ -175,6 +183,24 @@ data XMPPServerParameters =
175 } 183 }
176 184
177 185
186enableClientHacks "Pidgin" version replyto = do
187 wlog "Enabling hack SimulatedChatErrors for client Pidgin"
188 donevar <- atomically newEmptyTMVar
189 sendReply donevar
190 (InternalEnableHack SimulatedChatErrors)
191 []
192 replyto
193enableClientHacks _ _ _ = return ()
194
195cacheMessageId id' replyto = do
196 wlog $ "Caching id " ++ Text.unpack id'
197 donevar <- atomically newEmptyTMVar
198 sendReply donevar
199 (InternalCacheId id')
200 []
201 replyto
202
203
178-- TODO: http://xmpp.org/rfcs/rfc6120.html#rules-remote-error 204-- TODO: http://xmpp.org/rfcs/rfc6120.html#rules-remote-error
179-- client connection 205-- client connection
180-- socat script to send stanza fragment 206-- socat script to send stanza fragment
@@ -303,6 +329,27 @@ conduitToChan c = do
303 atomically $ writeTVar clsrs Nothing 329 atomically $ writeTVar clsrs Nothing
304 return (chan,clsrs,quitvar) 330 return (chan,clsrs,quitvar)
305 331
332conduitToStanza
333 :: StanzaType
334 -> Maybe Text -- ^ id
335 -> Maybe Text -- ^ from
336 -> Maybe Text -- ^ to
337 -> Conduit () IO Event
338 -> IO Stanza
339conduitToStanza stype mid from to c = do
340 (chan,clsrs,quitvar) <- conduitToChan c
341 return
342 Stanza { stanzaType = stype
343 , stanzaId = mid
344 , stanzaTo = to
345 , stanzaFrom = from
346 , stanzaChan = chan
347 , stanzaClosers = clsrs
348 , stanzaInterrupt = quitvar
349 , stanzaOrigin = LocalPeer
350 }
351
352
306ioWriteChan :: MonadIO m => TChan a -> a -> m () 353ioWriteChan :: MonadIO m => TChan a -> a -> m ()
307ioWriteChan c v = liftIO . atomically $ writeTChan c v 354ioWriteChan c v = liftIO . atomically $ writeTChan c v
308 355
@@ -358,12 +405,16 @@ sendModifiedStanzaToClient stanza chan = do
358-- todo: this should probably be restricted to IO monad 405-- todo: this should probably be restricted to IO monad
359sendReply :: (Functor m, MonadIO m) => TMVar () -> StanzaType -> [Event] -> TChan Stanza -> m () 406sendReply :: (Functor m, MonadIO m) => TMVar () -> StanzaType -> [Event] -> TChan Stanza -> m ()
360sendReply donevar stype reply replychan = do 407sendReply donevar stype reply replychan = do
361 if null reply then return () 408 let stanzaTag = listToMaybe reply
362 else do 409 mid = stanzaTag >>= lookupAttrib "id" . tagAttrs
363 let stanzaTag = head reply 410 mfrom = stanzaTag >>= lookupAttrib "from" . tagAttrs
364 mid = lookupAttrib "id" (tagAttrs stanzaTag) 411 mto = stanzaTag >>= lookupAttrib "to" . tagAttrs
365 mfrom = lookupAttrib "from" (tagAttrs stanzaTag) 412 isInternal (InternalEnableHack {}) = True
366 mto = lookupAttrib "to" (tagAttrs stanzaTag) 413 isInternal (InternalCacheId {}) = True
414 isInternal _ = False
415 flip (maybe $ return ())
416 (fmap (const ()) stanzaTag `mplus` guard (isInternal stype))
417 . const $ do
367 replyStanza <- liftIO . atomically $ do 418 replyStanza <- liftIO . atomically $ do
368 replyChan <- newTChan 419 replyChan <- newTChan
369 replyClsrs <- newTVar (Just []) 420 replyClsrs <- newTVar (Just [])
@@ -391,11 +442,34 @@ grokStanzaIQGet stanza = do
391 "{jabber:iq:roster}query" -> return $ Just RequestRoster 442 "{jabber:iq:roster}query" -> return $ Just RequestRoster
392 name -> return . Just $ UnrecognizedQuery name 443 name -> return . Just $ UnrecognizedQuery name
393 444
394grokStanzaIQResult :: Monad m => XML.Event -> NestingXML o m (Maybe StanzaType) 445parseClientVersion :: NestingXML o IO (Maybe StanzaType)
446parseClientVersion = parseit Nothing Nothing
447 where
448 reportit mname mver = return $ do
449 name <- mname
450 ver <- mver
451 return NotifyClientVersion { versionName=name, versionVersion=ver }
452 parseit :: Maybe Text -> Maybe Text -> NestingXML o IO (Maybe StanzaType)
453 parseit mname mver = do
454 mtag <- nextElement
455 flip (maybe $ reportit mname mver) mtag $ \tag -> do
456 case tagName tag of
457 "{jabber:iq:version}name" -> do
458 x <- XML.content
459 parseit (Just x) mver
460 "{jabber:iq:version}version" -> do
461 x <- XML.content
462 parseit mname (Just x)
463 _ -> parseit mname mver
464
465
466grokStanzaIQResult :: XML.Event -> NestingXML o IO (Maybe StanzaType)
395grokStanzaIQResult stanza = do 467grokStanzaIQResult stanza = do
396 mtag <- nextElement 468 mtag <- nextElement
397 flip (maybe $ return (Just Pong)) mtag $ \tag -> do 469 flip (maybe $ return (Just Pong)) mtag $ \tag -> do
398 case tagName tag of 470 case tagName tag of
471 "{jabber:iq:version}query" | nameNamespace (tagName stanza)==Just "jabber:client"
472 -> parseClientVersion
399 _ -> return Nothing 473 _ -> return Nothing
400 474
401grokStanzaIQSet :: XML.Event -> NestingXML o IO (Maybe StanzaType) 475grokStanzaIQSet :: XML.Event -> NestingXML o IO (Maybe StanzaType)
@@ -598,13 +672,12 @@ xmppInbound :: Server ConnectionKey SockAddr
598 -> XMPPServerParameters 672 -> XMPPServerParameters
599 -> ConnectionKey 673 -> ConnectionKey
600 -> SockAddr 674 -> SockAddr
601 -> FlagCommand 675 -> FlagCommand -- ^ action to check whether the connection needs a ping
602 -> Source IO XML.Event 676 -> TChan Stanza -- ^ channel to announce incomming stanzas on
603 -> TChan Stanza 677 -> TChan Stanza -- ^ channel used to send stanzas
604 -> TChan Stanza 678 -> TMVar () -- ^ mvar that is filled when the connection quits
605 -> TMVar ()
606 -> Sink XML.Event IO () 679 -> Sink XML.Event IO ()
607xmppInbound sv xmpp k laddr pingflag src stanzas output donevar = doNestingXML $ do 680xmppInbound sv xmpp k laddr pingflag stanzas output donevar = doNestingXML $ do
608 let (namespace,tellmyname,tellyourname) = case k of 681 let (namespace,tellmyname,tellyourname) = case k of
609 ClientKey {} -> ( "jabber:client" 682 ClientKey {} -> ( "jabber:client"
610 , xmppTellMyNameToClient xmpp 683 , xmppTellMyNameToClient xmpp
@@ -726,9 +799,10 @@ streamFeatures "jabber:server" =
726 799
727 800
728greet' :: Text -> Text -> [XML.Event] 801greet' :: Text -> Text -> [XML.Event]
729greet' namespace host = 802greet' namespace host = EventBeginDocument : greet'' namespace host
730 [ EventBeginDocument 803
731 , EventBeginElement (streamP "stream") 804greet'' namespace host =
805 [ EventBeginElement (streamP "stream")
732 [("from",[ContentText host]) 806 [("from",[ContentText host])
733 ,("id",[ContentText "someid"]) 807 ,("id",[ContentText "someid"])
734 ,("xmlns",[ContentText namespace]) 808 ,("xmlns",[ContentText namespace])
@@ -770,6 +844,18 @@ iq_bind_reply mid jid =
770 , EventEndElement "{urn:ietf:params:xml:ns:xmpp-bind}jid" 844 , EventEndElement "{urn:ietf:params:xml:ns:xmpp-bind}jid"
771 , EventEndElement "{urn:ietf:params:xml:ns:xmpp-bind}bind" 845 , EventEndElement "{urn:ietf:params:xml:ns:xmpp-bind}bind"
772 , EventEndElement "{jabber:client}iq" 846 , EventEndElement "{jabber:client}iq"
847
848 {-
849 -- query for client version
850 , EventBeginElement "{jabber:client}iq"
851 [ attr "to" jid
852 , attr "from" hostname
853 , attr "type" "get"
854 , attr "id" "version"]
855 , EventBeginElement "{jabber:iq:version}query" []
856 , EventEndElement "{jabber:iq:version}query"
857 , EventEndElement "{jabber:client}iq"
858 -}
773 ] 859 ]
774 860
775iq_session_reply :: Maybe Text -> Text -> [XML.Event] 861iq_session_reply :: Maybe Text -> Text -> [XML.Event]
@@ -845,6 +931,26 @@ goodbye =
845 , EventEndDocument 931 , EventEndDocument
846 ] 932 ]
847 933
934simulateChatError err mfrom =
935 [ EventBeginElement "{jabber:client}message"
936 ((maybe id (\t->(attr "from" t:)) mfrom)
937 [attr "type" "normal" ])
938 , EventBeginElement "{jabber:client}body" []
939 , EventContent $ ContentText ("/me " <> errorText err)
940 , EventEndElement "{jabber:client}body"
941 , EventBeginElement "{http://jabber.org/protocol/xhtml-im}html" []
942 , EventBeginElement "{http://www.w3.org/1999/xhtml}body" []
943 , EventBeginElement "{http://www.w3.org/1999/xhtml}p"
944 [ attr "style" "font-weight:bold; color:red"
945 ]
946 , EventContent $ ContentText ("/me " <> errorText err)
947 , EventEndElement "{http://www.w3.org/1999/xhtml}p"
948 , EventEndElement "{http://www.w3.org/1999/xhtml}body"
949 , EventEndElement "{http://jabber.org/protocol/xhtml-im}html"
950 , EventEndElement "{jabber:client}message"
951 ]
952
953
848forkConnection :: Server ConnectionKey SockAddr 954forkConnection :: Server ConnectionKey SockAddr
849 -> XMPPServerParameters 955 -> XMPPServerParameters
850 -> ConnectionKey 956 -> ConnectionKey
@@ -917,6 +1023,8 @@ forkConnection sv xmpp k laddr pingflag src snk stanzas = do
917 mapM_ fail es' -- TODO: queue or save these for re-connect? 1023 mapM_ fail es' -- TODO: queue or save these for re-connect?
918 wlog $ "end post-queue fork: " ++ show k 1024 wlog $ "end post-queue fork: " ++ show k
919 output <- atomically newTChan 1025 output <- atomically newTChan
1026 hacks <- atomically $ newTVar Map.empty
1027 msgids <- atomically $ newTVar []
920 forkIO $ do 1028 forkIO $ do
921 -- mapM_ (atomically . Slotted.push slots Nothing) greetPeer 1029 -- mapM_ (atomically . Slotted.push slots Nothing) greetPeer
922 fix $ \loop -> do 1030 fix $ \loop -> do
@@ -936,9 +1044,33 @@ forkConnection sv xmpp k laddr pingflag src snk stanzas = do
936 PeerKey {} -> "P" 1044 PeerKey {} -> "P"
937 wlog "" 1045 wlog ""
938 stanzaToConduit dup $$ prettyPrint typ 1046 stanzaToConduit dup $$ prettyPrint typ
1047 case stanzaType stanza of
1048 InternalEnableHack hack -> do
1049 -- wlog $ "enable hack: " ++ show hack
1050 atomically $ modifyTVar' hacks (Map.insert hack ())
1051 InternalCacheId x -> do
1052 -- wlog $ "cache id thread: " ++ show x
1053 atomically $ modifyTVar' msgids (take 3 . (x:))
1054 _ -> return ()
939 stanzaToConduit stanza =$= wrapStanzaConduit stanza 1055 stanzaToConduit stanza =$= wrapStanzaConduit stanza
940 $$ awaitForever 1056 $$ awaitForever
941 $ liftIO . atomically . Slotted.push slots Nothing 1057 $ liftIO . atomically . Slotted.push slots Nothing
1058 case stanzaType stanza of
1059 Error err tag | tagName tag=="{jabber:client}message" -> do
1060 -- ids <- atomically $ readTVar msgids
1061 -- wlog $ "ids = " ++ show (stanzaId stanza, ids)
1062 b <- atomically $ do m <- readTVar hacks
1063 cached <- readTVar msgids
1064 flip (maybe $ return False) (stanzaId stanza) $ \id' -> do
1065 return $ Map.member SimulatedChatErrors m
1066 && elem id' cached
1067 when b $ do
1068 let sim = simulateChatError err (stanzaFrom stanza)
1069 wlog $ "sending simulated chat for error message."
1070 CL.sourceList sim =$= wrapStanzaConduit stanza -- not quite right, but whatever
1071 $$ awaitForever
1072 $ liftIO . atomically . Slotted.push slots Nothing
1073 _ -> return ()
942 loop 1074 loop
943 ,do pingflag >>= check 1075 ,do pingflag >>= check
944 return $ do 1076 return $ do
@@ -963,7 +1095,7 @@ forkConnection sv xmpp k laddr pingflag src snk stanzas = do
963 wlog $ "end pre-queue fork: " ++ show k 1095 wlog $ "end pre-queue fork: " ++ show k
964 forkIO $ do 1096 forkIO $ do
965 -- src $$ awaitForever (lift . putStrLn . takeWhile (/=' ') . show) 1097 -- src $$ awaitForever (lift . putStrLn . takeWhile (/=' ') . show)
966 src $$ xmppInbound sv xmpp k laddr pingflag src stanzas output rdone 1098 src $$ xmppInbound sv xmpp k laddr pingflag stanzas output rdone
967 atomically $ putTMVar rdone () 1099 atomically $ putTMVar rdone ()
968 wlog $ "end reader fork: " ++ show k 1100 wlog $ "end reader fork: " ++ show k
969 return output 1101 return output
@@ -1017,6 +1149,7 @@ sendRoster query xmpp replyto = do
1017 jid <- case k of 1149 jid <- case k of
1018 ClientKey {} -> xmppTellClientHisName xmpp k -- LookupClientJID xmpp k 1150 ClientKey {} -> xmppTellClientHisName xmpp k -- LookupClientJID xmpp k
1019 PeerKey {} -> xmppTellClientNameOfPeer xmpp k 1151 PeerKey {} -> xmppTellClientNameOfPeer xmpp k
1152 hostname <- xmppTellMyNameToClient xmpp
1020 let getlist f = do 1153 let getlist f = do
1021 bs <- f xmpp k 1154 bs <- f xmpp k
1022 -- js <- mapM parseHostNameJID bs 1155 -- js <- mapM parseHostNameJID bs
@@ -1041,17 +1174,23 @@ sendRoster query xmpp replyto = do
1041 xmlifyRosterItems solicited "none" subnone 1174 xmlifyRosterItems solicited "none" subnone
1042 yield $ EventEndElement "{jabber:iq:roster}query" 1175 yield $ EventEndElement "{jabber:iq:roster}query"
1043 yield $ EventEndElement "{jabber:client}iq" 1176 yield $ EventEndElement "{jabber:client}iq"
1044 (chan,clsrs,quitvar) <- conduitToChan roster 1177
1045 ioWriteChan replyto 1178 conduitToStanza Roster
1046 Stanza { stanzaType = Roster 1179 (stanzaId query)
1047 , stanzaId = (stanzaId query) 1180 Nothing
1048 , stanzaTo = Just jid 1181 (Just jid)
1049 , stanzaFrom = Nothing 1182 roster >>= ioWriteChan replyto
1050 , stanzaChan = chan 1183 {-
1051 , stanzaClosers = clsrs 1184 let debugpresence =
1052 , stanzaInterrupt = quitvar 1185 [ EventBeginElement "{jabber:client}presence"
1053 , stanzaOrigin = LocalPeer 1186 [ attr "from" "guest@oxio4inifatsetlx.onion"
1054 } 1187 , attr "to" jid]
1188 , EventEndElement "{jabber:client}presence"
1189 ]
1190 quitvar <- atomically newEmptyTMVar
1191 sendReply quitvar Unrecognized debugpresence replyto
1192 -}
1193
1055 1194
1056socketFromKey :: Server ConnectionKey SockAddr -> ConnectionKey -> IO SockAddr 1195socketFromKey :: Server ConnectionKey SockAddr -> ConnectionKey -> IO SockAddr
1057socketFromKey sv k = do 1196socketFromKey sv k = do
@@ -1065,6 +1204,152 @@ socketFromKey sv k = do
1065 -- Shouldnt happen anyway. 1204 -- Shouldnt happen anyway.
1066 Just cd -> return $ cdata cd 1205 Just cd -> return $ cdata cd
1067 1206
1207class StanzaFirstTag a where
1208 stanzaFirstTag :: StanzaWrap a -> IO XML.Event
1209instance StanzaFirstTag (TChan XML.Event) where
1210 stanzaFirstTag stanza = do
1211 e <-atomically $ peekTChan (stanzaChan stanza)
1212 return e
1213
1214data StanzaError
1215 = BadRequest
1216 | Conflict
1217 | FeatureNotImplemented
1218 | Forbidden
1219 | Gone
1220 | InternalServerError
1221 | ItemNotFound
1222 | JidMalformed
1223 | NotAcceptable
1224 | NotAllowed
1225 | NotAuthorized
1226 | PaymentRequired
1227 | RecipientUnavailable
1228 | Redirect
1229 | RegistrationRequired
1230 | RemoteServerNotFound
1231 | RemoteServerTimeout
1232 | ResourceConstraint
1233 | ServiceUnavailable
1234 | SubscriptionRequired
1235 | UndefinedCondition
1236 | UnexpectedRequest
1237 deriving (Show,Enum,Ord,Eq)
1238
1239xep0086 e =
1240 case e of
1241 BadRequest -> ("modify", 400)
1242 Conflict -> ("cancel", 409)
1243 FeatureNotImplemented -> ("cancel", 501)
1244 Forbidden -> ("auth", 403)
1245 Gone -> ("modify", 302)
1246 InternalServerError -> ("wait", 500)
1247 ItemNotFound -> ("cancel", 404)
1248 JidMalformed -> ("modify", 400)
1249 NotAcceptable -> ("modify", 406)
1250 NotAllowed -> ("cancel", 405)
1251 NotAuthorized -> ("auth", 401)
1252 PaymentRequired -> ("auth", 402)
1253 RecipientUnavailable -> ("wait", 404)
1254 Redirect -> ("modify", 302)
1255 RegistrationRequired -> ("auth", 407)
1256 RemoteServerNotFound -> ("cancel", 404)
1257 RemoteServerTimeout -> ("wait", 504)
1258 ResourceConstraint -> ("wait", 500)
1259 ServiceUnavailable -> ("cancel", 503)
1260 SubscriptionRequired -> ("auth", 407)
1261 UndefinedCondition -> ("", 500)
1262 UnexpectedRequest -> ("wait", 400)
1263
1264errorText :: StanzaError -> Text
1265errorText e =
1266 case e of
1267 BadRequest -> "Bad request"
1268 Conflict -> "Conflict"
1269 FeatureNotImplemented -> "This feature is not implemented"
1270 Forbidden -> "Forbidden"
1271 Gone -> "Recipient can no longer be contacted"
1272 InternalServerError -> "Internal server error"
1273 ItemNotFound -> "Item not found"
1274 JidMalformed -> "JID Malformed"
1275 NotAcceptable -> "Message was rejected"
1276 NotAllowed -> "Not allowed"
1277 NotAuthorized -> "Not authorized"
1278 PaymentRequired -> "Payment is required"
1279 RecipientUnavailable -> "Recipient is unavailable"
1280 Redirect -> "Redirect"
1281 RegistrationRequired -> "Registration required"
1282 RemoteServerNotFound -> "Recipient's server not found"
1283 RemoteServerTimeout -> "Remote server timeout"
1284 ResourceConstraint -> "The server is low on resources"
1285 ServiceUnavailable -> "The service is unavailable"
1286 SubscriptionRequired -> "A subscription is required"
1287 UndefinedCondition -> "Undefined condition"
1288 UnexpectedRequest -> "Unexpected request"
1289
1290eventContent cs = maybe "" (foldr1 (<>) . map content1) cs
1291 where content1 (ContentText t) = t
1292 content1 (ContentEntity t) = t
1293
1294makeErrorStanza :: StanzaFirstTag a => StanzaWrap a -> IO [XML.Event]
1295makeErrorStanza stanza = do
1296 startTag <- stanzaFirstTag stanza
1297 let n = tagName startTag
1298 endTag = EventEndElement n
1299 amap0 = Map.fromList (tagAttrs startTag)
1300 mto = Map.lookup "to" amap0
1301 mfrom = Map.lookup "from" amap0
1302 mtype = Map.lookup "type" amap0
1303 mid = Map.lookup "id" amap0
1304 amap1 = Map.alter (const mto) "from" amap0
1305 -- amap2 = Map.alter (const $ Just $ [ContentText "blackbird"]) {-mfrom)-} "to" amap1
1306 amap2 = Map.alter (const mfrom) "to" amap1
1307 amap3 = Map.insert "type" [XML.ContentText "error"] amap2
1308 startTag' = EventBeginElement
1309 (tagName startTag)
1310 (Map.toList amap3)
1311 -- err = Gone -- FeatureNotImplemented -- UndefinedCondition -- RecipientUnavailable
1312 err = RecipientUnavailable
1313 errname = n { nameLocalName = "error" }
1314 -- errattrs = [attr "type" "wait"] -- "modify"]
1315 errorAttribs e xs = ys ++ xs -- todo replace instead of append
1316 where (typ,code) = xep0086 e
1317 ys = [attr "type" typ, attr "code" (Text.pack . show $ code)]
1318 errorTagLocalName e = Text.pack . drop 1 $ do
1319 c <- show e
1320 if 'A' <= c && c <= 'Z'
1321 then [ '-', chr( ord c - ord 'A' + ord 'a') ]
1322 else return c
1323 errorTagName = Name { nameNamespace = Just "urn:ietf:params:xml:ns:xmpp-stanzas"
1324 , nameLocalName = errorTagLocalName err
1325 , namePrefix = Nothing }
1326 errattrs = errorAttribs err []
1327 let wlogd v s = do
1328 wlog $ "error "++show (lookupAttrib "id" $ tagAttrs startTag)++" " ++ v ++ " = " ++ show s
1329 {-
1330 wlogd "amap0" amap0
1331 wlogd "mto" mto
1332 wlogd "mfrom" mfrom
1333 wlogd "amap3" amap3
1334 -}
1335 if eventContent mtype=="error" then return [] else do
1336 return [ startTag'
1337 , EventBeginElement errname errattrs
1338 , EventBeginElement errorTagName []
1339 , EventEndElement errorTagName
1340 , EventEndElement errname
1341 {-
1342 , EventBeginElement "{jabber:client}body" []
1343 , EventContent (ContentText "what?")
1344 , EventEndElement "{jabber:client}body"
1345 -}
1346 {-
1347 , EventBeginElement "{154ae29f-98f2-4af4-826d-a40c8a188574}dummy" []
1348 , EventEndElement "{154ae29f-98f2-4af4-826d-a40c8a188574}dummy"
1349 -}
1350 , endTag
1351 ]
1352
1068monitor :: 1353monitor ::
1069 Server ConnectionKey SockAddr 1354 Server ConnectionKey SockAddr
1070 -> ConnectionParameters ConnectionKey SockAddr 1355 -> ConnectionParameters ConnectionKey SockAddr
@@ -1100,11 +1385,6 @@ monitor sv params xmpp = do
1100 return dup 1385 return dup
1101 _ -> return stanza 1386 _ -> return stanza
1102 forkIO $ do 1387 forkIO $ do
1103 case stanzaType stanza of
1104 Message {} -> do
1105 let fail = wlog $ "Failed delivery id="++show (stanzaId stanza) -- TODO
1106 xmppDeliverMessage xmpp fail stanza
1107 _ -> return ()
1108 case stanzaOrigin stanza of 1388 case stanzaOrigin stanza of
1109 NetworkOrigin k@(ClientKey {}) replyto -> 1389 NetworkOrigin k@(ClientKey {}) replyto ->
1110 case stanzaType stanza of 1390 case stanzaType stanza of
@@ -1112,7 +1392,34 @@ monitor sv params xmpp = do
1112 sockaddr <- socketFromKey sv k 1392 sockaddr <- socketFromKey sv k
1113 rsc <- xmppChooseResourceName xmpp k sockaddr wanted 1393 rsc <- xmppChooseResourceName xmpp k sockaddr wanted
1114 let reply = iq_bind_reply (stanzaId stanza) rsc 1394 let reply = iq_bind_reply (stanzaId stanza) rsc
1395 -- sendReply quitVar SetResource reply replyto
1396 hostname <- xmppTellMyNameToClient xmpp
1397 let requestVersion = do
1398 yield $ EventBeginElement "{jabber:client}iq"
1399 [ attr "to" rsc
1400 , attr "from" hostname
1401 , attr "type" "get"
1402 , attr "id" "version"]
1403 yield $ EventBeginElement "{jabber:iq:version}query" []
1404 yield $ EventEndElement "{jabber:iq:version}query"
1405 yield $ EventEndElement "{jabber:client}iq"
1406 {-
1407 -- XXX Debug chat:
1408 yield $ EventBeginElement "{jabber:client}message"
1409 [ attr "from" $ eventContent (Just [ContentText rsc])
1410 , attr "type" "normal" ] -- "blackbird" ]
1411 yield $ EventBeginElement "{jabber:client}body" []
1412 yield $ EventContent $ ContentText ("hello?")
1413 yield $ EventEndElement "{jabber:client}body"
1414 yield $ EventEndElement "{jabber:client}message"
1415 -}
1115 sendReply quitVar SetResource reply replyto 1416 sendReply quitVar SetResource reply replyto
1417 conduitToStanza (UnrecognizedQuery "{jabber:iq:version}query")
1418 Nothing -- id
1419 (Just hostname) -- from
1420 (Just rsc) -- to
1421 requestVersion
1422 >>= ioWriteChan replyto
1116 SessionRequest -> do 1423 SessionRequest -> do
1117 me <- xmppTellMyNameToClient xmpp 1424 me <- xmppTellMyNameToClient xmpp
1118 let reply = iq_session_reply (stanzaId stanza) me 1425 let reply = iq_session_reply (stanzaId stanza) me
@@ -1122,12 +1429,36 @@ monitor sv params xmpp = do
1122 xmppSubscribeToRoster xmpp k 1429 xmppSubscribeToRoster xmpp k
1123 PresenceStatus {} -> do 1430 PresenceStatus {} -> do
1124 xmppInformClientPresence xmpp k stanza 1431 xmppInformClientPresence xmpp k stanza
1432 NotifyClientVersion name version -> do
1433 enableClientHacks name version replyto
1125 UnrecognizedQuery query -> do 1434 UnrecognizedQuery query -> do
1126 me <- xmppTellMyNameToClient xmpp 1435 me <- xmppTellMyNameToClient xmpp
1127 let reply = iq_service_unavailable (stanzaId stanza) me query 1436 let reply = iq_service_unavailable (stanzaId stanza) me query
1128 sendReply quitVar Error reply replyto 1437 sendReply quitVar (Error ServiceUnavailable (head reply)) reply replyto
1438 Message {} -> do
1439 -- wlog $ "LANGMAP "++show (stanzaId stanza, msgLangMap (stanzaType stanza))
1440 maybe (return ()) (flip cacheMessageId replyto) $ do
1441 guard . not . null . mapMaybe (msgBody . snd) $ msgLangMap (stanzaType stanza)
1442 stanzaId stanza
1129 _ -> return () 1443 _ -> return ()
1130 _ -> return () 1444 _ -> return ()
1445 case stanzaType stanza of
1446 Message {} -> do
1447 case stanzaOrigin stanza of
1448 LocalPeer {} -> return ()
1449 NetworkOrigin _ replyto -> do
1450 let fail = wlog $ "Failed delivery id="++show (stanzaId stanza) -- TODO
1451 xmppDeliverMessage xmpp fail stanza
1452 {-
1453 -- test error
1454 reply <- makeErrorStanza stanza
1455 tag <- stanzaFirstTag stanza
1456 sendReply quitVar (Error RecipientUnavailable tag) reply replyto
1457 -}
1458 -- -- bad idea:
1459 -- let newStream = greet'' "jabber:client" "blackbird"
1460 -- sendReply quitVar Error newStream replyto
1461 _ -> return ()
1131 -- We need to clone in the case the stanza is passed on as for Message. 1462 -- We need to clone in the case the stanza is passed on as for Message.
1132#ifndef PINGNOISE 1463#ifndef PINGNOISE
1133 let notping f = case stanzaType stanza of Pong -> return () 1464 let notping f = case stanzaType stanza of Pong -> return ()