7 changed files with 147 additions and 8 deletions
@ -0,0 +1,137 @@ |
|||||||
|
{-# LANGUAGE NoMonomorphismRestriction #-} |
||||||
|
{-# LANGUAGE OverloadedStrings #-} |
||||||
|
{-# LANGUAGE TupleSections #-} |
||||||
|
|
||||||
|
-- XEP 0030: Service Discovery (disco) |
||||||
|
|
||||||
|
module Network.Xmpp.Xep.ServiceDiscovery |
||||||
|
( QueryInfoResult(..) |
||||||
|
, Identity(..) |
||||||
|
, queryInfo |
||||||
|
, Item |
||||||
|
, queryItems |
||||||
|
, DiscoError(..) |
||||||
|
) |
||||||
|
where |
||||||
|
|
||||||
|
import Control.Applicative((<$>)) |
||||||
|
import Control.Monad.IO.Class |
||||||
|
import Control.Monad.Error |
||||||
|
|
||||||
|
import qualified Data.Text as Text |
||||||
|
import Data.XML.Pickle |
||||||
|
import Data.XML.Types |
||||||
|
|
||||||
|
import Network.Xmpp.Pickle |
||||||
|
import Network.Xmpp |
||||||
|
|
||||||
|
data DiscoError = DiscoNoQueryElement |
||||||
|
| DiscoIQError IQError |
||||||
|
| DiscoXMLError Element UnpickleError |
||||||
|
|
||||||
|
deriving (Show) |
||||||
|
|
||||||
|
instance Error DiscoError |
||||||
|
|
||||||
|
data Identity = Ident { iCategory :: Text.Text |
||||||
|
, iName :: Maybe Text.Text |
||||||
|
, iType :: Text.Text |
||||||
|
, iLang :: Maybe LangTag |
||||||
|
} deriving Show |
||||||
|
|
||||||
|
data QueryInfoResult = QIR { qiNode :: Maybe Text.Text |
||||||
|
, qiIdentities :: [Identity] |
||||||
|
, qiFeatures :: [Text.Text] |
||||||
|
} deriving Show |
||||||
|
|
||||||
|
discoInfoNS :: Text.Text |
||||||
|
discoInfoNS = "http://jabber.org/protocol/disco#info" |
||||||
|
|
||||||
|
infoN :: Text.Text -> Name |
||||||
|
infoN name = (Name name (Just discoInfoNS) Nothing) |
||||||
|
|
||||||
|
xpIdentities = xpWrap (map $(\(cat, n, tp, lang) -> Ident cat n tp lang) . fst) |
||||||
|
(map $ \(Ident cat n tp lang) -> ((cat, n, tp, lang),())) $ |
||||||
|
xpElems (infoN "identity") |
||||||
|
(xp4Tuple |
||||||
|
(xpAttr "category" xpText) |
||||||
|
(xpAttrImplied "name" xpText) |
||||||
|
(xpAttr "type" xpText) |
||||||
|
xpLangTag |
||||||
|
) |
||||||
|
xpUnit |
||||||
|
|
||||||
|
xpFeatures :: PU [Node] [Text.Text] |
||||||
|
xpFeatures = xpWrap (map fst) (map (,())) $ |
||||||
|
xpElems (infoN "feature") |
||||||
|
(xpAttr "var" xpText) |
||||||
|
xpUnit |
||||||
|
|
||||||
|
xpQueryInfo = xpWrap (\(nd, (feats, ids)) -> QIR nd ids feats) |
||||||
|
(\(QIR nd ids feats) -> (nd, (feats, ids))) $ |
||||||
|
xpElem (infoN "query") |
||||||
|
(xpAttrImplied "node" xpText) |
||||||
|
(xp2Tuple |
||||||
|
xpFeatures |
||||||
|
xpIdentities |
||||||
|
) |
||||||
|
|
||||||
|
-- | Query an entity for it's identity and features |
||||||
|
queryInfo :: Jid -- ^ Entity to query |
||||||
|
-> Maybe Text.Text -- ^ Node |
||||||
|
-> Xmpp (Either DiscoError QueryInfoResult) |
||||||
|
queryInfo to node = do |
||||||
|
res <- sendIQ' (Just to) Get Nothing queryBody |
||||||
|
return $ case res of |
||||||
|
Left e -> Left $ DiscoIQError e |
||||||
|
Right r -> case iqResultPayload r of |
||||||
|
Nothing -> Left DiscoNoQueryElement |
||||||
|
Just p -> case unpickleElem xpQueryInfo p of |
||||||
|
Left e -> Left $ DiscoXMLError p e |
||||||
|
Right r -> Right r |
||||||
|
where |
||||||
|
queryBody = pickleElem xpQueryInfo (QIR node [] []) |
||||||
|
|
||||||
|
-- |
||||||
|
-- Items |
||||||
|
-- |
||||||
|
|
||||||
|
data Item = Item { itemJid :: Jid |
||||||
|
, itemName :: Maybe Text.Text |
||||||
|
, itemNode :: Maybe Text.Text |
||||||
|
} deriving Show |
||||||
|
|
||||||
|
discoItemsNS :: Text.Text |
||||||
|
discoItemsNS = "http://jabber.org/protocol/disco#items" |
||||||
|
|
||||||
|
itemsN :: Text.Text -> Name |
||||||
|
itemsN n = Name n (Just discoItemsNS) Nothing |
||||||
|
|
||||||
|
xpItem = xpWrap (\(jid, name, node) -> Item jid name node) |
||||||
|
(\(Item jid name node) -> (jid, name, node)) $ |
||||||
|
xpElemAttrs (itemsN "item") |
||||||
|
(xp3Tuple |
||||||
|
(xpAttr "jid" xpPrim) |
||||||
|
(xpAttrImplied "name" xpText) |
||||||
|
(xpAttrImplied "node" xpText)) |
||||||
|
|
||||||
|
|
||||||
|
xpQueryItems = xpElem (itemsN "query") |
||||||
|
(xpAttrImplied "node" xpText) |
||||||
|
(xpAll xpItem) |
||||||
|
|
||||||
|
-- | Query an entity for Items of a node |
||||||
|
queryItems :: Jid -- ^ Entity to query |
||||||
|
-> Maybe Text.Text -- ^ Node |
||||||
|
-> Xmpp (Either DiscoError (Maybe Text.Text, [Item])) |
||||||
|
queryItems to node = do |
||||||
|
res <- sendIQ' (Just to) Get Nothing queryBody |
||||||
|
return $ case res of |
||||||
|
Left e -> Left $ DiscoIQError e |
||||||
|
Right r -> case iqResultPayload r of |
||||||
|
Nothing -> Left DiscoNoQueryElement |
||||||
|
Just p -> case unpickleElem xpQueryItems p of |
||||||
|
Left e -> Left $ DiscoXMLError p e |
||||||
|
Right r -> Right r |
||||||
|
where |
||||||
|
queryBody = pickleElem xpQueryItems (node, []) |
||||||
Loading…
Reference in new issue