Browse Source

OPER command

tags/v0.1.0
Jeremy Latt 11 years ago
parent
commit
41e79e3b09
5 changed files with 119 additions and 33 deletions
  1. 18
    8
      src/irc/client.go
  2. 62
    15
      src/irc/commands.go
  3. 2
    0
      src/irc/parse.go
  4. 11
    1
      src/irc/reply.go
  5. 26
    9
      src/irc/server.go

+ 18
- 8
src/irc/client.go View File

@@ -6,17 +6,27 @@ import (
6 6
 )
7 7
 
8 8
 type Client struct {
9
-	conn       net.Conn
10
-	hostname   string
11
-	send       chan<- Reply
12
-	recv       <-chan string
9
+	// communication
10
+	conn net.Conn
11
+	send chan<- Reply
12
+	recv <-chan string
13
+	// basic info
13 14
 	username   string
14 15
 	realname   string
16
+	hostname   string
15 17
 	nick       string
16
-	registered bool
17
-	invisible  bool
18
-	channels   ChannelSet
19
-	server     *Server
18
+	serverPass bool
19
+	// modes
20
+	away          bool
21
+	registered    bool
22
+	invisible     bool
23
+	wallOps       bool
24
+	restricted    bool
25
+	operator      bool
26
+	localOperator bool
27
+	// relations
28
+	server   *Server
29
+	channels ChannelSet
20 30
 }
21 31
 
22 32
 type ClientSet map[*Client]bool

+ 62
- 15
src/irc/commands.go View File

@@ -13,8 +13,8 @@ type Message interface {
13 13
 }
14 14
 
15 15
 var (
16
-	ErrNotEnoughArgs    = errors.New("not enough arguments")
17
-	ErrUModeUnknownFlag = errors.New("unknown umode flag")
16
+	NotEnoughArgsError    = errors.New("not enough arguments")
17
+	UModeUnknownFlagError = errors.New("unknown umode flag")
18 18
 )
19 19
 
20 20
 // unknown
@@ -38,7 +38,7 @@ type PingMessage struct {
38 38
 
39 39
 func NewPingMessage(args []string) (Message, error) {
40 40
 	if len(args) < 1 {
41
-		return nil, ErrNotEnoughArgs
41
+		return nil, NotEnoughArgsError
42 42
 	}
43 43
 	msg := &PingMessage{server: args[0]}
44 44
 	if len(args) > 1 {
@@ -60,7 +60,7 @@ type PongMessage struct {
60 60
 
61 61
 func NewPongMessage(args []string) (Message, error) {
62 62
 	if len(args) < 1 {
63
-		return nil, ErrNotEnoughArgs
63
+		return nil, NotEnoughArgsError
64 64
 	}
65 65
 	message := &PongMessage{server1: args[0]}
66 66
 	if len(args) > 1 {
@@ -73,6 +73,27 @@ func (m *PongMessage) Handle(s *Server, c *Client) {
73 73
 	// no-op
74 74
 }
75 75
 
76
+// PASS <password>
77
+
78
+type PassMessage struct {
79
+	password string
80
+}
81
+
82
+func NewPassMessage(args []string) (Message, error) {
83
+	if len(args) < 1 {
84
+		return nil, NotEnoughArgsError
85
+	}
86
+	return &PassMessage{password: args[0]}
87
+}
88
+
89
+func (m *PassMessage) Handle(s *Server, c *Client) {
90
+	if m.password == server.password {
91
+		c.serverPass = true
92
+	} else {
93
+		c.send <- ErrPass
94
+	}
95
+}
96
+
76 97
 // NICK
77 98
 
78 99
 type NickMessage struct {
@@ -81,7 +102,7 @@ type NickMessage struct {
81 102
 
82 103
 func NewNickMessage(args []string) (Message, error) {
83 104
 	if len(args) != 1 {
84
-		return nil, ErrNotEnoughArgs
105
+		return nil, NotEnoughArgsError
85 106
 	}
86 107
 	return &NickMessage{args[0]}, nil
87 108
 }
@@ -101,7 +122,7 @@ type UserMessage struct {
101 122
 
102 123
 func NewUserMessage(args []string) (Message, error) {
103 124
 	if len(args) != 4 {
104
-		return nil, ErrNotEnoughArgs
125
+		return nil, NotEnoughArgsError
105 126
 	}
106 127
 	msg := &UserMessage{
107 128
 		user:     args[0],
@@ -119,7 +140,7 @@ func (m *UserMessage) Handle(s *Server, c *Client) {
119 140
 	s.UserLogin(c, m.user, m.realname)
120 141
 }
121 142
 
122
-// QUIT
143
+// QUIT [ <Quit Message> ]
123 144
 
124 145
 type QuitMessage struct {
125 146
 	message string
@@ -137,18 +158,19 @@ func (m *QuitMessage) Handle(s *Server, c *Client) {
137 158
 	s.Quit(c, m.message)
138 159
 }
139 160
 
140
-// MODE
161
+// MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
141 162
 
142 163
 type ModeMessage struct {
143 164
 	nickname string
144 165
 	modes    []string
145 166
 }
146 167
 
147
-var MODE_RE = regexp.MustCompile("^[-+][a-zA-Z]+$")
168
+// mode s is accepted but ignored, like some other modes
169
+var MODE_RE = regexp.MustCompile("^[-+][iwroOs]+$")
148 170
 
149 171
 func NewModeMessage(args []string) (Message, error) {
150 172
 	if len(args) < 1 {
151
-		return nil, ErrNotEnoughArgs
173
+		return nil, NotEnoughArgsError
152 174
 	}
153 175
 	msg := &ModeMessage{
154 176
 		nickname: args[0],
@@ -174,7 +196,7 @@ func (m *ModeMessage) Handle(s *Server, c *Client) {
174 196
 	s.ChangeUserMode(c, m.modes)
175 197
 }
176 198
 
177
-// JOIN
199
+// JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
178 200
 
179 201
 type JoinMessage struct {
180 202
 	channels []string
@@ -224,7 +246,7 @@ type PartMessage struct {
224 246
 
225 247
 func NewPartMessage(args []string) (Message, error) {
226 248
 	if len(args) < 1 {
227
-		return nil, ErrNotEnoughArgs
249
+		return nil, NotEnoughArgsError
228 250
 	}
229 251
 	msg := &PartMessage{channels: strings.Split(args[0], ",")}
230 252
 	if len(args) > 1 {
@@ -255,7 +277,7 @@ type PrivMsgMessage struct {
255 277
 
256 278
 func NewPrivMsgMessage(args []string) (Message, error) {
257 279
 	if len(args) < 2 {
258
-		return nil, ErrNotEnoughArgs
280
+		return nil, NotEnoughArgsError
259 281
 	}
260 282
 	return &PrivMsgMessage{
261 283
 		target:  args[0],
@@ -298,7 +320,7 @@ type TopicMessage struct {
298 320
 
299 321
 func NewTopicMessage(args []string) (Message, error) {
300 322
 	if len(args) < 1 {
301
-		return nil, ErrNotEnoughArgs
323
+		return nil, NotEnoughArgsError
302 324
 	}
303 325
 	msg := &TopicMessage{channel: args[0]}
304 326
 	if len(args) > 1 {
@@ -329,7 +351,7 @@ type InviteMessage struct {
329 351
 
330 352
 func NewInviteMessage(args []string) (Message, error) {
331 353
 	if len(args) < 2 {
332
-		return nil, ErrNotEnoughArgs
354
+		return nil, NotEnoughArgsError
333 355
 	}
334 356
 	return &InviteMessage{
335 357
 		nickname: args[0],
@@ -352,3 +374,28 @@ func (m *InviteMessage) Handle(s *Server, c *Client) {
352 374
 
353 375
 	channel.Invite(c, invitee)
354 376
 }
377
+
378
+// OPER <name> <password>
379
+
380
+type OperMessage struct {
381
+	name     string
382
+	password string
383
+}
384
+
385
+func NewOperMessage(args []string) Message {
386
+	if len(args) < 2 {
387
+		return nil, NotEnoughArgsError
388
+	}
389
+	return &OperMessage{
390
+		name:     args[0],
391
+		password: args[1],
392
+	}
393
+}
394
+
395
+func (m *OperMessage) Handle(s *Server, c *Client) {
396
+	if s.operators[m.name] == m.password {
397
+		c.send <- RplYoureOper(s)
398
+	} else {
399
+		c.send <- ErrPasswdMismatch(s)
400
+	}
401
+}

+ 2
- 0
src/irc/parse.go View File

@@ -15,12 +15,14 @@ var (
15 15
 		"MODE":    NewModeMessage,
16 16
 		"NICK":    NewNickMessage,
17 17
 		"PART":    NewPartMessage,
18
+		"PASS":    NewPassMessage,
18 19
 		"PING":    NewPingMessage,
19 20
 		"PONG":    NewPongMessage,
20 21
 		"PRIVMSG": NewPrivMsgMessage,
21 22
 		"QUIT":    NewQuitMessage,
22 23
 		"TOPIC":   NewTopicMessage,
23 24
 		"USER":    NewUserMessage,
25
+		"OPER":    NewOperMessage,
24 26
 	}
25 27
 )
26 28
 

+ 11
- 1
src/irc/reply.go View File

@@ -77,7 +77,7 @@ func RplCreated(server *Server) Reply {
77 77
 
78 78
 func RplMyInfo(server *Server) Reply {
79 79
 	return NewReply(server, RPL_MYINFO,
80
-		fmt.Sprintf("%s %s i ik", server.name, VERSION))
80
+		fmt.Sprintf("%s %s iwroO ik", server.name, VERSION))
81 81
 }
82 82
 
83 83
 func RplUModeIs(server *Server, client *Client) Reply {
@@ -122,6 +122,12 @@ func RplPong(server *Server) Reply {
122 122
 	return NewReply(server, RPL_PONG, "")
123 123
 }
124 124
 
125
+// server functions
126
+
127
+func RplYoureOper(server *Server) Reply {
128
+	return NewReply(server, RPL_YOUREOPER, ":You are now an IRC operator")
129
+}
130
+
125 131
 // errors
126 132
 
127 133
 func ErrAlreadyRegistered(source Identifier) Reply {
@@ -177,3 +183,7 @@ func ErrNoSuchNick(source Identifier, nick string) Reply {
177 183
 	return NewReply(source, ERR_NOSUCHNICK,
178 184
 		nick+" :No such nick/channel")
179 185
 }
186
+
187
+func ErrPasswdMismatch(server *Server) Reply {
188
+	return NewReply(server, ERR_PASSWDMISMATCH, ":Password incorrect")
189
+}

+ 26
- 9
src/irc/server.go View File

@@ -7,12 +7,14 @@ import (
7 7
 )
8 8
 
9 9
 type Server struct {
10
-	hostname string
11
-	ctime    time.Time
12
-	name     string
13
-	recv     chan<- *ClientMessage
14
-	nicks    map[string]*Client
15
-	channels map[string]*Channel
10
+	hostname  string
11
+	ctime     time.Time
12
+	name      string
13
+	recv      chan<- *ClientMessage
14
+	nicks     map[string]*Client
15
+	channels  map[string]*Channel
16
+	password  string
17
+	operators map[string]string
16 18
 }
17 19
 
18 20
 type ClientMessage struct {
@@ -68,6 +70,10 @@ func (s *Server) GetOrMakeChannel(name string) *Channel {
68 70
 	return channel
69 71
 }
70 72
 
73
+func (s *Server) AddOperator(name string, password string) {
74
+	s.operators[name] = password
75
+}
76
+
71 77
 // Send a message to clients of channels fromClient is a member.
72 78
 func (s *Server) SendToInterestedClients(fromClient *Client, reply Reply) {
73 79
 	clients := make(map[*Client]bool)
@@ -114,7 +120,7 @@ func (s *Server) UserLogin(c *Client, user string, realName string) {
114 120
 }
115 121
 
116 122
 func (s *Server) tryRegister(c *Client) {
117
-	if !c.registered && c.HasNick() && c.HasUser() {
123
+	if !c.registered && c.HasNick() && c.HasUser() && (s.password == "" || c.serverAuth) {
118 124
 		c.registered = true
119 125
 		c.send <- RplWelcome(s, c)
120 126
 		c.send <- RplYourHost(s, c)
@@ -134,10 +140,21 @@ func (s *Server) Quit(c *Client, message string) {
134 140
 
135 141
 func (s *Server) ChangeUserMode(c *Client, modes []string) {
136 142
 	for _, mode := range modes {
137
-		if mode == "+i" {
143
+		switch mode {
144
+		case "+i":
138 145
 			c.invisible = true
139
-		} else if mode == "-i" {
146
+		case "-i":
140 147
 			c.invisible = false
148
+		case "-o":
149
+			c.operator = false
150
+		case "-O":
151
+			c.localOperator = false
152
+		case "+r":
153
+			c.restricted = true
154
+		case "+w":
155
+			c.wallOps = true
156
+		case "-w":
157
+			c.wallOps = false
141 158
 		}
142 159
 	}
143 160
 	c.send <- RplUModeIs(s, c)

Loading…
Cancel
Save