irc 0.2.3 → 0.4
raw patch · 8 files changed
+490/−324 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Network.IRC.Parser: maybeP :: GenParser tok st a -> GenParser tok st (Maybe a)
- Network.IRC.Types: Add :: [p] -> Mode p
- Network.IRC.Types: BanMask :: ChanProp
- Network.IRC.Types: ChanOp :: ChanProp
- Network.IRC.Types: Invisible :: UserProp
- Network.IRC.Types: InviteOnly :: ChanProp
- Network.IRC.Types: Message :: (Maybe Prefix) -> Command -> [Parameter] -> Message
- Network.IRC.Types: Moderated :: ChanProp
- Network.IRC.Types: NickName :: String -> (Maybe UserName) -> (Maybe ServerName) -> Prefix
- Network.IRC.Types: NoOutsideMessages :: ChanProp
- Network.IRC.Types: Password :: ChanProp
- Network.IRC.Types: Private :: ChanProp
- Network.IRC.Types: Remove :: [p] -> Mode p
- Network.IRC.Types: Secret :: ChanProp
- Network.IRC.Types: Server :: ServerName -> Prefix
- Network.IRC.Types: ServerNotices :: UserProp
- Network.IRC.Types: Speak :: ChanProp
- Network.IRC.Types: TopicOpOnly :: ChanProp
- Network.IRC.Types: UserLimit :: ChanProp
- Network.IRC.Types: UserOp :: UserProp
- Network.IRC.Types: Wallops :: UserProp
- Network.IRC.Types: class Prop a
- Network.IRC.Types: data ChanProp
- Network.IRC.Types: data Message
- Network.IRC.Types: data Mode p
- Network.IRC.Types: data Prefix
- Network.IRC.Types: data UserProp
- Network.IRC.Types: instance (Show p) => Show (Mode p)
- Network.IRC.Types: instance Eq ChanProp
- Network.IRC.Types: instance Eq Message
- Network.IRC.Types: instance Eq Prefix
- Network.IRC.Types: instance Eq UserProp
- Network.IRC.Types: instance Prop ChanProp
- Network.IRC.Types: instance Prop UserProp
- Network.IRC.Types: instance Read Message
- Network.IRC.Types: instance Read Prefix
- Network.IRC.Types: instance Show ChanProp
- Network.IRC.Types: instance Show Message
- Network.IRC.Types: instance Show Prefix
- Network.IRC.Types: instance Show UserProp
- Network.IRC.Types: render :: Message -> String
- Network.IRC.Types: renderMode :: (Prop p) => Mode p -> String
- Network.IRC.Types: renderProp :: (Prop a) => a -> String
- Network.IRC.Types: translateReply :: Command -> String
- Network.IRC.Types: type Command = String
- Network.IRC.Types: type Parameter = String
- Network.IRC.Types: type RealName = String
- Network.IRC.Types: type ServerName = String
- Network.IRC.Types: type UserName = String
+ Network.IRC.Base: Message :: (Maybe Prefix) -> Command -> [Parameter] -> Message
+ Network.IRC.Base: NickName :: String -> (Maybe UserName) -> (Maybe ServerName) -> Prefix
+ Network.IRC.Base: Server :: ServerName -> Prefix
+ Network.IRC.Base: data Message
+ Network.IRC.Base: data Prefix
+ Network.IRC.Base: encode :: Message -> String
+ Network.IRC.Base: instance Eq Message
+ Network.IRC.Base: instance Eq Prefix
+ Network.IRC.Base: instance Read Message
+ Network.IRC.Base: instance Read Prefix
+ Network.IRC.Base: instance Show Message
+ Network.IRC.Base: instance Show Prefix
+ Network.IRC.Base: render :: Message -> String
+ Network.IRC.Base: replyTable :: [(String, String)]
+ Network.IRC.Base: showMessage :: Message -> String
+ Network.IRC.Base: showParameters :: [Parameter] -> String
+ Network.IRC.Base: showPrefix :: Prefix -> String
+ Network.IRC.Base: translateReply :: Command -> String
+ Network.IRC.Base: type Command = String
+ Network.IRC.Base: type Parameter = String
+ Network.IRC.Base: type RealName = String
+ Network.IRC.Base: type ServerName = String
+ Network.IRC.Base: type UserName = String
+ Network.IRC.Commands: joinChan :: Channel -> Message
+ Network.IRC.Commands: nick :: UserName -> Message
+ Network.IRC.Commands: part :: Channel -> Message
+ Network.IRC.Commands: privmsg :: String -> String -> Message
+ Network.IRC.Commands: quit :: Maybe String -> Message
+ Network.IRC.Commands: type Channel = String
+ Network.IRC.Commands: type Password = String
+ Network.IRC.Commands: user :: UserName -> ServerName -> ServerName -> RealName -> Message
+ Network.IRC.Parser: decode :: String -> Maybe Message
Files
- Network/IRC.hs +8/−4
- Network/IRC/Base.hs +228/−0
- Network/IRC/Commands.hs +43/−0
- Network/IRC/Parser.hs +26/−24
- Network/IRC/Types.hs +0/−283
- irc.cabal +21/−13
- tests/Makefile +14/−0
- tests/Tests.hs +150/−0
Network/IRC.hs view
@@ -20,7 +20,7 @@ -- -- Maintainer : trevor@geekgateway.com -- Stability : experimental--- Portability : non-portable (GADT's)+-- Portability : non-portable -- -- library for parsing IRC messages --@@ -28,9 +28,13 @@ -- * Parsers module Network.IRC.Parser - -- * Types- , module Network.IRC.Types+ -- * Base+ , module Network.IRC.Base+ + -- * Message API+ , module Network.IRC.Commands ) where import Network.IRC.Parser-import Network.IRC.Types+import Network.IRC.Base+import Network.IRC.Commands
+ Network/IRC/Base.hs view
@@ -0,0 +1,228 @@+-- This file is part of irc.++-- irc 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.++-- irc 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 this program. If not, see <http://www.gnu.org/licenses/>.++-- | Datatypes for representing IRC messages, as well as formatting them.+module Network.IRC.Base (+ -- * Type Synonyms+ Parameter+ , ServerName+ , UserName+ , RealName+ , Command++ -- * IRC Datatypes+ , Prefix(Server, NickName)+ , Message(Message)++ -- * Formatting functions+ , encode -- :: Message -> String+ , showMessage, showPrefix, showParameters+ , translateReply -- :: String -> String+ , replyTable -- :: [(String,String)]++ -- * Deprecated+ , render+ ) where++import Data.Maybe++-- ---------------------------------------------------------+-- Data Types++type Parameter = String+type ServerName = String+type UserName = String+type RealName = String+type Command = String+++-- | IRC messages are parsed as:+-- [ ':' prefix space ] command { space param } crlf+data Message+ = -- | IRC Message+ Message (Maybe Prefix) Command [Parameter]+ deriving (Show,Read,Eq)+++-- | The optional beginning of an IRC messages+data Prefix+ = -- | Server Prefix+ Server ServerName+ | -- | Nickname Prefix+ NickName String (Maybe UserName) (Maybe ServerName)+ deriving (Show,Read,Eq)+++-- ---------------------------------------------------------+-- Formatting+++-- | Encode a message to its string representation+encode :: Message -> String+encode m = showMessage m++-- | This is the deprecated version of encode+render :: Message -> String+render = encode++showMessage :: Message -> String+showMessage (Message p c ps) = showMaybe p ++ c ++ showParameters ps+ where showMaybe = maybe "" ((++ " ") . (':':) . showPrefix)++showPrefix :: Prefix -> String+showPrefix (Server s) = s+showPrefix (NickName n u h) = n ++ showMaybe '!' u ++ showMaybe '@' h+ where showMaybe c e = maybe "" (c:) e++showParameters :: [Parameter] -> String+showParameters [] = []+showParameters ps = " " ++ (unwords $ showp ps)+ where showp [] = []+ showp p@(x:xs) | ' ' `elem` x = [':' : unwords p]+ | otherwise = x : showp xs+++-- ---------------------------------------------------------+-- Message Translation++-- | Translate a reply into its text description.+-- If no text is available, the argument is returned.+translateReply :: Command -- ^ Reply+ -> String -- ^ Text translation+translateReply r = fromMaybe r $ lookup r replyTable+++-- One big lookup table of codes and errors+replyTable :: [(String,String)]+replyTable =+ [ ("401","ERR_NOSUCHNICK")+ , ("402","ERR_NOSUCHSERVER")+ , ("403","ERR_NOSUCHCHANNEL")+ , ("404","ERR_CANNOTSENDTOCHAN")+ , ("405","ERR_TOOMANYCHANNELS")+ , ("406","ERR_WASNOSUCHNICK")+ , ("407","ERR_TOOMANYTARGETS")+ , ("409","ERR_NOORIGIN")+ , ("411","ERR_NORECIPIENT")+ , ("412","ERR_NOTEXTTOSEND")+ , ("413","ERR_NOTOPLEVEL")+ , ("414","ERR_WILDTOPLEVEL")+ , ("421","ERR_UNKNOWNCOMMAND")+ , ("422","ERR_NOMOTD")+ , ("423","ERR_NOADMININFO")+ , ("424","ERR_FILEERROR")+ , ("431","ERR_NONICKNAMEGIVEN")+ , ("432","ERR_ERRONEUSNICKNAME")+ , ("433","ERR_NICKNAMEINUSE")+ , ("436","ERR_NICKCOLLISION")+ , ("441","ERR_USERNOTINCHANNEL")+ , ("442","ERR_NOTONCHANNEL")+ , ("443","ERR_USERONCHANNEL")+ , ("444","ERR_NOLOGIN")+ , ("445","ERR_SUMMONDISABLED")+ , ("446","ERR_USERSDISABLED")+ , ("451","ERR_NOTREGISTERED")+ , ("461","ERR_NEEDMOREPARAMS")+ , ("462","ERR_ALREADYREGISTRED")+ , ("463","ERR_NOPERMFORHOST")+ , ("464","ERR_PASSWDMISMATCH")+ , ("465","ERR_YOUREBANNEDCREEP")+ , ("467","ERR_KEYSET")+ , ("471","ERR_CHANNELISFULL")+ , ("472","ERR_UNKNOWNMODE")+ , ("473","ERR_INVITEONLYCHAN")+ , ("474","ERR_BANNEDFROMCHAN")+ , ("475","ERR_BADCHANNELKEY")+ , ("481","ERR_NOPRIVILEGES")+ , ("482","ERR_CHANOPRIVSNEEDED")+ , ("483","ERR_CANTKILLSERVER")+ , ("491","ERR_NOOPERHOST")+ , ("501","ERR_UMODEUNKNOWNFLAG")+ , ("502","ERR_USERSDONTMATCH")+ , ("300","RPL_NONE")+ , ("302","RPL_USERHOST")+ , ("303","RPL_ISON")+ , ("301","RPL_AWAY")+ , ("305","RPL_UNAWAY")+ , ("306","RPL_NOWAWAY")+ , ("311","RPL_WHOISUSER")+ , ("312","RPL_WHOISSERVER")+ , ("313","RPL_WHOISOPERATOR")+ , ("317","RPL_WHOISIDLE")+ , ("318","RPL_ENDOFWHOIS")+ , ("319","RPL_WHOISCHANNELS")+ , ("314","RPL_WHOWASUSER")+ , ("369","RPL_ENDOFWHOWAS")+ , ("321","RPL_LISTSTART")+ , ("322","RPL_LIST")+ , ("323","RPL_LISTEND")+ , ("324","RPL_CHANNELMODEIS")+ , ("331","RPL_NOTOPIC")+ , ("332","RPL_TOPIC")+ , ("341","RPL_INVITING")+ , ("342","RPL_SUMMONING")+ , ("351","RPL_VERSION")+ , ("352","RPL_WHOREPLY")+ , ("315","RPL_ENDOFWHO")+ , ("353","RPL_NAMREPLY")+ , ("366","RPL_ENDOFNAMES")+ , ("364","RPL_LINKS")+ , ("365","RPL_ENDOFLINKS")+ , ("367","RPL_BANLIST")+ , ("368","RPL_ENDOFBANLIST")+ , ("371","RPL_INFO")+ , ("374","RPL_ENDOFINFO")+ , ("375","RPL_MOTDSTART")+ , ("372","RPL_MOTD")+ , ("376","RPL_ENDOFMOTD")+ , ("381","RPL_YOUREOPER")+ , ("382","RPL_REHASHING")+ , ("391","RPL_TIME")+ , ("392","RPL_USERSSTART")+ , ("393","RPL_USERS")+ , ("394","RPL_ENDOFUSERS")+ , ("395","RPL_NOUSERS")+ , ("200","RPL_TRACELINK")+ , ("201","RPL_TRACECONNECTING")+ , ("202","RPL_TRACEHANDSHAKE")+ , ("203","RPL_TRACEUNKNOWN")+ , ("204","RPL_TRACEOPERATOR")+ , ("205","RPL_TRACEUSER")+ , ("206","RPL_TRACESERVER")+ , ("208","RPL_TRACENEWTYPE")+ , ("261","RPL_TRACELOG")+ , ("211","RPL_STATSLINKINFO")+ , ("212","RPL_STATSCOMMANDS")+ , ("213","RPL_STATSCLINE")+ , ("214","RPL_STATSNLINE")+ , ("215","RPL_STATSILINE")+ , ("216","RPL_STATSKLINE")+ , ("218","RPL_STATSYLINE")+ , ("219","RPL_ENDOFSTATS")+ , ("241","RPL_STATSLLINE")+ , ("242","RPL_STATSUPTIME")+ , ("243","RPL_STATSOLINE")+ , ("244","RPL_STATSHLINE")+ , ("221","RPL_UMODEIS")+ , ("251","RPL_LUSERCLIENT")+ , ("252","RPL_LUSEROP")+ , ("253","RPL_LUSERUNKNOWN")+ , ("254","RPL_LUSERCHANNELS")+ , ("255","RPL_LUSERME")+ , ("256","RPL_ADMINME")+ , ("257","RPL_ADMINLOC1")+ , ("258","RPL_ADMINLOC2")+ , ("259","RPL_ADMINEMAIL")+ ]
+ Network/IRC/Commands.hs view
@@ -0,0 +1,43 @@+module Network.IRC.Commands (+ -- * Types+ Channel+ , Password++ -- * IRC Functions+ , nick+ , user+ , joinChan+ , part+ , quit+ , privmsg+ ) where++import Network.IRC.Base++type Channel = String+type Password = String++mkMessage :: String -> [Parameter] -> Message+mkMessage cmd params = Message Nothing cmd params+++++nick :: UserName -> Message+nick u = mkMessage "NICK" [u]++user :: UserName -> ServerName -> ServerName -> RealName -> Message+user u h s r = mkMessage "USER" [u,h,s,r]++joinChan :: Channel -> Message+joinChan c = mkMessage "JOIN" [c]++part :: Channel -> Message+part c = mkMessage "PART" [c]++quit :: Maybe String -> Message+quit (Just m) = mkMessage "QUIT" [m]+quit Nothing = mkMessage "QUIT" []++privmsg :: String -> String -> Message+privmsg c m = mkMessage "PRIVMSG" [c,m]
Network/IRC/Parser.hs view
@@ -16,42 +16,44 @@ -- | Parsec parsers and a general parsing interface for IRC messages module Network.IRC.Parser ( -- * Parsing and Formatting Functions- parseMessage -- :: String -> Maybe Message+ decode -- :: String -> Maybe Message -- * Parsec Combinators for Parsing IRC messages- , prefix -- :: CharParser st Prefix- , serverPrefix -- :: CharParser st Prefix- , nicknamePrefix -- :: CharParser st Prefix- , command -- :: CharParser st Command- , parameter -- :: CharParser st Parameter- , message -- :: CharParser st Message- , crlf -- :: CharParser st ()- , spaces -- :: CharParser st ()+ , prefix -- :: CharParser st Prefix+ , serverPrefix -- :: CharParser st Prefix+ , nicknamePrefix -- :: CharParser st Prefix+ , command -- :: CharParser st Command+ , parameter -- :: CharParser st Parameter+ , message -- :: CharParser st Message+ , crlf -- :: CharParser st ()+ , spaces -- :: CharParser st () -- * Other Parser Combinators- , maybeP -- :: GenParser tok st a -> GenParser tok st (Maybe a) , tokenize -- :: CharParser st a -> CharParser st a , takeUntil -- :: String -> CharParser st String++ -- * Deprecated Functions+ , parseMessage ) where +import Network.IRC.Base+ import Control.Monad import Data.Maybe import Text.ParserCombinators.Parsec hiding (spaces) -import Network.IRC.Types- -- | Parse a String into a Message.-parseMessage :: String -- ^ Message string- -> Maybe Message -- ^ Parsed message-parseMessage = (either (const Nothing) Just) . (parse message "")+decode :: String -- ^ Message string+ -> Maybe Message -- ^ Parsed message+decode = (either (const Nothing) Just) . (parse message "") +-- | The deprecated version of decode+parseMessage :: String -> Maybe Message+parseMessage = decode+ -- | Take all tokens until one character from a given string is found takeUntil :: String -> CharParser st String-takeUntil = many1 . noneOf---- | Convert a parser into an optional one that returns a Maybe-maybeP :: GenParser tok st a -> GenParser tok st (Maybe a)-maybeP p = option Nothing (liftM Just p)+takeUntil s = anyChar `manyTill` (lookAhead (oneOf s)) -- | Convert a parser that consumes all space after it tokenize :: CharParser st a -> CharParser st a@@ -75,13 +77,13 @@ n <- takeUntil " .!@\r\n" p <- option False (char '.' >> return True) when p (fail "")- u <- maybeP $ char '!' >> takeUntil " @\r\n"- s <- maybeP $ char '@' >> takeUntil " \r\n"+ u <- optionMaybe $ char '!' >> takeUntil " @\r\n"+ s <- optionMaybe $ char '@' >> takeUntil " \r\n" return $ NickName n u s -- | Parse a command. Either a string of capital letters, or 3 digits. command :: CharParser st Command-command = many1 upper+command = (many1 upper) <|> do x <- digit y <- digit z <- digit@@ -99,7 +101,7 @@ -- | Parse a Message message :: CharParser st Message message = do- p <- maybeP $ tokenize prefix+ p <- optionMaybe $ tokenize prefix c <- command ps <- many (spaces >> parameter) crlf >> eof
− Network/IRC/Types.hs
@@ -1,283 +0,0 @@--- This file is part of irc.---- irc 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.---- irc 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 this program. If not, see <http://www.gnu.org/licenses/>.---- | Datatypes for representing IRC messages, as well as formatting them.-module Network.IRC.Types (- -- * Type Synonyms- Parameter- , ServerName- , UserName- , RealName- , Command-- -- * Properties- , Prop(renderProp)- , Mode(Add, Remove)- , UserProp(..)- , ChanProp(..)-- -- * IRC Datatypes- , Prefix(Server, NickName)- , Message(Message)-- -- * Formatting functions- , render -- :: Message -> String- , renderMode -- :: (Prop p) => Mode p -> String- , translateReply -- :: String -> String- ) where--import Data.Maybe--type Command = String-type Parameter = String-type ServerName = String-type UserName = String-type RealName = String---- | IRC messages are parsed as:--- [ ':' prefix space ] command { space param } crlf-data Message- = -- | IRC Message- Message (Maybe Prefix) Command [Parameter]- deriving (Show,Read,Eq)---- | The optional beginning of an IRC messages-data Prefix- = -- | Server Prefix- Server ServerName- | -- | Nickname Prefix- NickName String (Maybe UserName) (Maybe ServerName)- deriving (Show,Read,Eq)---- | IRC Modes-data Mode p where- Add :: (Prop p) => [p] -> Mode p- Remove :: (Prop p) => [p] -> Mode p--instance Show p => Show (Mode p) where- show (Add ps) = "Add " ++ show ps- show (Remove ps) = "Remove " ++ show ps---- Render a mode string-renderMode :: (Prop p) => Mode p -> String-renderMode (Add ps) = "+" ++ (concat $ map renderProp ps)-renderMode (Remove ps) = "-" ++ (concat $ map renderProp ps)---- | Property class-class Prop a where- renderProp :: a -> String---- | User properties-data UserProp- = UserOp- | Invisible- | ServerNotices- | Wallops- deriving (Show,Eq)--instance Prop UserProp where- renderProp p = fromMaybe "" (p `lookup` userPropTable)--userPropTable :: [(UserProp,String)]-userPropTable =- [ (UserOp, "o")- , (Invisible, "i")- , (ServerNotices, "s")- , (Wallops, "w")- ]---- | Channel properties-data ChanProp- = ChanOp- | Private- | Secret- | InviteOnly- | TopicOpOnly- | NoOutsideMessages- | Moderated- | UserLimit- | BanMask- | Speak- | Password- deriving (Show,Eq)--instance Prop ChanProp where- renderProp p = fromMaybe "" (p `lookup` chanPropTable)--chanPropTable :: [(ChanProp,String)]-chanPropTable =- [ (ChanOp, "o")- , (Private, "p")- , (Secret, "s")- , (InviteOnly, "i")- , (TopicOpOnly, "t")- , (NoOutsideMessages, "n")- , (Moderated, "m")- , (UserLimit, "l")- , (BanMask, "b")- , (Speak, "v")- , (Password, "k")- ]---- | Message rendering-render :: Message -- ^ IRC Message- -> String -- ^ Rendered message-render (Message p c args) =- (maybe "" (\p' -> formatPrefix p' ++ " ") p) ++ c ++ " "- ++ formatArgs args- -formatPrefix :: Prefix -> String-formatPrefix (Server n) = ":" ++ n-formatPrefix (NickName n u s) = ":" ++ n- ++ maybe "" (\u' -> "!" ++ u') u- ++ maybe "" (\s' -> "@" ++ s') s---- Format a parameter string-formatArgs :: [Parameter] -> String-formatArgs = unwords . formatArgs' . filter ((>0) . length)--formatArgs' :: [Parameter] -> [String]-formatArgs' [] = []-formatArgs' l@(p:ps) | elem ' ' p = [":" ++ unwords l]- | otherwise = p : formatArgs' ps---- | Translate a reply into the text version of the reply.--- If no text version is available, the argument is returned.-translateReply :: Command -- ^ Reply- -> String -- ^ Text translation-translateReply r = fromMaybe r $ lookup r replyTable---- One big lookup table of codes and errors-replyTable :: [(String,String)]-replyTable =- [ ("401","ERR_NOSUCHNICK")- , ("402","ERR_NOSUCHSERVER")- , ("403","ERR_NOSUCHCHANNEL")- , ("404","ERR_CANNOTSENDTOCHAN")- , ("405","ERR_TOOMANYCHANNELS")- , ("406","ERR_WASNOSUCHNICK")- , ("407","ERR_TOOMANYTARGETS")- , ("409","ERR_NOORIGIN")- , ("411","ERR_NORECIPIENT")- , ("412","ERR_NOTEXTTOSEND")- , ("413","ERR_NOTOPLEVEL")- , ("414","ERR_WILDTOPLEVEL")- , ("421","ERR_UNKNOWNCOMMAND")- , ("422","ERR_NOMOTD")- , ("423","ERR_NOADMININFO")- , ("424","ERR_FILEERROR")- , ("431","ERR_NONICKNAMEGIVEN")- , ("432","ERR_ERRONEUSNICKNAME")- , ("433","ERR_NICKNAMEINUSE")- , ("436","ERR_NICKCOLLISION")- , ("441","ERR_USERNOTINCHANNEL")- , ("442","ERR_NOTONCHANNEL")- , ("443","ERR_USERONCHANNEL")- , ("444","ERR_NOLOGIN")- , ("445","ERR_SUMMONDISABLED")- , ("446","ERR_USERSDISABLED")- , ("451","ERR_NOTREGISTERED")- , ("461","ERR_NEEDMOREPARAMS")- , ("462","ERR_ALREADYREGISTRED")- , ("463","ERR_NOPERMFORHOST")- , ("464","ERR_PASSWDMISMATCH")- , ("465","ERR_YOUREBANNEDCREEP")- , ("467","ERR_KEYSET")- , ("471","ERR_CHANNELISFULL")- , ("472","ERR_UNKNOWNMODE")- , ("473","ERR_INVITEONLYCHAN")- , ("474","ERR_BANNEDFROMCHAN")- , ("475","ERR_BADCHANNELKEY")- , ("481","ERR_NOPRIVILEGES")- , ("482","ERR_CHANOPRIVSNEEDED")- , ("483","ERR_CANTKILLSERVER")- , ("491","ERR_NOOPERHOST")- , ("501","ERR_UMODEUNKNOWNFLAG")- , ("502","ERR_USERSDONTMATCH")- , ("300","RPL_NONE")- , ("302","RPL_USERHOST")- , ("303","RPL_ISON")- , ("301","RPL_AWAY")- , ("305","RPL_UNAWAY")- , ("306","RPL_NOWAWAY")- , ("311","RPL_WHOISUSER")- , ("312","RPL_WHOISSERVER")- , ("313","RPL_WHOISOPERATOR")- , ("317","RPL_WHOISIDLE")- , ("318","RPL_ENDOFWHOIS")- , ("319","RPL_WHOISCHANNELS")- , ("314","RPL_WHOWASUSER")- , ("369","RPL_ENDOFWHOWAS")- , ("321","RPL_LISTSTART")- , ("322","RPL_LIST")- , ("323","RPL_LISTEND")- , ("324","RPL_CHANNELMODEIS")- , ("331","RPL_NOTOPIC")- , ("332","RPL_TOPIC")- , ("341","RPL_INVITING")- , ("342","RPL_SUMMONING")- , ("351","RPL_VERSION")- , ("352","RPL_WHOREPLY")- , ("315","RPL_ENDOFWHO")- , ("353","RPL_NAMREPLY")- , ("366","RPL_ENDOFNAMES")- , ("364","RPL_LINKS")- , ("365","RPL_ENDOFLINKS")- , ("367","RPL_BANLIST")- , ("368","RPL_ENDOFBANLIST")- , ("371","RPL_INFO")- , ("374","RPL_ENDOFINFO")- , ("375","RPL_MOTDSTART")- , ("372","RPL_MOTD")- , ("376","RPL_ENDOFMOTD")- , ("381","RPL_YOUREOPER")- , ("382","RPL_REHASHING")- , ("391","RPL_TIME")- , ("392","RPL_USERSSTART")- , ("393","RPL_USERS")- , ("394","RPL_ENDOFUSERS")- , ("395","RPL_NOUSERS")- , ("200","RPL_TRACELINK")- , ("201","RPL_TRACECONNECTING")- , ("202","RPL_TRACEHANDSHAKE")- , ("203","RPL_TRACEUNKNOWN")- , ("204","RPL_TRACEOPERATOR")- , ("205","RPL_TRACEUSER")- , ("206","RPL_TRACESERVER")- , ("208","RPL_TRACENEWTYPE")- , ("261","RPL_TRACELOG")- , ("211","RPL_STATSLINKINFO")- , ("212","RPL_STATSCOMMANDS")- , ("213","RPL_STATSCLINE")- , ("214","RPL_STATSNLINE")- , ("215","RPL_STATSILINE")- , ("216","RPL_STATSKLINE")- , ("218","RPL_STATSYLINE")- , ("219","RPL_ENDOFSTATS")- , ("241","RPL_STATSLLINE")- , ("242","RPL_STATSUPTIME")- , ("243","RPL_STATSOLINE")- , ("244","RPL_STATSHLINE")- , ("221","RPL_UMODEIS")- , ("251","RPL_LUSERCLIENT")- , ("252","RPL_LUSEROP")- , ("253","RPL_LUSERUNKNOWN")- , ("254","RPL_LUSERCHANNELS")- , ("255","RPL_LUSERME")- , ("256","RPL_ADMINME")- , ("257","RPL_ADMINLOC1")- , ("258","RPL_ADMINLOC2")- , ("259","RPL_ADMINEMAIL")- ]
irc.cabal view
@@ -1,13 +1,21 @@-name: irc-synopsis: A small library for parsing IRC messages.-description: A set of combinators and types for parsing IRC messages.-version: 0.2.3-category: Data-license: LGPL-license-file: COPYING-author: Trevor Elliott-maintainer: trevor@geekgateway.com-extra-source-files: COPYING.LESSER-build-depends: base, parsec >= 2.0-exposed-Modules: Network.IRC, Network.IRC.Parser, Network.IRC.Types-ghc-options: -Wall -fglasgow-exts+name: irc+synopsis: A small library for parsing IRC messages.+description: A set of combinators and types for parsing IRC messages.+version: 0.4+category: Data+license: LGPL+license-file: COPYING+author: Trevor Elliott+maintainer: trevor@geekgateway.com+extra-source-files: COPYING.LESSER,+ tests/Makefile,+ tests/Tests.hs+cabal-version: >= 1.2.0++library+ ghc-options: -Wall+ build-depends: base, parsec >= 2.0+ exposed-Modules: Network.IRC,+ Network.IRC.Base,+ Network.IRC.Commands,+ Network.IRC.Parser
+ tests/Makefile view
@@ -0,0 +1,14 @@+ODIR = .ghc+TARGET = Tests++all : $(ODIR)+ ghc --make -odir=$(ODIR) -hidir=$(ODIR) $(TARGET)+ ./$(TARGET)++$(ODIR) :+ mkdir $(ODIR)++clean :+ $(RM) -r $(ODIR) $(TARGET)++.PHONY: all clean
+ tests/Tests.hs view
@@ -0,0 +1,150 @@+module Main where++-- Friends+import Network.IRC++-- Libraries+import Control.Applicative+import Control.Monad+import System.Random+import Test.QuickCheck+import Test.HUnit+++instance Applicative Gen where+ (<*>) = ap+ pure = return++-- ---------------------------------------------------------+-- Helpful Wrappers++-- An identifier starts with a letter, and consists of interspersed numbers+-- and special characters+newtype Identifier = Identifier { unIdentifier :: String }+ deriving (Read,Show,Eq)++instance Arbitrary Identifier where+ coarbitrary = undefined+ arbitrary = do+ l <- letter+ ls <- sized $ \n -> loop n+ return $ Identifier (l:ls)+ where loop n | n <= 0 = return []+ | otherwise = do i <- identifier+ is <- loop (n-1)+ return (i:is)++-- A hostname is a string that starts and ends with an identifier, and has+-- periods peppered in the middle.+newtype Host = Host { unHost :: String }++instance Arbitrary Host where+ coarbitrary = undefined+ arbitrary = do+ l <- identifier+ ls <- sized $ \n -> loop n+ js <- sized $ \n -> loop n+ e <- identifier+ return $ Host (l:ls ++ ('.':js) ++ [e])+ where loop n | n <= 0 = return []+ | otherwise = do i <- host+ is <- loop (n-1)+ return (i:is)+++letter :: Gen Char+letter = frequency+ [ (50, choose ('a','z'))+ , (50, choose ('A','Z'))+ ]++digit :: Gen Char+digit = choose ('0','9')++special :: Gen Char+special = elements ['_','-']++identifier :: Gen Char+identifier = frequency+ [ (50, letter)+ , (30, digit)+ , (10, special)+ ]++host :: Gen Char+host = frequency+ [ (90, identifier)+ , (20, return '.')+ ]++-- ---------------------------------------------------------+-- IRC Types++newtype Cmd = Cmd { unCmd :: String }+ deriving (Read,Show,Eq)++instance Arbitrary Cmd where+ arbitrary =+ let c = (replyTable !!) <$> choose (0, length replyTable - 1)+ in Cmd . fst <$> c+ coarbitrary = undefined+++instance Arbitrary Prefix where+ arbitrary = oneof+ [ do name <- unIdentifier <$> arbitrary+ user <- (liftM unIdentifier) <$> arbitrary+ host <- (liftM unIdentifier) <$> arbitrary+ return $ NickName name user host+ , do host <- unHost <$> arbitrary+ return $ Server host+ ]+ coarbitrary = undefined+++instance Arbitrary Message where+ arbitrary =+ let params = map unIdentifier <$> sized vector+ cmd = unCmd <$> arbitrary+ in Message <$> arbitrary <*> cmd <*> params+ coarbitrary = undefined+++-- ---------------------------------------------------------+-- Properties++prop_ircId :: Message -> Bool+prop_ircId msg = (decode . (++ "\r\n") . encode $ msg) == Just msg+++-- ---------------------------------------------------------+-- Unit Tests++tests :: Test+tests = TestList $ map TestCase+ -- Initial colon encoding tests+ [ encode (Message Nothing "PRIVMSG" ["#foo", ":bar bas"]) @?=+ "PRIVMSG #foo ::bar bas"+ , encode (Message Nothing "PRIVMSG" ["#foo", ":bar"]) @?=+ "PRIVMSG #foo :bar"++ -- Corrected case+ , decode ":talon.nl.eu.SwiftIRC.net 332 foo #bar :\n" @?=+ Just (Message (Just $ Server "talon.nl.eu.SwiftIRC.net")+ "332" ["foo","#bar",""])+ ]+++-- ---------------------------------------------------------+-- Test Running++header :: String -> IO ()+header s = putStrLn "" >> putStrLn s >> putStrLn (replicate 60 '*')++main :: IO Counts+main = do+ header "Checking irc encode/decode identity"+ quickCheck prop_ircId++ header "Checking individual test cases"+ runTestTT tests