Bladeren bron

Merge remote-tracking branch 'origin/master' into cleanup

Conflicts:
	irc/client.go
	irc/commands.go
	irc/constants.go
	irc/reply.go
	irc/server.go
	irc/types.go
tags/v0.1.0
Jeremy Latt 10 jaren geleden
bovenliggende
commit
39b7c2a915
12 gewijzigde bestanden met toevoegingen van 323 en 268 verwijderingen
  1. 26
    28
      irc/channel.go
  2. 15
    19
      irc/client.go
  3. 24
    24
      irc/client_lookup_set.go
  4. 117
    118
      irc/commands.go
  5. 3
    3
      irc/config.go
  6. 0
    6
      irc/constants.go
  7. 8
    8
      irc/net.go
  8. 27
    27
      irc/reply.go
  9. 23
    21
      irc/server.go
  10. 66
    0
      irc/strings.go
  11. 9
    9
      irc/types.go
  12. 5
    5
      irc/whowas.go

+ 26
- 28
irc/channel.go Bestand weergeven

@@ -3,27 +3,22 @@ package irc
3 3
 import (
4 4
 	"log"
5 5
 	"strconv"
6
-	"strings"
7 6
 )
8 7
 
9 8
 type Channel struct {
10 9
 	flags     ChannelModeSet
11 10
 	lists     map[ChannelMode]*UserMaskSet
12
-	key       string
11
+	key       Text
13 12
 	members   MemberSet
14
-	name      string
13
+	name      Name
15 14
 	server    *Server
16
-	topic     string
15
+	topic     Text
17 16
 	userLimit uint64
18 17
 }
19 18
 
20
-func IsChannel(target string) bool {
21
-	return ChannelNameExpr.MatchString(target)
22
-}
23
-
24 19
 // NewChannel creates a new channel from a `Server` and a `name`
25 20
 // string, which must be unique on the server.
26
-func NewChannel(s *Server, name string) *Channel {
21
+func NewChannel(s *Server, name Name) *Channel {
27 22
 	channel := &Channel{
28 23
 		flags: make(ChannelModeSet),
29 24
 		lists: map[ChannelMode]*UserMaskSet{
@@ -32,7 +27,7 @@ func NewChannel(s *Server, name string) *Channel {
32 27
 			InviteMask: NewUserMaskSet(),
33 28
 		},
34 29
 		members: make(MemberSet),
35
-		name:    strings.ToLower(name),
30
+		name:    name,
36 31
 		server:  s,
37 32
 	}
38 33
 
@@ -73,22 +68,22 @@ func (channel *Channel) Nicks(target *Client) []string {
73 68
 				nicks[i] += "+"
74 69
 			}
75 70
 		}
76
-		nicks[i] += client.Nick()
71
+		nicks[i] += client.Nick().String()
77 72
 		i += 1
78 73
 	}
79 74
 	return nicks
80 75
 }
81 76
 
82
-func (channel *Channel) Id() string {
77
+func (channel *Channel) Id() Name {
83 78
 	return channel.name
84 79
 }
85 80
 
86
-func (channel *Channel) Nick() string {
81
+func (channel *Channel) Nick() Name {
87 82
 	return channel.name
88 83
 }
89 84
 
90 85
 func (channel *Channel) String() string {
91
-	return channel.Id()
86
+	return channel.Id().String()
92 87
 }
93 88
 
94 89
 // <mode> <mode params>
@@ -117,7 +112,7 @@ func (channel *Channel) ModeString(client *Client) (str string) {
117 112
 	// args for flags with args: The order must match above to keep
118 113
 	// positional arguments in place.
119 114
 	if showKey {
120
-		str += " " + channel.key
115
+		str += " " + channel.key.String()
121 116
 	}
122 117
 	if showUserLimit {
123 118
 		str += " " + strconv.FormatUint(channel.userLimit, 10)
@@ -131,11 +126,11 @@ func (channel *Channel) IsFull() bool {
131 126
 		(uint64(len(channel.members)) >= channel.userLimit)
132 127
 }
133 128
 
134
-func (channel *Channel) CheckKey(key string) bool {
129
+func (channel *Channel) CheckKey(key Text) bool {
135 130
 	return (channel.key == "") || (channel.key == key)
136 131
 }
137 132
 
138
-func (channel *Channel) Join(client *Client, key string) {
133
+func (channel *Channel) Join(client *Client, key Text) {
139 134
 	if channel.members.Has(client) {
140 135
 		// already joined, no message?
141 136
 		return
@@ -179,7 +174,7 @@ func (channel *Channel) Join(client *Client, key string) {
179 174
 	channel.Names(client)
180 175
 }
181 176
 
182
-func (channel *Channel) Part(client *Client, message string) {
177
+func (channel *Channel) Part(client *Client, message Text) {
183 178
 	if !channel.members.Has(client) {
184 179
 		client.ErrNotOnChannel(channel)
185 180
 		return
@@ -207,7 +202,7 @@ func (channel *Channel) GetTopic(client *Client) {
207 202
 	client.RplTopic(channel)
208 203
 }
209 204
 
210
-func (channel *Channel) SetTopic(client *Client, topic string) {
205
+func (channel *Channel) SetTopic(client *Client, topic Text) {
211 206
 	if !(client.flags[Operator] || channel.members.Has(client)) {
212 207
 		client.ErrNotOnChannel(channel)
213 208
 		return
@@ -244,7 +239,7 @@ func (channel *Channel) CanSpeak(client *Client) bool {
244 239
 	return true
245 240
 }
246 241
 
247
-func (channel *Channel) PrivMsg(client *Client, message string) {
242
+func (channel *Channel) PrivMsg(client *Client, message Text) {
248 243
 	if !channel.CanSpeak(client) {
249 244
 		client.ErrCannotSendToChan(channel)
250 245
 		return
@@ -283,7 +278,7 @@ func (channel *Channel) applyModeFlag(client *Client, mode ChannelMode,
283 278
 }
284 279
 
285 280
 func (channel *Channel) applyModeMember(client *Client, mode ChannelMode,
286
-	op ModeOp, nick string) bool {
281
+	op ModeOp, nick Name) bool {
287 282
 	if !channel.ClientIsOperator(client) {
288 283
 		client.ErrChanOPrivIsNeeded(channel)
289 284
 		return false
@@ -331,7 +326,7 @@ func (channel *Channel) ShowMaskList(client *Client, mode ChannelMode) {
331 326
 }
332 327
 
333 328
 func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeOp,
334
-	mask string) bool {
329
+	mask Name) bool {
335 330
 	list := channel.lists[mode]
336 331
 	if list == nil {
337 332
 		// This should never happen, but better safe than panicky.
@@ -362,7 +357,8 @@ func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeO
362 357
 func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) bool {
363 358
 	switch change.mode {
364 359
 	case BanMask, ExceptMask, InviteMask:
365
-		return channel.applyModeMask(client, change.mode, change.op, change.arg)
360
+		return channel.applyModeMask(client, change.mode, change.op,
361
+			NewName(change.arg))
366 362
 
367 363
 	case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Persistent, Private:
368 364
 		return channel.applyModeFlag(client, change.mode, change.op)
@@ -379,11 +375,12 @@ func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) boo
379 375
 				client.ErrNeedMoreParams("MODE")
380 376
 				return false
381 377
 			}
382
-			if change.arg == channel.key {
378
+			key := NewText(change.arg)
379
+			if key == channel.key {
383 380
 				return false
384 381
 			}
385 382
 
386
-			channel.key = change.arg
383
+			channel.key = key
387 384
 			return true
388 385
 
389 386
 		case Remove:
@@ -405,7 +402,8 @@ func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) boo
405 402
 		return true
406 403
 
407 404
 	case ChannelOperator, Voice:
408
-		return channel.applyModeMember(client, change.mode, change.op, change.arg)
405
+		return channel.applyModeMember(client, change.mode, change.op,
406
+			NewName(change.arg))
409 407
 
410 408
 	default:
411 409
 		client.ErrUnknownMode(change.mode, channel)
@@ -456,7 +454,7 @@ func (channel *Channel) Persist() (err error) {
456 454
 	return
457 455
 }
458 456
 
459
-func (channel *Channel) Notice(client *Client, message string) {
457
+func (channel *Channel) Notice(client *Client, message Text) {
460 458
 	if !channel.CanSpeak(client) {
461 459
 		client.ErrCannotSendToChan(channel)
462 460
 		return
@@ -478,7 +476,7 @@ func (channel *Channel) Quit(client *Client) {
478 476
 	}
479 477
 }
480 478
 
481
-func (channel *Channel) Kick(client *Client, target *Client, comment string) {
479
+func (channel *Channel) Kick(client *Client, target *Client, comment Text) {
482 480
 	if !(client.flags[Operator] || channel.members.Has(client)) {
483 481
 		client.ErrNotOnChannel(channel)
484 482
 		return

+ 15
- 19
irc/client.go Bestand weergeven

@@ -12,14 +12,10 @@ const (
12 12
 	QUIT_TIMEOUT  = time.Minute     // how long after idle before a client is kicked
13 13
 )
14 14
 
15
-func IsNickname(nick string) bool {
16
-	return NicknameExpr.MatchString(nick)
17
-}
18
-
19 15
 type Client struct {
20 16
 	atime        time.Time
21 17
 	authorized   bool
22
-	awayMessage  string
18
+	awayMessage  Text
23 19
 	capabilities CapabilitySet
24 20
 	capState     CapState
25 21
 	channels     ChannelSet
@@ -28,16 +24,16 @@ type Client struct {
28 24
 	flags        map[UserMode]bool
29 25
 	hasQuit      bool
30 26
 	hops         uint
31
-	hostname     string
27
+	hostname     Name
32 28
 	idleTimer    *time.Timer
33 29
 	loginTimer   *time.Timer
34
-	nick         string
30
+	nick         Name
35 31
 	quitTimer    *time.Timer
36
-	realname     string
32
+	realname     Text
37 33
 	registered   bool
38 34
 	server       *Server
39 35
 	socket       *Socket
40
-	username     string
36
+	username     Name
41 37
 }
42 38
 
43 39
 func NewClient(server *Server, conn net.Conn) *Client {
@@ -191,27 +187,27 @@ func (c *Client) ModeString() (str string) {
191 187
 	return
192 188
 }
193 189
 
194
-func (c *Client) UserHost() string {
190
+func (c *Client) UserHost() Name {
195 191
 	username := "*"
196 192
 	if c.HasUsername() {
197
-		username = c.username
193
+		username = c.username.String()
198 194
 	}
199
-	return fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostname)
195
+	return Name(fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostname))
200 196
 }
201 197
 
202
-func (c *Client) Nick() string {
198
+func (c *Client) Nick() Name {
203 199
 	if c.HasNick() {
204 200
 		return c.nick
205 201
 	}
206
-	return "*"
202
+	return Name("*")
207 203
 }
208 204
 
209
-func (c *Client) Id() string {
205
+func (c *Client) Id() Name {
210 206
 	return c.UserHost()
211 207
 }
212 208
 
213 209
 func (c *Client) String() string {
214
-	return c.Id()
210
+	return c.Id().String()
215 211
 }
216 212
 
217 213
 func (client *Client) Friends() ClientSet {
@@ -225,12 +221,12 @@ func (client *Client) Friends() ClientSet {
225 221
 	return friends
226 222
 }
227 223
 
228
-func (client *Client) SetNickname(nickname string) {
224
+func (client *Client) SetNickname(nickname Name) {
229 225
 	client.nick = nickname
230 226
 	client.server.clients.Add(client)
231 227
 }
232 228
 
233
-func (client *Client) ChangeNickname(nickname string) {
229
+func (client *Client) ChangeNickname(nickname Name) {
234 230
 	// Make reply before changing nick to capture original source id.
235 231
 	reply := RplNick(client, nickname)
236 232
 	client.server.clients.Remove(client)
@@ -249,7 +245,7 @@ func (client *Client) Reply(reply string, args ...interface{}) {
249 245
 	client.socket.Write(reply)
250 246
 }
251 247
 
252
-func (client *Client) Quit(message string) {
248
+func (client *Client) Quit(message Text) {
253 249
 	if client.hasQuit {
254 250
 		return
255 251
 	}

+ 24
- 24
irc/client_lookup_set.go Bestand weergeven

@@ -25,36 +25,36 @@ func HasWildcards(mask string) bool {
25 25
 	return wildMaskExpr.MatchString(mask)
26 26
 }
27 27
 
28
-func ExpandUserHost(userhost string) (expanded string) {
28
+func ExpandUserHost(userhost Name) (expanded Name) {
29 29
 	expanded = userhost
30 30
 	// fill in missing wildcards for nicks
31
-	if !strings.Contains(expanded, "!") {
31
+	if !strings.Contains(expanded.String(), "!") {
32 32
 		expanded += "!*"
33 33
 	}
34
-	if !strings.Contains(expanded, "@") {
34
+	if !strings.Contains(expanded.String(), "@") {
35 35
 		expanded += "@*"
36 36
 	}
37 37
 	return
38 38
 }
39 39
 
40
-func QuoteLike(userhost string) string {
41
-	return likeQuoter.Replace(userhost)
40
+func QuoteLike(userhost Name) Name {
41
+	return Name(likeQuoter.Replace(userhost.String()))
42 42
 }
43 43
 
44 44
 type ClientLookupSet struct {
45
-	byNick map[string]*Client
45
+	byNick map[Name]*Client
46 46
 	db     *ClientDB
47 47
 }
48 48
 
49 49
 func NewClientLookupSet() *ClientLookupSet {
50 50
 	return &ClientLookupSet{
51
-		byNick: make(map[string]*Client),
51
+		byNick: make(map[Name]*Client),
52 52
 		db:     NewClientDB(),
53 53
 	}
54 54
 }
55 55
 
56
-func (clients *ClientLookupSet) Get(nick string) *Client {
57
-	return clients.byNick[strings.ToLower(nick)]
56
+func (clients *ClientLookupSet) Get(nick Name) *Client {
57
+	return clients.byNick[nick.ToLower()]
58 58
 }
59 59
 
60 60
 func (clients *ClientLookupSet) Add(client *Client) error {
@@ -64,7 +64,7 @@ func (clients *ClientLookupSet) Add(client *Client) error {
64 64
 	if clients.Get(client.nick) != nil {
65 65
 		return ErrNicknameInUse
66 66
 	}
67
-	clients.byNick[strings.ToLower(client.nick)] = client
67
+	clients.byNick[client.Nick().ToLower()] = client
68 68
 	clients.db.Add(client)
69 69
 	return nil
70 70
 }
@@ -76,12 +76,12 @@ func (clients *ClientLookupSet) Remove(client *Client) error {
76 76
 	if clients.Get(client.nick) != client {
77 77
 		return ErrNicknameMismatch
78 78
 	}
79
-	delete(clients.byNick, strings.ToLower(client.nick))
79
+	delete(clients.byNick, client.nick.ToLower())
80 80
 	clients.db.Remove(client)
81 81
 	return nil
82 82
 }
83 83
 
84
-func (clients *ClientLookupSet) FindAll(userhost string) (set ClientSet) {
84
+func (clients *ClientLookupSet) FindAll(userhost Name) (set ClientSet) {
85 85
 	userhost = ExpandUserHost(userhost)
86 86
 	set = make(ClientSet)
87 87
 	rows, err := clients.db.db.Query(
@@ -92,7 +92,7 @@ func (clients *ClientLookupSet) FindAll(userhost string) (set ClientSet) {
92 92
 		return
93 93
 	}
94 94
 	for rows.Next() {
95
-		var nickname string
95
+		var nickname Name
96 96
 		err := rows.Scan(&nickname)
97 97
 		if err != nil {
98 98
 			Log.error.Println("ClientLookupSet.FindAll.Scan:", err)
@@ -108,12 +108,12 @@ func (clients *ClientLookupSet) FindAll(userhost string) (set ClientSet) {
108 108
 	return
109 109
 }
110 110
 
111
-func (clients *ClientLookupSet) Find(userhost string) *Client {
111
+func (clients *ClientLookupSet) Find(userhost Name) *Client {
112 112
 	userhost = ExpandUserHost(userhost)
113 113
 	row := clients.db.db.QueryRow(
114 114
 		`SELECT nickname FROM client WHERE userhost LIKE ? ESCAPE '\' LIMIT 1`,
115 115
 		QuoteLike(userhost))
116
-	var nickname string
116
+	var nickname Name
117 117
 	err := row.Scan(&nickname)
118 118
 	if err != nil {
119 119
 		Log.error.Println("ClientLookupSet.Find:", err)
@@ -172,17 +172,17 @@ func (db *ClientDB) Remove(client *Client) {
172 172
 //
173 173
 
174 174
 type UserMaskSet struct {
175
-	masks  map[string]bool
175
+	masks  map[Name]bool
176 176
 	regexp *regexp.Regexp
177 177
 }
178 178
 
179 179
 func NewUserMaskSet() *UserMaskSet {
180 180
 	return &UserMaskSet{
181
-		masks: make(map[string]bool),
181
+		masks: make(map[Name]bool),
182 182
 	}
183 183
 }
184 184
 
185
-func (set *UserMaskSet) Add(mask string) bool {
185
+func (set *UserMaskSet) Add(mask Name) bool {
186 186
 	if set.masks[mask] {
187 187
 		return false
188 188
 	}
@@ -191,7 +191,7 @@ func (set *UserMaskSet) Add(mask string) bool {
191 191
 	return true
192 192
 }
193 193
 
194
-func (set *UserMaskSet) AddAll(masks []string) (added bool) {
194
+func (set *UserMaskSet) AddAll(masks []Name) (added bool) {
195 195
 	for _, mask := range masks {
196 196
 		if !added && !set.masks[mask] {
197 197
 			added = true
@@ -202,7 +202,7 @@ func (set *UserMaskSet) AddAll(masks []string) (added bool) {
202 202
 	return
203 203
 }
204 204
 
205
-func (set *UserMaskSet) Remove(mask string) bool {
205
+func (set *UserMaskSet) Remove(mask Name) bool {
206 206
 	if !set.masks[mask] {
207 207
 		return false
208 208
 	}
@@ -211,18 +211,18 @@ func (set *UserMaskSet) Remove(mask string) bool {
211 211
 	return true
212 212
 }
213 213
 
214
-func (set *UserMaskSet) Match(userhost string) bool {
214
+func (set *UserMaskSet) Match(userhost Name) bool {
215 215
 	if set.regexp == nil {
216 216
 		return false
217 217
 	}
218
-	return set.regexp.MatchString(userhost)
218
+	return set.regexp.MatchString(userhost.String())
219 219
 }
220 220
 
221 221
 func (set *UserMaskSet) String() string {
222 222
 	masks := make([]string, len(set.masks))
223 223
 	index := 0
224 224
 	for mask := range set.masks {
225
-		masks[index] = mask
225
+		masks[index] = mask.String()
226 226
 		index += 1
227 227
 	}
228 228
 	return strings.Join(masks, " ")
@@ -243,7 +243,7 @@ func (set *UserMaskSet) setRegexp() {
243 243
 	maskExprs := make([]string, len(set.masks))
244 244
 	index := 0
245 245
 	for mask := range set.masks {
246
-		manyParts := strings.Split(mask, "*")
246
+		manyParts := strings.Split(mask.String(), "*")
247 247
 		manyExprs := make([]string, len(manyParts))
248 248
 		for mindex, manyPart := range manyParts {
249 249
 			oneParts := strings.Split(manyPart, "?")

+ 117
- 118
irc/commands.go Bestand weergeven

@@ -1,7 +1,6 @@
1 1
 package irc
2 2
 
3 3
 import (
4
-	"code.google.com/p/go.text/unicode/norm"
5 4
 	"errors"
6 5
 	"fmt"
7 6
 	"regexp"
@@ -115,14 +114,14 @@ func ParseLine(line string) (command StringCode, args []string) {
115 114
 		_, line = splitArg(line)
116 115
 	}
117 116
 	arg, line := splitArg(line)
118
-	command = StringCode(strings.ToUpper(arg))
117
+	command = StringCode(NewName(strings.ToUpper(arg)))
119 118
 	for len(line) > 0 {
120 119
 		if strings.HasPrefix(line, ":") {
121
-			args = append(args, norm.NFC.String(line[len(":"):]))
120
+			args = append(args, line[len(":"):])
122 121
 			break
123 122
 		}
124 123
 		arg, line = splitArg(line)
125
-		args = append(args, norm.NFKC.String(arg))
124
+		args = append(args, arg)
126 125
 	}
127 126
 	return
128 127
 }
@@ -148,8 +147,8 @@ func NewUnknownCommand(args []string) *UnknownCommand {
148 147
 
149 148
 type PingCommand struct {
150 149
 	BaseCommand
151
-	server  string
152
-	server2 string
150
+	server  Name
151
+	server2 Name
153 152
 }
154 153
 
155 154
 func (cmd *PingCommand) String() string {
@@ -161,10 +160,10 @@ func NewPingCommand(args []string) (Command, error) {
161 160
 		return nil, NotEnoughArgsError
162 161
 	}
163 162
 	msg := &PingCommand{
164
-		server: args[0],
163
+		server: NewName(args[0]),
165 164
 	}
166 165
 	if len(args) > 1 {
167
-		msg.server2 = args[1]
166
+		msg.server2 = NewName(args[1])
168 167
 	}
169 168
 	return msg, nil
170 169
 }
@@ -173,8 +172,8 @@ func NewPingCommand(args []string) (Command, error) {
173 172
 
174 173
 type PongCommand struct {
175 174
 	BaseCommand
176
-	server1 string
177
-	server2 string
175
+	server1 Name
176
+	server2 Name
178 177
 }
179 178
 
180 179
 func (cmd *PongCommand) String() string {
@@ -186,10 +185,10 @@ func NewPongCommand(args []string) (Command, error) {
186 185
 		return nil, NotEnoughArgsError
187 186
 	}
188 187
 	message := &PongCommand{
189
-		server1: args[0],
188
+		server1: NewName(args[0]),
190 189
 	}
191 190
 	if len(args) > 1 {
192
-		message.server2 = args[1]
191
+		message.server2 = NewName(args[1])
193 192
 	}
194 193
 	return message, nil
195 194
 }
@@ -231,7 +230,7 @@ func NewPassCommand(args []string) (Command, error) {
231 230
 
232 231
 type NickCommand struct {
233 232
 	BaseCommand
234
-	nickname string
233
+	nickname Name
235 234
 }
236 235
 
237 236
 func (m *NickCommand) String() string {
@@ -243,21 +242,21 @@ func NewNickCommand(args []string) (Command, error) {
243 242
 		return nil, NotEnoughArgsError
244 243
 	}
245 244
 	return &NickCommand{
246
-		nickname: args[0],
245
+		nickname: NewName(args[0]),
247 246
 	}, nil
248 247
 }
249 248
 
250 249
 type UserCommand struct {
251 250
 	BaseCommand
252
-	username string
253
-	realname string
251
+	username Name
252
+	realname Text
254 253
 }
255 254
 
256 255
 // USER <username> <hostname> <servername> <realname>
257 256
 type RFC1459UserCommand struct {
258 257
 	UserCommand
259
-	hostname   string
260
-	servername string
258
+	hostname   Name
259
+	servername Name
261 260
 }
262 261
 
263 262
 func (cmd *RFC1459UserCommand) String() string {
@@ -298,17 +297,17 @@ func NewUserCommand(args []string) (Command, error) {
298 297
 			mode:   uint8(mode),
299 298
 			unused: args[2],
300 299
 		}
301
-		msg.username = args[0]
302
-		msg.realname = args[3]
300
+		msg.username = NewName(args[0])
301
+		msg.realname = NewText(args[3])
303 302
 		return msg, nil
304 303
 	}
305 304
 
306 305
 	msg := &RFC1459UserCommand{
307
-		hostname:   args[1],
308
-		servername: args[2],
306
+		hostname:   NewName(args[1]),
307
+		servername: NewName(args[2]),
309 308
 	}
310
-	msg.username = args[0]
311
-	msg.realname = args[3]
309
+	msg.username = NewName(args[0])
310
+	msg.realname = NewText(args[3])
312 311
 	return msg, nil
313 312
 }
314 313
 
@@ -316,7 +315,7 @@ func NewUserCommand(args []string) (Command, error) {
316 315
 
317 316
 type QuitCommand struct {
318 317
 	BaseCommand
319
-	message string
318
+	message Text
320 319
 }
321 320
 
322 321
 func (cmd *QuitCommand) String() string {
@@ -326,7 +325,7 @@ func (cmd *QuitCommand) String() string {
326 325
 func NewQuitCommand(args []string) (Command, error) {
327 326
 	msg := &QuitCommand{}
328 327
 	if len(args) > 0 {
329
-		msg.message = args[0]
328
+		msg.message = NewText(args[0])
330 329
 	}
331 330
 	return msg, nil
332 331
 }
@@ -335,7 +334,7 @@ func NewQuitCommand(args []string) (Command, error) {
335 334
 
336 335
 type JoinCommand struct {
337 336
 	BaseCommand
338
-	channels map[string]string
337
+	channels map[Name]Text
339 338
 	zero     bool
340 339
 }
341 340
 
@@ -345,7 +344,7 @@ func (cmd *JoinCommand) String() string {
345 344
 
346 345
 func NewJoinCommand(args []string) (Command, error) {
347 346
 	msg := &JoinCommand{
348
-		channels: make(map[string]string),
347
+		channels: make(map[Name]Text),
349 348
 	}
350 349
 
351 350
 	if len(args) == 0 {
@@ -365,7 +364,7 @@ func NewJoinCommand(args []string) (Command, error) {
365 364
 		}
366 365
 	}
367 366
 	for i, channel := range channels {
368
-		msg.channels[channel] = keys[i]
367
+		msg.channels[NewName(channel)] = NewText(keys[i])
369 368
 	}
370 369
 
371 370
 	return msg, nil
@@ -375,13 +374,13 @@ func NewJoinCommand(args []string) (Command, error) {
375 374
 
376 375
 type PartCommand struct {
377 376
 	BaseCommand
378
-	channels []string
379
-	message  string
377
+	channels []Name
378
+	message  Text
380 379
 }
381 380
 
382
-func (cmd *PartCommand) Message() string {
381
+func (cmd *PartCommand) Message() Text {
383 382
 	if cmd.message == "" {
384
-		return cmd.Client().Nick()
383
+		return cmd.Client().Nick().Text()
385 384
 	}
386 385
 	return cmd.message
387 386
 }
@@ -395,10 +394,10 @@ func NewPartCommand(args []string) (Command, error) {
395 394
 		return nil, NotEnoughArgsError
396 395
 	}
397 396
 	msg := &PartCommand{
398
-		channels: strings.Split(args[0], ","),
397
+		channels: NewNames(strings.Split(args[0], ",")),
399 398
 	}
400 399
 	if len(args) > 1 {
401
-		msg.message = args[1]
400
+		msg.message = NewText(args[1])
402 401
 	}
403 402
 	return msg, nil
404 403
 }
@@ -407,8 +406,8 @@ func NewPartCommand(args []string) (Command, error) {
407 406
 
408 407
 type PrivMsgCommand struct {
409 408
 	BaseCommand
410
-	target  string
411
-	message string
409
+	target  Name
410
+	message Text
412 411
 }
413 412
 
414 413
 func (cmd *PrivMsgCommand) String() string {
@@ -420,8 +419,8 @@ func NewPrivMsgCommand(args []string) (Command, error) {
420 419
 		return nil, NotEnoughArgsError
421 420
 	}
422 421
 	return &PrivMsgCommand{
423
-		target:  args[0],
424
-		message: args[1],
422
+		target:  NewName(args[0]),
423
+		message: NewText(args[1]),
425 424
 	}, nil
426 425
 }
427 426
 
@@ -429,9 +428,9 @@ func NewPrivMsgCommand(args []string) (Command, error) {
429 428
 
430 429
 type TopicCommand struct {
431 430
 	BaseCommand
432
-	channel  string
431
+	channel  Name
433 432
 	setTopic bool
434
-	topic    string
433
+	topic    Text
435 434
 }
436 435
 
437 436
 func (cmd *TopicCommand) String() string {
@@ -443,11 +442,11 @@ func NewTopicCommand(args []string) (Command, error) {
443 442
 		return nil, NotEnoughArgsError
444 443
 	}
445 444
 	msg := &TopicCommand{
446
-		channel: args[0],
445
+		channel: NewName(args[0]),
447 446
 	}
448 447
 	if len(args) > 1 {
449 448
 		msg.setTopic = true
450
-		msg.topic = args[1]
449
+		msg.topic = NewText(args[1])
451 450
 	}
452 451
 	return msg, nil
453 452
 }
@@ -483,18 +482,18 @@ func (changes ModeChanges) String() string {
483 482
 
484 483
 type ModeCommand struct {
485 484
 	BaseCommand
486
-	nickname string
485
+	nickname Name
487 486
 	changes  ModeChanges
488 487
 }
489 488
 
490 489
 // MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
491
-func NewUserModeCommand(args []string) (Command, error) {
490
+func NewUserModeCommand(nickname Name, args []string) (Command, error) {
492 491
 	cmd := &ModeCommand{
493
-		nickname: args[0],
492
+		nickname: nickname,
494 493
 		changes:  make(ModeChanges, 0),
495 494
 	}
496 495
 
497
-	for _, modeChange := range args[1:] {
496
+	for _, modeChange := range args {
498 497
 		if len(modeChange) == 0 {
499 498
 			continue
500 499
 		}
@@ -560,17 +559,16 @@ func (changes ChannelModeChanges) String() (str string) {
560 559
 
561 560
 type ChannelModeCommand struct {
562 561
 	BaseCommand
563
-	channel string
562
+	channel Name
564 563
 	changes ChannelModeChanges
565 564
 }
566 565
 
567 566
 // MODE <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
568
-func NewChannelModeCommand(args []string) (Command, error) {
567
+func NewChannelModeCommand(channel Name, args []string) (Command, error) {
569 568
 	cmd := &ChannelModeCommand{
570
-		channel: args[0],
569
+		channel: channel,
571 570
 		changes: make(ChannelModeChanges, 0),
572 571
 	}
573
-	args = args[1:]
574 572
 
575 573
 	for len(args) > 0 {
576 574
 		if len(args[0]) == 0 {
@@ -617,17 +615,18 @@ func NewModeCommand(args []string) (Command, error) {
617 615
 		return nil, NotEnoughArgsError
618 616
 	}
619 617
 
620
-	if IsChannel(args[0]) {
621
-		return NewChannelModeCommand(args)
618
+	name := NewName(args[0])
619
+	if name.IsChannel() {
620
+		return NewChannelModeCommand(name, args[1:])
622 621
 	} else {
623
-		return NewUserModeCommand(args)
622
+		return NewUserModeCommand(name, args[1:])
624 623
 	}
625 624
 }
626 625
 
627 626
 type WhoisCommand struct {
628 627
 	BaseCommand
629
-	target string
630
-	masks  []string
628
+	target Name
629
+	masks  []Name
631 630
 }
632 631
 
633 632
 // WHOIS [ <target> ] <mask> *( "," <mask> )
@@ -647,8 +646,8 @@ func NewWhoisCommand(args []string) (Command, error) {
647 646
 	}
648 647
 
649 648
 	return &WhoisCommand{
650
-		target: target,
651
-		masks:  strings.Split(masks, ","),
649
+		target: NewName(target),
650
+		masks:  NewNames(strings.Split(masks, ",")),
652 651
 	}, nil
653 652
 }
654 653
 
@@ -658,7 +657,7 @@ func (msg *WhoisCommand) String() string {
658 657
 
659 658
 type WhoCommand struct {
660 659
 	BaseCommand
661
-	mask         string
660
+	mask         Name
662 661
 	operatorOnly bool
663 662
 }
664 663
 
@@ -667,7 +666,7 @@ func NewWhoCommand(args []string) (Command, error) {
667 666
 	cmd := &WhoCommand{}
668 667
 
669 668
 	if len(args) > 0 {
670
-		cmd.mask = args[0]
669
+		cmd.mask = NewName(args[0])
671 670
 	}
672 671
 
673 672
 	if (len(args) > 1) && (args[1] == "o") {
@@ -683,7 +682,7 @@ func (msg *WhoCommand) String() string {
683 682
 
684 683
 type OperCommand struct {
685 684
 	PassCommand
686
-	name string
685
+	name Name
687 686
 }
688 687
 
689 688
 func (msg *OperCommand) String() string {
@@ -701,7 +700,7 @@ func NewOperCommand(args []string) (Command, error) {
701 700
 	}
702 701
 
703 702
 	cmd := &OperCommand{
704
-		name: args[0],
703
+		name: NewName(args[0]),
705 704
 	}
706 705
 	cmd.password = []byte(args[1])
707 706
 	return cmd, nil
@@ -740,12 +739,12 @@ func NewCapCommand(args []string) (Command, error) {
740 739
 // HAPROXY support
741 740
 type ProxyCommand struct {
742 741
 	BaseCommand
743
-	net        string
744
-	sourceIP   string
745
-	destIP     string
746
-	sourcePort string
747
-	destPort   string
748
-	hostname   string // looked up in socket thread
742
+	net        Name
743
+	sourceIP   Name
744
+	destIP     Name
745
+	sourcePort Name
746
+	destPort   Name
747
+	hostname   Name // looked up in socket thread
749 748
 }
750 749
 
751 750
 func (msg *ProxyCommand) String() string {
@@ -757,18 +756,18 @@ func NewProxyCommand(args []string) (Command, error) {
757 756
 		return nil, NotEnoughArgsError
758 757
 	}
759 758
 	return &ProxyCommand{
760
-		net:        args[0],
761
-		sourceIP:   args[1],
762
-		destIP:     args[2],
763
-		sourcePort: args[3],
764
-		destPort:   args[4],
765
-		hostname:   LookupHostname(args[1]),
759
+		net:        NewName(args[0]),
760
+		sourceIP:   NewName(args[1]),
761
+		destIP:     NewName(args[2]),
762
+		sourcePort: NewName(args[3]),
763
+		destPort:   NewName(args[4]),
764
+		hostname:   LookupHostname(NewName(args[1])),
766 765
 	}, nil
767 766
 }
768 767
 
769 768
 type AwayCommand struct {
770 769
 	BaseCommand
771
-	text string
770
+	text Text
772 771
 	away bool
773 772
 }
774 773
 
@@ -780,7 +779,7 @@ func NewAwayCommand(args []string) (Command, error) {
780 779
 	cmd := &AwayCommand{}
781 780
 
782 781
 	if len(args) > 0 {
783
-		cmd.text = args[0]
782
+		cmd.text = NewText(args[0])
784 783
 		cmd.away = true
785 784
 	}
786 785
 
@@ -789,7 +788,7 @@ func NewAwayCommand(args []string) (Command, error) {
789 788
 
790 789
 type IsOnCommand struct {
791 790
 	BaseCommand
792
-	nicks []string
791
+	nicks []Name
793 792
 }
794 793
 
795 794
 func (msg *IsOnCommand) String() string {
@@ -802,27 +801,27 @@ func NewIsOnCommand(args []string) (Command, error) {
802 801
 	}
803 802
 
804 803
 	return &IsOnCommand{
805
-		nicks: args,
804
+		nicks: NewNames(args),
806 805
 	}, nil
807 806
 }
808 807
 
809 808
 type MOTDCommand struct {
810 809
 	BaseCommand
811
-	target string
810
+	target Name
812 811
 }
813 812
 
814 813
 func NewMOTDCommand(args []string) (Command, error) {
815 814
 	cmd := &MOTDCommand{}
816 815
 	if len(args) > 0 {
817
-		cmd.target = args[0]
816
+		cmd.target = NewName(args[0])
818 817
 	}
819 818
 	return cmd, nil
820 819
 }
821 820
 
822 821
 type NoticeCommand struct {
823 822
 	BaseCommand
824
-	target  string
825
-	message string
823
+	target  Name
824
+	message Text
826 825
 }
827 826
 
828 827
 func (cmd *NoticeCommand) String() string {
@@ -834,20 +833,20 @@ func NewNoticeCommand(args []string) (Command, error) {
834 833
 		return nil, NotEnoughArgsError
835 834
 	}
836 835
 	return &NoticeCommand{
837
-		target:  args[0],
838
-		message: args[1],
836
+		target:  NewName(args[0]),
837
+		message: NewText(args[1]),
839 838
 	}, nil
840 839
 }
841 840
 
842 841
 type KickCommand struct {
843 842
 	BaseCommand
844
-	kicks   map[string]string
845
-	comment string
843
+	kicks   map[Name]Name
844
+	comment Text
846 845
 }
847 846
 
848
-func (msg *KickCommand) Comment() string {
847
+func (msg *KickCommand) Comment() Text {
849 848
 	if msg.comment == "" {
850
-		return msg.Client().Nick()
849
+		return msg.Client().Nick().Text()
851 850
 	}
852 851
 	return msg.comment
853 852
 }
@@ -856,13 +855,13 @@ func NewKickCommand(args []string) (Command, error) {
856 855
 	if len(args) < 2 {
857 856
 		return nil, NotEnoughArgsError
858 857
 	}
859
-	channels := strings.Split(args[0], ",")
860
-	users := strings.Split(args[1], ",")
858
+	channels := NewNames(strings.Split(args[0], ","))
859
+	users := NewNames(strings.Split(args[1], ","))
861 860
 	if (len(channels) != len(users)) && (len(users) != 1) {
862 861
 		return nil, NotEnoughArgsError
863 862
 	}
864 863
 	cmd := &KickCommand{
865
-		kicks: make(map[string]string),
864
+		kicks: make(map[Name]Name),
866 865
 	}
867 866
 	for index, channel := range channels {
868 867
 		if len(users) == 1 {
@@ -872,48 +871,48 @@ func NewKickCommand(args []string) (Command, error) {
872 871
 		}
873 872
 	}
874 873
 	if len(args) > 2 {
875
-		cmd.comment = args[2]
874
+		cmd.comment = NewText(args[2])
876 875
 	}
877 876
 	return cmd, nil
878 877
 }
879 878
 
880 879
 type ListCommand struct {
881 880
 	BaseCommand
882
-	channels []string
883
-	target   string
881
+	channels []Name
882
+	target   Name
884 883
 }
885 884
 
886 885
 func NewListCommand(args []string) (Command, error) {
887 886
 	cmd := &ListCommand{}
888 887
 	if len(args) > 0 {
889
-		cmd.channels = strings.Split(args[0], ",")
888
+		cmd.channels = NewNames(strings.Split(args[0], ","))
890 889
 	}
891 890
 	if len(args) > 1 {
892
-		cmd.target = args[1]
891
+		cmd.target = NewName(args[1])
893 892
 	}
894 893
 	return cmd, nil
895 894
 }
896 895
 
897 896
 type NamesCommand struct {
898 897
 	BaseCommand
899
-	channels []string
900
-	target   string
898
+	channels []Name
899
+	target   Name
901 900
 }
902 901
 
903 902
 func NewNamesCommand(args []string) (Command, error) {
904 903
 	cmd := &NamesCommand{}
905 904
 	if len(args) > 0 {
906
-		cmd.channels = strings.Split(args[0], ",")
905
+		cmd.channels = NewNames(strings.Split(args[0], ","))
907 906
 	}
908 907
 	if len(args) > 1 {
909
-		cmd.target = args[1]
908
+		cmd.target = NewName(args[1])
910 909
 	}
911 910
 	return cmd, nil
912 911
 }
913 912
 
914 913
 type DebugCommand struct {
915 914
 	BaseCommand
916
-	subCommand string
915
+	subCommand Name
917 916
 }
918 917
 
919 918
 func NewDebugCommand(args []string) (Command, error) {
@@ -922,27 +921,27 @@ func NewDebugCommand(args []string) (Command, error) {
922 921
 	}
923 922
 
924 923
 	return &DebugCommand{
925
-		subCommand: strings.ToUpper(args[0]),
924
+		subCommand: NewName(strings.ToUpper(args[0])),
926 925
 	}, nil
927 926
 }
928 927
 
929 928
 type VersionCommand struct {
930 929
 	BaseCommand
931
-	target string
930
+	target Name
932 931
 }
933 932
 
934 933
 func NewVersionCommand(args []string) (Command, error) {
935 934
 	cmd := &VersionCommand{}
936 935
 	if len(args) > 0 {
937
-		cmd.target = args[0]
936
+		cmd.target = NewName(args[0])
938 937
 	}
939 938
 	return cmd, nil
940 939
 }
941 940
 
942 941
 type InviteCommand struct {
943 942
 	BaseCommand
944
-	nickname string
945
-	channel  string
943
+	nickname Name
944
+	channel  Name
946 945
 }
947 946
 
948 947
 func NewInviteCommand(args []string) (Command, error) {
@@ -951,28 +950,28 @@ func NewInviteCommand(args []string) (Command, error) {
951 950
 	}
952 951
 
953 952
 	return &InviteCommand{
954
-		nickname: args[0],
955
-		channel:  args[1],
953
+		nickname: NewName(args[0]),
954
+		channel:  NewName(args[1]),
956 955
 	}, nil
957 956
 }
958 957
 
959 958
 type TimeCommand struct {
960 959
 	BaseCommand
961
-	target string
960
+	target Name
962 961
 }
963 962
 
964 963
 func NewTimeCommand(args []string) (Command, error) {
965 964
 	cmd := &TimeCommand{}
966 965
 	if len(args) > 0 {
967
-		cmd.target = args[0]
966
+		cmd.target = NewName(args[0])
968 967
 	}
969 968
 	return cmd, nil
970 969
 }
971 970
 
972 971
 type KillCommand struct {
973 972
 	BaseCommand
974
-	nickname string
975
-	comment  string
973
+	nickname Name
974
+	comment  Text
976 975
 }
977 976
 
978 977
 func NewKillCommand(args []string) (Command, error) {
@@ -980,16 +979,16 @@ func NewKillCommand(args []string) (Command, error) {
980 979
 		return nil, NotEnoughArgsError
981 980
 	}
982 981
 	return &KillCommand{
983
-		nickname: args[0],
984
-		comment:  args[1],
982
+		nickname: NewName(args[0]),
983
+		comment:  NewText(args[1]),
985 984
 	}, nil
986 985
 }
987 986
 
988 987
 type WhoWasCommand struct {
989 988
 	BaseCommand
990
-	nicknames []string
989
+	nicknames []Name
991 990
 	count     int64
992
-	target    string
991
+	target    Name
993 992
 }
994 993
 
995 994
 func NewWhoWasCommand(args []string) (Command, error) {
@@ -997,13 +996,13 @@ func NewWhoWasCommand(args []string) (Command, error) {
997 996
 		return nil, NotEnoughArgsError
998 997
 	}
999 998
 	cmd := &WhoWasCommand{
1000
-		nicknames: strings.Split(args[0], ","),
999
+		nicknames: NewNames(strings.Split(args[0], ",")),
1001 1000
 	}
1002 1001
 	if len(args) > 1 {
1003 1002
 		cmd.count, _ = strconv.ParseInt(args[1], 10, 64)
1004 1003
 	}
1005 1004
 	if len(args) > 2 {
1006
-		cmd.target = args[2]
1005
+		cmd.target = NewName(args[2])
1007 1006
 	}
1008 1007
 	return cmd, nil
1009 1008
 }

+ 3
- 3
irc/config.go Bestand weergeven

@@ -31,10 +31,10 @@ type Config struct {
31 31
 	Operator map[string]*PassConfig
32 32
 }
33 33
 
34
-func (conf *Config) Operators() map[string][]byte {
35
-	operators := make(map[string][]byte)
34
+func (conf *Config) Operators() map[Name][]byte {
35
+	operators := make(map[Name][]byte)
36 36
 	for name, opConf := range conf.Operator {
37
-		operators[name] = opConf.PasswordBytes()
37
+		operators[NewName(name)] = opConf.PasswordBytes()
38 38
 	}
39 39
 	return operators
40 40
 }

+ 0
- 6
irc/constants.go Bestand weergeven

@@ -2,17 +2,11 @@ package irc
2 2
 
3 3
 import (
4 4
 	"errors"
5
-	"regexp"
6 5
 )
7 6
 
8 7
 var (
9 8
 	// errors
10 9
 	ErrAlreadyDestroyed = errors.New("already destroyed")
11
-
12
-	// regexps
13
-	ChannelNameExpr = regexp.MustCompile(`^[&!#+][\pL\pN]{1,63}$`)
14
-	NicknameExpr    = regexp.MustCompile(
15
-		"^[\\pL\\pN\\pP\\pS]{1,32}$")
16 10
 )
17 11
 
18 12
 const (

+ 8
- 8
irc/net.go Bestand weergeven

@@ -5,25 +5,25 @@ import (
5 5
 	"strings"
6 6
 )
7 7
 
8
-func IPString(addr net.Addr) string {
8
+func IPString(addr net.Addr) Name {
9 9
 	addrStr := addr.String()
10 10
 	ipaddr, _, err := net.SplitHostPort(addrStr)
11 11
 	if err != nil {
12
-		return addrStr
12
+		return Name(addrStr)
13 13
 	}
14
-	return ipaddr
14
+	return Name(ipaddr)
15 15
 }
16 16
 
17
-func AddrLookupHostname(addr net.Addr) string {
17
+func AddrLookupHostname(addr net.Addr) Name {
18 18
 	return LookupHostname(IPString(addr))
19 19
 }
20 20
 
21
-func LookupHostname(addr string) string {
22
-	names, err := net.LookupAddr(addr)
21
+func LookupHostname(addr Name) Name {
22
+	names, err := net.LookupAddr(addr.String())
23 23
 	if err != nil {
24
-		return addr
24
+		return Name(addr)
25 25
 	}
26 26
 
27 27
 	hostname := strings.TrimSuffix(names[0], ".")
28
-	return hostname
28
+	return Name(hostname)
29 29
 }

+ 27
- 27
irc/reply.go Bestand weergeven

@@ -95,23 +95,23 @@ func (target *Client) MultilineReply(names []string, code NumericCode, format st
95 95
 // messaging replies
96 96
 //
97 97
 
98
-func RplPrivMsg(source Identifiable, target Identifiable, message string) string {
98
+func RplPrivMsg(source Identifiable, target Identifiable, message Text) string {
99 99
 	return NewStringReply(source, PRIVMSG, "%s :%s", target.Nick(), message)
100 100
 }
101 101
 
102
-func RplNotice(source Identifiable, target Identifiable, message string) string {
102
+func RplNotice(source Identifiable, target Identifiable, message Text) string {
103 103
 	return NewStringReply(source, NOTICE, "%s :%s", target.Nick(), message)
104 104
 }
105 105
 
106
-func RplNick(source Identifiable, newNick string) string {
107
-	return NewStringReply(source, NICK, newNick)
106
+func RplNick(source Identifiable, newNick Name) string {
107
+	return NewStringReply(source, NICK, newNick.String())
108 108
 }
109 109
 
110 110
 func RplJoin(client *Client, channel *Channel) string {
111
-	return NewStringReply(client, JOIN, channel.name)
111
+	return NewStringReply(client, JOIN, channel.name.String())
112 112
 }
113 113
 
114
-func RplPart(client *Client, channel *Channel, message string) string {
114
+func RplPart(client *Client, channel *Channel, message Text) string {
115 115
 	return NewStringReply(client, PART, "%s :%s", channel, message)
116 116
 }
117 117
 
@@ -133,10 +133,10 @@ func RplPing(target Identifiable) string {
133 133
 }
134 134
 
135 135
 func RplPong(client *Client) string {
136
-	return NewStringReply(nil, PONG, client.Nick())
136
+	return NewStringReply(nil, PONG, client.Nick().String())
137 137
 }
138 138
 
139
-func RplQuit(client *Client, message string) string {
139
+func RplQuit(client *Client, message Text) string {
140 140
 	return NewStringReply(client, QUIT, ":%s", message)
141 141
 }
142 142
 
@@ -144,16 +144,16 @@ func RplError(message string) string {
144 144
 	return NewStringReply(nil, ERROR, ":%s", message)
145 145
 }
146 146
 
147
-func RplInviteMsg(inviter *Client, invitee *Client, channel string) string {
147
+func RplInviteMsg(inviter *Client, invitee *Client, channel Name) string {
148 148
 	return NewStringReply(inviter, INVITE, "%s :%s", invitee.Nick(), channel)
149 149
 }
150 150
 
151
-func RplKick(channel *Channel, client *Client, target *Client, comment string) string {
151
+func RplKick(channel *Channel, client *Client, target *Client, comment Text) string {
152 152
 	return NewStringReply(client, KICK, "%s %s :%s",
153 153
 		channel, target.Nick(), comment)
154 154
 }
155 155
 
156
-func RplKill(client *Client, target *Client, comment string) string {
156
+func RplKill(client *Client, target *Client, comment Text) string {
157 157
 	return NewStringReply(client, KICK,
158 158
 		"%s :%s", target.Nick(), comment)
159 159
 }
@@ -200,7 +200,7 @@ func (target *Client) RplTopic(channel *Channel) {
200 200
 
201 201
 // <nick> <channel>
202 202
 // NB: correction in errata
203
-func (target *Client) RplInvitingMsg(invitee *Client, channel string) {
203
+func (target *Client) RplInvitingMsg(invitee *Client, channel Name) {
204 204
 	target.NumericReply(RPL_INVITING,
205 205
 		"%s %s", invitee.Nick(), channel)
206 206
 }
@@ -269,7 +269,7 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
269 269
 	}
270 270
 
271 271
 	if channel != nil {
272
-		channelName = channel.name
272
+		channelName = channel.name.String()
273 273
 		if target.capabilities[MultiPrefix] {
274 274
 			if channel.members[client][ChannelOperator] {
275 275
 				flags += "@"
@@ -291,12 +291,12 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
291 291
 }
292 292
 
293 293
 // <name> :End of WHO list
294
-func (target *Client) RplEndOfWho(name string) {
294
+func (target *Client) RplEndOfWho(name Name) {
295 295
 	target.NumericReply(RPL_ENDOFWHO,
296 296
 		"%s :End of WHO list", name)
297 297
 }
298 298
 
299
-func (target *Client) RplMaskList(mode ChannelMode, channel *Channel, mask string) {
299
+func (target *Client) RplMaskList(mode ChannelMode, channel *Channel, mask Name) {
300 300
 	switch mode {
301 301
 	case BanMask:
302 302
 		target.RplBanList(channel, mask)
@@ -322,7 +322,7 @@ func (target *Client) RplEndOfMaskList(mode ChannelMode, channel *Channel) {
322 322
 	}
323 323
 }
324 324
 
325
-func (target *Client) RplBanList(channel *Channel, mask string) {
325
+func (target *Client) RplBanList(channel *Channel, mask Name) {
326 326
 	target.NumericReply(RPL_BANLIST,
327 327
 		"%s %s", channel, mask)
328 328
 }
@@ -332,7 +332,7 @@ func (target *Client) RplEndOfBanList(channel *Channel) {
332 332
 		"%s :End of channel ban list", channel)
333 333
 }
334 334
 
335
-func (target *Client) RplExceptList(channel *Channel, mask string) {
335
+func (target *Client) RplExceptList(channel *Channel, mask Name) {
336 336
 	target.NumericReply(RPL_EXCEPTLIST,
337 337
 		"%s %s", channel, mask)
338 338
 }
@@ -342,7 +342,7 @@ func (target *Client) RplEndOfExceptList(channel *Channel) {
342 342
 		"%s :End of channel exception list", channel)
343 343
 }
344 344
 
345
-func (target *Client) RplInviteList(channel *Channel, mask string) {
345
+func (target *Client) RplInviteList(channel *Channel, mask Name) {
346 346
 	target.NumericReply(RPL_INVITELIST,
347 347
 		"%s %s", channel, mask)
348 348
 }
@@ -412,7 +412,7 @@ func (target *Client) RplVersion() {
412 412
 		"%s %s", SEM_VER, target.server.name)
413 413
 }
414 414
 
415
-func (target *Client) RplInviting(invitee *Client, channel string) {
415
+func (target *Client) RplInviting(invitee *Client, channel Name) {
416 416
 	target.NumericReply(RPL_INVITING,
417 417
 		"%s %s", invitee.Nick(), channel)
418 418
 }
@@ -428,7 +428,7 @@ func (target *Client) RplWhoWasUser(whoWas *WhoWas) {
428 428
 		whoWas.nickname, whoWas.username, whoWas.hostname, whoWas.realname)
429 429
 }
430 430
 
431
-func (target *Client) RplEndOfWhoWas(nickname string) {
431
+func (target *Client) RplEndOfWhoWas(nickname Name) {
432 432
 	target.NumericReply(RPL_ENDOFWHOWAS,
433 433
 		"%s :End of WHOWAS", nickname)
434 434
 }
@@ -442,7 +442,7 @@ func (target *Client) ErrAlreadyRegistered() {
442 442
 		":You may not reregister")
443 443
 }
444 444
 
445
-func (target *Client) ErrNickNameInUse(nick string) {
445
+func (target *Client) ErrNickNameInUse(nick Name) {
446 446
 	target.NumericReply(ERR_NICKNAMEINUSE,
447 447
 		"%s :Nickname is already in use", nick)
448 448
 }
@@ -457,12 +457,12 @@ func (target *Client) ErrUsersDontMatch() {
457 457
 		":Cannot change mode for other users")
458 458
 }
459 459
 
460
-func (target *Client) ErrNeedMoreParams(command string) {
460
+func (target *Client) ErrNeedMoreParams(command StringCode) {
461 461
 	target.NumericReply(ERR_NEEDMOREPARAMS,
462 462
 		"%s :Not enough parameters", command)
463 463
 }
464 464
 
465
-func (target *Client) ErrNoSuchChannel(channel string) {
465
+func (target *Client) ErrNoSuchChannel(channel Name) {
466 466
 	target.NumericReply(ERR_NOSUCHCHANNEL,
467 467
 		"%s :No such channel", channel)
468 468
 }
@@ -487,7 +487,7 @@ func (target *Client) ErrBadChannelKey(channel *Channel) {
487 487
 		"%s :Cannot join channel (+k)", channel.name)
488 488
 }
489 489
 
490
-func (target *Client) ErrNoSuchNick(nick string) {
490
+func (target *Client) ErrNoSuchNick(nick Name) {
491 491
 	target.NumericReply(ERR_NOSUCHNICK,
492 492
 		"%s :No such nick/channel", nick)
493 493
 }
@@ -509,7 +509,7 @@ func (target *Client) ErrRestricted() {
509 509
 	target.NumericReply(ERR_RESTRICTED, ":Your connection is restricted!")
510 510
 }
511 511
 
512
-func (target *Client) ErrNoSuchServer(server string) {
512
+func (target *Client) ErrNoSuchServer(server Name) {
513 513
 	target.NumericReply(ERR_NOSUCHSERVER, "%s :No such server", server)
514 514
 }
515 515
 
@@ -537,7 +537,7 @@ func (target *Client) ErrNoNicknameGiven() {
537 537
 	target.NumericReply(ERR_NONICKNAMEGIVEN, ":No nickname given")
538 538
 }
539 539
 
540
-func (target *Client) ErrErroneusNickname(nick string) {
540
+func (target *Client) ErrErroneusNickname(nick Name) {
541 541
 	target.NumericReply(ERR_ERRONEUSNICKNAME,
542 542
 		"%s :Erroneous nickname", nick)
543 543
 }
@@ -552,7 +552,7 @@ func (target *Client) ErrChannelIsFull(channel *Channel) {
552 552
 		"%s :Cannot join channel (+l)", channel)
553 553
 }
554 554
 
555
-func (target *Client) ErrWasNoSuchNick(nickname string) {
555
+func (target *Client) ErrWasNoSuchNick(nickname Name) {
556 556
 	target.NumericReply(ERR_WASNOSUCHNICK,
557 557
 		"%s :There was no such nickname", nickname)
558 558
 }

+ 23
- 21
irc/server.go Bestand weergeven

@@ -34,9 +34,9 @@ type Server struct {
34 34
 	db        *sql.DB
35 35
 	idle      chan *Client
36 36
 	motdFile  string
37
-	name      string
37
+	name      Name
38 38
 	newConns  chan net.Conn
39
-	operators map[string][]byte
39
+	operators map[Name][]byte
40 40
 	password  []byte
41 41
 	signals   chan os.Signal
42 42
 	whoWas    *WhoWasList
@@ -56,7 +56,7 @@ func NewServer(config *Config) *Server {
56 56
 		db:        OpenDB(config.Server.Database),
57 57
 		idle:      make(chan *Client),
58 58
 		motdFile:  config.Server.MOTD,
59
-		name:      config.Server.Name,
59
+		name:      NewName(config.Server.Name),
60 60
 		newConns:  make(chan net.Conn),
61 61
 		operators: config.Operators(),
62 62
 		signals:   make(chan os.Signal, len(SERVER_SIGNALS)),
@@ -82,7 +82,7 @@ func loadChannelList(channel *Channel, list string, maskMode ChannelMode) {
82 82
 	if list == "" {
83 83
 		return
84 84
 	}
85
-	channel.lists[maskMode].AddAll(strings.Split(list, " "))
85
+	channel.lists[maskMode].AddAll(NewNames(strings.Split(list, " ")))
86 86
 }
87 87
 
88 88
 func (server *Server) loadChannels() {
@@ -94,7 +94,9 @@ func (server *Server) loadChannels() {
94 94
 		log.Fatal("error loading channels: ", err)
95 95
 	}
96 96
 	for rows.Next() {
97
-		var name, flags, key, topic string
97
+		var name Name
98
+		var flags string
99
+		var key, topic Text
98 100
 		var userLimit uint64
99 101
 		var banList, exceptList, inviteList string
100 102
 		err = rows.Scan(&name, &flags, &key, &topic, &userLimit, &banList,
@@ -256,15 +258,15 @@ func (server *Server) MOTD(client *Client) {
256 258
 	client.RplMOTDEnd()
257 259
 }
258 260
 
259
-func (s *Server) Id() string {
261
+func (s *Server) Id() Name {
260 262
 	return s.name
261 263
 }
262 264
 
263 265
 func (s *Server) String() string {
264
-	return s.name
266
+	return s.name.String()
265 267
 }
266 268
 
267
-func (s *Server) Nick() string {
269
+func (s *Server) Nick() Name {
268 270
 	return s.Id()
269 271
 }
270 272
 
@@ -309,7 +311,7 @@ func (m *NickCommand) HandleRegServer(s *Server) {
309 311
 		return
310 312
 	}
311 313
 
312
-	if !IsNickname(m.nickname) {
314
+	if !m.nickname.IsNickname() {
313 315
 		client.ErrErroneusNickname(m.nickname)
314 316
 		return
315 317
 	}
@@ -386,7 +388,7 @@ func (msg *NickCommand) HandleServer(server *Server) {
386 388
 		return
387 389
 	}
388 390
 
389
-	if !IsNickname(msg.nickname) {
391
+	if !msg.nickname.IsNickname() {
390 392
 		client.ErrErroneusNickname(msg.nickname)
391 393
 		return
392 394
 	}
@@ -417,13 +419,13 @@ func (m *JoinCommand) HandleServer(s *Server) {
417 419
 
418 420
 	if m.zero {
419 421
 		for channel := range client.channels {
420
-			channel.Part(client, client.Nick())
422
+			channel.Part(client, client.Nick().Text())
421 423
 		}
422 424
 		return
423 425
 	}
424 426
 
425 427
 	for name, key := range m.channels {
426
-		if !IsChannel(name) {
428
+		if !name.IsChannel() {
427 429
 			client.ErrNoSuchChannel(name)
428 430
 			continue
429 431
 		}
@@ -467,7 +469,7 @@ func (msg *TopicCommand) HandleServer(server *Server) {
467 469
 
468 470
 func (msg *PrivMsgCommand) HandleServer(server *Server) {
469 471
 	client := msg.Client()
470
-	if IsChannel(msg.target) {
472
+	if msg.target.IsChannel() {
471 473
 		channel := server.channels.Get(msg.target)
472 474
 		if channel == nil {
473 475
 			client.ErrNoSuchChannel(msg.target)
@@ -547,13 +549,13 @@ func (client *Client) WhoisChannelsNames() []string {
547 549
 	for channel := range client.channels {
548 550
 		switch {
549 551
 		case channel.members[client][ChannelOperator]:
550
-			chstrs[index] = "@" + channel.name
552
+			chstrs[index] = "@" + channel.name.String()
551 553
 
552 554
 		case channel.members[client][Voice]:
553
-			chstrs[index] = "+" + channel.name
555
+			chstrs[index] = "+" + channel.name.String()
554 556
 
555 557
 		default:
556
-			chstrs[index] = channel.name
558
+			chstrs[index] = channel.name.String()
557 559
 		}
558 560
 		index += 1
559 561
 	}
@@ -605,7 +607,7 @@ func (msg *WhoCommand) HandleServer(server *Server) {
605 607
 		for _, channel := range server.channels {
606 608
 			whoChannel(client, channel, friends)
607 609
 		}
608
-	} else if IsChannel(mask) {
610
+	} else if mask.IsChannel() {
609 611
 		// TODO implement wildcard matching
610 612
 		channel := server.channels.Get(mask)
611 613
 		if channel != nil {
@@ -655,7 +657,7 @@ func (msg *IsOnCommand) HandleServer(server *Server) {
655 657
 	ison := make([]string, 0)
656 658
 	for _, nick := range msg.nicks {
657 659
 		if iclient := server.clients.Get(nick); iclient != nil {
658
-			ison = append(ison, iclient.Nick())
660
+			ison = append(ison, iclient.Nick().String())
659 661
 		}
660 662
 	}
661 663
 
@@ -668,7 +670,7 @@ func (msg *MOTDCommand) HandleServer(server *Server) {
668 670
 
669 671
 func (msg *NoticeCommand) HandleServer(server *Server) {
670 672
 	client := msg.Client()
671
-	if IsChannel(msg.target) {
673
+	if msg.target.IsChannel() {
672 674
 		channel := server.channels.Get(msg.target)
673 675
 		if channel == nil {
674 676
 			client.ErrNoSuchChannel(msg.target)
@@ -755,7 +757,7 @@ func (msg *NamesCommand) HandleServer(server *Server) {
755 757
 }
756 758
 
757 759
 func (server *Server) Reply(target *Client, format string, args ...interface{}) {
758
-	target.Reply(RplPrivMsg(server, target, fmt.Sprintf(format, args...)))
760
+	target.Reply(RplPrivMsg(server, target, NewText(fmt.Sprintf(format, args...))))
759 761
 }
760 762
 
761 763
 func (msg *DebugCommand) HandleServer(server *Server) {
@@ -850,7 +852,7 @@ func (msg *KillCommand) HandleServer(server *Server) {
850 852
 	}
851 853
 
852 854
 	quitMsg := fmt.Sprintf("KILLed by %s: %s", client.Nick(), msg.comment)
853
-	target.Quit(quitMsg)
855
+	target.Quit(NewText(quitMsg))
854 856
 }
855 857
 
856 858
 func (msg *WhoWasCommand) HandleServer(server *Server) {

+ 66
- 0
irc/strings.go Bestand weergeven

@@ -0,0 +1,66 @@
1
+package irc
2
+
3
+import (
4
+	"code.google.com/p/go.text/unicode/norm"
5
+	"regexp"
6
+	"strings"
7
+)
8
+
9
+var (
10
+	// regexps
11
+	ChannelNameExpr = regexp.MustCompile(`^[&!#+][\pL\pN]{1,63}$`)
12
+	NicknameExpr    = regexp.MustCompile("^[\\pL\\pN\\pP\\pS]{1,32}$")
13
+)
14
+
15
+// Names are normalized and canonicalized to remove formatting marks
16
+// and simplify usage. They are things like hostnames and usermasks.
17
+type Name string
18
+
19
+func NewName(str string) Name {
20
+	return Name(norm.NFKC.String(str))
21
+}
22
+
23
+func NewNames(strs []string) []Name {
24
+	names := make([]Name, len(strs))
25
+	for index, str := range strs {
26
+		names[index] = NewName(str)
27
+	}
28
+	return names
29
+}
30
+
31
+// tests
32
+
33
+func (name Name) IsChannel() bool {
34
+	return ChannelNameExpr.MatchString(name.String())
35
+}
36
+
37
+func (name Name) IsNickname() bool {
38
+	return NicknameExpr.MatchString(name.String())
39
+}
40
+
41
+// conversions
42
+
43
+func (name Name) String() string {
44
+	return string(name)
45
+}
46
+
47
+func (name Name) ToLower() Name {
48
+	return Name(strings.ToLower(name.String()))
49
+}
50
+
51
+// It's safe to coerce a Name to Text. Name is a strict subset of Text.
52
+func (name Name) Text() Text {
53
+	return Text(name)
54
+}
55
+
56
+// Text is PRIVMSG, NOTICE, or TOPIC data. It's canonicalized UTF8
57
+// data to simplify but keeps all formatting.
58
+type Text string
59
+
60
+func NewText(str string) Text {
61
+	return Text(norm.NFC.String(str))
62
+}
63
+
64
+func (text Text) String() string {
65
+	return string(text)
66
+}

+ 9
- 9
irc/types.go Bestand weergeven

@@ -30,25 +30,25 @@ func (mode ChannelMode) String() string {
30 30
 	return string(mode)
31 31
 }
32 32
 
33
-type ChannelNameMap map[string]*Channel
33
+type ChannelNameMap map[Name]*Channel
34 34
 
35
-func (channels ChannelNameMap) Get(name string) *Channel {
36
-	return channels[strings.ToLower(name)]
35
+func (channels ChannelNameMap) Get(name Name) *Channel {
36
+	return channels[name.ToLower()]
37 37
 }
38 38
 
39 39
 func (channels ChannelNameMap) Add(channel *Channel) error {
40
-	if channels[channel.name] != nil {
40
+	if channels[channel.name.ToLower()] != nil {
41 41
 		return fmt.Errorf("%s: already set", channel.name)
42 42
 	}
43
-	channels[channel.name] = channel
43
+	channels[channel.name.ToLower()] = channel
44 44
 	return nil
45 45
 }
46 46
 
47 47
 func (channels ChannelNameMap) Remove(channel *Channel) error {
48
-	if channel != channels[channel.name] {
48
+	if channel != channels[channel.name.ToLower()] {
49 49
 		return fmt.Errorf("%s: mismatch", channel.name)
50 50
 	}
51
-	delete(channels, channel.name)
51
+	delete(channels, channel.name.ToLower())
52 52
 	return nil
53 53
 }
54 54
 
@@ -126,6 +126,6 @@ func (channels ChannelSet) First() *Channel {
126 126
 //
127 127
 
128 128
 type Identifiable interface {
129
-	Id() string
130
-	Nick() string
129
+	Id() Name
130
+	Nick() Name
131 131
 }

+ 5
- 5
irc/whowas.go Bestand weergeven

@@ -7,10 +7,10 @@ type WhoWasList struct {
7 7
 }
8 8
 
9 9
 type WhoWas struct {
10
-	nickname string
11
-	username string
12
-	hostname string
13
-	realname string
10
+	nickname Name
11
+	username Name
12
+	hostname Name
13
+	realname Text
14 14
 }
15 15
 
16 16
 func NewWhoWasList(size uint) *WhoWasList {
@@ -32,7 +32,7 @@ func (list *WhoWasList) Append(client *Client) {
32 32
 	}
33 33
 }
34 34
 
35
-func (list *WhoWasList) Find(nickname string, limit int64) []*WhoWas {
35
+func (list *WhoWasList) Find(nickname Name, limit int64) []*WhoWas {
36 36
 	results := make([]*WhoWas, 0)
37 37
 	for whoWas := range list.Each() {
38 38
 		if nickname != whoWas.nickname {

Laden…
Annuleren
Opslaan