OPER command

This commit is contained in:
Jeremy Latt 2012-12-09 20:24:53 -08:00
parent 85e2f65b1b
commit 41e79e3b09
5 changed files with 119 additions and 33 deletions

View File

@ -6,17 +6,27 @@ import (
) )
type Client struct { type Client struct {
// communication
conn net.Conn conn net.Conn
hostname string
send chan<- Reply send chan<- Reply
recv <-chan string recv <-chan string
// basic info
username string username string
realname string realname string
hostname string
nick string nick string
serverPass bool
// modes
away bool
registered bool registered bool
invisible bool invisible bool
channels ChannelSet wallOps bool
restricted bool
operator bool
localOperator bool
// relations
server *Server server *Server
channels ChannelSet
} }
type ClientSet map[*Client]bool type ClientSet map[*Client]bool

View File

@ -13,8 +13,8 @@ type Message interface {
} }
var ( var (
ErrNotEnoughArgs = errors.New("not enough arguments") NotEnoughArgsError = errors.New("not enough arguments")
ErrUModeUnknownFlag = errors.New("unknown umode flag") UModeUnknownFlagError = errors.New("unknown umode flag")
) )
// unknown // unknown
@ -38,7 +38,7 @@ type PingMessage struct {
func NewPingMessage(args []string) (Message, error) { func NewPingMessage(args []string) (Message, error) {
if len(args) < 1 { if len(args) < 1 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
msg := &PingMessage{server: args[0]} msg := &PingMessage{server: args[0]}
if len(args) > 1 { if len(args) > 1 {
@ -60,7 +60,7 @@ type PongMessage struct {
func NewPongMessage(args []string) (Message, error) { func NewPongMessage(args []string) (Message, error) {
if len(args) < 1 { if len(args) < 1 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
message := &PongMessage{server1: args[0]} message := &PongMessage{server1: args[0]}
if len(args) > 1 { if len(args) > 1 {
@ -73,6 +73,27 @@ func (m *PongMessage) Handle(s *Server, c *Client) {
// no-op // no-op
} }
// PASS <password>
type PassMessage struct {
password string
}
func NewPassMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
return &PassMessage{password: args[0]}
}
func (m *PassMessage) Handle(s *Server, c *Client) {
if m.password == server.password {
c.serverPass = true
} else {
c.send <- ErrPass
}
}
// NICK // NICK
type NickMessage struct { type NickMessage struct {
@ -81,7 +102,7 @@ type NickMessage struct {
func NewNickMessage(args []string) (Message, error) { func NewNickMessage(args []string) (Message, error) {
if len(args) != 1 { if len(args) != 1 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
return &NickMessage{args[0]}, nil return &NickMessage{args[0]}, nil
} }
@ -101,7 +122,7 @@ type UserMessage struct {
func NewUserMessage(args []string) (Message, error) { func NewUserMessage(args []string) (Message, error) {
if len(args) != 4 { if len(args) != 4 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
msg := &UserMessage{ msg := &UserMessage{
user: args[0], user: args[0],
@ -119,7 +140,7 @@ func (m *UserMessage) Handle(s *Server, c *Client) {
s.UserLogin(c, m.user, m.realname) s.UserLogin(c, m.user, m.realname)
} }
// QUIT // QUIT [ <Quit Message> ]
type QuitMessage struct { type QuitMessage struct {
message string message string
@ -137,18 +158,19 @@ func (m *QuitMessage) Handle(s *Server, c *Client) {
s.Quit(c, m.message) s.Quit(c, m.message)
} }
// MODE // MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
type ModeMessage struct { type ModeMessage struct {
nickname string nickname string
modes []string modes []string
} }
var MODE_RE = regexp.MustCompile("^[-+][a-zA-Z]+$") // mode s is accepted but ignored, like some other modes
var MODE_RE = regexp.MustCompile("^[-+][iwroOs]+$")
func NewModeMessage(args []string) (Message, error) { func NewModeMessage(args []string) (Message, error) {
if len(args) < 1 { if len(args) < 1 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
msg := &ModeMessage{ msg := &ModeMessage{
nickname: args[0], nickname: args[0],
@ -174,7 +196,7 @@ func (m *ModeMessage) Handle(s *Server, c *Client) {
s.ChangeUserMode(c, m.modes) s.ChangeUserMode(c, m.modes)
} }
// JOIN // JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
type JoinMessage struct { type JoinMessage struct {
channels []string channels []string
@ -224,7 +246,7 @@ type PartMessage struct {
func NewPartMessage(args []string) (Message, error) { func NewPartMessage(args []string) (Message, error) {
if len(args) < 1 { if len(args) < 1 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
msg := &PartMessage{channels: strings.Split(args[0], ",")} msg := &PartMessage{channels: strings.Split(args[0], ",")}
if len(args) > 1 { if len(args) > 1 {
@ -255,7 +277,7 @@ type PrivMsgMessage struct {
func NewPrivMsgMessage(args []string) (Message, error) { func NewPrivMsgMessage(args []string) (Message, error) {
if len(args) < 2 { if len(args) < 2 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
return &PrivMsgMessage{ return &PrivMsgMessage{
target: args[0], target: args[0],
@ -298,7 +320,7 @@ type TopicMessage struct {
func NewTopicMessage(args []string) (Message, error) { func NewTopicMessage(args []string) (Message, error) {
if len(args) < 1 { if len(args) < 1 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
msg := &TopicMessage{channel: args[0]} msg := &TopicMessage{channel: args[0]}
if len(args) > 1 { if len(args) > 1 {
@ -329,7 +351,7 @@ type InviteMessage struct {
func NewInviteMessage(args []string) (Message, error) { func NewInviteMessage(args []string) (Message, error) {
if len(args) < 2 { if len(args) < 2 {
return nil, ErrNotEnoughArgs return nil, NotEnoughArgsError
} }
return &InviteMessage{ return &InviteMessage{
nickname: args[0], nickname: args[0],
@ -352,3 +374,28 @@ func (m *InviteMessage) Handle(s *Server, c *Client) {
channel.Invite(c, invitee) channel.Invite(c, invitee)
} }
// OPER <name> <password>
type OperMessage struct {
name string
password string
}
func NewOperMessage(args []string) Message {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
return &OperMessage{
name: args[0],
password: args[1],
}
}
func (m *OperMessage) Handle(s *Server, c *Client) {
if s.operators[m.name] == m.password {
c.send <- RplYoureOper(s)
} else {
c.send <- ErrPasswdMismatch(s)
}
}

View File

@ -15,12 +15,14 @@ var (
"MODE": NewModeMessage, "MODE": NewModeMessage,
"NICK": NewNickMessage, "NICK": NewNickMessage,
"PART": NewPartMessage, "PART": NewPartMessage,
"PASS": NewPassMessage,
"PING": NewPingMessage, "PING": NewPingMessage,
"PONG": NewPongMessage, "PONG": NewPongMessage,
"PRIVMSG": NewPrivMsgMessage, "PRIVMSG": NewPrivMsgMessage,
"QUIT": NewQuitMessage, "QUIT": NewQuitMessage,
"TOPIC": NewTopicMessage, "TOPIC": NewTopicMessage,
"USER": NewUserMessage, "USER": NewUserMessage,
"OPER": NewOperMessage,
} }
) )

View File

@ -77,7 +77,7 @@ func RplCreated(server *Server) Reply {
func RplMyInfo(server *Server) Reply { func RplMyInfo(server *Server) Reply {
return NewReply(server, RPL_MYINFO, return NewReply(server, RPL_MYINFO,
fmt.Sprintf("%s %s i ik", server.name, VERSION)) fmt.Sprintf("%s %s iwroO ik", server.name, VERSION))
} }
func RplUModeIs(server *Server, client *Client) Reply { func RplUModeIs(server *Server, client *Client) Reply {
@ -122,6 +122,12 @@ func RplPong(server *Server) Reply {
return NewReply(server, RPL_PONG, "") return NewReply(server, RPL_PONG, "")
} }
// server functions
func RplYoureOper(server *Server) Reply {
return NewReply(server, RPL_YOUREOPER, ":You are now an IRC operator")
}
// errors // errors
func ErrAlreadyRegistered(source Identifier) Reply { func ErrAlreadyRegistered(source Identifier) Reply {
@ -177,3 +183,7 @@ func ErrNoSuchNick(source Identifier, nick string) Reply {
return NewReply(source, ERR_NOSUCHNICK, return NewReply(source, ERR_NOSUCHNICK,
nick+" :No such nick/channel") nick+" :No such nick/channel")
} }
func ErrPasswdMismatch(server *Server) Reply {
return NewReply(server, ERR_PASSWDMISMATCH, ":Password incorrect")
}

View File

@ -13,6 +13,8 @@ type Server struct {
recv chan<- *ClientMessage recv chan<- *ClientMessage
nicks map[string]*Client nicks map[string]*Client
channels map[string]*Channel channels map[string]*Channel
password string
operators map[string]string
} }
type ClientMessage struct { type ClientMessage struct {
@ -68,6 +70,10 @@ func (s *Server) GetOrMakeChannel(name string) *Channel {
return channel return channel
} }
func (s *Server) AddOperator(name string, password string) {
s.operators[name] = password
}
// Send a message to clients of channels fromClient is a member. // Send a message to clients of channels fromClient is a member.
func (s *Server) SendToInterestedClients(fromClient *Client, reply Reply) { func (s *Server) SendToInterestedClients(fromClient *Client, reply Reply) {
clients := make(map[*Client]bool) clients := make(map[*Client]bool)
@ -114,7 +120,7 @@ func (s *Server) UserLogin(c *Client, user string, realName string) {
} }
func (s *Server) tryRegister(c *Client) { func (s *Server) tryRegister(c *Client) {
if !c.registered && c.HasNick() && c.HasUser() { if !c.registered && c.HasNick() && c.HasUser() && (s.password == "" || c.serverAuth) {
c.registered = true c.registered = true
c.send <- RplWelcome(s, c) c.send <- RplWelcome(s, c)
c.send <- RplYourHost(s, c) c.send <- RplYourHost(s, c)
@ -134,10 +140,21 @@ func (s *Server) Quit(c *Client, message string) {
func (s *Server) ChangeUserMode(c *Client, modes []string) { func (s *Server) ChangeUserMode(c *Client, modes []string) {
for _, mode := range modes { for _, mode := range modes {
if mode == "+i" { switch mode {
case "+i":
c.invisible = true c.invisible = true
} else if mode == "-i" { case "-i":
c.invisible = false c.invisible = false
case "-o":
c.operator = false
case "-O":
c.localOperator = false
case "+r":
c.restricted = true
case "+w":
c.wallOps = true
case "-w":
c.wallOps = false
} }
} }
c.send <- RplUModeIs(s, c) c.send <- RplUModeIs(s, c)