8 changed files with 334 additions and 81 deletions
@ -0,0 +1,85 @@ |
|||||||
|
{-# LANGUAGE OverloadedStrings #-} |
||||||
|
|
||||||
|
-- | XEP 0004: Data Forms (http://xmpp.org/extensions/xep-0004.html) |
||||||
|
|
||||||
|
module Network.Xmpp.Xep.DataForms where |
||||||
|
|
||||||
|
import qualified Data.Text as Text |
||||||
|
import qualified Data.XML.Types as XML |
||||||
|
|
||||||
|
import Data.XML.Pickle |
||||||
|
import qualified Data.Text as Text |
||||||
|
|
||||||
|
dataFormNs = "jabber:x:data" |
||||||
|
|
||||||
|
data FormType = FormF | SubmitF | CancelF | ResultF |
||||||
|
|
||||||
|
instance Show FormType where |
||||||
|
show FormF = "form" |
||||||
|
show SubmitF = "submit" |
||||||
|
show CancelF = "cancel" |
||||||
|
show ResultF = "result" |
||||||
|
|
||||||
|
instance Read FormType where |
||||||
|
readsPrec _ "form" = [(FormF , "")] |
||||||
|
readsPrec _ "submit" = [(SubmitF, "")] |
||||||
|
readsPrec _ "cancel" = [(CancelF, "")] |
||||||
|
readsPrec _ "result" = [(ResultF, "")] |
||||||
|
readsPrec _ _ = [] |
||||||
|
|
||||||
|
data Option = Option { label :: Text.Text |
||||||
|
, options :: [Text.Text] |
||||||
|
} |
||||||
|
|
||||||
|
data Field = Field { fieldType :: FieldType |
||||||
|
, desc :: Maybe Text.Text |
||||||
|
, required :: Bool |
||||||
|
, value :: [Text.Text] |
||||||
|
, option :: [Option] |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
data Form = Form { formType :: FormType |
||||||
|
, title :: Maybe Text.Text |
||||||
|
, instructions :: Maybe Text.Text |
||||||
|
, field :: [Field] |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
data FieldType = Boolean |
||||||
|
| Fixed |
||||||
|
| Hidden |
||||||
|
| JidMulti |
||||||
|
| JidSingle |
||||||
|
| ListMulti |
||||||
|
| ListSingle |
||||||
|
| TextMulti |
||||||
|
| TextPrivate |
||||||
|
| TextSingle |
||||||
|
|
||||||
|
|
||||||
|
instance Show FieldType where |
||||||
|
show Boolean = "boolean" |
||||||
|
show Fixed = "fixed" |
||||||
|
show Hidden = "hidden" |
||||||
|
show JidMulti = "jid-multi" |
||||||
|
show JidSingle = "jid-single" |
||||||
|
show ListMulti = "list-multi" |
||||||
|
show ListSingle = "list-single" |
||||||
|
show TextMulti = "text-multi" |
||||||
|
show TextPrivate = "text-private" |
||||||
|
show TextSingle = "text-single" |
||||||
|
|
||||||
|
instance Read FieldType where |
||||||
|
readsPrec _ "boolean" = [(Boolean ,"")] |
||||||
|
readsPrec _ "fixed" = [(Fixed ,"")] |
||||||
|
readsPrec _ "hidden" = [(Hidden ,"")] |
||||||
|
readsPrec _ "jid-multi" = [(JidMulti ,"")] |
||||||
|
readsPrec _ "jid-single" = [(JidSingle ,"")] |
||||||
|
readsPrec _ "list-multi" = [(ListMulti ,"")] |
||||||
|
readsPrec _ "list-single" = [(ListSingle ,"")] |
||||||
|
readsPrec _ "text-multi" = [(TextMulti ,"")] |
||||||
|
readsPrec _ "text-private" = [(TextPrivate ,"")] |
||||||
|
readsPrec _ "text-single" = [(TextSingle ,"")] |
||||||
|
readsPrec _ _ = [] |
||||||
@ -0,0 +1,172 @@ |
|||||||
|
-- | XEP 0077: In-Band Registration |
||||||
|
-- http://xmpp.org/extensions/xep-0077.html |
||||||
|
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-} |
||||||
|
{-# LANGUAGE NoMonomorphismRestriction #-} |
||||||
|
{-# LANGUAGE PatternGuards #-} |
||||||
|
{-# LANGUAGE OverloadedStrings #-} |
||||||
|
|
||||||
|
module Network.Xmpp.Xep.InbandRegistration where |
||||||
|
|
||||||
|
import Control.Applicative((<$>)) |
||||||
|
import Control.Arrow(left) |
||||||
|
import Control.Exception |
||||||
|
import Control.Monad.Error |
||||||
|
import Control.Monad.State |
||||||
|
|
||||||
|
import Data.Either (partitionEithers) |
||||||
|
import qualified Data.Text as Text |
||||||
|
import Data.XML.Pickle |
||||||
|
import qualified Data.XML.Types as XML |
||||||
|
|
||||||
|
import Network.Xmpp.Monad |
||||||
|
import Network.Xmpp.Pickle |
||||||
|
import Network.Xmpp.Types |
||||||
|
|
||||||
|
|
||||||
|
-- In-Band Registration name space |
||||||
|
ibrns :: Text.Text |
||||||
|
ibrns = "jabber:iq:register" |
||||||
|
|
||||||
|
ibrName x = (XML.Name x (Just ibrns) Nothing) |
||||||
|
|
||||||
|
data Query = Query { instructions :: Maybe Text.Text |
||||||
|
, registered :: Bool |
||||||
|
, fields ::[(Field, Maybe Text.Text)] |
||||||
|
} deriving Show |
||||||
|
|
||||||
|
emptyQuery = Query Nothing False [] |
||||||
|
|
||||||
|
supported = do |
||||||
|
fs <- other <$> gets sFeatures |
||||||
|
let fe = XML.Element "{http://jabber.org/features/iq-register}register" [] [] |
||||||
|
return $ fe `elem` fs |
||||||
|
|
||||||
|
|
||||||
|
data IbrError = IbrNotSupported |
||||||
|
| IbrIQError IQError |
||||||
|
deriving (Show) |
||||||
|
instance Error IbrError |
||||||
|
|
||||||
|
query :: Query -> XmppConMonad (Either IbrError Query) |
||||||
|
query x = do |
||||||
|
answer <- xmppSendIQ' "ibr" Nothing Get Nothing (pickleElem xpQuery x) |
||||||
|
case answer of |
||||||
|
Right IQResult{iqResultPayload = Just b} -> |
||||||
|
case unpickleElem xpQuery b of |
||||||
|
Right query -> return $ Right query |
||||||
|
Left e -> throw . StreamXMLError $ |
||||||
|
"RequestField: unpickle failed, got " |
||||||
|
++ Text.unpack (ppUnpickleError e) |
||||||
|
++ " saw " ++ ppElement b |
||||||
|
Left e -> return . Left $ IbrIQError e |
||||||
|
|
||||||
|
data RegisterError = IbrError IbrError |
||||||
|
| MissingFields [Field] |
||||||
|
| AlreadyRegistered |
||||||
|
deriving (Show) |
||||||
|
|
||||||
|
instance Error RegisterError |
||||||
|
|
||||||
|
mapError f = mapErrorT (liftM $ left f) |
||||||
|
|
||||||
|
registerWith :: [(Field, Text.Text)] -> XmppConMonad (Either RegisterError Query) |
||||||
|
registerWith givenFields = runErrorT $ do |
||||||
|
fs <- mapError IbrError $ ErrorT requestFields |
||||||
|
when (registered fs) . throwError $ AlreadyRegistered |
||||||
|
let res = flip map (fields fs) $ \(field,_) -> |
||||||
|
case lookup field givenFields of |
||||||
|
Just entry -> Right (field, Just entry) |
||||||
|
Nothing -> Left field |
||||||
|
fields <- case partitionEithers res of |
||||||
|
([],fs) -> return fs |
||||||
|
(fs,_) -> throwError $ MissingFields fs |
||||||
|
result <- mapError IbrError . ErrorT . query $ emptyQuery {fields} |
||||||
|
return result |
||||||
|
|
||||||
|
requestFields = runErrorT $ do |
||||||
|
supp <- supported |
||||||
|
unless supp $ throwError $ IbrNotSupported |
||||||
|
qr <- ErrorT $ query emptyQuery |
||||||
|
return $ qr |
||||||
|
|
||||||
|
xpQuery :: PU [XML.Node] Query |
||||||
|
xpQuery = xpWrap |
||||||
|
(\(is, r, fs) -> Query is r fs) |
||||||
|
(\(Query is r fs) -> (is, r, fs)) $ |
||||||
|
xpElemNodes (ibrName "query") $ |
||||||
|
xp3Tuple |
||||||
|
(xpOption $ |
||||||
|
xpElemNodes (ibrName "instructions") (xpContent $ xpText)) |
||||||
|
(xpElemExists (ibrName "registered")) |
||||||
|
(xpAllByNamespace ibrns ( xpWrap |
||||||
|
(\(name,_,c) -> (name, c)) |
||||||
|
(\(name,c) -> (name,(),c)) $ |
||||||
|
xpElemByNamespace ibrns xpPrim xpUnit |
||||||
|
(xpOption $ xpContent xpText) |
||||||
|
)) |
||||||
|
|
||||||
|
data Field = Username |
||||||
|
| Nick |
||||||
|
| Password |
||||||
|
| Name |
||||||
|
| First |
||||||
|
| Last |
||||||
|
| Email |
||||||
|
| Address |
||||||
|
| City |
||||||
|
| State |
||||||
|
| Zip |
||||||
|
| Phone |
||||||
|
| Url |
||||||
|
| Date |
||||||
|
| Misc |
||||||
|
| Text |
||||||
|
| Key |
||||||
|
| OtherField Text.Text |
||||||
|
deriving Eq |
||||||
|
|
||||||
|
instance Show Field where |
||||||
|
show Username = "username" |
||||||
|
show Nick = "nick" |
||||||
|
show Password = "password" |
||||||
|
show Name = "name" |
||||||
|
show First = "first" |
||||||
|
show Last = "last" |
||||||
|
show Email = "email" |
||||||
|
show Address = "address" |
||||||
|
show City = "city" |
||||||
|
show State = "state" |
||||||
|
show Zip = "zip" |
||||||
|
show Phone = "phone" |
||||||
|
show Url = "url" |
||||||
|
show Date = "date" |
||||||
|
show Misc = "misc" |
||||||
|
show Text = "text" |
||||||
|
show Key = "key" |
||||||
|
show (OtherField x) = Text.unpack x |
||||||
|
|
||||||
|
instance Read Field where |
||||||
|
readsPrec _ "username" = [(Username , "")] |
||||||
|
readsPrec _ "nick" = [(Nick , "")] |
||||||
|
readsPrec _ "password" = [(Password , "")] |
||||||
|
readsPrec _ "name" = [(Name , "")] |
||||||
|
readsPrec _ "first" = [(First , "")] |
||||||
|
readsPrec _ "last" = [(Last , "")] |
||||||
|
readsPrec _ "email" = [(Email , "")] |
||||||
|
readsPrec _ "address" = [(Address , "")] |
||||||
|
readsPrec _ "city" = [(City , "")] |
||||||
|
readsPrec _ "state" = [(State , "")] |
||||||
|
readsPrec _ "zip" = [(Zip , "")] |
||||||
|
readsPrec _ "phone" = [(Phone , "")] |
||||||
|
readsPrec _ "url" = [(Url , "")] |
||||||
|
readsPrec _ "date" = [(Date , "")] |
||||||
|
readsPrec _ "misc" = [(Misc , "")] |
||||||
|
readsPrec _ "text" = [(Text , "")] |
||||||
|
readsPrec _ "key" = [(Key , "")] |
||||||
|
readsPrec _ x = [(OtherField $ Text.pack x , "")] |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Registered |
||||||
|
-- Instructions |
||||||
Loading…
Reference in new issue