|
@@ -346,8 +346,7 @@ func (channel *Channel) IsEmpty() bool {
|
346
|
346
|
|
347
|
347
|
// Join joins the given client to this channel (if they can be joined).
|
348
|
348
|
func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *ResponseBuffer) {
|
349
|
|
- account := client.Account()
|
350
|
|
- nickMaskCasefolded := client.NickMaskCasefolded()
|
|
349
|
+ details := client.Details()
|
351
|
350
|
|
352
|
351
|
channel.stateMutex.RLock()
|
353
|
352
|
chname := channel.name
|
|
@@ -357,7 +356,7 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
357
|
356
|
limit := channel.userLimit
|
358
|
357
|
chcount := len(channel.members)
|
359
|
358
|
_, alreadyJoined := channel.members[client]
|
360
|
|
- persistentMode := channel.accountToUMode[account]
|
|
359
|
+ persistentMode := channel.accountToUMode[details.account]
|
361
|
360
|
channel.stateMutex.RUnlock()
|
362
|
361
|
|
363
|
362
|
if alreadyJoined {
|
|
@@ -367,7 +366,7 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
367
|
366
|
|
368
|
367
|
// the founder can always join (even if they disabled auto +q on join);
|
369
|
368
|
// anyone who automatically receives halfop or higher can always join
|
370
|
|
- hasPrivs := isSajoin || (founder != "" && founder == account) || (persistentMode != 0 && persistentMode != modes.Voice)
|
|
369
|
+ hasPrivs := isSajoin || (founder != "" && founder == details.account) || (persistentMode != 0 && persistentMode != modes.Voice)
|
371
|
370
|
|
372
|
371
|
if !hasPrivs && limit != 0 && chcount >= limit {
|
373
|
372
|
rb.Add(nil, client.server.name, ERR_CHANNELISFULL, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
|
|
@@ -379,20 +378,20 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
379
|
378
|
return
|
380
|
379
|
}
|
381
|
380
|
|
382
|
|
- isInvited := client.CheckInvited(chcfname) || channel.lists[modes.InviteMask].Match(nickMaskCasefolded)
|
|
381
|
+ isInvited := client.CheckInvited(chcfname) || channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded)
|
383
|
382
|
if !hasPrivs && channel.flags.HasMode(modes.InviteOnly) && !isInvited {
|
384
|
383
|
rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
|
385
|
384
|
return
|
386
|
385
|
}
|
387
|
386
|
|
388
|
|
- if !hasPrivs && channel.lists[modes.BanMask].Match(nickMaskCasefolded) &&
|
|
387
|
+ if !hasPrivs && channel.lists[modes.BanMask].Match(details.nickMaskCasefolded) &&
|
389
|
388
|
!isInvited &&
|
390
|
|
- !channel.lists[modes.ExceptMask].Match(nickMaskCasefolded) {
|
|
389
|
+ !channel.lists[modes.ExceptMask].Match(details.nickMaskCasefolded) {
|
391
|
390
|
rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
|
392
|
391
|
return
|
393
|
392
|
}
|
394
|
393
|
|
395
|
|
- client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", client.nick, chname))
|
|
394
|
+ client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", details.nick, chname))
|
396
|
395
|
|
397
|
396
|
newChannel, givenMode := func() (newChannel bool, givenMode modes.Mode) {
|
398
|
397
|
channel.joinPartMutex.Lock()
|
|
@@ -416,15 +415,19 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
416
|
415
|
}()
|
417
|
416
|
|
418
|
417
|
channel.regenerateMembersCache()
|
|
418
|
+
|
|
419
|
+ channel.history.Add(history.Item{
|
|
420
|
+ Type: history.Join,
|
|
421
|
+ Nick: details.nickMask,
|
|
422
|
+ AccountName: details.accountName,
|
|
423
|
+ Msgid: details.realname,
|
|
424
|
+ })
|
|
425
|
+
|
419
|
426
|
return
|
420
|
427
|
}()
|
421
|
428
|
|
422
|
429
|
client.addChannel(channel)
|
423
|
430
|
|
424
|
|
- nick := client.Nick()
|
425
|
|
- nickmask := client.NickMaskString()
|
426
|
|
- realname := client.Realname()
|
427
|
|
- accountName := client.AccountName()
|
428
|
431
|
var modestr string
|
429
|
432
|
if givenMode != 0 {
|
430
|
433
|
modestr = fmt.Sprintf("+%v", givenMode)
|
|
@@ -435,19 +438,19 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
435
|
438
|
continue
|
436
|
439
|
}
|
437
|
440
|
if member.capabilities.Has(caps.ExtendedJoin) {
|
438
|
|
- member.Send(nil, nickmask, "JOIN", chname, accountName, realname)
|
|
441
|
+ member.Send(nil, details.nickMask, "JOIN", chname, details.accountName, details.realname)
|
439
|
442
|
} else {
|
440
|
|
- member.Send(nil, nickmask, "JOIN", chname)
|
|
443
|
+ member.Send(nil, details.nickMask, "JOIN", chname)
|
441
|
444
|
}
|
442
|
445
|
if givenMode != 0 {
|
443
|
|
- member.Send(nil, client.server.name, "MODE", chname, modestr, nick)
|
|
446
|
+ member.Send(nil, client.server.name, "MODE", chname, modestr, details.nick)
|
444
|
447
|
}
|
445
|
448
|
}
|
446
|
449
|
|
447
|
450
|
if client.capabilities.Has(caps.ExtendedJoin) {
|
448
|
|
- rb.Add(nil, nickmask, "JOIN", chname, accountName, realname)
|
|
451
|
+ rb.Add(nil, details.nickMask, "JOIN", chname, details.accountName, details.realname)
|
449
|
452
|
} else {
|
450
|
|
- rb.Add(nil, nickmask, "JOIN", chname)
|
|
453
|
+ rb.Add(nil, details.nickMask, "JOIN", chname)
|
451
|
454
|
}
|
452
|
455
|
|
453
|
456
|
// don't send topic when it's an entirely new channel
|
|
@@ -458,22 +461,19 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
458
|
461
|
channel.Names(client, rb)
|
459
|
462
|
|
460
|
463
|
if givenMode != 0 {
|
461
|
|
- rb.Add(nil, client.server.name, "MODE", chname, modestr, nick)
|
|
464
|
+ rb.Add(nil, client.server.name, "MODE", chname, modestr, details.nick)
|
462
|
465
|
}
|
463
|
466
|
|
464
|
|
- channel.history.Add(history.Item{
|
465
|
|
- Type: history.Join,
|
466
|
|
- Nick: nickmask,
|
467
|
|
- AccountName: accountName,
|
468
|
|
- Msgid: realname,
|
469
|
|
- })
|
470
|
|
-
|
471
|
467
|
// TODO #259 can be implemented as Flush(false) (i.e., nonblocking) while holding joinPartMutex
|
472
|
468
|
rb.Flush(true)
|
473
|
469
|
|
474
|
470
|
replayLimit := channel.server.Config().History.AutoreplayOnJoin
|
475
|
471
|
if replayLimit > 0 {
|
476
|
|
- items := channel.history.Latest(replayLimit)
|
|
472
|
+ // don't replay the client's own events
|
|
473
|
+ matcher := func(item history.Item) bool {
|
|
474
|
+ return item.Nick != details.nickMask
|
|
475
|
+ }
|
|
476
|
+ items := channel.history.Match(matcher, replayLimit)
|
477
|
477
|
channel.replayHistoryItems(rb, items)
|
478
|
478
|
rb.Flush(true)
|
479
|
479
|
}
|
|
@@ -489,20 +489,20 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
|
489
|
489
|
|
490
|
490
|
channel.Quit(client)
|
491
|
491
|
|
492
|
|
- nickmask := client.NickMaskString()
|
|
492
|
+ details := client.Details()
|
493
|
493
|
for _, member := range channel.Members() {
|
494
|
|
- member.Send(nil, nickmask, "PART", chname, message)
|
|
494
|
+ member.Send(nil, details.nickMask, "PART", chname, message)
|
495
|
495
|
}
|
496
|
|
- rb.Add(nil, nickmask, "PART", chname, message)
|
|
496
|
+ rb.Add(nil, details.nickMask, "PART", chname, message)
|
497
|
497
|
|
498
|
498
|
channel.history.Add(history.Item{
|
499
|
499
|
Type: history.Part,
|
500
|
|
- Nick: nickmask,
|
501
|
|
- AccountName: client.AccountName(),
|
|
500
|
+ Nick: details.nickMask,
|
|
501
|
+ AccountName: details.accountName,
|
502
|
502
|
Message: utils.MakeSplitMessage(message, true),
|
503
|
503
|
})
|
504
|
504
|
|
505
|
|
- client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", client.nick, chname))
|
|
505
|
+ client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", details.nick, chname))
|
506
|
506
|
}
|
507
|
507
|
|
508
|
508
|
// Resume is called after a successful global resume to:
|