tangled
alpha
login
or
join now
benharri.org
/
ircsharp
1
fork
atom
IRC parsing, tokenization, and state handling in C#
1
fork
atom
overview
issues
pulls
pipelines
wow lots of tests passing!
benharri.org
5 years ago
aef26a40
a0fbcf83
+351
-93
7 changed files
expand all
collapse all
unified
split
IrcStates
Channel.cs
Extensions.cs
ISupport.cs
ISupportChanModes.cs
Server.cs
Tests
Cap.cs
Mode.cs
+1
-1
IrcStates/Channel.cs
···
40
40
{
41
41
if (!ListModes.ContainsKey(ch)) ListModes[ch] = new List<string>();
42
42
43
43
-
if (ListModes[ch].Contains(param)) ListModes[ch].Add(param ?? string.Empty);
43
43
+
if (!ListModes[ch].Contains(param)) ListModes[ch].Add(param ?? string.Empty);
44
44
}
45
45
else
46
46
{
+1
-1
IrcStates/Extensions.cs
···
30
30
: Delegate.CreateDelegate(getType(types.ToArray()), target, methodInfo);
31
31
}
32
32
33
33
-
public static void Update<TKey, TValue>(this Dictionary<TKey, TValue> dict, Dictionary<TKey, TValue> other)
33
33
+
public static void UpdateWith<TKey, TValue>(this Dictionary<TKey, TValue> dict, Dictionary<TKey, TValue> other)
34
34
{
35
35
if (dict == null || other == null || !other.Any()) return;
36
36
+15
-8
IrcStates/ISupport.cs
···
16
16
CaseMapping = Casemap.CaseMapping.Rfc1459;
17
17
Prefix = new ISupportPrefix("(ov)@+");
18
18
ChanModes = new ISupportChanModes("b,k,l,imnpst");
19
19
+
ChanTypes = new List<string> {"#"};
19
20
StatusMsg = new List<string>();
20
21
Whox = false;
21
22
}
···
46
47
{
47
48
var split = token.Split('=', 2);
48
49
var key = split[0];
49
49
-
var value = split[1];
50
50
51
51
-
if (split.Length > 1) Raw[key] = value;
52
52
-
51
51
+
var value = string.Empty;
52
52
+
if (split.Length > 1)
53
53
+
{
54
54
+
value = split[1];
55
55
+
Raw[key] = value;
56
56
+
}
57
57
+
53
58
switch (split[0])
54
59
{
55
60
case "NETWORK":
···
62
67
Prefix = new ISupportPrefix(value);
63
68
break;
64
69
case "STATUSMSG":
65
65
-
StatusMsg = new List<string> {value};
70
70
+
StatusMsg = new List<string>();
71
71
+
StatusMsg.AddRange(value.Select(c => c.ToString(CultureInfo.InvariantCulture)));
66
72
break;
67
73
case "MODES":
68
74
Modes = int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
···
77
83
if (Enum.TryParse(value, true, out Casemap.CaseMapping caseMapping)) CaseMapping = caseMapping;
78
84
break;
79
85
case "CHANTYPES":
80
80
-
ChanTypes = new List<string> {value};
86
86
+
ChanTypes = new List<string>();
87
87
+
ChanTypes.AddRange(value.Select(c => c.ToString(CultureInfo.InvariantCulture)));
81
88
break;
82
89
case "CALLERID":
83
83
-
CallerId = string.IsNullOrEmpty(value) ? value : "g";
90
90
+
CallerId = string.IsNullOrEmpty(value) ? "g" : value;
84
91
break;
85
92
case "EXCEPTS":
86
86
-
Excepts = string.IsNullOrEmpty(value) ? value : "e";
93
93
+
Excepts = string.IsNullOrEmpty(value) ? "e" : value;
87
94
break;
88
95
case "INVEX":
89
89
-
Invex = string.IsNullOrEmpty(value) ? value : "I";
96
96
+
Invex = string.IsNullOrEmpty(value) ? "I" : value;
90
97
break;
91
98
case "WHOX":
92
99
Whox = true;
+14
-4
IrcStates/ISupportChanModes.cs
···
1
1
using System.Collections.Generic;
2
2
+
using System.Globalization;
3
3
+
using System.Linq;
2
4
3
5
namespace IrcStates
4
6
{
···
9
11
if (splitVal == null) return;
10
12
11
13
var split = splitVal.Split(',', 4);
12
12
-
ListModes = new List<string> {split[0]};
13
13
-
SettingBModes = new List<string> {split[1]};
14
14
-
SettingCModes = new List<string> {split[2]};
15
15
-
SettingDModes = new List<string> {split[3]};
14
14
+
15
15
+
ListModes = new List<string>();
16
16
+
ListModes.AddRange(split[0].Select(c => c.ToString(CultureInfo.InvariantCulture)));
17
17
+
18
18
+
SettingBModes = new List<string>();
19
19
+
SettingBModes.AddRange(split[1].Select(c => c.ToString(CultureInfo.InvariantCulture)));
20
20
+
21
21
+
SettingCModes = new List<string>();
22
22
+
SettingCModes.AddRange(split[2].Select(c => c.ToString(CultureInfo.InvariantCulture)));
23
23
+
24
24
+
SettingDModes = new List<string>();
25
25
+
SettingDModes.AddRange(split[3].Select(c => c.ToString(CultureInfo.InvariantCulture)));
16
26
}
17
27
18
28
public List<string> ListModes { get; set; }
+315
-73
IrcStates/Server.cs
···
1
1
using System;
2
2
using System.Collections.Generic;
3
3
+
using System.ComponentModel.Design;
3
4
using System.Globalization;
4
5
using System.Linq;
5
6
using IrcTokens;
···
59
60
return Casemap.CaseFold(ISupport.CaseMapping, str);
60
61
}
61
62
62
62
-
public bool CaseFoldEquals(string s1, string s2)
63
63
+
private bool CaseFoldEquals(string s1, string s2)
63
64
{
64
65
return CaseFold(s1) == CaseFold(s2);
65
66
}
66
67
67
67
-
public bool IsMe(string nickname)
68
68
+
private bool IsMe(string nickname)
68
69
{
69
70
return CaseFold(nickname) == NickNameLower;
70
71
}
71
72
72
72
-
public bool HasUser(string nickname)
73
73
+
private bool HasUser(string nickname)
73
74
{
74
75
return Users.ContainsKey(CaseFold(nickname));
75
76
}
76
77
77
77
-
private void AddUser(string nickname, string nicknameLower)
78
78
+
private User AddUser(string nickname, string nicknameLower)
78
79
{
79
80
var user = CreateUser(nickname, nicknameLower);
80
81
Users[nicknameLower] = user;
82
82
+
return user;
81
83
}
82
84
83
85
private User CreateUser(string nickname, string nicknameLower)
···
87
89
return user;
88
90
}
89
91
90
90
-
public bool IsChannel(string target)
92
92
+
private bool IsChannel(string target)
91
93
{
92
94
return !string.IsNullOrEmpty(target) &&
93
95
ISupport.ChanTypes.Contains(target[0].ToString(CultureInfo.InvariantCulture));
94
96
}
95
97
96
96
-
public bool HasChannel(string name)
98
98
+
private bool HasChannel(string name)
97
99
{
98
100
return Channels.ContainsKey(CaseFold(name));
99
101
}
100
102
101
101
-
public Channel GetChannel(string name)
103
103
+
private Channel GetChannel(string name)
102
104
{
103
105
return HasChannel(name) ? Channels[name] : null;
104
106
}
···
138
140
if (!user.Channels.Any()) Users.Remove(nickLower);
139
141
}
140
142
141
141
-
if (nickLower == NickNameLower)
143
143
+
if (IsMe(nickName))
142
144
{
143
145
Channels.Remove(channelLower);
144
146
foreach (var userToRemove in channel.Users.Keys.Select(u => Users[u]))
···
152
154
return (emit, user);
153
155
}
154
156
157
157
+
private void SetChannelModes(Channel channel, IEnumerable<(bool, string)> modes, IList<string> parameters)
158
158
+
{
159
159
+
foreach (var (add, c) in modes)
160
160
+
{
161
161
+
var listMode = ISupport.ChanModes.ListModes.Contains(c);
162
162
+
if (ISupport.Prefix.Modes.Contains(c))
163
163
+
{
164
164
+
var nicknameLower = CaseFold(parameters.First());
165
165
+
parameters.RemoveAt(0);
166
166
+
if (!HasUser(nicknameLower)) continue;
167
167
+
168
168
+
var channelUser = channel.Users[nicknameLower];
169
169
+
if (add)
170
170
+
{
171
171
+
if (!channelUser.Modes.Contains(c))
172
172
+
{
173
173
+
channelUser.Modes.Add(c);
174
174
+
}
175
175
+
}
176
176
+
else if (channelUser.Modes.Contains(c))
177
177
+
{
178
178
+
channelUser.Modes.Remove(c);
179
179
+
}
180
180
+
}
181
181
+
else if (add && (listMode ||
182
182
+
ISupport.ChanModes.SettingBModes.Contains(c) ||
183
183
+
ISupport.ChanModes.SettingCModes.Contains(c)))
184
184
+
{
185
185
+
channel.AddMode(c, parameters.First(), listMode);
186
186
+
parameters.RemoveAt(0);
187
187
+
}
188
188
+
else if (!add && (listMode || ISupport.ChanModes.SettingBModes.Contains(c)))
189
189
+
{
190
190
+
channel.RemoveMode(c, parameters.First());
191
191
+
parameters.RemoveAt(0);
192
192
+
}
193
193
+
else if (add)
194
194
+
{
195
195
+
channel.AddMode(c, null, false);
196
196
+
}
197
197
+
else
198
198
+
{
199
199
+
channel.RemoveMode(c, null);
200
200
+
}
201
201
+
}
202
202
+
}
203
203
+
155
204
public List<(Line, Emit)> Recv(byte[] data)
156
205
{
157
206
if (data == null) return null;
···
166
215
{
167
216
if (line == null) return null;
168
217
169
169
-
switch (line.Command)
218
218
+
var emit = line.Command switch
170
219
{
171
171
-
case Numeric.RPL_WELCOME: return HandleWelcome(line);
172
172
-
case Numeric.RPL_ISUPPORT: return HandleISupport(line);
173
173
-
case Numeric.RPL_MOTDSTART:
174
174
-
case Numeric.RPL_MOTD:
175
175
-
return HandleMotd(line);
176
176
-
case Commands.Nick: return HandleNick(line);
177
177
-
case Commands.Join: return HandleJoin(line);
178
178
-
case Commands.Part: return HandlePart(line);
179
179
-
case Commands.Kick: return HandleKick(line);
180
180
-
case Commands.Quit: return HandleQuit(line);
181
181
-
case Commands.Error: return HandleError(line);
182
182
-
case Numeric.RPL_NAMREPLY: return HandleNames(line);
183
183
-
case Numeric.RPL_CREATIONTIME: return HandleCreationTime(line);
184
184
-
case Commands.Topic: return HandleTopic(line);
185
185
-
case Numeric.RPL_TOPIC: return HandleTopicNumeric(line);
186
186
-
case Numeric.RPL_TOPICWHOTIME: return HandleTopicTime(line);
187
187
-
case Commands.Mode: return HandleMode(line);
188
188
-
case Numeric.RPL_CHANNELMODEIS: return HandleChannelModeIs(line);
189
189
-
case Numeric.RPL_UMODEIS: return HandleUModeIs(line);
190
190
-
case Commands.Privmsg:
191
191
-
case Commands.Notice:
192
192
-
case Commands.Tagmsg:
193
193
-
return HandleMessage(line);
194
194
-
case Numeric.RPL_VISIBLEHOST: return HandleVisibleHost(line);
195
195
-
case Numeric.RPL_WHOREPLY: return HandleWhoReply(line);
196
196
-
case Numeric.RPL_WHOSPCRPL: return HandleWhox(line);
197
197
-
case Numeric.RPL_WHOISUSER: return HandleWhoIsUser(line);
198
198
-
case Commands.Chghost: return HandleChghost(line);
199
199
-
case Commands.Setname: return HandleSetname(line);
200
200
-
case Commands.Away: return HandleAway(line);
201
201
-
case Commands.Account: return HandleAccount(line);
202
202
-
case Commands.Cap: return HandleCap(line);
203
203
-
case Numeric.RPL_LOGGEDIN: return HandleLoggedIn(line);
204
204
-
case Numeric.RPL_LOGGEDOUT: return HandleLoggedOut(line);
205
205
-
}
220
220
+
Numeric.RPL_WELCOME => HandleWelcome(line),
221
221
+
Numeric.RPL_ISUPPORT => HandleISupport(line),
222
222
+
Numeric.RPL_MOTDSTART => HandleMotd(line),
223
223
+
Numeric.RPL_MOTD => HandleMotd(line),
224
224
+
Commands.Nick => HandleNick(line),
225
225
+
Commands.Join => HandleJoin(line),
226
226
+
Commands.Part => HandlePart(line),
227
227
+
Commands.Kick => HandleKick(line),
228
228
+
Commands.Quit => HandleQuit(line),
229
229
+
Commands.Error => HandleError(line),
230
230
+
Numeric.RPL_NAMREPLY => HandleNames(line),
231
231
+
Numeric.RPL_CREATIONTIME => HandleCreationTime(line),
232
232
+
Commands.Topic => HandleTopic(line),
233
233
+
Numeric.RPL_TOPIC => HandleTopicNumeric(line),
234
234
+
Numeric.RPL_TOPICWHOTIME => HandleTopicTime(line),
235
235
+
Commands.Mode => HandleMode(line),
236
236
+
Numeric.RPL_CHANNELMODEIS => HandleChannelModeIs(line),
237
237
+
Numeric.RPL_UMODEIS => HandleUModeIs(line),
238
238
+
Commands.Privmsg => HandleMessage(line),
239
239
+
Commands.Notice => HandleMessage(line),
240
240
+
Commands.Tagmsg => HandleMessage(line),
241
241
+
Numeric.RPL_VISIBLEHOST => HandleVisibleHost(line),
242
242
+
Numeric.RPL_WHOREPLY => HandleWhoReply(line),
243
243
+
Numeric.RPL_WHOSPCRPL => HandleWhox(line),
244
244
+
Numeric.RPL_WHOISUSER => HandleWhoIsUser(line),
245
245
+
Commands.Chghost => HandleChghost(line),
246
246
+
Commands.Setname => HandleSetname(line),
247
247
+
Commands.Away => HandleAway(line),
248
248
+
Commands.Account => HandleAccount(line),
249
249
+
Commands.Cap => HandleCap(line),
250
250
+
Numeric.RPL_LOGGEDIN => HandleLoggedIn(line),
251
251
+
Numeric.RPL_LOGGEDOUT => HandleLoggedOut(line),
252
252
+
_ => null
253
253
+
};
206
254
207
207
-
return new Emit();
255
255
+
if (emit != null)
256
256
+
emit.Command = line.Command;
257
257
+
else
258
258
+
emit = new Emit();
259
259
+
260
260
+
return emit;
208
261
}
209
262
210
263
private Emit HandleSetname(Line line)
···
213
266
var realname = line.Params[0];
214
267
var nicknameLower = CaseFold(line.Hostmask.NickName);
215
268
216
216
-
if (nicknameLower == NickNameLower)
269
269
+
if (IsMe(nicknameLower))
217
270
{
218
271
emit.Self = true;
219
272
RealName = realname;
···
235
288
var away = line.Params.FirstOrDefault();
236
289
var nicknameLower = CaseFold(line.Hostmask.NickName);
237
290
238
238
-
if (nicknameLower == NickNameLower)
291
291
+
if (IsMe(nicknameLower))
239
292
{
240
293
emit.Self = true;
241
294
Away = away;
···
257
310
var account = line.Params[0].Trim('*');
258
311
var nicknameLower = CaseFold(line.Hostmask.NickName);
259
312
260
260
-
if (nicknameLower == NickNameLower)
313
313
+
if (IsMe(nicknameLower))
261
314
{
262
315
emit.Self = true;
263
316
Account = account;
···
289
342
tokens[kv[0]] = kv.Length > 1 ? kv[1] : string.Empty;
290
343
}
291
344
292
292
-
var emit = new Emit();
293
293
-
emit.Subcommand = subcommand;
294
294
-
emit.Finished = !multiline;
295
295
-
emit.Tokens = tokensStr;
345
345
+
var emit = new Emit {Subcommand = subcommand, Finished = !multiline, Tokens = tokensStr};
296
346
297
347
switch (subcommand)
298
348
{
299
349
case "LS":
300
300
-
TempCaps = tokens;
350
350
+
TempCaps.UpdateWith(tokens);
301
351
if (!multiline)
302
352
{
303
303
-
AvailableCaps = TempCaps;
353
353
+
AvailableCaps.UpdateWith(TempCaps);
304
354
TempCaps.Clear();
305
355
}
306
356
307
357
break;
308
358
case "NEW":
309
309
-
AvailableCaps.Update(tokens);
359
359
+
AvailableCaps.UpdateWith(tokens);
310
360
break;
311
361
case "DEL":
312
362
foreach (var key in tokens.Keys.Where(key => AvailableCaps.ContainsKey(key)))
···
323
373
var k = key.Substring(1);
324
374
if (AgreedCaps.Contains(k)) AgreedCaps.Remove(k);
325
375
}
326
326
-
else if (!AgreedCaps.Contains(key) && !AvailableCaps.ContainsKey(key))
376
376
+
else if (!AgreedCaps.Contains(key) && AvailableCaps.ContainsKey(key))
327
377
{
328
378
AgreedCaps.Add(key);
329
379
}
···
348
398
var hostname = line.Params[1];
349
399
var nicknameLower = CaseFold(line.Hostmask.NickName);
350
400
351
351
-
if (nicknameLower == NickNameLower)
401
401
+
if (IsMe(nicknameLower))
352
402
{
353
403
emit.Self = true;
354
404
UserName = username;
···
368
418
369
419
private Emit HandleWhoIsUser(Line line)
370
420
{
371
371
-
throw new NotImplementedException();
421
421
+
var emit = new Emit();
422
422
+
var nickname = line.Params[1];
423
423
+
var username = line.Params[2];
424
424
+
var hostname = line.Params[3];
425
425
+
var realname = line.Params[5];
426
426
+
427
427
+
if (IsMe(nickname))
428
428
+
{
429
429
+
emit.Self = true;
430
430
+
UserName = username;
431
431
+
HostName = hostname;
432
432
+
RealName = realname;
433
433
+
}
434
434
+
435
435
+
if (HasUser(nickname))
436
436
+
{
437
437
+
var user = Users[CaseFold(nickname)];
438
438
+
emit.User = user;
439
439
+
user.UserName = username;
440
440
+
user.HostName = hostname;
441
441
+
user.RealName = realname;
442
442
+
}
443
443
+
444
444
+
return emit;
372
445
}
373
446
374
447
private Emit HandleWhox(Line line)
375
448
{
376
376
-
throw new NotImplementedException();
449
449
+
var emit = new Emit();
450
450
+
if (line.Params[1] == WhoType && line.Params.Count == 8)
451
451
+
{
452
452
+
var nickname = line.Params[5];
453
453
+
var username = line.Params[2];
454
454
+
var hostname = line.Params[4];
455
455
+
var realname = line.Params[7];
456
456
+
var account = line.Params[6] == "0" ? null : line.Params[6];
457
457
+
458
458
+
if (IsMe(nickname))
459
459
+
{
460
460
+
emit.Self = true;
461
461
+
UserName = username;
462
462
+
HostName = hostname;
463
463
+
RealName = realname;
464
464
+
Account = account;
465
465
+
}
466
466
+
467
467
+
if (HasUser(nickname))
468
468
+
{
469
469
+
var user = Users[CaseFold(nickname)];
470
470
+
emit.User = user;
471
471
+
user.UserName = username;
472
472
+
user.HostName = hostname;
473
473
+
user.RealName = realname;
474
474
+
user.Account = account;
475
475
+
}
476
476
+
}
477
477
+
478
478
+
return emit;
377
479
}
378
480
379
481
private Emit HandleWhoReply(Line line)
380
482
{
381
381
-
throw new NotImplementedException();
483
483
+
var emit = new Emit {Target = line.Params[1]};
484
484
+
var nickname = line.Params[5];
485
485
+
var username = line.Params[2];
486
486
+
var hostname = line.Params[3];
487
487
+
var realname = line.Params[7].Split(' ', 2)[1];
488
488
+
489
489
+
if (IsMe(nickname))
490
490
+
{
491
491
+
emit.Self = true;
492
492
+
UserName = username;
493
493
+
HostName = hostname;
494
494
+
RealName = realname;
495
495
+
}
496
496
+
497
497
+
if (HasUser(nickname))
498
498
+
{
499
499
+
var user = Users[CaseFold(nickname)];
500
500
+
emit.User = user;
501
501
+
user.UserName = username;
502
502
+
user.HostName = hostname;
503
503
+
user.RealName = realname;
504
504
+
}
505
505
+
506
506
+
return emit;
382
507
}
383
508
384
509
private Emit HandleVisibleHost(Line line)
385
510
{
386
386
-
throw new NotImplementedException();
511
511
+
var split = line.Params[1].Split('@', 2);
512
512
+
switch (split.Length)
513
513
+
{
514
514
+
case 1:
515
515
+
HostName = split[0];
516
516
+
break;
517
517
+
case 2:
518
518
+
HostName = split[1];
519
519
+
UserName = split[0];
520
520
+
break;
521
521
+
}
522
522
+
523
523
+
return new Emit();
387
524
}
388
525
389
526
private Emit HandleMessage(Line line)
390
527
{
391
391
-
throw new NotImplementedException();
528
528
+
var emit = new Emit();
529
529
+
var message = line.Params.Count > 1 ? line.Params[1] : null;
530
530
+
if (message != null) emit.Text = message;
531
531
+
532
532
+
var nickLower = CaseFold(line.Hostmask.NickName);
533
533
+
if (IsMe(nickLower))
534
534
+
{
535
535
+
emit.SelfSource = true;
536
536
+
SelfHostmask(line.Hostmask);
537
537
+
}
538
538
+
539
539
+
var user = HasUser(nickLower)
540
540
+
? Users[nickLower]
541
541
+
: AddUser(line.Hostmask.NickName, nickLower);
542
542
+
emit.User = user;
543
543
+
544
544
+
if (line.Hostmask.UserName != null) user.UserName = line.Hostmask.UserName;
545
545
+
if (line.Hostmask.HostName != null) user.HostName = line.Hostmask.HostName;
546
546
+
547
547
+
var target = line.Params[0];
548
548
+
var statusMsg = new List<string>();
549
549
+
while (target.Length > 0)
550
550
+
{
551
551
+
var t = target[0].ToString(CultureInfo.InvariantCulture);
552
552
+
if (ISupport.StatusMsg.Contains(t))
553
553
+
{
554
554
+
statusMsg.Add(t);
555
555
+
target = target.Substring(1);
556
556
+
}
557
557
+
else
558
558
+
break;
559
559
+
}
560
560
+
561
561
+
emit.Target = line.Params[0];
562
562
+
563
563
+
if (IsChannel(target) && HasChannel(target))
564
564
+
{
565
565
+
emit.Channel = Channels[CaseFold(target)];
566
566
+
}
567
567
+
else if (IsMe(target))
568
568
+
{
569
569
+
emit.SelfTarget = true;
570
570
+
}
571
571
+
572
572
+
return emit;
392
573
}
393
574
394
575
private Emit HandleUModeIs(Line line)
395
576
{
396
396
-
throw new NotImplementedException();
577
577
+
foreach (var c in line.Params[1]
578
578
+
.TrimStart('+')
579
579
+
.Select(m => m.ToString(CultureInfo.InvariantCulture))
580
580
+
.Where(m => !Modes.Contains(m)))
581
581
+
{
582
582
+
Modes.Add(c);
583
583
+
}
584
584
+
585
585
+
return new Emit();
397
586
}
398
587
399
588
private Emit HandleChannelModeIs(Line line)
400
589
{
401
401
-
throw new NotImplementedException();
590
590
+
var emit = new Emit();
591
591
+
if (HasChannel(line.Params[1]))
592
592
+
{
593
593
+
var channel = Channels[CaseFold(line.Params[1])];
594
594
+
emit.Channel = channel;
595
595
+
var modes = line.Params[2]
596
596
+
.TrimStart('+')
597
597
+
.Select(p => (true, p.ToString(CultureInfo.InvariantCulture)));
598
598
+
var parameters = line.Params.Skip(3).ToList();
599
599
+
SetChannelModes(channel, modes, parameters);
600
600
+
}
601
601
+
602
602
+
return emit;
402
603
}
403
604
404
605
private Emit HandleMode(Line line)
405
606
{
406
406
-
throw new NotImplementedException();
607
607
+
var emit = new Emit();
608
608
+
var target = line.Params[0];
609
609
+
var modeString = line.Params[1];
610
610
+
var parameters = line.Params.Skip(2).ToList();
611
611
+
612
612
+
var modifier = '+';
613
613
+
var modes = new List<(bool, string)>();
614
614
+
var tokens = new List<string>();
615
615
+
616
616
+
foreach (var c in modeString)
617
617
+
{
618
618
+
if (new[] {'+', '-'}.Contains(c))
619
619
+
{
620
620
+
modifier = c;
621
621
+
}
622
622
+
else
623
623
+
{
624
624
+
modes.Add((modifier == '+', c.ToString(CultureInfo.InvariantCulture)));
625
625
+
tokens.Add($"{modifier}{c}");
626
626
+
}
627
627
+
}
628
628
+
629
629
+
emit.Tokens = tokens;
630
630
+
631
631
+
if (IsMe(target))
632
632
+
{
633
633
+
emit.SelfTarget = true;
634
634
+
foreach (var (add, c) in modes)
635
635
+
{
636
636
+
if (add && !Modes.Contains(c))
637
637
+
Modes.Add(c);
638
638
+
else if (Modes.Contains(c)) Modes.Remove(c);
639
639
+
}
640
640
+
}
641
641
+
else if (HasChannel(target))
642
642
+
{
643
643
+
var channel = GetChannel(CaseFold(target));
644
644
+
emit.Channel = channel;
645
645
+
SetChannelModes(channel, modes, parameters);
646
646
+
}
647
647
+
648
648
+
return emit;
407
649
}
408
650
409
651
private Emit HandleTopicTime(Line line)
···
502
744
if (hostmask.UserName != null) user.UserName = hostmask.UserName;
503
745
if (hostmask.HostName != null) user.HostName = hostmask.HostName;
504
746
505
505
-
if (nickLower == NickNameLower) SelfHostmask(hostmask);
747
747
+
if (IsMe(nickLower)) SelfHostmask(hostmask);
506
748
507
749
foreach (var mode in modes.Select(c => c.ToString(CultureInfo.InvariantCulture)))
508
750
if (!channelUser.Modes.Contains(mode))
···
525
767
var nickLower = CaseFold(line.Hostmask.NickName);
526
768
if (line.Params.Any()) emit.Text = line.Params[0];
527
769
528
528
-
if (nickLower == NickNameLower || line.Source == null)
770
770
+
if (IsMe(nickLower) || line.Source == null)
529
771
{
530
772
emit.Self = true;
531
773
Users.Clear();
···
556
798
if (kicked != null)
557
799
{
558
800
emit.UserTarget = kicked;
559
559
-
if (kicked.NickNameLower == NickNameLower) emit.Self = true;
801
801
+
if (IsMe(kicked.NickName)) emit.Self = true;
560
802
561
561
-
var kickerLower = CaseFold(line.Hostmask.NickName);
562
562
-
if (kickerLower == NickNameLower) emit.SelfSource = true;
803
803
+
var kickerLower = CaseFold(line.Hostmask.NickName);
804
804
+
if (IsMe(kickerLower)) emit.SelfSource = true;
563
805
564
806
emit.UserSource = Users.ContainsKey(kickerLower)
565
807
? Users[kickerLower]
···
575
817
if (user != null)
576
818
{
577
819
emit.User = user;
578
578
-
if (user.NickNameLower == NickNameLower) emit.Self = true;
820
820
+
if (IsMe(user.NickName)) emit.Self = true;
579
821
}
580
822
581
823
return emit;
···
593
835
var nickLower = CaseFold(line.Hostmask.NickName);
594
836
595
837
// handle own join
596
596
-
if (nickLower == NickNameLower)
838
838
+
if (IsMe(nickLower))
597
839
{
598
840
emit.Self = true;
599
841
if (!HasChannel(channelLower))
···
661
903
}
662
904
}
663
905
664
664
-
if (nickLower == NickNameLower)
906
906
+
if (IsMe(nickLower))
665
907
{
666
908
emit.Self = true;
667
909
NickName = nick;
+3
-2
IrcStates/Tests/Cap.cs
···
30
30
_server.Parse(new Line("CAP * LS * :a b"));
31
31
CollectionAssert.AreEqual(new Dictionary<string, string>(), _server.AvailableCaps);
32
32
_server.Parse(new Line("CAP * LS :c"));
33
33
-
CollectionAssert.AreEqual(new Dictionary<string, string> {{"a", ""}, {"b", ""}, {"c", ""}},
34
34
-
_server.AvailableCaps);
33
33
+
Assert.IsTrue(_server.AvailableCaps.ContainsKey("a"));
34
34
+
Assert.IsTrue(_server.AvailableCaps.ContainsKey("b"));
35
35
+
Assert.IsTrue(_server.AvailableCaps.ContainsKey("c"));
35
36
}
36
37
37
38
[TestMethod]
+2
-4
IrcStates/Tests/Mode.cs
···
63
63
_server.Parse(new Line("MODE #chan +b asd!*@*"));
64
64
65
65
var channel = _server.Channels["#chan"];
66
66
-
CollectionAssert.AreEqual(new Dictionary<string, List<string>> {{"b", new List<string> {"asd!*@*"}}},
67
67
-
channel.ListModes);
66
66
+
CollectionAssert.AreEqual(new List<string> {"asd!*@*"}, channel.ListModes["b"]);
68
67
}
69
68
70
69
[TestMethod]
···
150
149
var channel = _server.Channels["#chan"];
151
150
CollectionAssert.AreEqual(new Dictionary<string, string> {{"k", "pass"}, {"l", "10"}, {"i", null}},
152
151
channel.Modes);
153
153
-
CollectionAssert.AreEqual(new Dictionary<string, List<string>> {{"b", new List<string> {"*!*@*"}}},
154
154
-
channel.ListModes);
152
152
+
CollectionAssert.AreEqual(new List<string> {"*!*@*"}, channel.ListModes["b"]);
155
153
}
156
154
157
155
[TestMethod]