diff --git a/irc/client.go b/irc/client.go index f984cfac..02de0bc0 100644 --- a/irc/client.go +++ b/irc/client.go @@ -15,6 +15,7 @@ type Client struct { hostname string invisible bool nick string + operator bool realname string registered bool replies chan<- Reply @@ -109,6 +110,10 @@ func (c *Client) ModeString() (str string) { if c.invisible { str += Invisible.String() } + if c.operator { + str += Operator.String() + } + if len(str) > 0 { str = "+" + str } diff --git a/irc/commands.go b/irc/commands.go index c5785cf8..c3d19cff 100644 --- a/irc/commands.go +++ b/irc/commands.go @@ -21,6 +21,7 @@ var ( "JOIN": NewJoinCommand, "MODE": NewModeCommand, "NICK": NewNickCommand, + "OPER": NewOperCommand, "PART": NewPartCommand, "PASS": NewPassCommand, "PING": NewPingCommand, @@ -541,3 +542,25 @@ func NewWhoCommand(args []string) (editableCommand, error) { func (msg *WhoCommand) String() string { return fmt.Sprintf("WHO(mask=%s, operatorOnly=%s)", msg.mask, msg.operatorOnly) } + +type OperCommand struct { + BaseCommand + name string + password string +} + +func (msg *OperCommand) String() string { + return fmt.Sprintf("OPER(name=%s, password=%s)", msg.name, msg.password) +} + +// OPER +func NewOperCommand(args []string) (editableCommand, error) { + if len(args) < 2 { + return nil, NotEnoughArgsError + } + + return &OperCommand{ + name: args[0], + password: args[1], + }, nil +} diff --git a/irc/config.go b/irc/config.go index 5df7c267..fa13c5f6 100644 --- a/irc/config.go +++ b/irc/config.go @@ -6,10 +6,16 @@ import ( ) type Config struct { + Name string + Listen string + Password string + Operators []OperatorConfig + Debug map[string]bool +} + +type OperatorConfig struct { Name string - Listen string Password string - Debug map[string]bool } func LoadConfig() (config *Config, err error) { diff --git a/irc/reply.go b/irc/reply.go index 64a3cf21..6d7206ed 100644 --- a/irc/reply.go +++ b/irc/reply.go @@ -206,9 +206,9 @@ func RplEndOfNames(channel *Channel) Reply { "%s :End of NAMES list", channel.name) } +// :You are now an IRC operator func RplYoureOper(server *Server) Reply { - return NewNumericReply(server, RPL_YOUREOPER, - ":You are now an IRC operator") + return NewNumericReply(server, RPL_YOUREOPER, ":You are now an IRC operator") } func RplWhoisUser(server *Server, client *Client) Reply { diff --git a/irc/server.go b/irc/server.go index 03e72f69..76bbcf45 100644 --- a/irc/server.go +++ b/irc/server.go @@ -10,25 +10,32 @@ import ( ) type Server struct { - channels ChannelNameMap - commands chan<- Command - ctime time.Time - hostname string - name string - password string - clients ClientNameMap + channels ChannelNameMap + commands chan<- Command + ctime time.Time + hostname string + name string + operators map[string]string + password string + clients ClientNameMap } func NewServer(config *Config) *Server { commands := make(chan Command) server := &Server{ - channels: make(ChannelNameMap), - clients: make(ClientNameMap), - commands: commands, - ctime: time.Now(), - name: config.Name, - password: config.Password, + channels: make(ChannelNameMap), + clients: make(ClientNameMap), + commands: commands, + ctime: time.Now(), + name: config.Name, + operators: make(map[string]string), + password: config.Password, } + + for _, opConf := range config.Operators { + server.operators[opConf.Name] = opConf.Password + } + go server.receiveCommands(commands) go server.listen(config.Listen) return server @@ -352,3 +359,17 @@ func (msg *WhoCommand) HandleServer(server *Server) { client.Reply(RplEndOfWho(server, mask)) } + +func (msg *OperCommand) HandleServer(server *Server) { + client := msg.Client() + + if server.operators[msg.name] != msg.password { + client.Reply(ErrPasswdMismatch(server)) + return + } + + client.operator = true + + client.Reply(RplYoureOper(server)) + client.Reply(RplUModeIs(server, client)) +}