mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
Merge pull request #25 from edmund-huber/theater_mode
WIP: adding theater-mode, fixes #15
This commit is contained in:
commit
6403e79a5b
@ -9,3 +9,6 @@ password = "JDJhJDA0JHJzVFFlNXdOUXNhLmtkSGRUQVVEVHVYWXRKUmdNQ3FKVTRrczRSMTlSWGRP
|
||||
|
||||
[operator "root"]
|
||||
password = "JDJhJDA0JEhkcm10UlNFRkRXb25iOHZuSDVLZXVBWlpyY0xyNkQ4dlBVc1VMWVk1LlFjWFpQbGxZNUtl" ; 'toor'
|
||||
|
||||
[theater "#ghostbusters"]
|
||||
password = "JDJhJDA0JG0yY1h4cTRFUHhkcjIzN2p1M2Nvb2VEYjAzSHh4eTB3YkZ0VFRLV1ZPVXdqeFBSRUtmRlBT" ; 'venkman'
|
||||
|
@ -6,14 +6,15 @@ import (
|
||||
)
|
||||
|
||||
type Channel struct {
|
||||
flags ChannelModeSet
|
||||
lists map[ChannelMode]*UserMaskSet
|
||||
key Text
|
||||
members MemberSet
|
||||
name Name
|
||||
server *Server
|
||||
topic Text
|
||||
userLimit uint64
|
||||
flags ChannelModeSet
|
||||
lists map[ChannelMode]*UserMaskSet
|
||||
key Text
|
||||
members MemberSet
|
||||
name Name
|
||||
server *Server
|
||||
topic Text
|
||||
userLimit uint64
|
||||
theaterUser *Client
|
||||
}
|
||||
|
||||
// NewChannel creates a new channel from a `Server` and a `name`
|
||||
@ -405,9 +406,11 @@ func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) boo
|
||||
return channel.applyModeMember(client, change.mode, change.op,
|
||||
NewName(change.arg))
|
||||
|
||||
case Theater:
|
||||
client.ErrConfiguredMode(change.mode)
|
||||
|
||||
default:
|
||||
client.ErrUnknownMode(change.mode, channel)
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -13,27 +13,28 @@ const (
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
atime time.Time
|
||||
authorized bool
|
||||
awayMessage Text
|
||||
capabilities CapabilitySet
|
||||
capState CapState
|
||||
channels ChannelSet
|
||||
commands chan Command
|
||||
ctime time.Time
|
||||
flags map[UserMode]bool
|
||||
hasQuit bool
|
||||
hops uint
|
||||
hostname Name
|
||||
idleTimer *time.Timer
|
||||
loginTimer *time.Timer
|
||||
nick Name
|
||||
quitTimer *time.Timer
|
||||
realname Text
|
||||
registered bool
|
||||
server *Server
|
||||
socket *Socket
|
||||
username Name
|
||||
atime time.Time
|
||||
authorized bool
|
||||
awayMessage Text
|
||||
capabilities CapabilitySet
|
||||
capState CapState
|
||||
channels ChannelSet
|
||||
commands chan Command
|
||||
ctime time.Time
|
||||
flags map[UserMode]bool
|
||||
hasQuit bool
|
||||
hops uint
|
||||
hostname Name
|
||||
idleTimer *time.Timer
|
||||
loginTimer *time.Timer
|
||||
nick Name
|
||||
quitTimer *time.Timer
|
||||
realname Text
|
||||
registered bool
|
||||
server *Server
|
||||
socket *Socket
|
||||
username Name
|
||||
theaterChannels []*Channel
|
||||
}
|
||||
|
||||
func NewClient(server *Server, conn net.Conn) *Client {
|
||||
@ -259,6 +260,10 @@ func (client *Client) Quit(message Text) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, channel := range client.theaterChannels {
|
||||
delete(channel.flags, Theater)
|
||||
}
|
||||
|
||||
client.Reply(RplError("connection closed"))
|
||||
client.hasQuit = true
|
||||
client.server.whoWas.Append(client)
|
||||
|
@ -49,6 +49,7 @@ var (
|
||||
PRIVMSG: NewPrivMsgCommand,
|
||||
PROXY: NewProxyCommand,
|
||||
QUIT: NewQuitCommand,
|
||||
THEATER: NewTheaterCommand, // nonstandard
|
||||
TIME: NewTimeCommand,
|
||||
TOPIC: NewTopicCommand,
|
||||
USER: NewUserCommand,
|
||||
@ -947,6 +948,31 @@ func NewInviteCommand(args []string) (Command, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewTheaterCommand(args []string) (Command, error) {
|
||||
if len(args) < 1 {
|
||||
return nil, NotEnoughArgsError
|
||||
} else if upperSubCmd := strings.ToUpper(args[0]); upperSubCmd == "IDENTIFY" && len(args) == 3 {
|
||||
return &TheaterIdentifyCommand{
|
||||
channel: NewName(args[1]),
|
||||
PassCommand: PassCommand{password: []byte(args[2])},
|
||||
}, nil
|
||||
} else if upperSubCmd == "PRIVMSG" && len(args) == 4 {
|
||||
return &TheaterPrivMsgCommand{
|
||||
channel: NewName(args[1]),
|
||||
asNick: NewName(args[2]),
|
||||
message: NewText(args[3]),
|
||||
}, nil
|
||||
} else if upperSubCmd == "ACTION" && len(args) == 4 {
|
||||
return &TheaterActionCommand{
|
||||
channel: NewName(args[1]),
|
||||
asNick: NewName(args[2]),
|
||||
action: NewText(args[3]),
|
||||
}, nil
|
||||
} else {
|
||||
return nil, ErrParseCommand
|
||||
}
|
||||
}
|
||||
|
||||
type TimeCommand struct {
|
||||
BaseCommand
|
||||
target Name
|
||||
|
@ -29,6 +29,8 @@ type Config struct {
|
||||
}
|
||||
|
||||
Operator map[string]*PassConfig
|
||||
|
||||
Theater map[string]*PassConfig
|
||||
}
|
||||
|
||||
func (conf *Config) Operators() map[Name][]byte {
|
||||
@ -39,6 +41,18 @@ func (conf *Config) Operators() map[Name][]byte {
|
||||
return operators
|
||||
}
|
||||
|
||||
func (conf *Config) Theaters() map[Name][]byte {
|
||||
theaters := make(map[Name][]byte)
|
||||
for s, theaterConf := range conf.Theater {
|
||||
name := NewName(s)
|
||||
if !name.IsChannel() {
|
||||
log.Fatal("config uses a non-channel for a theater!")
|
||||
}
|
||||
theaters[name] = theaterConf.PasswordBytes()
|
||||
}
|
||||
return theaters
|
||||
}
|
||||
|
||||
func LoadConfig(filename string) (config *Config, err error) {
|
||||
config = &Config{}
|
||||
err = gcfg.ReadFileInto(config, filename)
|
||||
|
@ -30,6 +30,7 @@ const (
|
||||
PRIVMSG StringCode = "PRIVMSG"
|
||||
PROXY StringCode = "PROXY"
|
||||
QUIT StringCode = "QUIT"
|
||||
THEATER StringCode = "THEATER" // nonstandard
|
||||
TIME StringCode = "TIME"
|
||||
TOPIC StringCode = "TOPIC"
|
||||
USER StringCode = "USER"
|
||||
|
@ -83,6 +83,7 @@ const (
|
||||
Quiet ChannelMode = 'q' // flag
|
||||
ReOp ChannelMode = 'r' // flag
|
||||
Secret ChannelMode = 's' // flag, deprecated
|
||||
Theater ChannelMode = 'T' // flag arg, nonstandard
|
||||
UserLimit ChannelMode = 'l' // flag arg
|
||||
Voice ChannelMode = 'v' // arg
|
||||
)
|
||||
@ -90,7 +91,7 @@ const (
|
||||
var (
|
||||
SupportedChannelModes = ChannelModes{
|
||||
BanMask, ExceptMask, InviteMask, InviteOnly, Key, NoOutside,
|
||||
OpOnlyTopic, Persistent, Private, UserLimit,
|
||||
OpOnlyTopic, Persistent, Private, Theater, UserLimit,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -548,6 +548,11 @@ func (target *Client) ErrUnknownMode(mode ChannelMode, channel *Channel) {
|
||||
"%s :is unknown mode char to me for %s", mode, channel)
|
||||
}
|
||||
|
||||
func (target *Client) ErrConfiguredMode(mode ChannelMode) {
|
||||
target.NumericReply(ERR_UNKNOWNMODE,
|
||||
"%s :can only change this mode in daemon configuration", mode)
|
||||
}
|
||||
|
||||
func (target *Client) ErrChannelIsFull(channel *Channel) {
|
||||
target.NumericReply(ERR_CHANNELISFULL,
|
||||
"%s :Cannot join channel (+l)", channel)
|
||||
|
@ -40,6 +40,7 @@ type Server struct {
|
||||
password []byte
|
||||
signals chan os.Signal
|
||||
whoWas *WhoWasList
|
||||
theaters map[Name][]byte
|
||||
}
|
||||
|
||||
var (
|
||||
@ -61,6 +62,7 @@ func NewServer(config *Config) *Server {
|
||||
operators: config.Operators(),
|
||||
signals: make(chan os.Signal, len(SERVER_SIGNALS)),
|
||||
whoWas: NewWhoWasList(100),
|
||||
theaters: config.Theaters(),
|
||||
}
|
||||
|
||||
if config.Server.Password != "" {
|
||||
|
121
irc/theater.go
Normal file
121
irc/theater.go
Normal file
@ -0,0 +1,121 @@
|
||||
package irc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type TheaterClient Name
|
||||
|
||||
func (c TheaterClient) Id() Name {
|
||||
return Name(c)
|
||||
}
|
||||
|
||||
func (c TheaterClient) Nick() Name {
|
||||
return Name(c)
|
||||
}
|
||||
|
||||
type TheaterSubCommand string
|
||||
|
||||
type theaterSubCommand interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
type TheaterIdentifyCommand struct {
|
||||
PassCommand
|
||||
channel Name
|
||||
}
|
||||
|
||||
func (m *TheaterIdentifyCommand) LoadPassword(s *Server) {
|
||||
m.hash = s.theaters[m.channel]
|
||||
}
|
||||
|
||||
func (cmd *TheaterIdentifyCommand) String() string {
|
||||
return fmt.Sprintf("THEATER_IDENTIFY(channel=%s)", cmd.channel)
|
||||
}
|
||||
|
||||
func (m *TheaterIdentifyCommand) HandleServer(s *Server) {
|
||||
client := m.Client()
|
||||
if !m.channel.IsChannel() {
|
||||
client.ErrNoSuchChannel(m.channel)
|
||||
return
|
||||
}
|
||||
|
||||
channel := s.channels.Get(m.channel)
|
||||
if channel == nil {
|
||||
client.ErrNoSuchChannel(m.channel)
|
||||
return
|
||||
}
|
||||
|
||||
if (m.hash == nil) || (m.err != nil) {
|
||||
client.ErrPasswdMismatch()
|
||||
return
|
||||
}
|
||||
|
||||
if channel.theaterUser == nil {
|
||||
client.theaterChannels = append(client.theaterChannels, channel)
|
||||
channel.flags[Theater] = true
|
||||
channel.theaterUser = client
|
||||
}
|
||||
}
|
||||
|
||||
type TheaterPrivMsgCommand struct {
|
||||
BaseCommand
|
||||
channel Name
|
||||
asNick Name
|
||||
message Text
|
||||
}
|
||||
|
||||
func (cmd *TheaterPrivMsgCommand) String() string {
|
||||
return fmt.Sprintf("THEATER_PRIVMSG(channel=%s, asNick=%s, message=%s)", cmd.channel, cmd.asNick, cmd.message)
|
||||
|
||||
}
|
||||
func (m *TheaterPrivMsgCommand) HandleServer(s *Server) {
|
||||
client := m.Client()
|
||||
if !m.channel.IsChannel() {
|
||||
client.ErrNoSuchChannel(m.channel)
|
||||
return
|
||||
}
|
||||
|
||||
channel := s.channels.Get(m.channel)
|
||||
if channel == nil {
|
||||
client.ErrNoSuchChannel(m.channel)
|
||||
return
|
||||
}
|
||||
|
||||
if channel.theaterUser == client {
|
||||
for member := range channel.members {
|
||||
member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, m.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TheaterActionCommand struct {
|
||||
BaseCommand
|
||||
channel Name
|
||||
asNick Name
|
||||
action Text
|
||||
}
|
||||
|
||||
func (cmd *TheaterActionCommand) String() string {
|
||||
return fmt.Sprintf("THEATER_ACTION(channel=%s, asNick=%s, action=%s)", cmd.channel, cmd.asNick, cmd.action)
|
||||
}
|
||||
|
||||
func (m *TheaterActionCommand) HandleServer(s *Server) {
|
||||
client := m.Client()
|
||||
if m.channel.IsChannel() {
|
||||
client.ErrNoSuchChannel(m.channel)
|
||||
return
|
||||
}
|
||||
|
||||
channel := s.channels.Get(m.channel)
|
||||
if channel == nil {
|
||||
client.ErrNoSuchChannel(m.channel)
|
||||
return
|
||||
}
|
||||
|
||||
if channel.theaterUser == client {
|
||||
for member := range channel.members {
|
||||
member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, NewText(fmt.Sprintf("\001ACTION %s\001", m.action))))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user