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 {
conn net.Conn
hostname string
send chan<- Reply
recv <-chan string
// communication
conn net.Conn
send chan<- Reply
recv <-chan string
// basic info
username string
realname string
hostname string
nick string
registered bool
invisible bool
channels ChannelSet
server *Server
serverPass bool
// modes
away bool
registered bool
invisible bool
wallOps bool
restricted bool
operator bool
localOperator bool
// relations
server *Server
channels ChannelSet
}
type ClientSet map[*Client]bool

View File

@ -13,8 +13,8 @@ type Message interface {
}
var (
ErrNotEnoughArgs = errors.New("not enough arguments")
ErrUModeUnknownFlag = errors.New("unknown umode flag")
NotEnoughArgsError = errors.New("not enough arguments")
UModeUnknownFlagError = errors.New("unknown umode flag")
)
// unknown
@ -38,7 +38,7 @@ type PingMessage struct {
func NewPingMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
msg := &PingMessage{server: args[0]}
if len(args) > 1 {
@ -60,7 +60,7 @@ type PongMessage struct {
func NewPongMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
message := &PongMessage{server1: args[0]}
if len(args) > 1 {
@ -73,6 +73,27 @@ func (m *PongMessage) Handle(s *Server, c *Client) {
// 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
type NickMessage struct {
@ -81,7 +102,7 @@ type NickMessage struct {
func NewNickMessage(args []string) (Message, error) {
if len(args) != 1 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
return &NickMessage{args[0]}, nil
}
@ -101,7 +122,7 @@ type UserMessage struct {
func NewUserMessage(args []string) (Message, error) {
if len(args) != 4 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
msg := &UserMessage{
user: args[0],
@ -119,7 +140,7 @@ func (m *UserMessage) Handle(s *Server, c *Client) {
s.UserLogin(c, m.user, m.realname)
}
// QUIT
// QUIT [ <Quit Message> ]
type QuitMessage struct {
message string
@ -137,18 +158,19 @@ func (m *QuitMessage) Handle(s *Server, c *Client) {
s.Quit(c, m.message)
}
// MODE
// MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
type ModeMessage struct {
nickname 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) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
msg := &ModeMessage{
nickname: args[0],
@ -174,7 +196,7 @@ func (m *ModeMessage) Handle(s *Server, c *Client) {
s.ChangeUserMode(c, m.modes)
}
// JOIN
// JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
type JoinMessage struct {
channels []string
@ -224,7 +246,7 @@ type PartMessage struct {
func NewPartMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
msg := &PartMessage{channels: strings.Split(args[0], ",")}
if len(args) > 1 {
@ -255,7 +277,7 @@ type PrivMsgMessage struct {
func NewPrivMsgMessage(args []string) (Message, error) {
if len(args) < 2 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
return &PrivMsgMessage{
target: args[0],
@ -298,7 +320,7 @@ type TopicMessage struct {
func NewTopicMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
msg := &TopicMessage{channel: args[0]}
if len(args) > 1 {
@ -329,7 +351,7 @@ type InviteMessage struct {
func NewInviteMessage(args []string) (Message, error) {
if len(args) < 2 {
return nil, ErrNotEnoughArgs
return nil, NotEnoughArgsError
}
return &InviteMessage{
nickname: args[0],
@ -352,3 +374,28 @@ func (m *InviteMessage) Handle(s *Server, c *Client) {
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,
"NICK": NewNickMessage,
"PART": NewPartMessage,
"PASS": NewPassMessage,
"PING": NewPingMessage,
"PONG": NewPongMessage,
"PRIVMSG": NewPrivMsgMessage,
"QUIT": NewQuitMessage,
"TOPIC": NewTopicMessage,
"USER": NewUserMessage,
"OPER": NewOperMessage,
}
)

View File

@ -77,7 +77,7 @@ func RplCreated(server *Server) Reply {
func RplMyInfo(server *Server) Reply {
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 {
@ -122,6 +122,12 @@ func RplPong(server *Server) Reply {
return NewReply(server, RPL_PONG, "")
}
// server functions
func RplYoureOper(server *Server) Reply {
return NewReply(server, RPL_YOUREOPER, ":You are now an IRC operator")
}
// errors
func ErrAlreadyRegistered(source Identifier) Reply {
@ -177,3 +183,7 @@ func ErrNoSuchNick(source Identifier, nick string) Reply {
return NewReply(source, ERR_NOSUCHNICK,
nick+" :No such nick/channel")
}
func ErrPasswdMismatch(server *Server) Reply {
return NewReply(server, ERR_PASSWDMISMATCH, ":Password incorrect")
}

View File

@ -7,12 +7,14 @@ import (
)
type Server struct {
hostname string
ctime time.Time
name string
recv chan<- *ClientMessage
nicks map[string]*Client
channels map[string]*Channel
hostname string
ctime time.Time
name string
recv chan<- *ClientMessage
nicks map[string]*Client
channels map[string]*Channel
password string
operators map[string]string
}
type ClientMessage struct {
@ -68,6 +70,10 @@ func (s *Server) GetOrMakeChannel(name string) *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.
func (s *Server) SendToInterestedClients(fromClient *Client, reply Reply) {
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) {
if !c.registered && c.HasNick() && c.HasUser() {
if !c.registered && c.HasNick() && c.HasUser() && (s.password == "" || c.serverAuth) {
c.registered = true
c.send <- RplWelcome(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) {
for _, mode := range modes {
if mode == "+i" {
switch mode {
case "+i":
c.invisible = true
} else if mode == "-i" {
case "-i":
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)