Browse Source

refactor monitor and /oper implementations

tags/v0.9.2-beta
Shivaram Lingamneni 6 years ago
parent
commit
26686d7e86
5 changed files with 184 additions and 172 deletions
  1. 28
    31
      irc/client.go
  2. 18
    0
      irc/getters.go
  3. 119
    115
      irc/monitor.go
  4. 1
    1
      irc/nickname.go
  5. 18
    25
      irc/server.go

+ 28
- 31
irc/client.go View File

61
 	idleTimer          *time.Timer
61
 	idleTimer          *time.Timer
62
 	isDestroyed        bool
62
 	isDestroyed        bool
63
 	isQuitting         bool
63
 	isQuitting         bool
64
-	monitoring         map[string]bool
65
-	monitoringMutex    sync.RWMutex
66
 	nick               string
64
 	nick               string
67
 	nickCasefolded     string
65
 	nickCasefolded     string
68
 	nickMaskCasefolded string
66
 	nickMaskCasefolded string
81
 	saslValue          string
79
 	saslValue          string
82
 	server             *Server
80
 	server             *Server
83
 	socket             *Socket
81
 	socket             *Socket
82
+	stateMutex         sync.RWMutex // generic protection for mutable state
84
 	timerMutex         sync.Mutex
83
 	timerMutex         sync.Mutex
85
 	username           string
84
 	username           string
86
 	vhost              string
85
 	vhost              string
101
 		channels:       make(ChannelSet),
100
 		channels:       make(ChannelSet),
102
 		ctime:          now,
101
 		ctime:          now,
103
 		flags:          make(map[Mode]bool),
102
 		flags:          make(map[Mode]bool),
104
-		monitoring:     make(map[string]bool),
105
 		server:         server,
103
 		server:         server,
106
 		socket:         &socket,
104
 		socket:         &socket,
107
 		account:        &NoAccount,
105
 		account:        &NoAccount,
302
 	client.registered = true
300
 	client.registered = true
303
 	client.Touch()
301
 	client.Touch()
304
 
302
 
305
-	client.updateNickMask()
306
-	client.alertMonitors()
303
+	client.updateNickMask("")
304
+	client.server.monitorManager.alertMonitors(client, true)
307
 }
305
 }
308
 
306
 
309
 // IdleTime returns how long this client's been idle.
307
 // IdleTime returns how long this client's been idle.
393
 	return friends
391
 	return friends
394
 }
392
 }
395
 
393
 
396
-// updateNick updates the casefolded nickname.
397
-func (client *Client) updateNick() {
398
-	casefoldedName, err := CasefoldName(client.nick)
394
+// updateNick updates `nick` and `nickCasefolded`.
395
+func (client *Client) updateNick(nick string) {
396
+	casefoldedName, err := CasefoldName(nick)
399
 	if err != nil {
397
 	if err != nil {
400
 		log.Println(fmt.Sprintf("ERROR: Nick [%s] couldn't be casefolded... this should never happen. Printing stacktrace.", client.nick))
398
 		log.Println(fmt.Sprintf("ERROR: Nick [%s] couldn't be casefolded... this should never happen. Printing stacktrace.", client.nick))
401
 		debug.PrintStack()
399
 		debug.PrintStack()
402
 	}
400
 	}
401
+	client.stateMutex.Lock()
402
+	client.nick = nick
403
 	client.nickCasefolded = casefoldedName
403
 	client.nickCasefolded = casefoldedName
404
+	client.stateMutex.Unlock()
404
 }
405
 }
405
 
406
 
406
 // updateNickMask updates the casefolded nickname and nickmask.
407
 // updateNickMask updates the casefolded nickname and nickmask.
407
-func (client *Client) updateNickMask() {
408
-	client.updateNick()
408
+func (client *Client) updateNickMask(nick string) {
409
+	// on "", just regenerate the nickmask etc.
410
+	// otherwise, update the actual nick
411
+	if nick != "" {
412
+		client.updateNick(nick)
413
+	}
414
+
415
+	client.stateMutex.Lock()
409
 
416
 
410
 	if len(client.vhost) > 0 {
417
 	if len(client.vhost) > 0 {
411
 		client.hostname = client.vhost
418
 		client.hostname = client.vhost
413
 		client.hostname = client.rawHostname
420
 		client.hostname = client.rawHostname
414
 	}
421
 	}
415
 
422
 
416
-	client.nickMaskString = fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.hostname)
417
-
418
-	nickMaskCasefolded, err := Casefold(client.nickMaskString)
423
+	nickMaskString := fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.hostname)
424
+	nickMaskCasefolded, err := Casefold(nickMaskString)
419
 	if err != nil {
425
 	if err != nil {
420
 		log.Println(fmt.Sprintf("ERROR: Nickmask [%s] couldn't be casefolded... this should never happen. Printing stacktrace.", client.nickMaskString))
426
 		log.Println(fmt.Sprintf("ERROR: Nickmask [%s] couldn't be casefolded... this should never happen. Printing stacktrace.", client.nickMaskString))
421
 		debug.PrintStack()
427
 		debug.PrintStack()
422
 	}
428
 	}
429
+
430
+	client.nickMaskString = nickMaskString
423
 	client.nickMaskCasefolded = nickMaskCasefolded
431
 	client.nickMaskCasefolded = nickMaskCasefolded
432
+
433
+	client.stateMutex.Unlock()
424
 }
434
 }
425
 
435
 
426
 // AllNickmasks returns all the possible nickmasks for the client.
436
 // AllNickmasks returns all the possible nickmasks for the client.
458
 
468
 
459
 	err := client.server.clients.Add(client, nickname)
469
 	err := client.server.clients.Add(client, nickname)
460
 	if err == nil {
470
 	if err == nil {
461
-		client.nick = nickname
462
-		client.updateNick()
471
+		client.updateNick(nickname)
463
 	}
472
 	}
464
 	return err
473
 	return err
465
 }
474
 }
472
 		client.server.logger.Debug("nick", fmt.Sprintf("%s changed nickname to %s", client.nick, nickname))
481
 		client.server.logger.Debug("nick", fmt.Sprintf("%s changed nickname to %s", client.nick, nickname))
473
 		client.server.snomasks.Send(sno.LocalNicks, fmt.Sprintf(ircfmt.Unescape("$%s$r changed nickname to %s"), client.nick, nickname))
482
 		client.server.snomasks.Send(sno.LocalNicks, fmt.Sprintf(ircfmt.Unescape("$%s$r changed nickname to %s"), client.nick, nickname))
474
 		client.server.whoWas.Append(client)
483
 		client.server.whoWas.Append(client)
475
-		client.nick = nickname
476
-		client.updateNickMask()
484
+		client.updateNickMask(nickname)
477
 		for friend := range client.Friends() {
485
 		for friend := range client.Friends() {
478
 			friend.Send(nil, origNickMask, "NICK", nickname)
486
 			friend.Send(nil, origNickMask, "NICK", nickname)
479
 		}
487
 		}
530
 		client.server.connectionLimitsMutex.Unlock()
538
 		client.server.connectionLimitsMutex.Unlock()
531
 	}
539
 	}
532
 
540
 
533
-	// remove from opers list
534
-	_, exists := client.server.currentOpers[client]
535
-	if exists {
536
-		delete(client.server.currentOpers, client)
537
-	}
538
-
539
 	// alert monitors
541
 	// alert monitors
540
-	client.server.monitoringMutex.RLock()
541
-	for _, mClient := range client.server.monitoring[client.nickCasefolded] {
542
-		mClient.Send(nil, client.server.name, RPL_MONOFFLINE, mClient.nick, client.nick)
543
-	}
544
-	client.server.monitoringMutex.RUnlock()
545
-
546
-	// remove my monitors
547
-	client.clearMonitorList()
542
+	client.server.monitorManager.alertMonitors(client, false)
543
+	// clean up monitor state
544
+	client.server.monitorManager.clearMonitorList(client)
548
 
545
 
549
 	// clean up channels
546
 	// clean up channels
550
 	client.server.channelJoinPartMutex.Lock()
547
 	client.server.channelJoinPartMutex.Lock()

+ 18
- 0
irc/getters.go View File

20
 	defer server.configurableStateMutex.RUnlock()
20
 	defer server.configurableStateMutex.RUnlock()
21
 	return server.password
21
 	return server.password
22
 }
22
 }
23
+
24
+func (client *Client) getNick() string {
25
+	client.stateMutex.RLock()
26
+	defer client.stateMutex.RUnlock()
27
+	return client.nick
28
+}
29
+
30
+func (client *Client) getNickMaskString() string {
31
+	client.stateMutex.RLock()
32
+	defer client.stateMutex.RUnlock()
33
+	return client.nickMaskString
34
+}
35
+
36
+func (client *Client) getNickCasefolded() string {
37
+	client.stateMutex.RLock()
38
+	defer client.stateMutex.RUnlock()
39
+	return client.nickCasefolded
40
+}

+ 119
- 115
irc/monitor.go View File

4
 package irc
4
 package irc
5
 
5
 
6
 import (
6
 import (
7
+	"errors"
7
 	"strconv"
8
 	"strconv"
8
 	"strings"
9
 	"strings"
10
+	"sync"
9
 
11
 
10
 	"github.com/goshuirc/irc-go/ircmsg"
12
 	"github.com/goshuirc/irc-go/ircmsg"
11
 )
13
 )
12
 
14
 
13
-// alertMonitors alerts everyone monitoring us that we're online.
14
-func (client *Client) alertMonitors() {
15
-	// get monitors
16
-	client.server.monitoringMutex.RLock()
17
-	monitors := client.server.monitoring[client.nickCasefolded]
18
-	client.server.monitoringMutex.RUnlock()
19
-
20
-	// alert monitors
21
-	for _, mClient := range monitors {
22
-		// don't have to notify ourselves
23
-		if mClient != client {
24
-			mClient.SendFromClient("", client, nil, RPL_MONONLINE, mClient.nick, client.nickMaskString)
25
-		}
15
+type MonitorManager struct {
16
+	sync.RWMutex
17
+	// client -> nicks it's watching
18
+	watching map[*Client]map[string]bool
19
+	// nick -> clients watching it
20
+	watchedby map[string]map[*Client]bool
21
+	// (all nicks must be normalized externally by casefolding)
22
+}
23
+
24
+func NewMonitorManager() *MonitorManager {
25
+	mm := MonitorManager{
26
+		watching:  make(map[*Client]map[string]bool),
27
+		watchedby: make(map[string]map[*Client]bool),
26
 	}
28
 	}
29
+	return &mm
27
 }
30
 }
28
 
31
 
29
-// clearMonitorList clears our MONITOR list.
30
-func (client *Client) clearMonitorList() {
31
-	// lockin' everything
32
-	client.monitoringMutex.Lock()
33
-	defer client.monitoringMutex.Unlock()
34
-	client.server.monitoringMutex.Lock()
35
-	defer client.server.monitoringMutex.Unlock()
36
-
37
-	for name := range client.monitoring {
38
-		// just removes current client from the list
39
-		orig := client.server.monitoring[name]
40
-		var index int
41
-		for i, cli := range orig {
42
-			if cli == client {
43
-				index = i
44
-				break
32
+var MonitorLimitExceeded = errors.New("Monitor limit exceeded")
33
+
34
+// alertMonitors alerts everyone monitoring us that we're online.
35
+func (manager *MonitorManager) alertMonitors(client *Client, online bool) {
36
+	cfnick := client.getNickCasefolded()
37
+	nick := client.getNick()
38
+	var watchers []*Client
39
+	// safely copy the list of clients watching our nick
40
+	manager.RLock()
41
+	for client := range manager.watchedby[cfnick] {
42
+		watchers = append(watchers, client)
43
+	}
44
+	manager.RUnlock()
45
+
46
+	command := RPL_MONOFFLINE
47
+	if online {
48
+		command = RPL_MONONLINE
49
+	}
50
+
51
+	// asynchronously send all the notifications
52
+	go func() {
53
+		for _, mClient := range watchers {
54
+			// don't have to notify ourselves
55
+			if mClient != client {
56
+				mClient.SendFromClient("", client, nil, command, mClient.getNick(), nick)
45
 			}
57
 			}
46
 		}
58
 		}
47
-		client.server.monitoring[name] = append(orig[:index], orig[index+1:]...)
59
+	}()
60
+}
61
+
62
+// clearMonitorList clears our MONITOR list.
63
+func (manager *MonitorManager) clearMonitorList(client *Client) {
64
+	manager.Lock()
65
+	defer manager.Unlock()
66
+
67
+	for nick, _ := range manager.watching[client] {
68
+		delete(manager.watchedby[nick], client)
69
+	}
70
+	delete(manager.watching, client)
71
+}
72
+
73
+func (manager *MonitorManager) addMonitor(client *Client, nick string, limit int) error {
74
+	manager.Lock()
75
+	defer manager.Unlock()
76
+
77
+	if manager.watching[client] == nil {
78
+		manager.watching[client] = make(map[string]bool)
79
+	}
80
+	if manager.watchedby[nick] == nil {
81
+		manager.watchedby[nick] = make(map[*Client]bool)
48
 	}
82
 	}
49
 
83
 
50
-	client.monitoring = make(map[string]bool)
84
+	if len(manager.watching[client]) >= limit {
85
+		return MonitorLimitExceeded
86
+	}
87
+
88
+	manager.watching[client][nick] = true
89
+	manager.watchedby[nick][client] = true
90
+	return nil
91
+}
92
+
93
+func (manager *MonitorManager) removeMonitor(client *Client, nick string) error {
94
+	manager.Lock()
95
+	defer manager.Unlock()
96
+	// deleting from nil maps is fine
97
+	delete(manager.watching[client], nick)
98
+	delete(manager.watchedby[nick], client)
99
+	return nil
100
+}
101
+
102
+func (manager *MonitorManager) listMonitors(client *Client) (nicks []string) {
103
+	manager.RLock()
104
+	defer manager.RUnlock()
105
+	for nick := range manager.watching[client] {
106
+		nicks = append(nicks, nick)
107
+	}
108
+	return nicks
51
 }
109
 }
52
 
110
 
53
 var (
111
 var (
64
 	handler, exists := metadataSubcommands[strings.ToLower(msg.Params[0])]
122
 	handler, exists := metadataSubcommands[strings.ToLower(msg.Params[0])]
65
 
123
 
66
 	if !exists {
124
 	if !exists {
67
-		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "MONITOR", msg.Params[0], "Unknown subcommand")
125
+		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.getNick(), "MONITOR", msg.Params[0], "Unknown subcommand")
68
 		return false
126
 		return false
69
 	}
127
 	}
70
 
128
 
73
 
131
 
74
 func monitorRemoveHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
132
 func monitorRemoveHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
75
 	if len(msg.Params) < 2 {
133
 	if len(msg.Params) < 2 {
76
-		client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
134
+		client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.getNick(), msg.Command, "Not enough parameters")
77
 		return false
135
 		return false
78
 	}
136
 	}
79
 
137
 
80
 	targets := strings.Split(msg.Params[1], ",")
138
 	targets := strings.Split(msg.Params[1], ",")
81
-	for len(targets) > 0 {
82
-		// check name length
83
-		if len(targets[0]) < 1 {
84
-			targets = targets[1:]
85
-			continue
86
-		}
87
-
88
-		// remove target
89
-		casefoldedTarget, err := CasefoldName(targets[0])
139
+	for _, target := range targets {
140
+		cfnick, err := CasefoldName(target)
90
 		if err != nil {
141
 		if err != nil {
91
-			// skip silently I guess
92
-			targets = targets[1:]
93
 			continue
142
 			continue
94
 		}
143
 		}
95
-
96
-		client.monitoringMutex.Lock()
97
-		client.server.monitoringMutex.Lock()
98
-
99
-		if client.monitoring[casefoldedTarget] {
100
-			// just removes current client from the list
101
-			orig := server.monitoring[casefoldedTarget]
102
-			var index int
103
-			for i, cli := range orig {
104
-				if cli == client {
105
-					index = i
106
-					break
107
-				}
108
-			}
109
-			server.monitoring[casefoldedTarget] = append(orig[:index], orig[index+1:]...)
110
-
111
-			delete(client.monitoring, casefoldedTarget)
112
-		}
113
-
114
-		client.monitoringMutex.Unlock()
115
-		client.server.monitoringMutex.Unlock()
116
-
117
-		// remove first element of targets list
118
-		targets = targets[1:]
144
+		server.monitorManager.removeMonitor(client, cfnick)
119
 	}
145
 	}
120
 
146
 
121
 	return false
147
 	return false
123
 
149
 
124
 func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
150
 func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
125
 	if len(msg.Params) < 2 {
151
 	if len(msg.Params) < 2 {
126
-		client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
152
+		client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.getNick(), msg.Command, "Not enough parameters")
127
 		return false
153
 		return false
128
 	}
154
 	}
129
 
155
 
130
 	var online []string
156
 	var online []string
131
 	var offline []string
157
 	var offline []string
132
 
158
 
159
+	limit := server.getLimits().MonitorEntries
160
+
133
 	targets := strings.Split(msg.Params[1], ",")
161
 	targets := strings.Split(msg.Params[1], ",")
134
-	for len(targets) > 0 {
162
+	for _, target := range targets {
135
 		// check name length
163
 		// check name length
136
-		if len(targets[0]) < 1 || len(targets[0]) > server.limits.NickLen {
137
-			targets = targets[1:]
164
+		if len(target) < 1 || len(targets) > server.limits.NickLen {
138
 			continue
165
 			continue
139
 		}
166
 		}
140
 
167
 
141
-		// check the monitor list length
142
-		if len(client.monitoring) >= server.limits.MonitorEntries {
143
-			client.Send(nil, server.name, ERR_MONLISTFULL, client.nick, strconv.Itoa(server.limits.MonitorEntries), strings.Join(targets, ","))
144
-			break
145
-		}
146
-
147
 		// add target
168
 		// add target
148
 		casefoldedTarget, err := CasefoldName(targets[0])
169
 		casefoldedTarget, err := CasefoldName(targets[0])
149
 		if err != nil {
170
 		if err != nil {
150
-			// skip silently I guess
151
-			targets = targets[1:]
152
 			continue
171
 			continue
153
 		}
172
 		}
154
 
173
 
155
-		client.monitoringMutex.Lock()
156
-		client.server.monitoringMutex.Lock()
157
-
158
-		if !client.monitoring[casefoldedTarget] {
159
-			client.monitoring[casefoldedTarget] = true
160
-
161
-			orig := server.monitoring[casefoldedTarget]
162
-			server.monitoring[casefoldedTarget] = append(orig, client)
174
+		err = server.monitorManager.addMonitor(client, casefoldedTarget, limit)
175
+		if err == MonitorLimitExceeded {
176
+			client.Send(nil, server.name, ERR_MONLISTFULL, client.getNick(), strconv.Itoa(server.limits.MonitorEntries), strings.Join(targets, ","))
177
+			break
178
+		} else if err != nil {
179
+			continue
163
 		}
180
 		}
164
 
181
 
165
-		client.monitoringMutex.Unlock()
166
-		client.server.monitoringMutex.Unlock()
167
-
168
 		// add to online / offline lists
182
 		// add to online / offline lists
169
-		target := server.clients.Get(casefoldedTarget)
170
-		if target == nil {
183
+		if target := server.clients.Get(casefoldedTarget); target == nil {
171
 			offline = append(offline, targets[0])
184
 			offline = append(offline, targets[0])
172
 		} else {
185
 		} else {
173
-			online = append(online, target.nickMaskString)
186
+			online = append(online, target.getNick())
174
 		}
187
 		}
175
-
176
-		// remove first element of targets list
177
-		targets = targets[1:]
178
 	}
188
 	}
179
 
189
 
180
 	if len(online) > 0 {
190
 	if len(online) > 0 {
181
-		client.Send(nil, server.name, RPL_MONONLINE, client.nick, strings.Join(online, ","))
191
+		client.Send(nil, server.name, RPL_MONONLINE, client.getNick(), strings.Join(online, ","))
182
 	}
192
 	}
183
 	if len(offline) > 0 {
193
 	if len(offline) > 0 {
184
-		client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, strings.Join(offline, ","))
194
+		client.Send(nil, server.name, RPL_MONOFFLINE, client.getNick(), strings.Join(offline, ","))
185
 	}
195
 	}
186
 
196
 
187
 	return false
197
 	return false
188
 }
198
 }
189
 
199
 
190
 func monitorClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
200
 func monitorClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
191
-	client.clearMonitorList()
192
-
201
+	server.monitorManager.clearMonitorList(client)
193
 	return false
202
 	return false
194
 }
203
 }
195
 
204
 
196
 func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
205
 func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
197
-	var monitorList []string
198
-	client.monitoringMutex.RLock()
199
-	for name := range client.monitoring {
200
-		monitorList = append(monitorList, name)
201
-	}
202
-	client.monitoringMutex.RUnlock()
206
+	monitorList := server.monitorManager.listMonitors(client)
203
 
207
 
204
 	for _, line := range argsToStrings(maxLastArgLength, monitorList, ",") {
208
 	for _, line := range argsToStrings(maxLastArgLength, monitorList, ",") {
205
-		client.Send(nil, server.name, RPL_MONLIST, client.nick, line)
209
+		client.Send(nil, server.name, RPL_MONLIST, client.getNick(), line)
206
 	}
210
 	}
207
 
211
 
212
+	client.Send(nil, server.name, RPL_ENDOFMONLIST, "End of MONITOR list")
213
+
208
 	return false
214
 	return false
209
 }
215
 }
210
 
216
 
212
 	var online []string
218
 	var online []string
213
 	var offline []string
219
 	var offline []string
214
 
220
 
215
-	client.monitoringMutex.RLock()
216
-	monitoring := client.monitoring
217
-	client.monitoringMutex.RUnlock()
221
+	monitorList := server.monitorManager.listMonitors(client)
218
 
222
 
219
-	for name := range monitoring {
223
+	for _, name := range monitorList {
220
 		target := server.clients.Get(name)
224
 		target := server.clients.Get(name)
221
 		if target == nil {
225
 		if target == nil {
222
 			offline = append(offline, name)
226
 			offline = append(offline, name)
223
 		} else {
227
 		} else {
224
-			online = append(online, target.nickMaskString)
228
+			online = append(online, target.getNick())
225
 		}
229
 		}
226
 	}
230
 	}
227
 
231
 
228
 	if len(online) > 0 {
232
 	if len(online) > 0 {
229
 		for _, line := range argsToStrings(maxLastArgLength, online, ",") {
233
 		for _, line := range argsToStrings(maxLastArgLength, online, ",") {
230
-			client.Send(nil, server.name, RPL_MONONLINE, client.nick, line)
234
+			client.Send(nil, server.name, RPL_MONONLINE, client.getNick(), line)
231
 		}
235
 		}
232
 	}
236
 	}
233
 	if len(offline) > 0 {
237
 	if len(offline) > 0 {
234
 		for _, line := range argsToStrings(maxLastArgLength, offline, ",") {
238
 		for _, line := range argsToStrings(maxLastArgLength, offline, ",") {
235
-			client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, line)
239
+			client.Send(nil, server.name, RPL_MONOFFLINE, client.getNick(), line)
236
 		}
240
 		}
237
 	}
241
 	}
238
 
242
 

+ 1
- 1
irc/nickname.go View File

57
 		return false
57
 		return false
58
 	}
58
 	}
59
 	if client.registered {
59
 	if client.registered {
60
-		client.alertMonitors()
60
+		client.server.monitorManager.alertMonitors(client, true)
61
 	}
61
 	}
62
 	server.tryRegister(client)
62
 	server.tryRegister(client)
63
 	return false
63
 	return false

+ 18
- 25
irc/server.go View File

94
 	connectionThrottle           *ConnectionThrottle
94
 	connectionThrottle           *ConnectionThrottle
95
 	connectionThrottleMutex      sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack
95
 	connectionThrottleMutex      sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack
96
 	ctime                        time.Time
96
 	ctime                        time.Time
97
-	currentOpers                 map[*Client]bool
98
 	defaultChannelModes          Modes
97
 	defaultChannelModes          Modes
99
 	dlines                       *DLineManager
98
 	dlines                       *DLineManager
100
 	isupport                     *ISupportList
99
 	isupport                     *ISupportList
103
 	listeners                    map[string]*ListenerWrapper
102
 	listeners                    map[string]*ListenerWrapper
104
 	logger                       *logger.Manager
103
 	logger                       *logger.Manager
105
 	MaxSendQBytes                uint64
104
 	MaxSendQBytes                uint64
106
-	monitoring                   map[string][]*Client
107
-	monitoringMutex              sync.RWMutex
105
+	monitorManager               *MonitorManager
108
 	motdLines                    []string
106
 	motdLines                    []string
109
 	name                         string
107
 	name                         string
110
 	nameCasefolded               string
108
 	nameCasefolded               string
155
 		channels:           *NewChannelNameMap(),
153
 		channels:           *NewChannelNameMap(),
156
 		clients:            NewClientLookupSet(),
154
 		clients:            NewClientLookupSet(),
157
 		commands:           make(chan Command),
155
 		commands:           make(chan Command),
158
-		currentOpers:       make(map[*Client]bool),
159
 		listeners:          make(map[string]*ListenerWrapper),
156
 		listeners:          make(map[string]*ListenerWrapper),
160
 		logger:             logger,
157
 		logger:             logger,
161
-		monitoring:         make(map[string][]*Client),
158
+		monitorManager:     NewMonitorManager(),
162
 		newConns:           make(chan clientConn),
159
 		newConns:           make(chan clientConn),
163
 		registeredChannels: make(map[string]*RegisteredChannel),
160
 		registeredChannels: make(map[string]*RegisteredChannel),
164
 		rehashSignal:       make(chan os.Signal, 1),
161
 		rehashSignal:       make(chan os.Signal, 1),
1143
 		client.Send(nil, server.name, ERR_UNKNOWNERROR, "OPER", "You're already opered-up!")
1140
 		client.Send(nil, server.name, ERR_UNKNOWNERROR, "OPER", "You're already opered-up!")
1144
 		return false
1141
 		return false
1145
 	}
1142
 	}
1146
-	hash := server.operators[name].Pass
1147
-	password := []byte(msg.Params[1])
1148
-
1149
-	err = ComparePassword(hash, password)
1143
+	server.configurableStateMutex.RLock()
1144
+	oper := server.operators[name]
1145
+	server.configurableStateMutex.RUnlock()
1150
 
1146
 
1151
-	if (hash == nil) || (err != nil) {
1147
+	password := []byte(msg.Params[1])
1148
+	err = ComparePassword(oper.Pass, password)
1149
+	if (oper.Pass == nil) || (err != nil) {
1152
 		client.Send(nil, server.name, ERR_PASSWDMISMATCH, client.nick, "Password incorrect")
1150
 		client.Send(nil, server.name, ERR_PASSWDMISMATCH, client.nick, "Password incorrect")
1153
 		return true
1151
 		return true
1154
 	}
1152
 	}
1155
 
1153
 
1156
 	client.flags[Operator] = true
1154
 	client.flags[Operator] = true
1157
 	client.operName = name
1155
 	client.operName = name
1158
-	client.class = server.operators[name].Class
1159
-	server.currentOpers[client] = true
1160
-	client.whoisLine = server.operators[name].WhoisLine
1156
+	client.class = oper.Class
1157
+	client.whoisLine = oper.WhoisLine
1161
 
1158
 
1162
 	// push new vhost if one is set
1159
 	// push new vhost if one is set
1163
-	if len(server.operators[name].Vhost) > 0 {
1160
+	if len(oper.Vhost) > 0 {
1164
 		for fClient := range client.Friends(caps.ChgHost) {
1161
 		for fClient := range client.Friends(caps.ChgHost) {
1165
-			fClient.SendFromClient("", client, nil, "CHGHOST", client.username, server.operators[name].Vhost)
1162
+			fClient.SendFromClient("", client, nil, "CHGHOST", client.username, oper.Vhost)
1166
 		}
1163
 		}
1167
 		// CHGHOST requires prefix nickmask to have original hostname, so do that before updating nickmask
1164
 		// CHGHOST requires prefix nickmask to have original hostname, so do that before updating nickmask
1168
-		client.vhost = server.operators[name].Vhost
1169
-		client.updateNickMask()
1165
+		client.vhost = oper.Vhost
1166
+		client.updateNickMask("")
1170
 	}
1167
 	}
1171
 
1168
 
1172
 	// set new modes
1169
 	// set new modes
1173
 	var applied ModeChanges
1170
 	var applied ModeChanges
1174
-	if 0 < len(server.operators[name].Modes) {
1175
-		modeChanges, unknownChanges := ParseUserModeChanges(strings.Split(server.operators[name].Modes, " ")...)
1171
+	if 0 < len(oper.Modes) {
1172
+		modeChanges, unknownChanges := ParseUserModeChanges(strings.Split(oper.Modes, " ")...)
1176
 		applied = client.applyUserModeChanges(true, modeChanges)
1173
 		applied = client.applyUserModeChanges(true, modeChanges)
1177
 		if 0 < len(unknownChanges) {
1174
 		if 0 < len(unknownChanges) {
1178
 			var runes string
1175
 			var runes string
1257
 	if err != nil {
1254
 	if err != nil {
1258
 		return fmt.Errorf("Error rehashing config file opers: %s", err.Error())
1255
 		return fmt.Errorf("Error rehashing config file opers: %s", err.Error())
1259
 	}
1256
 	}
1260
-	for client := range server.currentOpers {
1261
-		_, exists := opers[client.operName]
1262
-		if !exists {
1263
-			return fmt.Errorf("Oper [%s] no longer exists (used by client [%s])", client.operName, client.nickMaskString)
1264
-		}
1265
-	}
1257
+
1258
+	// TODO: support rehash of existing operator perms?
1266
 
1259
 
1267
 	// sanity checks complete, start modifying server state
1260
 	// sanity checks complete, start modifying server state
1268
 
1261
 

Loading…
Cancel
Save