-- | Module: $Header$ -- Description: JabberID (JID) data type and utility functions -- Copyright: Copyright © 2010-2011 Jon Kristensen -- License: BSD-3 -- -- Maintainer: info@pontarius.org -- Stability: unstable -- Portability: portable -- -- JIDs are written in the format of `node@server/resource'. An example of a -- JID is `jonkri@jabber.org'. -- -- The node identifier is the part before the `@' character in Jabber IDs. -- Node names are optional. The server identifier is the part after the `@' -- character in Jabber IDs (and before the `/' character). The server -- identifier is the only required field of a JID. The server identifier MAY -- be an IP address but SHOULD be a fully qualified domain name. The resource -- identifier is the part after the `/' character in Jabber IDs. Like with -- node names, the resource identifier is optional. -- -- A JID without a resource identifier (i.e. a JID in the form of -- `node@server') is called `bare JID'. A JID with a resource identifier is -- called `full JID'. -- Node identifiers MUST be formatted in such a way so that the Nodeprep profile -- (see RFC 3920: XMPP Core, Appendix A) of RFC 3454: Preparation of -- Internationalized Strings (`stringprep') can be applied without failing. -- Servers MUST and clients SHOULD apply the Nodeprep profile to node names -- prior to comparing them. Node identifiers MUST NOT be more than 1023 bytes in -- length. -- -- If it is a domain name it MUST be an `internationalized domain name' as -- defined in RFC 3490: Internationalizing Domain Names in Applications (IDNA), -- to which RFC 3491: Nameprep: A Stringprep Profile for Internationalized -- Domain Names (IDN) can be applied without failing. Servers MUST and clients -- SHOULD first apply the Nameprep profile to the domain names prior to -- comparing them. Like with node names, server identifiers MUST NOT be more -- than 1023 bytes in length. -- -- A resource identifier has to be formatted in such a way so that the -- Resourceprep profile of RFC 3454: Preparation of Internationalized Strings -- (`stringprep') can be applied without failing. Servers MUST and clients -- SHOULD first apply the Resourceprep profile (see RFC 3920: XMPP Core, -- Appendix B) to resource names prior to comparing them. The resource -- identifier MUST MOT be more than 1023 bytes in length. -- -- Given the length of the `@' and `/' characters as well as the restrictions -- imposed on the node, server and resource identifiers, a JID will never be -- longer than 3071 bytes. -- TODO: Make the regular expression only match valid JIDs. -- TODO: Use Perl regular expressions to use non-capturing groups with "(?:"? -- TODO: Validate the input in the jid and stringToJID functions. module Network.XMPP.JID ( JID (jidNode, jidServer, jidResource) , jid , jidIsFull , jidIsBare , stringToJID , jidToString ) where import Text.Regex.Posix ((=~)) -- JID is a data type that has to be constructed in this module using either jid -- or stringToJID. data JID = JID { jidNode :: Maybe String , jidServer :: String , jidResource :: Maybe String } deriving (Eq, Show) -- | Simple function to construct a JID. We will add validation to this function -- in a later release. jid :: Maybe String -> String -> Maybe String -> JID jid n s r = JID { jidNode = n, jidServer = s, jidResource = r } -- | Converts a (JID) String to a JID record. stringToJID :: String -> Maybe JID stringToJID string = matchToJID $ string =~ "^(([^@]+)@)?([^/]+)(/(.+))?$" where matchToJID [[_, _, "", server, _, ""]] = Just JID { jidNode = Nothing, jidServer = server, jidResource = Nothing } matchToJID [[_, _, node, server, _, ""]] = Just JID { jidNode = Just node , jidServer = server , jidResource = Nothing } matchToJID [[_, _, "", server, _, resource]] = Just JID { jidNode = Nothing , jidServer = server , jidResource = Just resource } matchToJID [[_, _, node, server, _, resource]] = Just JID { jidNode = Just node , jidServer = server , jidResource = Just resource } matchToJID _ = Nothing -- | Converts a JID to a String. jidToString :: JID -> String jidToString JID { jidNode = n, jidServer = s, jidResource = r } | n == Nothing && r == Nothing = s | r == Nothing = let Just n' = n in n' ++ "@" ++ s | n == Nothing = let Just r' = r in s ++ "/" ++ r' | otherwise = let Just n' = n; Just r' = r in n' ++ "@" ++ s ++ "/" ++ r' -- | JIDs are written in the format of `node@server/resource'. A JID without a -- resource identifier (i.e. a JID in the form of `server' or `node@server') -- is called a `bare JID'. A JID with a resource identifier is called `full -- JID'. This function returns True if the JID is `bare' and False otherwise. jidIsBare :: JID -> Bool jidIsBare j | jidResource j == Nothing = True | otherwise = False -- | JIDs are written in the format of `node@server/resource'. A JID without a -- resource identifier (i.e. a JID in the form of `server' or `node@server') -- is called a `bare JID'. A JID with a resource identifier is called `full -- JID'. This function returns True if the JID is `full' and False otherwise. -- This function is defined in terms of (not) jidIsBare. jidIsFull :: JID -> Bool jidIsFull jid = not $ jidIsBare jid