-- | Messages for IRC Clients, implementing the current "living standard", to be -- found at . This module does not include the -- responses. See "Network.Yak.Response" for standard-compliant responses. {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE RankNTypes #-} module Network.Yak.Client ( -- * Connection Messages Authenticate, authenticateArgument, Pass, passPassword, Nick, nickNickname, User, userUsername, userMode, userUnused, userRealname, Oper, operName, operPassword, Quit, quitMessage, -- * Channel Operations Join, Join0, joinChannels, joinKeys, Part, partChannels, partMessage, Topic, topicChannel, topicMessage, Names, namesChannels, List, listChannels, listElistCond, -- * Server Queries and Commands Motd, motdTarget, Lusers, lusersParam, lusersMask, lusersTarget, Version, versionTarget, Admin, adminTarget, Connect, connectTarget, connectConnInfo, Time, timeTarget, Stats, statsQuery, statsTarget, Info, infoTarget, Mode, modeTarget, modeSetter, modeChannel, modeNick, modeString, -- * Sending Messages Privmsg, privmsgTargets, privmsgMessage, privmsgChannel, privmsgNick, Notice, noticeTargets, noticeMessage, noticeChannel, noticeNick, -- * User-based queries Who, whoMask, whoFlag, WhoIs, whoIsTarget, whoIsMasks, WhoWas, whoWasNicks, whoWasParam, whoWasCount, whoWasTarget, -- * Optional Messages Userhost, userhostNick1, userhostNick2, userhostNick3, userhostNick4, userhostNick5, -- * Miscellaneous Messages Ping, pingServer1, pingServer2, Pong, pongServer1, pongServer2, Kill, killNick, killMessage, -- * Extras -- | Common messages that are not specified out in the document above. Kick, kickChannels, kickNicknames, kickMessage, Invite, inviteNickname, inviteChannel, -- * Common Accessors HasChannel(..), HasNick(..), HasHostname(..) ) where import Control.Lens import Data.ByteString.Char8 (ByteString) import Data.List.NonEmpty (NonEmpty) import Data.Text (Text) import Data.Word (Word) import Network.Yak.TH import Network.Yak.Types import Network.Yak.Modes (ServerModes, ModeStr, fetchModeStr) -- Connection Messages -- | > AUTHENTICATE type Authenticate = Msg "AUTHENTICATE" '[Text] makeMsgLenses ''Authenticate ["argument"] -- | > PASS type Pass = Msg "PASS" '[Text] makeMsgLenses ''Pass ["password"] -- | > NICK type Nick = Msg "NICK" '[Nickname] makeMsgLenses ''Nick ["nickname"] -- | > USER 0 * type User = Msg "USER" '[Username, Word, Unused "*", Message] makeMsgLenses ''User ["username", "mode", "unused", "realname"] -- | > OPER type Oper = Msg "OPER" '[Nickname, Text] makeMsgLenses ''Oper ["name", "password"] -- | > QUIT [] type Quit = Msg "QUIT" '[Message] makeMsgLenses ''Quit ["message"] -- Channel Operations -- | > JOIN {,} [{,}] type Join = Msg "JOIN" '[NonEmpty Channel, [Text]] type Join0 = Msg "JOIN" '[Unused "0"] makeMsgLenses ''Join ["channels", "keys"] -- | > PART {,} [] type Part = Msg "PART" '[NonEmpty Channel, Maybe Message] makeMsgLenses ''Part ["channels", "message"] -- | > TOPIC [] type Topic = Msg "TOPIC" '[Channel, Maybe Message] makeMsgLenses ''Topic ["channel", "message"] -- | > NAMES [{,}] type Names = Msg "NAMES" '[[Channel]] makeMsgLenses ''Names ["channels"] -- | > LIST [{,}] [{,}] type List = Msg "LIST" '[[Channel], Maybe Text] makeMsgLenses ''List ["channels", "elistCond"] -- Server Queries and Commands -- | > MOTD [] type Motd = Msg "MOTD" '[Hostname] makeMsgLenses ''Motd ["target"] -- | > LUSERS [ []] type Lusers = Msg "LUSERS" '[Maybe (Mask, Maybe Hostname)] makeMsgLenses ''Lusers ["param"] lusersMask :: Traversal' Lusers Mask lusersMask = lusersParam . _Just . _1 lusersTarget :: Traversal' Lusers Hostname lusersTarget = lusersParam . _Just . _2 . _Just -- | > VERSION [] type Version = Msg "VERSION" '[Maybe Hostname] makeMsgLenses ''Version ["target"] -- | > ADMIN [] type Admin = Msg "ADMIN" '[Maybe Hostname] makeMsgLenses ''Admin ["target"] -- | > CONNECT [ []] type Connect = Msg "CONNECT" '[Hostname, Maybe (Int, Maybe Hostname)] makeMsgLenses ''Connect ["target", "connInfo"] -- | > TIME [] type Time = Msg "TIME" '[Maybe Hostname] makeMsgLenses ''Time ["target"] -- | > STATS [] type Stats = Msg "STATS" '[Char, Maybe Hostname] makeMsgLenses ''Stats ["query", "target"] -- | > INFO [] type Info = Msg "INFO" '[Maybe Hostname] makeMsgLenses ''Info ["target"] -- | > MODE [ [...]] type Mode = Msg "MODE" '[Either Channel Nickname, Maybe ByteString] makeMsgLenses ''Mode ["target", "setter"] modeChannel :: Traversal' Mode Channel modeChannel = modeTarget . _Left modeNick :: Traversal' Mode Nickname modeNick = modeTarget . _Right modeString :: ServerModes -> Fold Mode ModeStr modeString m = modeSetter . _Just . to (fetchModeStr m) . _Just -- Sending Messages -- | > PRIVMSG {,} type Privmsg = Msg "PRIVMSG" '[NonEmpty (Either Channel Nickname), Message] makeMsgLenses ''Privmsg ["targets", "message"] privmsgChannel :: Traversal' Privmsg Channel privmsgChannel = privmsgTargets . traverse . _Left privmsgNick :: Traversal' Privmsg Nickname privmsgNick = privmsgTargets . traverse . _Right -- | > NOTICE {,} type Notice = Msg "NOTICE" '[NonEmpty (Either Channel Nickname), Message] makeMsgLenses ''Notice ["targets", "message"] noticeChannel :: Traversal' Notice Channel noticeChannel = noticeTargets . traverse . _Left noticeNick :: Traversal' Notice Nickname noticeNick = noticeTargets . traverse . _Right -- User based queries -- | > WHO [] [o] type Who = Msg "WHO" '[Maybe Mask, Flag "o"] makeMsgLenses ''Who ["mask", "flag"] -- | > WHOIS [] {,} type WhoIs = Msg "WHOIS" '[Maybe Hostname, NonEmpty Mask] makeMsgLenses ''WhoIs ["target", "masks"] -- | > WHOWAS {,, []] type WhoWas = Msg "WHOWAS" '[NonEmpty Nickname, Maybe (Int, Maybe Hostname)] makeMsgLenses ''WhoWas ["nicks", "param"] whoWasCount :: Traversal' WhoWas Int whoWasCount = whoWasParam . _Just . _1 whoWasTarget :: Traversal' WhoWas Hostname whoWasTarget = whoWasParam . _Just . _2 . _Just -- Optional Messages -- | > USERHOST { } type Userhost = Msg "USERHOST" '[Nickname, Maybe Nickname, Maybe Nickname, Maybe Nickname, Maybe Nickname] makeMsgLenses ''Userhost ["nick1", "nick2", "nick3", "nick4", "nick5"] -- because more than 5 would be ridiculous, and obviously we need space -- separation in random places. Thank you, IRC. -- Miscellaneous Messages -- | > PING [] type Ping = Msg "PING" '[Hostname, Maybe Hostname] makeMsgLenses ''Ping ["server1", "server2"] -- | > PONG [] type Pong = Msg "PONG" '[Hostname, Maybe Hostname] makeMsgLenses ''Pong ["server1", "server2"] -- | > KILL type Kill = Msg "KILL" '[Nickname, Message] makeMsgLenses ''Kill ["nick", "message"] -- | > KICK (,)* (,)* [message] -- As defined in RFC 2812 type Kick = Msg "KICK" '[NonEmpty Channel, NonEmpty Nickname, Maybe Message] makeMsgLenses ''Kick ["channels", "nicknames", "message"] -- | > INVITE -- As defined in RFC 2812 type Invite = Msg "INVITE" '[Nickname, Channel] makeMsgLenses ''Invite ["nickname", "channel"] -- | Class for extracting the channel out of messages that may contain channels class HasChannel a where channel :: Traversal' a Channel instance HasChannel Join where channel = joinChannels . traverse instance HasChannel Part where channel = partChannels . traverse instance HasChannel Topic where channel = topicChannel instance HasChannel Names where channel = namesChannels . traverse instance HasChannel List where channel = listChannels . traverse instance HasChannel Privmsg where channel = privmsgChannel instance HasChannel Mode where channel = modeChannel instance HasChannel Notice where channel = noticeChannel instance HasChannel Kick where channel = kickChannels . traverse instance HasChannel Invite where channel = inviteChannel -- | Messages containing a nickname in one (unambigious) position. class HasNick a where nick :: Traversal' a Nickname instance HasNick Nick where nick = nickNickname instance HasNick Oper where nick = operName instance HasNick Mode where nick = modeNick instance HasNick Privmsg where nick = privmsgNick instance HasNick Notice where nick = noticeNick instance HasNick WhoWas where nick = whoWasNicks . traverse instance HasNick Kill where nick = killNick instance HasNick Kick where nick = kickNicknames . traverse instance HasNick Invite where nick = inviteNickname -- | Messages containing a hostname in one (unambigious) position class HasHostname a where hostname :: Traversal' a Hostname instance HasHostname Motd where hostname = motdTarget instance HasHostname Lusers where hostname = lusersTarget instance HasHostname Version where hostname = versionTarget . _Just instance HasHostname Admin where hostname = adminTarget . _Just instance HasHostname Time where hostname = timeTarget . _Just instance HasHostname Stats where hostname = statsTarget . _Just instance HasHostname Info where hostname = infoTarget . _Just instance HasHostname WhoIs where hostname = whoIsTarget . _Just instance HasHostname WhoWas where hostname = whoWasTarget