Browse Source

fix some discrepancies to RFC6120/6121/6122

master
Philipp Balzarek 12 years ago
parent
commit
a5e25a5657
  1. 10
      source/Network/Xmpp/Concurrent/Presence.hs
  2. 48
      source/Network/Xmpp/IM/Roster.hs
  3. 14
      source/Network/Xmpp/Marshal.hs
  4. 9
      source/Network/Xmpp/Types.hs

10
source/Network/Xmpp/Concurrent/Presence.hs

@ -6,6 +6,7 @@ import Control.Concurrent.STM
import Network.Xmpp.Types import Network.Xmpp.Types
import Network.Xmpp.Concurrent.Types import Network.Xmpp.Concurrent.Types
import Network.Xmpp.Concurrent.Basic import Network.Xmpp.Concurrent.Basic
import Network.Xmpp.Lens
-- | Read a presence stanza from the inbound stanza channel, discards any other -- | Read a presence stanza from the inbound stanza channel, discards any other
-- stanzas. Returns the presence stanza with annotations. -- stanzas. Returns the presence stanza with annotations.
@ -40,4 +41,11 @@ waitForPresence f s = fst <$> waitForPresenceA (f . fst) s
-- | Send a presence stanza. -- | Send a presence stanza.
sendPresence :: Presence -> Session -> IO (Either XmppFailure ()) sendPresence :: Presence -> Session -> IO (Either XmppFailure ())
sendPresence p session = sendStanza (PresenceS p) session sendPresence p session = sendStanza (PresenceS checkedP) session
where
-- | RFC 6121 §3.1.1: When a user sends a presence subscription request to a
-- potential instant messaging and presence contact, the value of the 'to'
-- attribute MUST be a bare JID rather than a full JID
checkedP = case presenceType p of
Subscribe -> modify to (fmap toBare) p
_ -> p

48
source/Network/Xmpp/IM/Roster.hs

@ -31,22 +31,15 @@ import Network.Xmpp.Types
timeout :: Maybe Integer timeout :: Maybe Integer
timeout = Just 3000000 -- 3 seconds timeout = Just 3000000 -- 3 seconds
-- | Push a roster item to the server. The values for approved and ask are
-- ignored and all values for subsciption except "remove" are ignored.
rosterPush :: Item -> Session -> IO (Either IQSendError (Annotated IQResponse))
rosterPush item session = do
let el = pickleElem xpQuery (Query Nothing [fromItem item])
sendIQA' timeout Nothing Set Nothing el [] session
-- | Add or update an item to the roster. -- | Add or update an item to the roster.
-- --
-- To update the item just send the complete set of new data. -- To update the item just send the complete set of new data.
rosterAdd :: Jid -- ^ JID of the item rosterSet :: Jid -- ^ JID of the item
-> Maybe Text -- ^ Name alias -> Maybe Text -- ^ Name alias
-> [Text] -- ^ Groups (duplicates will be removed) -> [Text] -- ^ Groups (duplicates will be removed)
-> Session -> Session
-> IO (Either IQSendError (Annotated IQResponse)) -> IO (Either IQSendError (Annotated IQResponse))
rosterAdd j n gs session = do rosterSet j n gs session = do
let el = pickleElem xpQuery (Query Nothing let el = pickleElem xpQuery (Query Nothing
[QueryItem { qiApproved = Nothing [QueryItem { qiApproved = Nothing
, qiAsk = False , qiAsk = False
@ -57,6 +50,14 @@ rosterAdd j n gs session = do
}]) }])
sendIQA' timeout Nothing Set Nothing el [] session sendIQA' timeout Nothing Set Nothing el [] session
-- | Synonym to rosterSet
rosterAdd :: Jid
-> Maybe Text
-> [Text]
-> Session
-> IO (Either IQSendError (Annotated IQResponse))
rosterAdd = rosterSet
-- | Remove an item from the roster. Return 'True' when the item is sucessfully -- | Remove an item from the roster. Return 'True' when the item is sucessfully
-- removed or if it wasn't in the roster to begin with. -- removed or if it wasn't in the roster to begin with.
rosterRemove :: Jid -> Session -> IO Bool rosterRemove :: Jid -> Session -> IO Bool
@ -69,6 +70,13 @@ rosterRemove j sess = do
case res of case res of
Right (IQResponseResult IQResult{}, _) -> return True Right (IQResponseResult IQResult{}, _) -> return True
_ -> return False _ -> return False
where
rosterPush :: Item
-> Session
-> IO (Either IQSendError (Annotated IQResponse))
rosterPush item session = do
let el = pickleElem xpQuery (Query Nothing [fromItem item])
sendIQA' timeout Nothing Set Nothing el [] session
-- | Retrieve the current Roster state -- | Retrieve the current Roster state
getRoster :: Session -> IO Roster getRoster :: Session -> IO Roster
@ -157,9 +165,13 @@ toItem qi = Item { riApproved = fromMaybe False (qiApproved qi)
, riAsk = qiAsk qi , riAsk = qiAsk qi
, riJid = qiJid qi , riJid = qiJid qi
, riName = qiName qi , riName = qiName qi
, riSubscription = fromMaybe None (qiSubscription qi) , riSubscription = fromSubscription (qiSubscription qi)
, riGroups = nub $ qiGroups qi , riGroups = nub $ qiGroups qi
} }
where
fromSubscription Nothing = None
fromSubscription (Just s) | s `elem` [None, To, From, Both] = s
| otherwise = None
fromItem :: Item -> QueryItem fromItem :: Item -> QueryItem
fromItem i = QueryItem { qiApproved = Nothing fromItem i = QueryItem { qiApproved = Nothing
@ -198,17 +210,15 @@ xpQuery = xpWrap (\(ver_, items_) -> Query ver_ items_ )
xpSubscription :: PU Text Subscription xpSubscription :: PU Text Subscription
xpSubscription = ("xpSubscription", "") <?> xpSubscription = ("xpSubscription", "") <?>
xpPartial ( \input -> case subscriptionFromText input of xpIso subscriptionFromText
Nothing -> Left "Could not parse subscription."
Just j -> Right j)
subscriptionToText subscriptionToText
where where
subscriptionFromText "none" = Just None subscriptionFromText "none" = None
subscriptionFromText "to" = Just To subscriptionFromText "to" = To
subscriptionFromText "from" = Just From subscriptionFromText "from" = From
subscriptionFromText "both" = Just Both subscriptionFromText "both" = Both
subscriptionFromText "remove" = Just Remove subscriptionFromText "remove" = Remove
subscriptionFromText _ = Nothing subscriptionFromText _ = None
subscriptionToText None = "none" subscriptionToText None = "none"
subscriptionToText To = "to" subscriptionToText To = "to"
subscriptionToText From = "from" subscriptionToText From = "from"

14
source/Network/Xmpp/Marshal.hs

@ -400,16 +400,14 @@ xpIQRequestType = ("xpIQRequestType", "") <?>
xpMessageType :: PU Text MessageType xpMessageType :: PU Text MessageType
xpMessageType = ("xpMessageType", "") <?> xpMessageType = ("xpMessageType", "") <?>
xpPartial ( \input -> case messageTypeFromText input of xpIso messageTypeFromText
Nothing -> Left "Could not parse message type."
Just j -> Right j)
messageTypeToText messageTypeToText
where where
messageTypeFromText "chat" = Just Chat messageTypeFromText "chat" = Chat
messageTypeFromText "groupchat" = Just GroupChat messageTypeFromText "groupchat" = GroupChat
messageTypeFromText "headline" = Just Headline messageTypeFromText "headline" = Headline
messageTypeFromText "normal" = Just Normal messageTypeFromText "normal" = Normal
messageTypeFromText _ = Just Normal messageTypeFromText _ = Normal
messageTypeToText Chat = "chat" messageTypeToText Chat = "chat"
messageTypeToText GroupChat = "groupchat" messageTypeToText GroupChat = "groupchat"
messageTypeToText Headline = "headline" messageTypeToText Headline = "headline"

9
source/Network/Xmpp/Types.hs

@ -91,6 +91,7 @@ import Data.Text (Text)
import qualified Data.Text as Text import qualified Data.Text as Text
import Data.Typeable(Typeable) import Data.Typeable(Typeable)
import Data.XML.Types as XML import Data.XML.Types as XML
import qualified Data.Text.Encoding as Text
#if WITH_TEMPLATE_HASKELL #if WITH_TEMPLATE_HASKELL
import Language.Haskell.TH import Language.Haskell.TH
import Language.Haskell.TH.Quote import Language.Haskell.TH.Quote
@ -1019,8 +1020,9 @@ jidFromTexts l d r = do
guard $ Text.all (`Set.notMember` prohibMap) l'' guard $ Text.all (`Set.notMember` prohibMap) l''
l''' <- nonEmpty l'' l''' <- nonEmpty l''
return $ Just l''' return $ Just l'''
domainPart' <- SP.runStringPrep (SP.namePrepProfile False) d domainPart' <- SP.runStringPrep (SP.namePrepProfile False) (stripSuffix d)
guard $ validDomainPart domainPart' guard $ validDomainPart domainPart'
guard $ validPartLength domainPart'
domainPart <- nonEmpty domainPart' domainPart <- nonEmpty domainPart'
resourcePart <- case r of resourcePart <- case r of
Nothing -> return Nothing Nothing -> return Nothing
@ -1036,7 +1038,10 @@ jidFromTexts l d r = do
-- checks -- checks
validPartLength :: Text -> Bool validPartLength :: Text -> Bool
validPartLength p = Text.length p > 0 && Text.length p < 1024 validPartLength p = Text.length p > 0
&& BS.length (Text.encodeUtf8 p) < 1024
-- RFC6122 §2.2
stripSuffix t = if Text.last t == '.' then Text.init t else t
-- | Returns 'True' if the JID is /bare/, that is, it doesn't have a resource -- | Returns 'True' if the JID is /bare/, that is, it doesn't have a resource
-- part, and 'False' otherwise. -- part, and 'False' otherwise.

Loading…
Cancel
Save