|
|
|
@ -3,6 +3,8 @@ |
|
|
|
|
|
|
|
|
|
|
|
{-# OPTIONS_HADDOCK hide #-} |
|
|
|
{-# OPTIONS_HADDOCK hide #-} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{-# LANGUAGE OverloadedStrings #-} |
|
|
|
|
|
|
|
|
|
|
|
module Network.XMPP.Stream ( |
|
|
|
module Network.XMPP.Stream ( |
|
|
|
isTLSSecured, |
|
|
|
isTLSSecured, |
|
|
|
xmlEnumerator, |
|
|
|
xmlEnumerator, |
|
|
|
@ -54,9 +56,6 @@ import Text.Parsec.ByteString (GenParser) |
|
|
|
|
|
|
|
|
|
|
|
import qualified Data.ByteString.Char8 as DBC (pack) |
|
|
|
import qualified Data.ByteString.Char8 as DBC (pack) |
|
|
|
|
|
|
|
|
|
|
|
import Data.List (intersperse) |
|
|
|
|
|
|
|
import Data.Char (toLower) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isTLSSecured :: TLSState -> Bool |
|
|
|
isTLSSecured :: TLSState -> Bool |
|
|
|
isTLSSecured (PostHandshake _) = True |
|
|
|
isTLSSecured (PostHandshake _) = True |
|
|
|
@ -151,7 +150,7 @@ processEventList e |
|
|
|
| nameLocalName name == DT.pack "iq" = XEIQ $ parseIQ $ eventsToElement e |
|
|
|
| nameLocalName name == DT.pack "iq" = XEIQ $ parseIQ $ eventsToElement e |
|
|
|
| nameLocalName name == DT.pack "presence" = XEPresence $ parsePresence $ eventsToElement e |
|
|
|
| nameLocalName name == DT.pack "presence" = XEPresence $ parsePresence $ eventsToElement e |
|
|
|
| nameLocalName name == DT.pack "message" = XEMessage $ parseMessage $ eventsToElement e |
|
|
|
| nameLocalName name == DT.pack "message" = XEMessage $ parseMessage $ eventsToElement e |
|
|
|
| otherwise = XEOther $ elementToString $ Just (eventsToElement e) |
|
|
|
| otherwise = XEOther "TODO: Element instead of String" -- Just (eventsToElement e) |
|
|
|
where |
|
|
|
where |
|
|
|
(EventBeginElement name attribs) = head e |
|
|
|
(EventBeginElement name attribs) = head e |
|
|
|
es = tail e |
|
|
|
es = tail e |
|
|
|
@ -169,314 +168,105 @@ counter c (Just (EventBeginElement _ _)) = (c + 1) |
|
|
|
counter c (Just (EventEndElement _) ) = (c - 1) |
|
|
|
counter c (Just (EventEndElement _) ) = (c - 1) |
|
|
|
counter c _ = c |
|
|
|
counter c _ = c |
|
|
|
|
|
|
|
|
|
|
|
presenceToXML :: Presence -> String |
|
|
|
|
|
|
|
presenceToXML p = "<presence" ++ from ++ id' ++ to ++ type' ++ ">" ++ |
|
|
|
|
|
|
|
(elementsToString $ presencePayload p) ++ "</presence>" |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
from :: String |
|
|
|
|
|
|
|
from = case presenceFrom p of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " from='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
id' :: String |
|
|
|
|
|
|
|
id' = case presenceID p of |
|
|
|
|
|
|
|
Just (SID s) -> " id='" ++ s ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
to :: String |
|
|
|
|
|
|
|
to = case presenceTo p of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " to='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type' :: String |
|
|
|
|
|
|
|
type' = case presenceType p of |
|
|
|
|
|
|
|
Available -> "" |
|
|
|
|
|
|
|
t -> " type='" ++ (presenceTypeToString t) ++ "'" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iqToXML :: IQ -> String |
|
|
|
|
|
|
|
iqToXML (IQReq (IQGet { iqRequestID = i, iqRequestPayload = p, iqRequestFrom = f, iqRequestTo = t })) = |
|
|
|
|
|
|
|
let type' = " type='get'" in "<iq" ++ from ++ id' ++ to ++ type' ++ ">" ++ (elementToString (Just p)) ++ "</iq>" |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
from :: String |
|
|
|
|
|
|
|
from = case f of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " from='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
id' :: String |
|
|
|
|
|
|
|
id' = case i of |
|
|
|
|
|
|
|
Just (SID s) -> " id='" ++ s ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
to :: String |
|
|
|
|
|
|
|
to = case t of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " to='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iqToXML (IQReq (IQSet { iqRequestID = i, iqRequestPayload = p, iqRequestFrom = f, iqRequestTo = t })) = |
|
|
|
|
|
|
|
let type' = " type='set'" in "<iq" ++ from ++ id' ++ to ++ type' ++ ">" ++ (elementToString (Just p)) ++ "</iq>" |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
from :: String |
|
|
|
|
|
|
|
from = case f of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " from='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
id' :: String |
|
|
|
|
|
|
|
id' = case i of |
|
|
|
|
|
|
|
Just (SID s) -> " id='" ++ s ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
to :: String |
|
|
|
|
|
|
|
to = case t of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " to='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iqToXML (IQRes (IQResult { iqResponseID = i, iqResponsePayload = p, iqResponseFrom = f, iqResponseTo = t })) = |
|
|
|
|
|
|
|
let type' = " type='result'" in "<iq" ++ from ++ id' ++ to ++ type' ++ ">" ++ (elementToString p) ++ "</iq>" |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
from :: String |
|
|
|
|
|
|
|
from = case f of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " from='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
id' :: String |
|
|
|
|
|
|
|
id' = case i of |
|
|
|
|
|
|
|
Just (SID s) -> " id='" ++ s ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
to :: String |
|
|
|
|
|
|
|
to = case t of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " to='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- TODO: Turn message errors into XML. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
messageToXML :: Message -> String |
|
|
|
|
|
|
|
messageToXML Message { messageID = i, messageFrom = f, messageTo = t, messagePayload = p, messageType = ty } = "<message" ++ from ++ id' ++ to ++ type' ++ ">" ++ |
|
|
|
|
|
|
|
(elementsToString $ p) ++ "</message>" |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
from :: String |
|
|
|
|
|
|
|
from = case f of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " from='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
id' :: String |
|
|
|
|
|
|
|
id' = case i of |
|
|
|
|
|
|
|
Just (SID s) -> " id='" ++ s ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
to :: String |
|
|
|
|
|
|
|
to = case t of |
|
|
|
|
|
|
|
-- TODO: Lower-case |
|
|
|
|
|
|
|
Just s -> " to='" ++ (show s) ++ "'" |
|
|
|
|
|
|
|
Nothing -> "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type' :: String |
|
|
|
|
|
|
|
type' = case ty of |
|
|
|
|
|
|
|
Normal -> "" |
|
|
|
|
|
|
|
t -> " type='" ++ (messageTypeToString t) ++ "'" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parseIQ :: Element -> IQ |
|
|
|
|
|
|
|
parseIQ e | typeAttr == "get" = let (Just payloadMust) = payload |
|
|
|
|
|
|
|
in IQReq (IQGet idAttr fromAttr toAttr Nothing |
|
|
|
|
|
|
|
payloadMust) |
|
|
|
|
|
|
|
| typeAttr == "set" = let (Just payloadMust) = payload |
|
|
|
|
|
|
|
in IQReq (IQSet idAttr fromAttr toAttr Nothing |
|
|
|
|
|
|
|
payloadMust) |
|
|
|
|
|
|
|
| typeAttr == "result" = IQRes (IQResult idAttr fromAttr toAttr |
|
|
|
|
|
|
|
Nothing payload) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
-- TODO: Many duplicate functions from parsePresence. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
payload :: Maybe Element |
|
|
|
|
|
|
|
payload = case null (elementChildren e) of |
|
|
|
|
|
|
|
True -> Nothing |
|
|
|
|
|
|
|
False -> Just $ head $ elementChildren e |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typeAttr :: String |
|
|
|
|
|
|
|
typeAttr = case attributeText typeName e of |
|
|
|
|
|
|
|
-- Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> DT.unpack a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fromAttr :: Maybe Address |
|
|
|
|
|
|
|
fromAttr = case attributeText fromName e of |
|
|
|
|
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> X.fromString $ DT.unpack a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toAttr :: Maybe Address |
|
|
|
|
|
|
|
toAttr = case attributeText toName e of |
|
|
|
|
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> X.fromString $ DT.unpack a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idAttr :: Maybe StanzaID |
|
|
|
presenceToXML :: InternalPresence -> Element |
|
|
|
idAttr = case attributeText idName e of |
|
|
|
|
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> Just (SID (DT.unpack a)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typeName :: Name |
|
|
|
presenceToXML (Right p) = Element "presence" attribs nodes |
|
|
|
typeName = fromString "type" |
|
|
|
where |
|
|
|
|
|
|
|
|
|
|
|
fromName :: Name |
|
|
|
|
|
|
|
fromName = fromString "from" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toName :: Name |
|
|
|
|
|
|
|
toName = fromString "to" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idName :: Name |
|
|
|
|
|
|
|
idName = fromString "id" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- TODO: Parse xml:lang |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parsePresence :: Element -> Presence |
|
|
|
|
|
|
|
parsePresence e = Presence idAttr fromAttr toAttr Nothing typeAttr (elementChildren e) |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
-- TODO: Many duplicate functions from parseIQ. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typeAttr :: PresenceType |
|
|
|
|
|
|
|
typeAttr = case attributeText typeName e of |
|
|
|
|
|
|
|
Just t -> stringToPresenceType $ DT.unpack t |
|
|
|
|
|
|
|
Nothing -> Available |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fromAttr :: Maybe Address |
|
|
|
attribs :: [(Name, [Content])] |
|
|
|
fromAttr = case attributeText fromName e of |
|
|
|
attribs = stanzaNodes (presenceID p) (presenceFrom p) (presenceTo p) (presenceLangTag p) ++ |
|
|
|
Nothing -> Nothing |
|
|
|
[("type", [ContentText $ DT.pack $ show $ presenceType p])] |
|
|
|
Just a -> X.fromString $ DT.unpack a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toAttr :: Maybe Address |
|
|
|
nodes :: [Node] |
|
|
|
toAttr = case attributeText toName e of |
|
|
|
nodes = map (\ x -> NodeElement x) (presencePayload p) |
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> X.fromString $ DT.unpack a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idAttr :: Maybe StanzaID |
|
|
|
presenceToXML (Left p) = Element "presence" attribs nodes |
|
|
|
idAttr = case attributeText idName e of |
|
|
|
where |
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> Just (SID (DT.unpack a)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fromName :: Name |
|
|
|
attribs :: [(Name, [Content])] |
|
|
|
fromName = fromString "from" |
|
|
|
attribs = stanzaNodes (presenceErrorID p) (presenceErrorFrom p) (presenceErrorTo p) (presenceErrorLangTag p) ++ |
|
|
|
|
|
|
|
[("type", [ContentText $ DT.pack "error"])] |
|
|
|
|
|
|
|
|
|
|
|
typeName :: Name |
|
|
|
nodes :: [Node] |
|
|
|
typeName = fromString "type" |
|
|
|
nodes = case presenceErrorPayload p of |
|
|
|
|
|
|
|
Just elem -> map (\ x -> NodeElement x) elem |
|
|
|
|
|
|
|
Nothing -> [] |
|
|
|
|
|
|
|
|
|
|
|
toName :: Name |
|
|
|
|
|
|
|
toName = fromString "to" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idName :: Name |
|
|
|
iqToXML :: IQ -> Element |
|
|
|
idName = fromString "id" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parseMessage :: Element -> Message |
|
|
|
iqToXML = iqToXML |
|
|
|
parseMessage e = Message idAttr fromAttr toAttr Nothing typeAttr (elementChildren e) |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
-- TODO: Many duplicate functions from parseIQ. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typeAttr :: MessageType |
|
|
|
|
|
|
|
typeAttr = case attributeText typeName e of |
|
|
|
|
|
|
|
Just t -> stringToMessageType $ DT.unpack t |
|
|
|
|
|
|
|
Nothing -> Normal |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fromAttr :: Maybe Address |
|
|
|
messageToXML :: InternalMessage -> Element |
|
|
|
fromAttr = case attributeText fromName e of |
|
|
|
|
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> X.fromString $ DT.unpack a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toAttr :: Maybe Address |
|
|
|
messageToXML = messageToXML |
|
|
|
toAttr = case attributeText toName e of |
|
|
|
|
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> X.fromString $ DT.unpack a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idAttr :: Maybe StanzaID |
|
|
|
|
|
|
|
idAttr = case attributeText idName e of |
|
|
|
|
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
Just a -> Just (SID (DT.unpack a)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fromName :: Name |
|
|
|
stanzaNodes :: Maybe StanzaID -> Maybe From -> Maybe To -> Maybe LangTag -> [(Name, [Content])] |
|
|
|
fromName = fromString "from" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typeName :: Name |
|
|
|
stanzaNodes i f t l = if isJust $ i then [("id", [ContentText $ DT.pack $ show $ fromJust i])] else [] ++ |
|
|
|
typeName = fromString "type" |
|
|
|
if isJust $ f then [("from", [ContentText $ DT.pack $ show $ fromJust f])] else [] ++ |
|
|
|
|
|
|
|
if isJust $ t then [("to", [ContentText $ DT.pack $ show $ fromJust t])] else [] ++ |
|
|
|
|
|
|
|
if isJust $ l then [("xml:lang", [ContentText $ DT.pack $ show l])] else [] |
|
|
|
|
|
|
|
|
|
|
|
toName :: Name |
|
|
|
|
|
|
|
toName = fromString "to" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idName :: Name |
|
|
|
parseIQ :: Element -> IQ |
|
|
|
idName = fromString "id" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- stringToPresenceType "available" = Available |
|
|
|
parseIQ = parseIQ |
|
|
|
-- stringToPresenceType "away" = Away |
|
|
|
|
|
|
|
-- stringToPresenceType "chat" = Chat |
|
|
|
|
|
|
|
-- stringToPresenceType "dnd" = DoNotDisturb |
|
|
|
|
|
|
|
-- stringToPresenceType "xa" = ExtendedAway |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringToPresenceType "available" = Available -- TODO: Some client sent this |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringToPresenceType "probe" = Probe |
|
|
|
parsePresence :: Element -> InternalPresence |
|
|
|
-- stringToPresenceType "error" = PresenceError -- TODO: Special case |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringToPresenceType "unavailable" = Unavailable |
|
|
|
parsePresence = parsePresence |
|
|
|
stringToPresenceType "subscribe" = Subscribe |
|
|
|
|
|
|
|
stringToPresenceType "subscribed" = Subscribed |
|
|
|
|
|
|
|
stringToPresenceType "unsubscribe" = Unsubscribe |
|
|
|
|
|
|
|
stringToPresenceType "unsubscribed" = Unsubscribed |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- presenceTypeToString Available = "available" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- presenceTypeToString Away = "away" |
|
|
|
parseMessage :: Element -> InternalMessage |
|
|
|
-- presenceTypeToString Chat = "chat" |
|
|
|
|
|
|
|
-- presenceTypeToString DoNotDisturb = "dnd" |
|
|
|
|
|
|
|
-- presenceTypeToString ExtendedAway = "xa" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
presenceTypeToString Unavailable = "unavailable" |
|
|
|
parseMessage = parseMessage |
|
|
|
|
|
|
|
|
|
|
|
presenceTypeToString Probe = "probe" |
|
|
|
|
|
|
|
-- presenceTypeToString PresenceError = "error" -- TODO: Special case |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
presenceTypeToString Subscribe = "subscribe" |
|
|
|
stringToPresenceType :: String -> Maybe (Maybe PresenceType) |
|
|
|
presenceTypeToString Subscribed = "subscribed" |
|
|
|
|
|
|
|
presenceTypeToString Unsubscribe = "unsubscribe" |
|
|
|
|
|
|
|
presenceTypeToString Unsubscribed = "unsubscribed" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringToMessageType "chat" = Chat |
|
|
|
stringToPresenceType "probe" = Just $ Just Probe |
|
|
|
stringToMessageType "error" = Error |
|
|
|
stringToPresenceType "unavailable" = Just $ Just Unavailable |
|
|
|
stringToMessageType "groupchat" = Groupchat |
|
|
|
stringToPresenceType "subscribe" = Just $ Just Subscribe |
|
|
|
stringToMessageType "headline" = Headline |
|
|
|
stringToPresenceType "subscribed" = Just $ Just Subscribed |
|
|
|
stringToMessageType "normal" = Normal |
|
|
|
stringToPresenceType "unsubscribe" = Just $ Just Unsubscribe |
|
|
|
stringToMessageType s = OtherMessageType s |
|
|
|
stringToPresenceType "unsubscribed" = Just $ Just Unsubscribed |
|
|
|
|
|
|
|
stringToPresenceType "error" = Just Nothing |
|
|
|
|
|
|
|
stringToPresenceType _ = Nothing |
|
|
|
|
|
|
|
|
|
|
|
messageTypeToString Chat = "chat" |
|
|
|
|
|
|
|
messageTypeToString Error = "error" |
|
|
|
|
|
|
|
messageTypeToString Groupchat = "groupchat" |
|
|
|
|
|
|
|
messageTypeToString Headline = "headline" |
|
|
|
|
|
|
|
messageTypeToString Normal = "normal" |
|
|
|
|
|
|
|
messageTypeToString (OtherMessageType s) = s |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
presenceTypeToString :: Maybe PresenceType -> String |
|
|
|
|
|
|
|
|
|
|
|
data Version = Version { majorVersion :: Integer |
|
|
|
presenceTypeToString (Just Unavailable) = "unavailable" |
|
|
|
, minorVersion :: Integer } deriving (Eq) |
|
|
|
presenceTypeToString (Just Probe) = "probe" |
|
|
|
|
|
|
|
presenceTypeToString Nothing = "error" |
|
|
|
|
|
|
|
presenceTypeToString (Just Subscribe) = "subscribe" |
|
|
|
|
|
|
|
presenceTypeToString (Just Subscribed) = "subscribed" |
|
|
|
|
|
|
|
presenceTypeToString (Just Unsubscribe) = "unsubscribe" |
|
|
|
|
|
|
|
presenceTypeToString (Just Unsubscribed) = "unsubscribed" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Version numbers are displayed as "<major>.<minor>". |
|
|
|
stringToMessageType :: String -> Maybe (Maybe MessageType) |
|
|
|
|
|
|
|
|
|
|
|
instance Show Version where |
|
|
|
stringToMessageType "chat" = Just $ Just Chat |
|
|
|
show (Version major minor) = (show major) ++ "." ++ (show minor) |
|
|
|
stringToMessageType "error" = Just $ Nothing |
|
|
|
|
|
|
|
stringToMessageType "groupchat" = Just $ Just Groupchat |
|
|
|
|
|
|
|
stringToMessageType "headline" = Just $ Just Headline |
|
|
|
|
|
|
|
stringToMessageType "normal" = Just $ Just Normal |
|
|
|
|
|
|
|
stringToMessageType _ = Nothing |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- If the major version numbers are not equal, compare them. Otherwise, compare |
|
|
|
messageTypeToString :: Maybe MessageType -> String |
|
|
|
-- the minor version numbers. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
instance Ord Version where |
|
|
|
messageTypeToString (Just Chat) = "chat" |
|
|
|
compare (Version amajor aminor) (Version bmajor bminor) |
|
|
|
messageTypeToString Nothing = "error" |
|
|
|
| amajor /= bmajor = compare amajor bmajor |
|
|
|
messageTypeToString (Just Groupchat) = "groupchat" |
|
|
|
| otherwise = compare aminor bminor |
|
|
|
messageTypeToString (Just Headline) = "headline" |
|
|
|
|
|
|
|
messageTypeToString (Just Normal) = "normal" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Converts a "<major>.<minor>" numeric version number to a "Version" object. |
|
|
|
-- Converts a "<major>.<minor>" numeric version number to a "Version" object. |
|
|
|
@ -507,25 +297,6 @@ version = do |
|
|
|
return $ Version (read major) (read minor) |
|
|
|
return $ Version (read major) (read minor) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data LangTag = LangTag { primaryTag :: String |
|
|
|
|
|
|
|
, subtags :: [String] } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Displays the language tag in the form of "en-US". |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
instance Show LangTag where |
|
|
|
|
|
|
|
show (LangTag p []) = p |
|
|
|
|
|
|
|
show (LangTag p s) = p ++ "-" ++ (concat $ intersperse "-" s) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Two language tags are considered equal of they contain the same tags (case-insensitive). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
instance Eq LangTag where |
|
|
|
|
|
|
|
(LangTag ap as) == (LangTag bp bs) |
|
|
|
|
|
|
|
| length as == length bs && map toLower ap == map toLower bp = all (\ (a, b) -> map toLower a == map toLower b) $ zip as bs |
|
|
|
|
|
|
|
| otherwise = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- | |
|
|
|
-- | |
|
|
|
-- Parses, validates, and possibly constructs a "LangTag" object. |
|
|
|
-- Parses, validates, and possibly constructs a "LangTag" object. |
|
|
|
|
|
|
|
|
|
|
|
|