summaryrefslogtreecommitdiff
path: root/Presence
diff options
context:
space:
mode:
Diffstat (limited to 'Presence')
-rw-r--r--Presence/EventUtil.hs6
-rw-r--r--Presence/XMPPServer.hs99
2 files changed, 83 insertions, 22 deletions
diff --git a/Presence/EventUtil.hs b/Presence/EventUtil.hs
index a1c48e33..adcae1d3 100644
--- a/Presence/EventUtil.hs
+++ b/Presence/EventUtil.hs
@@ -29,6 +29,12 @@ isServerIQOf (EventBeginElement name attrs) testType
29 = True 29 = True
30isServerIQOf _ _ = False 30isServerIQOf _ _ = False
31 31
32isClientIQOf (EventBeginElement name attrs) testType
33 | name=="{jabber:client}iq"
34 && matchAttrib "type" testType attrs
35 = True
36isClientIQOf _ _ = False
37
32matchAttrib name value attrs = 38matchAttrib name value attrs =
33 case List.find ( (==name) . fst) attrs of 39 case List.find ( (==name) . fst) attrs of
34 Just (_,[ContentText x]) | x==value -> True 40 Just (_,[ContentText x]) | x==value -> True
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs
index 140c91af..92f59061 100644
--- a/Presence/XMPPServer.hs
+++ b/Presence/XMPPServer.hs
@@ -104,6 +104,8 @@ data Stanza
104data StanzaType = Unrecognized | Ping | Pong 104data StanzaType = Unrecognized | Ping | Pong
105 deriving Show 105 deriving Show
106 106
107data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey
108
107data Stanza = Stanza 109data Stanza = Stanza
108 { stanzaType :: StanzaType 110 { stanzaType :: StanzaType
109 , stanzaId :: Maybe Text 111 , stanzaId :: Maybe Text
@@ -112,6 +114,7 @@ data Stanza = Stanza
112 , stanzaChan :: TChan XML.Event 114 , stanzaChan :: TChan XML.Event
113 , stanzaClosers :: TVar (Maybe [XML.Event]) 115 , stanzaClosers :: TVar (Maybe [XML.Event])
114 , stanzaInterrupt :: TMVar () 116 , stanzaInterrupt :: TMVar ()
117 , stanzaOrigin :: StanzaOrigin
115 } 118 }
116 119
117copyToChannel f chan closer_stack = awaitForever copy 120copyToChannel f chan closer_stack = awaitForever copy
@@ -145,6 +148,17 @@ grockStanzaIQGet stanza = do
145 148
146ioWriteChan c v = liftIO . atomically $ writeTChan c v 149ioWriteChan c v = liftIO . atomically $ writeTChan c v
147 150
151
152grokStanza "jabber:server" stanzaTag =
153 case () of
154 _ | stanzaTag `isServerIQOf` "get" -> grockStanzaIQGet stanzaTag
155 _ -> return $ Just Unrecognized
156
157grokStanza "jabber:client" stanzaTag =
158 case () of
159 _ | stanzaTag `isClientIQOf` "get" -> grockStanzaIQGet stanzaTag
160 _ -> return $ Just Unrecognized
161
148xmppInbound :: ConnectionKey -> FlagCommand 162xmppInbound :: ConnectionKey -> FlagCommand
149 -> Source IO XML.Event 163 -> Source IO XML.Event
150 -> TChan Stanza 164 -> TChan Stanza
@@ -152,6 +166,9 @@ xmppInbound :: ConnectionKey -> FlagCommand
152 -> TMVar () 166 -> TMVar ()
153 -> Sink XML.Event IO () 167 -> Sink XML.Event IO ()
154xmppInbound k pingflag src stanzas output donevar = doNestingXML $ do 168xmppInbound k pingflag src stanzas output donevar = doNestingXML $ do
169 let namespace = case k of
170 ClientKey {} -> "jabber:client"
171 PeerKey {} -> "jabber:server"
155 withXML $ \begindoc -> do 172 withXML $ \begindoc -> do
156 when (begindoc==EventBeginDocument) $ do 173 when (begindoc==EventBeginDocument) $ do
157 whenJust nextElement $ \xml -> do 174 whenJust nextElement $ \xml -> do
@@ -169,16 +186,17 @@ xmppInbound k pingflag src stanzas output donevar = doNestingXML $ do
169 let mid = lookupAttrib "id" (tagAttrs stanzaTag) 186 let mid = lookupAttrib "id" (tagAttrs stanzaTag)
170 mfrom = lookupAttrib "from" (tagAttrs stanzaTag) 187 mfrom = lookupAttrib "from" (tagAttrs stanzaTag)
171 mto = lookupAttrib "to" (tagAttrs stanzaTag) 188 mto = lookupAttrib "to" (tagAttrs stanzaTag)
172 dispatch <- 189 dispatch <- grokStanza namespace stanzaTag
173 case () of
174 _ | stanzaTag `isServerIQOf` "get" -> grockStanzaIQGet stanzaTag
175 _ -> return $ Just Unrecognized
176 flip (maybe $ return ()) dispatch $ \dispatch -> 190 flip (maybe $ return ()) dispatch $ \dispatch ->
177 case dispatch of 191 case dispatch of
178 Ping -> do 192 Ping -> do
193 -- TODO: check that the to-address matches this server.
194 -- Otherwise it could be a client-to-client ping or a
195 -- client-to-server for some other server.
196 -- For now, assuming its for the immediate connection.
179 let to = maybe "todo" id mto 197 let to = maybe "todo" id mto
180 from = maybe "todo" id mfrom 198 from = maybe "todo" id mfrom
181 let pong = peerPong mid to from 199 let pong = makePong namespace mid to from
182 -- liftIO $ wlog "got ping, sending pong..." 200 -- liftIO $ wlog "got ping, sending pong..."
183 pongChan <- liftIO $ atomically newTChan 201 pongChan <- liftIO $ atomically newTChan
184 pongClsrs <- liftIO $ atomically $ newTVar (Just []) 202 pongClsrs <- liftIO $ atomically $ newTVar (Just [])
@@ -189,6 +207,7 @@ xmppInbound k pingflag src stanzas output donevar = doNestingXML $ do
189 , stanzaChan = pongChan 207 , stanzaChan = pongChan
190 , stanzaClosers = pongClsrs 208 , stanzaClosers = pongClsrs
191 , stanzaInterrupt = donevar 209 , stanzaInterrupt = donevar
210 , stanzaOrigin = LocalPeer
192 } 211 }
193 void . liftIO . forkIO $ do 212 void . liftIO . forkIO $ do
194 mapM_ (ioWriteChan pongChan) pong 213 mapM_ (ioWriteChan pongChan) pong
@@ -202,6 +221,7 @@ xmppInbound k pingflag src stanzas output donevar = doNestingXML $ do
202 , stanzaChan = chan 221 , stanzaChan = chan
203 , stanzaClosers = clsrs 222 , stanzaClosers = clsrs
204 , stanzaInterrupt = donevar 223 , stanzaInterrupt = donevar
224 , stanzaOrigin = NetworkOrigin k
205 } 225 }
206 awaitCloser stanza_lvl 226 awaitCloser stanza_lvl
207 liftIO . atomically $ writeTVar clsrs Nothing 227 liftIO . atomically $ writeTVar clsrs Nothing
@@ -230,16 +250,39 @@ readUntilNothing ch = do
230 return (x:xs)) 250 return (x:xs))
231 x 251 x
232 252
253greet' namespace host =
254 [ EventBeginDocument
255 , EventBeginElement (streamP "stream")
256 [("from",[ContentText host])
257 ,("id",[ContentText "someid"])
258 ,("xmlns",[ContentText namespace])
259 ,("xmlns:stream",[ContentText "http://etherx.jabber.org/streams"])
260 ,("version",[ContentText "1.0"])
261 ]
262 , EventBeginElement (streamP "features") []
263 , EventBeginElement "{urn:ietf:params:xml:ns:xmpp-bind}bind" []
264 , EventEndElement "{urn:ietf:params:xml:ns:xmpp-bind}bind"
265
266 {-
267 -- , " <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
268 , " <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
269 -- , " <mechanism>DIGEST-MD5</mechanism>"
270 , " <mechanism>PLAIN</mechanism>"
271 , " </mechanisms> "
272 -}
273
274 , EventEndElement (streamP "features")
275 ]
233 276
234greetPeer = 277greet namespace =
235 [ EventBeginDocument 278 [ EventBeginDocument
236 , EventBeginElement (streamP "stream") 279 , EventBeginElement (streamP "stream")
237 [ attr "xmlns" "jabber:server" 280 [ attr "xmlns" namespace
238 , attr "version" "1.0" 281 , attr "version" "1.0"
239 ] 282 ]
240 ] 283 ]
241 284
242goodbyePeer = 285goodbye =
243 [ EventEndElement (streamP "stream") 286 [ EventEndElement (streamP "stream")
244 , EventEndDocument 287 , EventEndDocument
245 ] 288 ]
@@ -248,10 +291,11 @@ data XMPPState
248 = PingSlot 291 = PingSlot
249 deriving (Eq,Ord) 292 deriving (Eq,Ord)
250 293
294mkname namespace name = (Name name (Just namespace) Nothing)
251 295
252peerPing :: Maybe Text -> Text -> Text -> [XML.Event] 296makePing :: Text -> Maybe Text -> Text -> Text -> [XML.Event]
253peerPing mid to from = 297makePing namespace mid to from =
254 [ EventBeginElement "{jabber:server}iq" 298 [ EventBeginElement (mkname namespace "iq")
255 $ (case mid of 299 $ (case mid of
256 Just c -> (("id",[ContentText c]):) 300 Just c -> (("id",[ContentText c]):)
257 _ -> id ) 301 _ -> id )
@@ -261,10 +305,10 @@ peerPing mid to from =
261 ] 305 ]
262 , EventBeginElement "{urn:xmpp:ping}ping" [] 306 , EventBeginElement "{urn:xmpp:ping}ping" []
263 , EventEndElement "{urn:xmpp:ping}ping" 307 , EventEndElement "{urn:xmpp:ping}ping"
264 , EventEndElement "{jabber:server}iq" ] 308 , EventEndElement $ mkname namespace "iq"]
265 309
266peerPong mid to from = 310makePong namespace mid to from =
267 [ EventBeginElement "{jabber:server}iq" 311 [ EventBeginElement (mkname namespace "iq")
268 $(case mid of 312 $(case mid of
269 Just c -> (("id",[ContentText c]):) 313 Just c -> (("id",[ContentText c]):)
270 _ -> id) 314 _ -> id)
@@ -272,7 +316,7 @@ peerPong mid to from =
272 , attr "to" to 316 , attr "to" to
273 , attr "from" from 317 , attr "from" from
274 ] 318 ]
275 , EventEndElement "{jabber:server}iq" 319 , EventEndElement (mkname namespace "iq")
276 ] 320 ]
277 321
278 322
@@ -283,12 +327,15 @@ forkConnection :: ConnectionKey
283 -> TChan Stanza 327 -> TChan Stanza
284 -> IO (TChan Stanza) 328 -> IO (TChan Stanza)
285forkConnection k pingflag src snk stanzas = do 329forkConnection k pingflag src snk stanzas = do
330 let namespace = case k of
331 ClientKey {} -> "jabber:client"
332 PeerKey {} -> "jabber:server"
286 rdone <- atomically newEmptyTMVar 333 rdone <- atomically newEmptyTMVar
287 slots <- atomically $ Slotted.new isEventBeginElement isEventEndElement 334 slots <- atomically $ Slotted.new isEventBeginElement isEventEndElement
288 needsFlush <- atomically $ newTVar False 335 needsFlush <- atomically $ newTVar False
289 let _ = slots :: Slotted.UpdateStream XMPPState XML.Event 336 let _ = slots :: Slotted.UpdateStream XMPPState XML.Event
290 let greet_src = do 337 let greet_src = do
291 CL.sourceList greetPeer =$= CL.map Chunk 338 CL.sourceList (greet' namespace "localhost") =$= CL.map Chunk
292 yield Flush 339 yield Flush
293 slot_src = do 340 slot_src = do
294 what <- lift . atomically $ foldr1 orElse 341 what <- lift . atomically $ foldr1 orElse
@@ -324,11 +371,13 @@ forkConnection k pingflag src snk stanzas = do
324 from = "todo" -- Look it up from Server object 371 from = "todo" -- Look it up from Server object
325 -- or pass it with Connection event. 372 -- or pass it with Connection event.
326 mid = Just "ping" 373 mid = Just "ping"
327 ping = peerPing mid to from 374 ping = makePing namespace mid to from
328 mapM_ (atomically . Slotted.push slots (Just $ PingSlot)) 375 mapM_ (atomically . Slotted.push slots (Just $ PingSlot))
329 ping 376 ping
330 wlog "" 377 wlog ""
331 CL.sourceList ping $$ prettyPrint "P<-Ping " 378 CL.sourceList ping $$ prettyPrint $ case k of
379 ClientKey {} -> "C<-Ping"
380 PeerKey {} -> "P<-Ping "
332 loop 381 loop
333 ,readTMVar rdone >> return (return ()) 382 ,readTMVar rdone >> return (return ())
334 ] 383 ]
@@ -409,7 +458,11 @@ monitor sv params = do
409 RequiresPing -> return () -- wlog $ tomsg k "RequiresPing" 458 RequiresPing -> return () -- wlog $ tomsg k "RequiresPing"
410 _ -> return () 459 _ -> return ()
411 , readTChan stanzas >>= \stanza -> return $ do 460 , readTChan stanzas >>= \stanza -> return $ do
412 let typ = Strict8.pack $ "P->"++(show (stanzaType stanza))++" " 461 let typ = Strict8.pack $ c ++ "->"++(show (stanzaType stanza))++" "
462 c = case stanzaOrigin stanza of
463 LocalPeer -> "*"
464 NetworkOrigin (ClientKey {}) -> "C"
465 NetworkOrigin (PeerKey {}) -> "P"
413 wlog "" 466 wlog ""
414 stanzaToConduit stanza $$ prettyPrint typ 467 stanzaToConduit stanza $$ prettyPrint typ
415 ] 468 ]
@@ -428,10 +481,12 @@ xmppServer = do
428 { pingInterval = 5000 481 { pingInterval = 5000
429 , timeout = 1000 482 , timeout = 1000
430 , duplex = False } 483 , duplex = False }
431 client_params = connectionDefaults clientKey 484 client_params = (connectionDefaults clientKey)
485 { pingInterval = 0
486 , timeout = 0
487 }
432 liftIO $ do 488 liftIO $ do
433 forkIO $ monitor sv peer_params 489 forkIO $ monitor sv peer_params
434 control sv (Listen peerport peer_params) 490 control sv (Listen peerport peer_params)
435 -- todo 491 control sv (Listen clientport client_params)
436 -- control sv (Listen clientport client_params)
437 return (sv,peer_params) 492 return (sv,peer_params)