summaryrefslogtreecommitdiff
path: root/Presence
diff options
context:
space:
mode:
Diffstat (limited to 'Presence')
-rw-r--r--Presence/EventUtil.hs34
-rw-r--r--Presence/Nesting.hs79
2 files changed, 113 insertions, 0 deletions
diff --git a/Presence/EventUtil.hs b/Presence/EventUtil.hs
index e62f8afc..bdea9fa2 100644
--- a/Presence/EventUtil.hs
+++ b/Presence/EventUtil.hs
@@ -3,6 +3,7 @@ module EventUtil where
3 3
4import Control.Monad 4import Control.Monad
5import Data.XML.Types as XML 5import Data.XML.Types as XML
6import qualified Data.List as List
6 7
7getStreamName (EventBeginElement name _) = name 8getStreamName (EventBeginElement name _) = name
8 9
@@ -21,3 +22,36 @@ elementAttrs _ _ = mzero
21streamP name = Name name (Just "http://etherx.jabber.org/streams") (Just "stream") 22streamP name = Name name (Just "http://etherx.jabber.org/streams") (Just "stream")
22 23
23attr name value = (name,[ContentText value]) 24attr name value = (name,[ContentText value])
25
26isServerIQOf (EventBeginElement name attrs) testType
27 | name=="{jabber:server}iq"
28 && matchAttrib "type" testType attrs
29 = True
30isServerIQOf _ _ = False
31
32matchAttrib name value attrs =
33 case List.find ( (==name) . fst) attrs of
34 Just (_,[ContentText x]) | x==value -> True
35 Just (_,[ContentEntity x]) | x==value -> True
36 _ -> False
37
38lookupAttrib name attrs =
39 case List.find ( (==name) . fst) attrs of
40 Just (_,[ContentText x]) -> Just x
41 Just (_,[ContentEntity x]) -> Just x
42 _ -> Nothing
43
44tagAttrs (EventBeginElement _ xs) = xs
45tagAttrs _ = []
46
47
48{-
49iqTypeSet = "set"
50iqTypeGet = "get"
51iqTypeResult = "result"
52iqTypeError = "error"
53-}
54
55
56tagName (EventBeginElement n _) = n
57tagName _ = ""
diff --git a/Presence/Nesting.hs b/Presence/Nesting.hs
new file mode 100644
index 00000000..24f9baad
--- /dev/null
+++ b/Presence/Nesting.hs
@@ -0,0 +1,79 @@
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE FlexibleContexts #-}
3module Nesting where
4
5import Data.Conduit
6import Data.Conduit.Lift
7import Data.XML.Types
8import qualified Data.Text as S
9import Control.Monad.State
10import qualified Data.List as List
11
12type Lang = S.Text
13
14data StrictList a = a :! !(StrictList a) | StrictNil
15
16data XMLState = XMLState {
17 nestingLevel :: Int,
18 langStack :: StrictList (Int,Lang)
19}
20
21type NestingXML o m a = ConduitM Event o (StateT XMLState m) a
22
23doNestingXML :: Monad m => NestingXML o m r -> ConduitM Event o m r
24doNestingXML m =
25 evalStateC (XMLState 0 StrictNil) (trackNesting =$= m)
26
27nesting :: Monad m => NestingXML o m Int
28nesting = lift $ (return . nestingLevel) =<< get
29
30
31trackNesting :: Monad m => ConduitM Event Event (StateT XMLState m) ()
32trackNesting = awaitForever doit
33 where
34 doit xml = do
35 XMLState lvl langs <- lift get
36 lift . put $ case xml of
37 EventBeginElement _ attrs ->
38 case lookupLang attrs of
39 Nothing -> XMLState (lvl+1) langs
40 Just lang -> XMLState (lvl+1) ( (lvl+1,lang) :! langs)
41 EventEndElement _ ->
42 case langs of
43 (llvl,_) :! ls | llvl==lvl -> XMLState (lvl-1) ls
44 _ | otherwise -> XMLState (lvl-1) langs
45 _ -> XMLState lvl langs
46 yield xml
47
48
49lookupLang attrs =
50 case List.find ( (=="xml:lang") . fst) attrs of
51 Just (_,[ContentText x]) -> Just x
52 Just (_,[ContentEntity x]) -> Just x
53 _ -> Nothing
54
55
56awaitCloser :: Monad m => Int -> NestingXML o m ()
57awaitCloser lvl = do
58 fix $ \loop -> do
59 lvl' <- nesting
60 when (lvl' >= lvl) $ do
61 xml <- await
62 maybe (return ()) (const loop) xml
63
64withXML f = await >>= maybe (return ()) f
65
66nextElement :: Monad m => NestingXML o m (Maybe Event)
67nextElement = do
68 lvl <- nesting
69 fix $ \loop -> do
70 xml <- await
71 case xml of
72 Nothing -> return Nothing
73 Just (EventBeginElement _ _) -> do
74 return xml
75 Just _ -> do
76 lvl' <- nesting
77 if (lvl'>=lvl) then loop
78 else return Nothing
79