{-# LANGUAGE OverloadedStrings #-} -- | This module provides a bridge between the low-level text protocol that -- IRC uses and the high-level events in the "Irc.Model" module. module Irc.Core ( MsgFromServer(..) , IrcError(..) , ircMsgToServerMsg ) where import Control.Lens (over, _2) import Data.ByteString (ByteString) import Data.Time import Data.Time.Clock.POSIX import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as B8 import Irc.Format -- | 'MsgFromServer' provides a typed view of the various IRC protocol messages. -- There are more messages defined for IRC (and many of those overlap) than -- are in common use. Please report a bug if a common message is missing -- from this type. data MsgFromServer -- 001-099 Client-server connection messages = RplWelcome ByteString -- ^ 001 "Welcome to the Internet Relay Network \!\\@\" | RplYourHost ByteString -- ^ 002 "Your host is \, running version \" | RplCreated ByteString -- ^ 003 "This server was created \" | RplMyInfo ByteString ByteString [ByteString] -- ^ 004 servername version *(modes) | RplISupport [(ByteString,ByteString)] -- ^ 005 *(KEY=VALUE) | RplSnoMask ByteString -- ^ 008 snomask | RplYourId ByteString -- ^ 042 unique-id -- 200-399 Command responses | RplStatsLinkInfo [ByteString] -- ^ 211 arguments | RplStatsCommands [ByteString] -- ^ 212 arguments | RplStatsCLine [ByteString] -- ^ 213 arguments | RplStatsNLine [ByteString] -- ^ 214 arguments | RplStatsILine [ByteString] -- ^ 215 arguments | RplStatsKLine [ByteString] -- ^ 216 arguments | RplStatsQLine [ByteString] -- ^ 217 arguments | RplStatsYLine [ByteString] -- ^ 218 arguments | RplEndOfStats Char -- ^ 219 mode | RplStatsPLine [ByteString] -- ^ 220 arguments | RplUmodeIs ByteString [ByteString] -- ^ 221 modes *(params) | RplStatsDLine [ByteString] -- ^ 225 | RplStatsVLine [ByteString] -- ^ 240 | RplStatsLLine [ByteString] -- ^ 241 | RplStatsUptime ByteString -- ^ 242 | RplStatsOLine [ByteString] -- ^ 243 | RplStatsHLine [ByteString] -- ^ 244 | RplStatsSLine [ByteString] -- ^ 245 | RplStatsPing [ByteString] -- ^ 246 | RplStatsXLine [ByteString] -- ^ 247 | RplStatsULine [ByteString] -- ^ 248 | RplStatsDebug [ByteString] -- ^ 249 | RplStatsConn ByteString -- ^ 250 connection | RplLuserClient ByteString -- ^ 251 "There are \ users and \ services on \ servers" | RplLuserOp ByteString -- ^ 252 number-of-ops | RplLuserUnknown ByteString -- ^ 253 number-of-unknown | RplLuserChannels ByteString -- ^ 254 number-of-channels | RplLuserMe ByteString -- ^ 255 "I have \ clients and \ servers" | RplLuserAdminMe ByteString -- ^ 256 server | RplLuserAdminLoc1 ByteString -- ^ 257 admin-info-1 | RplLuserAdminLoc2 ByteString -- ^ 258 admin-info-2 | RplLuserAdminEmail ByteString -- ^ 259 admin-email | RplLoadTooHigh ByteString -- ^ 263 command | RplLocalUsers [ByteString] -- ^ 265 [local] [max] txt | RplGlobalUsers [ByteString] -- ^ 266 [global] [max] txt | RplPrivs ByteString -- ^ 270 privstring | RplWhoisCertFp Identifier ByteString -- ^ 276 nick txt | RplAcceptList Identifier -- ^ 281 | RplEndOfAccept -- ^ 282 | RplAway Identifier ByteString -- ^ 301 nick away_message | RplUserHost [ByteString] -- ^ 302 *(user hosts) | RplIsOn [Identifier] -- ^ 303 *(nick) | RplSyntax ByteString -- ^ (inspircd) 304 text | RplUnAway -- ^ 305 | RplNowAway -- ^ 306 | RplWhoisUser Identifier ByteString ByteString ByteString -- ^ 311 nick user host realname | RplWhoisServer Identifier ByteString ByteString -- ^ 312 nick server serverinfo | RplWhoisOperator Identifier ByteString -- ^ 313 nick "is an IRC operator" | RplWhoWasUser Identifier ByteString ByteString ByteString -- ^ 314 nick user host realname | RplEndOfWho Identifier -- ^ 315 channel | RplWhoisIdle Identifier Integer (Maybe UTCTime) -- ^ 317 nick idle signon | RplEndOfWhois Identifier -- ^ 318 nick | RplWhoisChannels Identifier ByteString -- ^ 319 nick channels | RplListStart -- ^ 321 | RplList Identifier Integer ByteString -- ^ 322 channel usercount topic | RplListEnd -- ^ 323 | RplChannelModeIs Identifier ByteString [ByteString] -- ^ 324 channel modes *(params) | RplNoTopicSet Identifier -- ^ 331 channel | RplTopic Identifier ByteString -- ^ 332 channel topic | RplChannelUrl Identifier ByteString -- ^ 328 channel url | RplCreationTime Identifier UTCTime -- ^ 329 channel timestamp | RplWhoisAccount Identifier ByteString -- ^ 330 nick account | RplTopicWhoTime Identifier ByteString UTCTime -- ^ 333 channel nickname timestamp | RplInviting Identifier Identifier -- ^ 341 nick channel | RplInviteList Identifier ByteString ByteString UTCTime -- ^ 346 channel mask who timestamp | RplEndOfInviteList Identifier -- ^ 347 channel | RplExceptionList Identifier ByteString ByteString UTCTime -- ^ 348 channel mask who timestamp | RplEndOfExceptionList Identifier -- ^ 349 channel | RplVersion [ByteString] -- ^ 351 version server comments | RplWhoReply Identifier ByteString ByteString ByteString Identifier ByteString ByteString -- ^ 352 channel user host server nick flags txt | RplNameReply ChannelType Identifier [ByteString] -- ^ 353 channeltype channel names | RplLinks ByteString ByteString ByteString -- ^ 364 mask server info | RplEndOfLinks ByteString -- ^ 365 mask | RplEndOfNames Identifier -- ^ 366 channel | RplBanList Identifier ByteString ByteString UTCTime -- ^ 367 channel banned banner timestamp | RplEndOfBanList Identifier -- ^ 368 channel | RplEndOfWhoWas Identifier -- ^ 369 nick | RplMotd ByteString -- ^ 372 line-of-motd | RplMotdStart -- ^ 375 | RplEndOfMotd -- ^ 376 | RplTime ByteString ByteString -- ^ 391 server "\" | RplInfo ByteString -- ^ 371 info | RplEndOfInfo -- ^ 374 | RplWhoisHost Identifier ByteString -- ^ 378 nick host | RplWhoisModes Identifier ByteString [ByteString] -- ^ 379 nick modes *(args) | RplYoureOper ByteString -- ^ 381 text | RplHostHidden ByteString -- ^ 396 hostname | Err Identifier IrcError -- Random high-numbered stuff | RplWhoisSecure Identifier -- ^ 671 nick | RplHelpStart ByteString ByteString -- ^ 704 topic text | RplHelp ByteString ByteString -- ^ 705 topic text | RplEndOfHelp ByteString -- ^ 706 topic text | RplKnock Identifier UserInfo -- ^ 710 channel | RplKnockDelivered Identifier -- ^ 711 channel | RplTargNotify Identifier -- ^ 717 nick | RplUmodeGMsg Identifier ByteString -- ^ 718 nick mask | RplQuietList Identifier Char ByteString ByteString UTCTime -- ^ 728 channel mode mask who timestamp | RplEndOfQuietList Identifier Char -- ^ 729 channel mode -- SASL stuff | RplLoggedIn ByteString -- ^ 900 account | RplLoggedOut -- ^ 901 | RplNickLocked -- ^ 902 | RplSaslSuccess -- ^ 903 | RplSaslFail -- ^ 904 | RplSaslTooLong -- ^ 905 | RplSaslAborted -- ^ 906 | RplSaslAlready -- ^ 907 | RplSaslMechs ByteString -- ^ 908 comma-sep-mechs | Away UserInfo (Maybe ByteString) | Ping ByteString | Pong ByteString (Maybe ByteString) | Notice UserInfo Identifier ByteString | Topic UserInfo Identifier ByteString | PrivMsg UserInfo Identifier ByteString | ExtJoin UserInfo Identifier (Maybe ByteString) ByteString | Join UserInfo Identifier | Nick UserInfo Identifier | Mode UserInfo Identifier [ByteString] | Quit UserInfo ByteString | Cap ByteString ByteString | Kick UserInfo Identifier Identifier ByteString | Part UserInfo Identifier ByteString | Invite UserInfo Identifier | Error ByteString | Authenticate ByteString | Account UserInfo (Maybe ByteString) deriving (Read, Show) data IrcError -- 400-499 Errors = ErrNoSuchNick -- ^ 401 | ErrNoSuchServer ByteString -- ^ 402 server | ErrNoSuchChannel -- ^ 403 | ErrCannotSendToChan -- ^ 404 | ErrTooManyChannels -- ^ 405 | ErrWasNoSuchNick -- ^ 406 | ErrTooManyTargets -- ^ 407 | ErrNoOrigin -- ^ 409 | ErrNoRecipient -- ^ 411 | ErrNoTextToSend -- ^ 412 | ErrUnknownCommand ByteString -- ^ 421 command | ErrNoMotd -- ^ 422 | ErrNoAdminInfo ByteString -- ^ 423 server | ErrNoNicknameGiven -- ^ 431 | ErrErroneousNickname ByteString -- ^ 432 badnick | ErrNicknameInUse Identifier -- ^ 433 nick | ErrBanNickChange -- ^ 435 | ErrUnavailResource -- ^ 437 | ErrNickTooFast -- ^ 438 | ErrServicesDown -- ^ 440 | ErrUserNotInChannel Identifier -- ^ 441 nick | ErrNotOnChannel -- ^ 442 channel | ErrUserOnChannel Identifier -- ^ 443 nick | ErrNotRegistered -- ^ 451 | ErrAcceptFull -- ^ 456 | ErrAcceptExist -- ^ 457 | ErrAcceptNot -- ^ 458 | ErrNeedMoreParams ByteString -- ^ 461 command | ErrAlreadyRegistered -- ^ 462 | ErrNoPermForHost -- ^ 463 | ErrPasswordMismatch -- ^ 464 | ErrYoureBannedCreep -- ^ 465 | ErrLinkChannel Identifier -- ^ 470 dstchannel | ErrChannelFull -- ^ 471 channel | ErrUnknownMode Char -- ^ 472 mode | ErrInviteOnlyChan -- ^ 473 | ErrBannedFromChan -- ^ 474 | ErrBadChannelKey -- ^ 475 | ErrNeedReggedNick -- ^ 477 | ErrBanListFull Char -- ^ 478 mode | ErrBadChanName ByteString -- ^ 479 name | ErrThrottle -- ^ 480 | ErrNoPrivileges -- ^ 481 | ErrChanOpPrivsNeeded -- ^ 482 | ErrCantKillServer -- ^ 483 | ErrIsChanService Identifier -- ^ 484 nick | ErrNoNonReg -- ^ 486 | ErrVoiceNeeded -- ^ 489 | ErrNoOperHost -- ^ 491 | ErrOwnMode -- ^ 494 | ErrUnknownUmodeFlag Char -- ^ 501 mode | ErrUsersDontMatch -- ^ 502 | ErrHelpNotFound ByteString -- ^ 524 topic | ErrTooManyKnocks -- ^ 713 | ErrChanOpen -- ^ 713 | ErrKnockOnChan -- ^ 714 | ErrTargUmodeG -- ^ 716 | ErrNoPrivs ByteString -- ^ 723 priv | ErrMlockRestricted Char ByteString -- ^ 742 mode setting deriving (Read, Show) data ChannelType = SecretChannel | PrivateChannel | PublicChannel deriving (Read, Show) ircMsgToServerMsg :: RawIrcMsg -> Maybe MsgFromServer ircMsgToServerMsg ircmsg = case (msgCommand ircmsg, msgParams ircmsg) of ("001",[_,txt]) -> Just (RplWelcome txt) ("002",[_,txt]) -> Just (RplYourHost txt) ("003",[_,txt]) -> Just (RplCreated txt) ("004", _:host:version:modes) -> Just (RplMyInfo host version modes) ("005",_:params) | not (null params) -> let parse1 = over _2 (B.drop 1) . B8.break (=='=') in Just (RplISupport (map parse1 (init params))) ("008",[_,snomask,_]) -> Just (RplSnoMask (B.tail snomask)) ("042",[_,yourid,_]) -> Just (RplYourId yourid) ("211", _:linkinfo) -> Just (RplStatsLinkInfo linkinfo) ("212", _:commands) -> Just (RplStatsCommands commands) ("213", _:cline ) -> Just (RplStatsCLine cline) ("214", _:nline ) -> Just (RplStatsNLine nline) ("215", _:iline ) -> Just (RplStatsILine iline) ("216", _:kline ) -> Just (RplStatsKLine kline) ("217", _:qline ) -> Just (RplStatsQLine qline) ("218", _:yline ) -> Just (RplStatsYLine yline) ("219",[_,mode,_] ) -> Just (RplEndOfStats (B8.head mode)) ("220", _:pline ) -> Just (RplStatsPLine pline) ("221", _:mode:params) -> Just (RplUmodeIs mode params) ("225", _:dline ) -> Just (RplStatsDLine dline) ("240", _:vline ) -> Just (RplStatsVLine vline) ("241", _:lline ) -> Just (RplStatsLLine lline) ("242", [_,uptime]) -> Just (RplStatsUptime uptime) ("243", _:oline ) -> Just (RplStatsOLine oline) ("244", _:hline ) -> Just (RplStatsHLine hline) ("245", _:sline ) -> Just (RplStatsSLine sline) ("246", _:ping ) -> Just (RplStatsPing ping ) ("247", _:xline ) -> Just (RplStatsXLine xline) ("248", _:uline ) -> Just (RplStatsULine uline) ("249", _:debug ) -> Just (RplStatsDebug debug) ("250",[_,stats]) -> Just (RplStatsConn stats) ("251",[_,stats]) -> Just (RplLuserClient stats) ("252",[_,num,_]) -> Just (RplLuserOp num) ("253",[_,num,_]) -> Just (RplLuserUnknown num) ("254",[_,num,_]) -> Just (RplLuserChannels num) ("255",[_,txt]) -> Just (RplLuserMe txt) ("256",[_,server]) -> Just (RplLuserAdminMe server) ("257",[_,txt]) -> Just (RplLuserAdminLoc1 txt) ("258",[_,txt]) -> Just (RplLuserAdminLoc2 txt) ("259",[_,txt]) -> Just (RplLuserAdminEmail txt) ("263",[_,cmd,_]) -> Just (RplLoadTooHigh cmd) ("265", _:params) -> Just (RplLocalUsers params) ("266", _:params ) -> Just (RplGlobalUsers params) ("270",[_,txt]) -> Just (RplPrivs txt) ("276",[_,nick,txt]) -> Just (RplWhoisCertFp (mkId nick) txt) ("281",[_,nick]) -> Just (RplAcceptList (mkId nick)) ("282",[_,_]) -> Just RplEndOfAccept ("301",[_,nick,message]) -> Just (RplAway (mkId nick) message) ("302",[_,txt]) -> Just (RplUserHost (filter (not . B.null) (B8.split ' ' txt))) ("303",[_,txt]) -> Just (RplIsOn (map mkId (filter (not . B.null) (B8.split ' ' txt)))) ("304",[_,txt]) -> Just (RplSyntax txt) ("305",[_,_]) -> Just RplUnAway ("306",[_,_]) -> Just RplNowAway ("311",[_,nick,user,host,_star,txt]) -> Just (RplWhoisUser (mkId nick) user host txt) ("312",[_,nick,server,txt]) -> Just (RplWhoisServer (mkId nick) server txt) ("314",[_,nick,user,host,_star,txt]) -> Just (RplWhoWasUser (mkId nick) user host txt) ("319",[_,nick,txt]) -> Just (RplWhoisChannels (mkId nick) txt) ("313",[_,nick,txt]) -> Just (RplWhoisOperator (mkId nick) txt) ("315",[_,chan,_]) -> Just (RplEndOfWho (mkId chan)) ("317",[_,nick,idle,signon,_txt]) -> Just (RplWhoisIdle (mkId nick) (asNumber idle) (Just (asTimeStamp signon))) ("317",[_,nick,idle,_txt]) -> Just (RplWhoisIdle (mkId nick) (asNumber idle) Nothing) ("318",[_,nick,_txt]) -> Just (RplEndOfWhois (mkId nick)) ("321",[_,_,_]) -> Just RplListStart ("322",[_,chan,num,topic]) -> Just (RplList (mkId chan) (asNumber num) topic) ("323",[_,_]) -> Just RplListEnd ("324",_:chan:modes:params) -> Just (RplChannelModeIs (mkId chan) modes params) ("328",[_,chan,url]) -> Just (RplChannelUrl (mkId chan) url) ("329",[_,chan,time]) -> Just (RplCreationTime (mkId chan) (asTimeStamp time)) ("330",[_,nick,account,_txt]) -> Just (RplWhoisAccount (mkId nick) account) ("331",[_,chan,_]) -> Just (RplNoTopicSet (mkId chan)) ("332",[_,chan,txt]) -> Just (RplTopic (mkId chan) txt) ("333",[_,chan,who,time]) -> Just (RplTopicWhoTime (mkId chan) who (asTimeStamp time)) ("341",[_,nick,chan,_]) -> Just (RplInviting (mkId nick) (mkId chan)) ("346",[_,chan,mask,who,time]) -> Just (RplInviteList (mkId chan) mask who (asTimeStamp time)) ("347",[_,chan,_txt]) -> Just (RplEndOfInviteList (mkId chan)) ("348",[_,chan,mask,who,time]) -> Just (RplExceptionList (mkId chan) mask who (asTimeStamp time)) ("349",[_,chan,_txt]) -> Just (RplEndOfExceptionList (mkId chan)) ("351", _:version) -> Just (RplVersion version) ("352",[_,chan,user,host,server,nick,flags,txt]) -> Just (RplWhoReply (mkId chan) user host server (mkId nick) flags txt) -- trailing is: ("353",[_,ty,chan,txt]) -> do ty' <- case ty of "=" -> Just PublicChannel "*" -> Just PrivateChannel "@" -> Just SecretChannel _ -> Nothing Just (RplNameReply ty' (mkId chan) (filter (not . B.null) (B8.split ' ' txt))) ("364",[_,mask,server,info]) -> Just (RplLinks mask server info) ("365",[_,mask,_] ) -> Just (RplEndOfLinks mask) ("366",[_,chan,_]) -> Just (RplEndOfNames (mkId chan)) ("367",[_,chan,banned,banner,time]) -> Just (RplBanList (mkId chan) banned banner (asTimeStamp time)) ("368",[_,chan,_txt]) -> Just (RplEndOfBanList (mkId chan)) ("369",[_,nick,_]) -> Just (RplEndOfWhoWas (mkId nick)) ("371",[_,txt]) -> Just (RplInfo txt) ("374",[_,_]) -> Just RplEndOfInfo ("375",[_,_]) -> Just RplMotdStart ("372",[_,txt]) -> Just (RplMotd txt) ("376",[_,_]) -> Just RplEndOfMotd ("379",_:nick:modes:args) -> Just (RplWhoisModes (mkId nick) modes args) ("378",[_,nick,txt]) -> Just (RplWhoisHost (mkId nick) txt) ("381",[_,txt]) -> Just (RplYoureOper txt) ("391",[_,server,txt]) -> Just (RplTime server txt) ("396",[_,host,_]) -> Just (RplHostHidden host) ("401",[_,nick,_]) -> Just (Err (mkId nick) ErrNoSuchNick) ("402",[_,server,_]) -> Just (Err "" (ErrNoSuchServer server)) ("403",[_,channel,_]) -> Just (Err (mkId channel) ErrNoSuchChannel) ("404",[_,channel,_]) -> Just (Err (mkId channel) ErrCannotSendToChan) ("405",[_,channel,_]) -> Just (Err (mkId channel) ErrTooManyChannels) ("406",[_,nick,_]) -> Just (Err (mkId nick) ErrWasNoSuchNick) ("407",[_,target,_]) -> Just (Err (mkId target) ErrTooManyTargets) ("409",[_,_]) -> Just (Err "" ErrNoOrigin) ("411",[_,_]) -> Just (Err "" ErrNoRecipient) ("412",[_,_]) -> Just (Err "" ErrNoTextToSend) ("421",[_,cmd,_]) -> Just (Err "" (ErrUnknownCommand cmd)) ("422",[_,_]) -> Just (Err "" ErrNoMotd) ("423",[_,server,_]) -> Just (Err "" (ErrNoAdminInfo server)) ("431",[_,_]) -> Just (Err "" ErrNoNicknameGiven) ("432",[_,nick,_]) -> Just (Err "" (ErrErroneousNickname nick)) ("433",[_,nick,_]) -> Just (Err "" (ErrNicknameInUse (mkId nick))) ("435",[_,chan,_]) -> Just (Err (mkId chan) ErrBanNickChange) ("437",[_,ident,_]) -> Just (Err (mkId ident) ErrUnavailResource) ("438",[_,_,_,_]) -> Just (Err "" ErrNickTooFast) ("441",[_,nick,_]) -> Just (Err (mkId nick) ErrServicesDown) ("441",[_,nick,chan,_]) -> Just (Err (mkId chan) (ErrUserNotInChannel (mkId nick))) ("442",[_,chan,_]) -> Just (Err (mkId chan) ErrNotOnChannel) ("443",[_,nick,chan,_]) -> Just (Err (mkId chan) (ErrUserOnChannel (mkId nick))) ("451",[_,_]) -> Just (Err "" ErrNotRegistered) ("456",[_,_]) -> Just (Err "" ErrAcceptFull) ("457",[_,nick,_]) -> Just (Err (mkId nick) ErrAcceptExist) ("458",[_,nick,_]) -> Just (Err (mkId nick) ErrAcceptNot) ("461",[_,cmd,_]) -> Just (Err "" (ErrNeedMoreParams cmd)) ("462",[_,_]) -> Just (Err "" ErrAlreadyRegistered) ("463",[_,_]) -> Just (Err "" ErrNoPermForHost) ("464",[_,_]) -> Just (Err "" ErrPasswordMismatch) ("465",[_,_]) -> Just (Err "" ErrYoureBannedCreep) ("470",[_,chan1,chan2,_]) -> Just (Err (mkId chan1) (ErrLinkChannel (mkId chan2))) ("471",[_,chan,_]) -> Just (Err (mkId chan) ErrChannelFull) ("472",[_,mode,_]) -> Just (Err "" (ErrUnknownMode (B8.head mode))) ("473",[_,chan,_]) -> Just (Err (mkId chan) ErrInviteOnlyChan) ("474",[_,chan,_]) -> Just (Err (mkId chan) ErrBannedFromChan) ("475",[_,chan,_]) -> Just (Err (mkId chan) ErrBadChannelKey) ("477",[_,chan,_]) -> Just (Err (mkId chan) ErrNeedReggedNick) ("478",[_,chan,mode,_]) -> Just (Err (mkId chan) (ErrBanListFull (B8.head mode))) ("479",[_,chan,_]) -> Just (Err "" (ErrBadChanName chan)) ("480",[_,chan,_]) -> Just (Err (mkId chan) ErrThrottle) ("481",[_,_]) -> Just (Err "" ErrNoPrivileges) ("482",[_,chan,_]) -> Just (Err (mkId chan) ErrChanOpPrivsNeeded) ("483",[_,_]) -> Just (Err "" ErrCantKillServer) ("484",[_,nick,chan,_]) -> Just (Err (mkId chan) (ErrIsChanService (mkId nick))) ("486",[_,nick,_]) -> Just (Err (mkId nick) ErrNoNonReg) ("489",[_,chan,_]) -> Just (Err (mkId chan) ErrVoiceNeeded) ("491",[_,_]) -> Just (Err "" ErrNoOperHost) ("494",[_,nick,_]) -> Just (Err (mkId nick) ErrOwnMode) ("501",[_,mode,_]) -> Just (Err "" (ErrUnknownUmodeFlag (B8.head mode))) ("502",[_,_]) -> Just (Err "" ErrUsersDontMatch) ("524",[_,topic,_]) -> Just (Err "" (ErrHelpNotFound topic)) ("671",[_,nick,_]) -> Just (RplWhoisSecure (mkId nick)) ("704",[_,topic,txt]) -> Just (RplHelpStart topic txt) ("705",[_,topic,txt]) -> Just (RplHelp topic txt) ("706",[_,topic,_]) -> Just (RplEndOfHelp topic) ("710",[_,chan,who,_]) -> Just (RplKnock (mkId chan) (parseUserInfo who)) ("711",[_,chan,_]) -> Just (RplKnockDelivered (mkId chan)) ("712",[_,chan,_]) -> Just (Err (mkId chan) ErrTooManyKnocks) ("713",[_,chan,_]) -> Just (Err (mkId chan) ErrChanOpen) ("714",[_,chan,_]) -> Just (Err (mkId chan) ErrKnockOnChan) ("716",[_,nick,_]) -> Just (Err (mkId nick) ErrTargUmodeG) ("723",[_,priv,_]) -> Just (Err "" (ErrNoPrivs priv)) ("717",[_,nick,_]) -> Just (RplTargNotify (mkId nick)) ("718",[_,nick,mask,_]) -> Just (RplUmodeGMsg (mkId nick) mask) ("728",[_,chan,mode,banned,banner,time]) -> Just (RplQuietList (mkId chan) (B8.head mode) banned banner (asTimeStamp time)) ("729",[_,chan,mode,_]) -> Just (RplEndOfQuietList (mkId chan) (B8.head mode)) ("742",[_,chan,mode,setting,_]) -> Just (Err (mkId chan) (ErrMlockRestricted (B8.head mode) setting)) ("900",[_,_,account,_]) -> Just (RplLoggedIn account) ("901",[_,_,_]) -> Just RplLoggedOut ("902",[_,_]) -> Just RplNickLocked ("903",[_,_]) -> Just RplSaslSuccess ("904",[_,_]) -> Just RplSaslFail ("905",[_,_]) -> Just RplSaslTooLong ("906",[_,_]) -> Just RplSaslAborted ("907",[_,_]) -> Just RplSaslAlready ("908",[_,mechs,_]) -> Just (RplSaslMechs mechs) ("PING",[txt]) -> Just (Ping txt) ("PONG",[server ]) -> Just (Pong server Nothing) ("PONG",[server,txt]) -> Just (Pong server (Just txt)) ("PRIVMSG",[dst,txt]) -> do src <- msgPrefix ircmsg Just (PrivMsg src (mkId dst) txt) ("NOTICE",[dst,txt]) -> do src <- msgPrefix ircmsg Just (Notice src (mkId dst) txt) ("TOPIC",[chan,txt]) -> do who <- msgPrefix ircmsg Just (Topic who (mkId chan) txt) ("JOIN",[chan,account,real]) -> do who <- msgPrefix ircmsg Just (ExtJoin who (mkId chan) (if account == "*" then Nothing else Just account) real) ("JOIN",[chan]) -> do who <- msgPrefix ircmsg Just (Join who (mkId chan)) ("NICK",[newnick]) -> do who <- msgPrefix ircmsg Just (Nick who (mkId newnick)) ("MODE",tgt:modes) -> do who <- msgPrefix ircmsg Just (Mode who (mkId tgt) modes) ("PART",[chan]) -> do who <- msgPrefix ircmsg Just (Part who (mkId chan) "") ("PART",[chan,txt]) -> do who <- msgPrefix ircmsg Just (Part who (mkId chan) txt) ("AWAY",[txt]) -> do who <- msgPrefix ircmsg Just (Away who (Just txt)) ("AWAY",[]) -> do who <- msgPrefix ircmsg Just (Away who Nothing) ("QUIT",[txt]) -> do who <- msgPrefix ircmsg Just (Quit who txt) ("KICK",[chan,tgt,txt]) -> do who <- msgPrefix ircmsg Just (Kick who (mkId chan) (mkId tgt) txt) ("INVITE",[_,chan]) -> do who <- msgPrefix ircmsg Just (Invite who (mkId chan)) ("CAP",[_,cmd,txt]) -> Just (Cap cmd txt) ("ERROR",[txt]) -> Just (Error txt) ("AUTHENTICATE",[txt]) -> Just (Authenticate txt) ("ACCOUNT",[acct]) -> do who <- msgPrefix ircmsg Just (Account who (if acct == "*" then Nothing else Just acct)) _ -> Nothing asTimeStamp :: ByteString -> UTCTime asTimeStamp = posixSecondsToUTCTime . fromInteger . asNumber asNumber :: ByteString -> Integer asNumber b = case B8.readInteger b of Nothing -> 0 Just (x,_) -> x