From b6b4d365bc2b1ec872069fab5744a7ac54739c0f Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Sun, 23 Dec 2018 13:25:02 -0500 Subject: [PATCH 1/2] fix #313 --- irc/channel.go | 14 ++++++-------- irc/client.go | 24 ++++++++++++++++++++++++ irc/getters.go | 6 ++++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/irc/channel.go b/irc/channel.go index b014aba9..8c5c9296 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -366,9 +366,11 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp channel.stateMutex.RLock() chname := channel.name + chcfname := channel.nameCasefolded founder := channel.registeredFounder channel.stateMutex.RUnlock() account := client.Account() + nickMaskCasefolded := client.NickMaskCasefolded() hasPrivs := isSajoin || (founder != "" && founder == account) if !hasPrivs && channel.IsFull() { @@ -381,15 +383,15 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp return } - isInvited := channel.lists[modes.InviteMask].Match(client.nickMaskCasefolded) + isInvited := client.CheckInvited(chcfname) || channel.lists[modes.InviteMask].Match(nickMaskCasefolded) if !hasPrivs && channel.flags.HasMode(modes.InviteOnly) && !isInvited { rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i")) return } - if !hasPrivs && channel.lists[modes.BanMask].Match(client.nickMaskCasefolded) && + if !hasPrivs && channel.lists[modes.BanMask].Match(nickMaskCasefolded) && !isInvited && - !channel.lists[modes.ExceptMask].Match(client.nickMaskCasefolded) { + !channel.lists[modes.ExceptMask].Match(nickMaskCasefolded) { rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b")) return } @@ -965,12 +967,8 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuf return } - //TODO(dan): handle this more nicely, keep a list of last X invited channels on invitee rather than explicitly modifying the invite list? if channel.flags.HasMode(modes.InviteOnly) { - nmc := invitee.NickCasefolded() - channel.stateMutex.Lock() - channel.lists[modes.InviteMask].Add(nmc) - channel.stateMutex.Unlock() + invitee.Invite(channel.NameCasefolded()) } for _, member := range channel.Members() { diff --git a/irc/client.go b/irc/client.go index dfadcb64..2ee4ba89 100644 --- a/irc/client.go +++ b/irc/client.go @@ -69,6 +69,7 @@ type Client struct { hops int hostname string idletimer *IdleTimer + invitedTo map[string]bool isDestroyed bool isQuitting bool languages []string @@ -1102,3 +1103,26 @@ func (client *Client) generateResumeToken() (token string, err error) { return client.resumeToken, err } + +// Records that the client has been invited to join an invite-only channel +func (client *Client) Invite(casefoldedChannel string) { + client.stateMutex.Lock() + defer client.stateMutex.Unlock() + + if client.invitedTo == nil { + client.invitedTo = make(map[string]bool) + } + + client.invitedTo[casefoldedChannel] = true +} + +// Checks that the client was invited to join a given channel +func (client *Client) CheckInvited(casefoldedChannel string) (invited bool) { + client.stateMutex.Lock() + defer client.stateMutex.Unlock() + + invited = client.invitedTo[casefoldedChannel] + // joining an invited channel "uses up" your invite, so you can't rejoin on kick + delete(client.invitedTo, casefoldedChannel) + return +} diff --git a/irc/getters.go b/irc/getters.go index ad072574..52a3b2d7 100644 --- a/irc/getters.go +++ b/irc/getters.go @@ -84,6 +84,12 @@ func (client *Client) NickCasefolded() string { return client.nickCasefolded } +func (client *Client) NickMaskCasefolded() string { + client.stateMutex.RLock() + defer client.stateMutex.RUnlock() + return client.nickMaskCasefolded +} + func (client *Client) Username() string { client.stateMutex.RLock() defer client.stateMutex.RUnlock() From f58c873f84d38e64411b87e5754d700c5236ac3f Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Sun, 23 Dec 2018 13:49:03 -0500 Subject: [PATCH 2/2] fix RPL_INVITING response to match modern ircdocs --- irc/channel.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/irc/channel.go b/irc/channel.go index 8c5c9296..a81796d0 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -957,13 +957,14 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string, rb // Invite invites the given client to the channel, if the inviter can do so. func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) { + chname := channel.Name() if channel.flags.HasMode(modes.InviteOnly) && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) { - rb.Add(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, channel.name, inviter.t("You're not a channel operator")) + rb.Add(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, chname, inviter.t("You're not a channel operator")) return } if !channel.hasClient(inviter) { - rb.Add(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, inviter.t("You're not on that channel")) + rb.Add(nil, inviter.server.name, ERR_NOTONCHANNEL, chname, inviter.t("You're not on that channel")) return } @@ -973,13 +974,12 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuf for _, member := range channel.Members() { if member.capabilities.Has(caps.InviteNotify) && member != inviter && member != invitee && channel.ClientIsAtLeast(member, modes.Halfop) { - member.Send(nil, inviter.NickMaskString(), "INVITE", invitee.Nick(), channel.name) + member.Send(nil, inviter.NickMaskString(), "INVITE", invitee.Nick(), chname) } } - //TODO(dan): should inviter.server.name here be inviter.nickMaskString ? - rb.Add(nil, inviter.server.name, RPL_INVITING, invitee.nick, channel.name) - invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, channel.name) + rb.Add(nil, inviter.server.name, RPL_INVITING, inviter.Nick(), invitee.Nick(), chname) + invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, chname) if invitee.HasMode(modes.Away) { rb.Add(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage) }