summaryrefslogtreecommitdiff
path: root/Presence
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2013-06-15 21:00:14 -0400
committerjoe <joe@jerkface.net>2013-06-15 21:00:14 -0400
commit42eb97f5574844d9899a42cf4b7c458c4a1b950e (patch)
tree57a4ca3e55d23f9d243aad1c49fdff64731dd13f /Presence
parent3f3cb58e3150d28a00c18324cecc44c6fc3a4e99 (diff)
Moved xmpp server into module
Diffstat (limited to 'Presence')
-rw-r--r--Presence/XMPPServer.hs199
-rw-r--r--Presence/main.hs1
2 files changed, 200 insertions, 0 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs
new file mode 100644
index 00000000..591acad6
--- /dev/null
+++ b/Presence/XMPPServer.hs
@@ -0,0 +1,199 @@
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ViewPatterns #-}
4module XMPPServer ( listenForXmppClients ) where
5
6import Data.HList.TypeEqGeneric1()
7import Data.HList.TypeCastGeneric1()
8import ByteStringOperators
9
10import Server
11import Data.ByteString.Lazy.Char8 as L
12 ( ByteString
13 , hPutStrLn
14 , unlines
15 , pack
16 , unpack
17 , init )
18import qualified Data.ByteString.Lazy.Char8 as L
19 ( putStrLn )
20import System.IO
21 ( Handle
22 )
23import Control.Concurrent (forkIO)
24import Control.Concurrent.Chan
25import Data.HList
26import AdaptServer
27import Text.XML.HaXml.Lex (xmlLex)
28import Text.XML.HaXml.Parse (xmlParseWith,element,doctypedecl,processinginstruction,elemOpenTag,elemCloseTag)
29import Text.XML.HaXml.Types as Hax (ElemTag,QName(..),Namespace(..),Element(..),Content(..),AttValue(..))
30import qualified Text.XML.HaXml.Types as Hax (Element)
31import Data.Maybe
32import Debug.Trace
33
34
35
36greet host = L.unlines
37 [ "<?xml version='1.0'?>"
38 , "<stream:stream"
39 , "from='" <++> host <++> "'"
40 , "id='someid'"
41 , "xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>"
42 , "<stream:features>"
43 , " <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
44 {-
45 -- , " <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
46 , " <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
47 -- , " <mechanism>DIGEST-MD5</mechanism>"
48 , " <mechanism>PLAIN</mechanism>"
49 , " </mechanisms> "
50 -}
51 , "</stream:features>"
52 ]
53
54startCon st = do
55 let h = hOccursFst st :: Handle
56 return (ConnectionFinalizer (return ()) .*. st)
57
58iq_query_unavailable host id mjid xmlns = L.unlines $
59 [ "<iq type='error'"
60 , " from='" <++> host <++> "'"
61 , case mjid of Just jid -> " to='" <++> jid <++> "'"
62 Nothing -> ""
63 , " id='" <++> id <++> "'>"
64 , " <query xmlns='" <++> xmlns <++> "'/>"
65 , " <error type='cancel'>"
66 , " <service-unavailable"
67 , " xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
68 , " </error>"
69 , "</iq>"
70 ]
71
72tagattrs tag content = Prelude.concatMap (\(CElem (Elem _ a _) _)->a)
73 $ Prelude.filter (bindElem tag) content
74
75bindElem tag (CElem (Elem (N n) _ _) _) | n==tag = True
76bindElem _ _ = False
77
78hasElem tag content =
79 not . Prelude.null . Prelude.filter (bindElem tag) $ content
80
81unattr (AttValue as) = listToMaybe $ Prelude.concatMap left as
82 where left (Left x) = [x]
83 left _ = []
84
85astring (AttValue [Left s]) = [s]
86
87tagcontent tag content = Prelude.concatMap (\(CElem (Elem _ _ c) _)->c)
88 $ Prelude.filter (bindElem tag) content
89
90iqresult host id (Just rsrc) = L.unlines $
91 [ "<iq type='result' id='" <++> id <++> "'>"
92 , "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
93 , "<jid>" <++> id <++> "@" <++> host <++> "/" <++> rsrc <++> "</jid>"
94 , "</bind>"
95 , "</iq> "
96 ]
97iqresult host id Nothing = L.unlines $
98 [ "<iq type='result'"
99 , " id='" <++> id <++> "'"
100 , " from='" <++> host <++> "'"
101 , " /> "
102 ]
103
104iqresult_info host id mjid = L.unlines $
105 [ "<iq type='result'"
106 , " from='" <++> host <++> "'"
107 , case mjid of Just jid -> " to='" <++> jid <++> "'"
108 Nothing -> ""
109 , " id='" <++> id <++> "'>"
110 , " <query xmlns='http://jabber.org/protocol/disco#info'>"
111 , " <identity"
112 , " category='server'"
113 , " type='im'"
114 , " name='" <++> host <++> "'/>"
115 , " <feature var='http://jabber.org/protocol/disco#info'/>"
116 , " <feature var='http://jabber.org/protocol/disco#items'/>"
117 , " </query>"
118 , "</iq>"
119 ]
120
121iqresponse host (Elem _ attrs content) = do
122 id <- fmap pack (lookup (N "id") attrs >>= unattr)
123 typ <- fmap pack (lookup (N "type") attrs >>= unattr)
124 case typ of
125 "set" -> do
126 let string (CString _ s _) = [s]
127 mplus (do
128 rsrc <- listToMaybe . Prelude.concatMap string . tagcontent "resource" . tagcontent "bind" $ content
129 Just $ iqresult host id (Just (pack rsrc)) )
130 (do
131 guard (hasElem "session" content)
132 Just (iqresult host id Nothing))
133
134 "get" -> trace ("iq-get "++show (attrs,content)) $ do
135 xmlns <- fmap pack $
136 lookup (N "xmlns") (tagattrs "query" content)
137 >>= listToMaybe . astring
138 Just (iq_query_unavailable host id Nothing xmlns)
139 _ -> Nothing
140
141
142
143doCon st elem cont = do
144 let h = hOccursFst st :: Handle
145 host = "localhost"
146 hsend r = do
147 hPutStrLn h r
148 L.putStrLn $ "SENT:\n" <++> r
149
150 case elem of
151 OpenTag _ ->
152 hsend (greet host)
153 Element e@(Elem (N "iq") _ _) ->
154 case iqresponse host e of
155 Nothing -> trace "no respones" $ return ()
156 Just r -> hsend r
157 _ -> return () -- putStrLn $ "unhandled: "++show v
158
159 putStrLn (show elem)
160 cont ()
161
162instance Show Hax.ElemTag where
163 show _ = "elemtag"
164
165data XmppObject e i t c
166 = Element e
167 | ProcessingInstruction i
168 | OpenTag t
169 | CloseTag c
170 deriving Show
171
172streamName = QN (Namespace {nsPrefix= "stream" , nsURI="http://etherx.jabber.org/streams" }) "stream"
173
174xmppParse ls =
175 case xmlParseWith element ls of
176 (Right e,rs) -> (Right (Element e), rs)
177 (Left _,_) ->
178 case xmlParseWith elemOpenTag ls of
179 (Right e,rs) -> (Right (OpenTag e),rs)
180 (Left _,_) ->
181 case xmlParseWith (elemCloseTag streamName) ls of
182 (Right e,rs) -> (Right (CloseTag e),rs)
183 (Left _,_) ->
184 case xmlParseWith processinginstruction ls of
185 (Right e,rs) -> (Right (ProcessingInstruction e),rs)
186 (Left err,rs) -> (Left err,rs)
187
188
189
190listenForXmppClients port st = do
191 let (start,dopkt) =
192 adaptServer ( xmlLex "stream" . unpack
193 , xmppParse)
194 (startCon,doCon)
195 doServer (port .*. st)
196 dopkt
197 start
198
199
diff --git a/Presence/main.hs b/Presence/main.hs
index 99f58ee4..1eb0c0ed 100644
--- a/Presence/main.hs
+++ b/Presence/main.hs
@@ -12,6 +12,7 @@ import Data.Maybe
12import System.INotify 12import System.INotify
13import UTmp 13import UTmp
14import FGConsole 14import FGConsole
15import XMPPServer
15 16
16jid user host rsrc = user ++ "@" ++ host ++ "/" ++ rsrc 17jid user host rsrc = user ++ "@" ++ host ++ "/" ++ rsrc
17 18