pontarius-xmpp-0.0.4.0: Network/XMPP/JID.hs
{-
Copyright © 2010-2011 Jon Kristensen.
This file is part of Pontarius XMPP.
Pontarius XMPP is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
Pontarius XMPP is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with Pontarius XMPP. If not, see <http://www.gnu.org/licenses/>.
-}
-- | Module: $Header$
-- Description: JabberID (JID) data type and utility functions
-- Copyright: Copyright © 2010-2011 Jon Kristensen
-- License: LGPL-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