Lots of haddock comments

master
Levi Pearson 2014-03-04 00:31:46 -07:00
parent 91fcf5f78c
commit 45eb76c8af
4 changed files with 247 additions and 44 deletions

View File

@ -126,10 +126,7 @@ cmdHandler srv cid =
-- handle resulting events -- handle resulting events
aliveL <- liftIO $ forM events $ ircEventHandler srv aliveL <- liftIO $ forM events $ ircEventHandler srv
{- -- debug
sState <- liftIO $ readTVarIO $ srv ^. ircState
liftIO $ BS.putStrLn $ BS.pack (show sState)
-}
-- loop for the next command -- loop for the next command
when (and aliveL) $ handle h newReg when (and aliveL) $ handle h newReg

View File

@ -41,7 +41,10 @@ import Data.Set (delete, empty, fromList, insert,
import Pipes.IRC.Server.Types import Pipes.IRC.Server.Types
newChannel :: NickKey -> IrcChannel -- | Create a new 'IrcChannel' record with the given nickname as the
-- only member.
newChannel :: NickKey -- ^ the nickname of the channel creator
-> IrcChannel -- ^ the resulting new 'IrcChannel' record
newChannel creator = IrcChannel { _chanTopic = Nothing newChannel creator = IrcChannel { _chanTopic = Nothing
, _chanPass = Nothing , _chanPass = Nothing
, _chanModeFlags = empty , _chanModeFlags = empty
@ -51,62 +54,154 @@ newChannel creator = IrcChannel { _chanTopic = Nothing
, _chanInvites = empty , _chanInvites = empty
} }
chanAddModeFlag, chanDelModeFlag :: IrcChanModeFlags -> IrcChannel -> IrcChannel chanAddModeFlag, chanDelModeFlag :: IrcChanModeFlags
-- ^ channel mode flag to change
-> IrcChannel
-- ^ channel on which to change mode
-> IrcChannel
-- ^ resulting channel with mode change
-- | Add a mode flag to the channel's set of mode flags. See
-- 'IrcChanModeFlags' for the available modes.
chanAddModeFlag cm = chanModeFlags %~ insert cm chanAddModeFlag cm = chanModeFlags %~ insert cm
-- | Remove the mode flag from the channel's set of mode flags. See
-- 'IrcChanModeFlags' for the available modes.
chanDelModeFlag cm = chanModeFlags %~ delete cm chanDelModeFlag cm = chanModeFlags %~ delete cm
chanAddUser, chanDelUser :: NickKey -> IrcChannel -> IrcChannel chanAddUser, chanDelUser :: NickKey -- ^ user to add to channel
chanAddUser un = chanUsers %~ insert un -> IrcChannel -- ^ channel on which to add user
chanDelUser un = (chanUsers %~ delete un) -> IrcChannel -- ^ channel with user added
. (chanOpers %~ delete un)
. (chanVoices %~ delete un)
chanHasUser :: NickKey -> IrcChannel -> Bool -- | Add a user to the channel's list of users. This does not change
-- the set of set of channels on the user or perform any checking;
-- this just performs the low-level change to the channel.
chanAddUser un = chanUsers %~ insert un
-- | Delete a user from the channel's list of users. This does not
-- change the set of channels on the user or perform any checking;
-- this just performs the low-level change to the channel.
chanDelUser un = (chanUsers %~ delete un)
. (chanOpers %~ delete un)
. (chanVoices %~ delete un)
-- | Is the user owning the given nick on the channel? Returns 'True'
-- if the user is in fact on the channel.
chanHasUser :: NickKey -- ^ user to check presence of on the channel
-> IrcChannel -- ^ channel in which to look for the user
-> Bool -- ^ 'True' if the user is in the channel
chanHasUser un ch = member un (ch ^. chanUsers) chanHasUser un ch = member un (ch ^. chanUsers)
chanSetTopic :: ByteString -> IrcChannel -> IrcChannel -- | Set the topic of discussion in the channel. This does not do any
-- permission or size checking; it just performs the low-level action.
chanSetTopic :: ByteString -- ^ topic of discussion for the channel
-> IrcChannel -- ^ channel on which to set the topic
-> IrcChannel -- ^ channel with the topic set
chanSetTopic top = chanTopic .~ Just top chanSetTopic top = chanTopic .~ Just top
chanHasTopic :: IrcChannel -> Bool -- | Does the channel have a topic of discussion set? Returns 'True'
-- if the topic is set.
chanHasTopic :: IrcChannel -- ^ channel on which to look for a topic
-> Bool -- ^ 'True' if the channel has a topic
chanHasTopic ch = isJust $ ch ^. chanTopic chanHasTopic ch = isJust $ ch ^. chanTopic
chanHasModeFlag :: IrcChanModeFlags -> IrcChannel -> Bool -- | Does the channel have a specific mode flag set? Returns 'True'
-- if it has the specified flag set.
chanHasModeFlag :: IrcChanModeFlags -- ^ mode flag to check for
-> IrcChannel -- ^ channel on which to check
-> Bool -- ^ 'True' if the flag is set
chanHasModeFlag cm ch = member cm $ ch ^. chanModeFlags chanHasModeFlag cm ch = member cm $ ch ^. chanModeFlags
chanSigil :: IrcChannel -> ByteString -- | Find the mode sigil determined by what privacy modes it has
-- set, if any.
chanSigil :: IrcChannel -- ^ channel of which to find the sigil
-> ByteString -- ^ the sigil associated with the channel
chanSigil ch | chanHasModeFlag Secret ch = "@" chanSigil ch | chanHasModeFlag Secret ch = "@"
| chanHasModeFlag Private ch = "*" | chanHasModeFlag Private ch = "*"
| otherwise = "=" | otherwise = "="
chanUserSigil :: NickKey -> IrcChannel -> ByteString -- | Find the mode sigil determined by a user's status on a channel,
-- e.g. "@" for a channel op or "+" for a user with voice status.
chanUserSigil :: NickKey -- ^ nickname of user of which to find sigil
-> IrcChannel -- ^ channel the user may have status in
-> ByteString -- ^ the sigil associated with the user's status
chanUserSigil un ch | member un $ ch ^. chanOpers = "@" chanUserSigil un ch | member un $ ch ^. chanOpers = "@"
| member un $ ch ^. chanVoices = "+" | member un $ ch ^. chanVoices = "+"
| otherwise = "" | otherwise = ""
chanSetPass :: ByteString -> IrcChannel -> IrcChannel -- | Set a password key that must be given with a JOIN command in
-- order to join the channel. This does no permission or error
-- checking, it just performs the low-level operation.
chanSetPass :: PassKey -- ^ password key to set for a channel
-> IrcChannel -- ^ channel to set the password key on
-> IrcChannel -- ^ channel with the password set
chanSetPass pwd = chanPass .~ Just pwd chanSetPass pwd = chanPass .~ Just pwd
chanHasPass :: IrcChannel -> Bool -- | Does the channel have a password key set? Returns 'True' if the
-- channel does have a password key set.
chanHasPass :: IrcChannel -- ^ channel on which to look for password key
-> Bool -- ^ 'True' if there is a password key set
chanHasPass ch = isJust $ ch ^. chanPass chanHasPass ch = isJust $ ch ^. chanPass
chanCheckPass :: ByteString -> IrcChannel -> Bool -- | Determine whether the given password key should give access to
-- the channel. If it matches the set password or there is no
-- password, the response will be 'True'.
chanCheckPass :: ByteString -- ^ password to try against the channel
-> IrcChannel -- ^ channel against which to try the password
-> Bool -- ^ 'True' if access should be granted
chanCheckPass pwd ch = case ch ^. chanPass of chanCheckPass pwd ch = case ch ^. chanPass of
Just chPass -> pwd == chPass Just chPass -> pwd == chPass
Nothing -> True Nothing -> True
chanAddOper, chanDelOper :: NickKey -> IrcChannel -> IrcChannel chanAddOper, chanDelOper :: NickKey -- ^ nickname of user
-> IrcChannel -- ^ channel to change status on
-> IrcChannel -- ^ channel with status changed
-- | Add the given nickname as an operator on the channel. This does
-- not perform any permission or error checks, it just performs the
-- low-level operation.
chanAddOper un = chanOpers %~ insert un chanAddOper un = chanOpers %~ insert un
-- | Remove the given nickname as an operator on the channel. This
-- does not perform any permission or error checks, it just performs
-- the low-level operation.
chanDelOper un = chanOpers %~ delete un chanDelOper un = chanOpers %~ delete un
chanAddVoice, chanDelVoice :: NickKey -> IrcChannel -> IrcChannel chanAddVoice, chanDelVoice :: NickKey -- ^ nickname of user
-> IrcChannel -- ^ channel to change voice on
-> IrcChannel -- ^ changed channel
-- | Give voice status to the given nickname on the channel. This
-- does not perform any permission or error checks, it just performs
-- the low-level operation.
chanAddVoice un = chanVoices %~ insert un chanAddVoice un = chanVoices %~ insert un
-- | Remove voice status from the given nickname on the channel. This
-- does not perform any permission or error checks, it just performs
-- the low-level operation.
chanDelVoice un = chanVoices %~ delete un chanDelVoice un = chanVoices %~ delete un
chanAddInvite, chanDelInvite :: NickKey -> IrcChannel -> IrcChannel chanAddInvite, chanDelInvite :: NickKey -- ^ nickname of user
-> IrcChannel -- ^ channel to change invitation
-> IrcChannel -- ^ channel with change applied
-- | Add a record of invitation for the nickname to join the channel.
-- This will allow the user to join when the channel is invite-only.
-- This does not perform any permission or error checks, it just does
-- the operation.
chanAddInvite un = chanInvites %~ insert un chanAddInvite un = chanInvites %~ insert un
-- | Remove record of the invitation for the nickname to join the
-- channel. This does not perform permission or error checks, it just
-- does the low-level operation.
chanDelInvite un = chanInvites %~ delete un chanDelInvite un = chanInvites %~ delete un
chanChangeNick :: NickKey -> NickKey -> IrcChannel -> IrcChannel -- | Change the nick of a user on the channel. This will replace the
-- old name with the news name in the member list, invitation list,
-- and the mode flags for privileges. It will only affect the
-- channel, not the user or other server records.
chanChangeNick :: NickKey -- ^ old nickname
-> NickKey -- ^ new nickname
-> IrcChannel -- ^ channel to modify
-> IrcChannel -- ^ channel with nickname changed
chanChangeNick old new ch = (chOps . chVoice . chInvite . chUsers) ch chanChangeNick old new ch = (chOps . chVoice . chInvite . chUsers) ch
where where
chOps chOps
@ -122,16 +217,37 @@ chanChangeNick old new ch = (chOps . chVoice . chInvite . chUsers) ch
| chanHasUser old ch = chanDelUser old . chanAddUser new | chanHasUser old ch = chanDelUser old . chanAddUser new
| otherwise = id | otherwise = id
chanUserIsOper :: NickKey -> IrcChannel -> Bool -- | Is the nickname an operator of the channel? Returns 'True' if
-- the user is a channel op. This does not consider any other
-- privileges.
chanUserIsOper :: NickKey -- ^ nickname to check
-> IrcChannel -- ^ channel to check
-> Bool -- ^ 'True' if nickname has ops on channel
chanUserIsOper un ch = member un $ ch ^. chanOpers chanUserIsOper un ch = member un $ ch ^. chanOpers
chanUserHasVoice :: NickKey -> IrcChannel -> Bool -- | Does the nickname have voice on the channel? Returns 'True' if
-- the user has the voice mode flag. This does not consider any other
-- privileges or conditions.
chanUserHasVoice :: NickKey -- ^ nickname to check
-> IrcChannel -- ^ channel to check
-> Bool -- ^ 'True' if nickname has voice on channel
chanUserHasVoice un ch = member un $ ch ^. chanVoices chanUserHasVoice un ch = member un $ ch ^. chanVoices
chanUserIsInvited :: NickKey -> IrcChannel -> Bool -- | Has the nickname been invited to the channel? Returns 'True' if
-- the user has been invited. This does not consider any other
-- privileges or conditions.
chanUserIsInvited :: NickKey -- ^ nickname to check
-> IrcChannel -- ^ channel to check
-> Bool -- ^ 'True' if nickname has been invited
chanUserIsInvited un ch = member un $ ch ^. chanInvites chanUserIsInvited un ch = member un $ ch ^. chanInvites
chanUserMaySpeak :: NickKey -> IrcChannel -> Bool -- | Is the nickname allowed to speak on the channel? Returns 'True'
-- if the relevant permission checks all pass. The checks consider
-- channel membership, the NoOutsideMsgs flag, the Moderated flag and
-- Voice status, and channel Operator status.
chanUserMaySpeak :: NickKey -- ^ nickname to check
-> IrcChannel -- ^ channel to check
-> Bool -- ^ 'True' if nickname may speak on channel
chanUserMaySpeak un ch chanUserMaySpeak un ch
| (chanHasUser un ch || not (chanHasModeFlag NoOutsideMsgs ch)) | (chanHasUser un ch || not (chanHasModeFlag NoOutsideMsgs ch))
&& not (chanHasModeFlag Moderated ch) = True && not (chanHasModeFlag Moderated ch) = True
@ -139,13 +255,22 @@ chanUserMaySpeak un ch
| chanUserHasVoice un ch = True | chanUserHasVoice un ch = True
| otherwise = False | otherwise = False
chanUserMayJoin :: NickKey -> IrcChannel -> Bool -- | Is the nickname allowed to join the channel? Returns 'True' if
-- the relevant permission checks all pass. The checks consider the
-- InviteOnly flag and whether an invitation has been issued.
chanUserMayJoin :: NickKey -- ^ nickname to check
-> IrcChannel -- ^ channel to check
-> Bool -- ^ 'True' if nickname may join the channel
chanUserMayJoin un ch chanUserMayJoin un ch
| not $ chanHasModeFlag InviteOnly ch = True | not $ chanHasModeFlag InviteOnly ch = True
| chanUserIsInvited un ch = True | chanUserIsInvited un ch = True
| otherwise = False | otherwise = False
chanUserMaySetTopic :: NickKey -> IrcChannel -> Bool -- | Is the nickname allowed to set the topic for the channel?
-- Returns 'True' if the relevant permission checks all pass.
chanUserMaySetTopic :: NickKey -- ^ nickname to check
-> IrcChannel -- ^ channel to check
-> Bool -- ^ 'True' if nickname may set the topic
chanUserMaySetTopic un ch chanUserMaySetTopic un ch
| not (chanHasModeFlag TopicOperOnly ch) && | not (chanHasModeFlag TopicOperOnly ch) &&
chanHasUser un ch = True chanHasUser un ch = True

View File

@ -1,11 +1,22 @@
-- | This module contains the pure functions for transforming the state of -- | This module contains the pure functions for transforming the state of
-- the IRC server record ('IrcServer') as commands are processed. It depends -- the IRC server record ('IrcServer') as commands are processed. It depends
-- on the "Server.User" and "Server.Channel" modules for some transformations -- on the "User" and "Channel" modules for some transformations of user and
-- of user and channel ('IrcUser' and 'IrcChannel') structures. -- channel ('IrcUser' and 'IrcChannel') structures.
module Pipes.IRC.Server.Server module Pipes.IRC.Server.Server
( ircAddUser, ircDelUser, ircHasUser, ircHasChan, ircJoin ( ircAddUser
, ircPart, ircInvite, ircInviteCheck, ircPassCheck , ircDelUser
, ircChangeNick ) , ircHasUser
, ircHasChan
, ircJoin
, ircPart
, ircInvite
, ircInviteCheck
, ircPassCheck
, ircChangeNick
, NickKey
, IrcUser(..)
, IrcUserMode(..)
)
where where
import Control.Lens import Control.Lens

View File

@ -3,7 +3,10 @@
module Pipes.IRC.Server.Types module Pipes.IRC.Server.Types
( module Pipes.IRC.Server.Types ( module Pipes.IRC.Server.Types
, HostPreference (..), ServiceName, SockAddr, Socket , HostPreference (..)
, ServiceName
, SockAddr
, Socket
) )
where where
@ -19,72 +22,139 @@ import Pipes.IRC.Message.Types (IrcMessage, NickName)
import Pipes.Network.TCP (HostPreference (..), ServiceName, import Pipes.Network.TCP (HostPreference (..), ServiceName,
SockAddr, Socket) SockAddr, Socket)
-- * Data structures for managing the pure component of the server
-- | A type alias for nicknames
type NickKey = ByteString type NickKey = ByteString
-- | A type alias for channel names
type ChanKey = ByteString type ChanKey = ByteString
-- | A type alias for password keys
type PassKey = ByteString type PassKey = ByteString
-- | A sequence of 'IrcEvent's
type IrcEvents = [IrcEvent] type IrcEvents = [IrcEvent]
-- | An 'IrcEvent' represents an action that should occur due to the processing
-- of actions within the 'IrcMonad'. It includes sending messages, closing
-- connections, etc.
data IrcEvent = Msg { _outMsg :: !IrcMessage data IrcEvent = Msg { _outMsg :: !IrcMessage
-- ^ An 'IrcMessage' to send over the network
, _outDest :: ![Int] , _outDest :: ![Int]
-- ^ The connection ids to send the message on
} }
| Close { _closeConn :: Int } | Close { _closeConn :: Int
| Pong { _pongConn :: Int } -- ^ The connection id to close
}
| Pong { _pongConn :: Int
-- ^ The connection id to send a PONG message to
}
deriving (Show) deriving (Show)
makeLenses ''IrcEvent makeLenses ''IrcEvent
data IrcUserMode = Away | Invisible | WallOps | Restricted -- | An 'IrcUserMode' represents some privilege or state of a user. They are
| Oper | LocalOper | ServerNotices -- used for various different purposes.
data IrcUserMode = Away -- ^ the user is marked as away from keyboard
| Invisible -- ^ the user does not show in WHO listings
| WallOps -- ^ the user receives WALLOPS messages
| Restricted -- ^ ???
| Oper -- ^ the user is an IRC operator
| LocalOper -- ^ the user is a local server operator
| ServerNotices -- ^ the user receives server notices
deriving (Show, Eq, Enum, Ord) deriving (Show, Eq, Enum, Ord)
-- | An 'IrcUser' record tracks the state of a registered user that is not
-- channel-specific.
data IrcUser = data IrcUser =
IrcUser { _userServerName :: !ByteString IrcUser { _userServerName :: !ByteString
-- ^ the server that the user connected from
, _userModes :: !(Set IrcUserMode) , _userModes :: !(Set IrcUserMode)
-- ^ the mode flags that the user has set
, _userChannels :: !(Set ChanKey) , _userChannels :: !(Set ChanKey)
-- ^ channels that the user is a current member of
, _userConn :: !Int , _userConn :: !Int
-- ^ an integer identifying the user's connection
, _userInvites :: !(Set ChanKey) , _userInvites :: !(Set ChanKey)
-- ^ the set of channels that the user is invited to
} deriving (Show, Eq) } deriving (Show, Eq)
makeLenses ''IrcUser makeLenses ''IrcUser
data IrcChanModeFlags = Anonymous | InviteOnly | Moderated | NoOutsideMsgs -- | The 'IrcChanModeFlags' represent some state that is specific to a channel.
| Quiet | Private | Secret | TopicOperOnly -- They are used for various purposes.
data IrcChanModeFlags = Anonymous -- ^ all communication is anonymized
| InviteOnly -- ^ only invited users may join
| Moderated -- ^ only ops or voice may speak
| NoOutsideMsgs -- ^ only members may speak
| Quiet -- ^ ???
| Private -- ^ channel shows up as private in list
| Secret -- ^ channel does not appear in list
| TopicOperOnly -- ^ topic may only be set by ops
deriving (Show, Eq, Enum, Ord) deriving (Show, Eq, Enum, Ord)
-- | An 'IrcChannel' record tracks the state of a channel.
data IrcChannel = data IrcChannel =
IrcChannel { _chanTopic :: !(Maybe ByteString) IrcChannel { _chanTopic :: !(Maybe ByteString)
-- ^ the topic of discussion for the channel
, _chanPass :: !(Maybe ByteString) , _chanPass :: !(Maybe ByteString)
-- ^ key that must be given to join the channel
, _chanModeFlags :: !(Set IrcChanModeFlags) , _chanModeFlags :: !(Set IrcChanModeFlags)
-- ^ various configuration options for channel behavior
, _chanUsers :: !(Set NickKey) , _chanUsers :: !(Set NickKey)
-- ^ users that have joined the channel
, _chanOpers :: !(Set NickKey) , _chanOpers :: !(Set NickKey)
-- ^ users in the channel with ops
, _chanVoices :: !(Set NickKey) , _chanVoices :: !(Set NickKey)
-- ^ users in the channel with voice
, _chanInvites :: !(Set NickKey) , _chanInvites :: !(Set NickKey)
-- ^ users that have been invited to the channel
} deriving (Show, Eq) } deriving (Show, Eq)
makeLenses ''IrcChannel makeLenses ''IrcChannel
-- | An 'IrcServer' record tracks the pure state of the server.
data IrcServer = data IrcServer =
IrcServer { _ircNicks :: !(Set NickKey) IrcServer { _ircNicks :: !(Set NickKey)
-- ^ the nicknames currently known to be in use
, _ircUsers :: !(Map NickKey IrcUser) , _ircUsers :: !(Map NickKey IrcUser)
-- ^ users that have been registered
, _ircChannels :: !(Map ChanKey IrcChannel) , _ircChannels :: !(Map ChanKey IrcChannel)
-- ^ channels that have at least one user
, _ircVersion :: !ByteString , _ircVersion :: !ByteString
-- ^ version of the server
} deriving (Show) } deriving (Show)
makeLenses ''IrcServer makeLenses ''IrcServer
-- | Configuration options for the server
data IrcConfig = data IrcConfig =
IrcConfig { _ircPort :: !ServiceName IrcConfig { _ircPort :: !ServiceName
-- ^ port on which the server should listen for connections
, _ircHost :: !HostPreference , _ircHost :: !HostPreference
-- ^ interface name on which the server should listen
, _ircHostName :: !ByteString , _ircHostName :: !ByteString
-- ^ official server name of the server
, _ircMotd :: ![ByteString] , _ircMotd :: ![ByteString]
-- ^ MOTD to send to new connections to the server
, _ircPass :: !(Maybe ByteString) , _ircPass :: !(Maybe ByteString)
-- ^ a secret password that must be entered to register
} deriving (Show) } deriving (Show)
makeLenses ''IrcConfig makeLenses ''IrcConfig
-- | Data that tracks the registration information of clients
data RegState = Unreg { _rcvdPass :: !(Maybe ByteString) data RegState = Unreg { _rcvdPass :: !(Maybe ByteString)
-- ^ the password given via PASS
, _rcvdNick :: !(Maybe NickKey) , _rcvdNick :: !(Maybe NickKey)
, _rcvdName :: !(Maybe ByteString) } -- ^ the nickname given during registration
| RegUser { _regdNick :: !NickName } , _rcvdName :: !(Maybe ByteString)
-- ^ the real name given during registration
}
| RegUser { _regdNick :: !NickName
-- ^ information about a user from registration
}
deriving (Show) deriving (Show)
makeLenses ''RegState makeLenses ''RegState
-- * Data structures for managing the IO portion of the server
data IrcConnection = data IrcConnection =
IrcConnection { _sock :: !Socket IrcConnection { _sock :: !Socket
, _addr :: !SockAddr , _addr :: !SockAddr