Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auditorium mode #1300

Merged
merged 1 commit into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 82 additions & 22 deletions irc/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,12 @@ func (channel *Channel) regenerateMembersCache() {

// Names sends the list of users joined to the channel to the given client.
func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
isJoined := channel.hasClient(client)
channel.stateMutex.RLock()
clientModes, isJoined := channel.members[client]
channel.stateMutex.RUnlock()
isOper := client.HasMode(modes.Operator)
respectAuditorium := channel.flags.HasMode(modes.Auditorium) && !isOper &&
(!isJoined || clientModes.HighestChannelUserMode() == modes.Mode(0))
isMultiPrefix := rb.session.capabilities.Has(caps.MultiPrefix)
isUserhostInNames := rb.session.capabilities.Has(caps.UserhostInNames)

Expand All @@ -464,6 +468,9 @@ func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
if !isJoined && target.HasMode(modes.Invisible) && !isOper {
continue
}
if respectAuditorium && modeSet.HighestChannelUserMode() == modes.Mode(0) {
continue
}
prefix := modeSet.Prefixes(isMultiPrefix)
if buffer.Len()+len(nick)+len(prefix)+1 > maxNamLen {
namesLines = append(namesLines, buffer.String())
Expand Down Expand Up @@ -748,8 +755,9 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
}()

var message utils.SplitMessage
respectAuditorium := givenMode == modes.Mode(0) && channel.flags.HasMode(modes.Auditorium)
// no history item for fake persistent joins
if rb != nil {
if rb != nil && !respectAuditorium {
message = utils.MakeMessage("")
histItem := history.Item{
Type: history.Join,
Expand All @@ -772,6 +780,14 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp

isAway, awayMessage := client.Away()
for _, member := range channel.Members() {
if respectAuditorium {
channel.stateMutex.RLock()
memberModes, ok := channel.members[member]
channel.stateMutex.RUnlock()
if !ok || memberModes.HighestChannelUserMode() == modes.Mode(0) {
continue
}
}
for _, session := range member.Sessions() {
if session == rb.session {
continue
Expand Down Expand Up @@ -889,8 +905,12 @@ func (channel *Channel) playJoinForSession(session *Session) {

// Part parts the given client from this channel, with the given message.
func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
chname := channel.Name()
if !channel.hasClient(client) {
channel.stateMutex.RLock()
chname := channel.name
clientModes, ok := channel.members[client]
channel.stateMutex.RUnlock()

if !ok {
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.Nick(), chname, client.t("You're not on that channel"))
return
}
Expand All @@ -905,7 +925,17 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
if message != "" {
params = append(params, message)
}
respectAuditorium := channel.flags.HasMode(modes.Auditorium) &&
clientModes.HighestChannelUserMode() == modes.Mode(0)
for _, member := range channel.Members() {
if respectAuditorium {
channel.stateMutex.RLock()
memberModes, ok := channel.members[member]
channel.stateMutex.RUnlock()
if !ok || memberModes.HighestChannelUserMode() == modes.Mode(0) {
continue
}
}
member.sendFromClientInternal(false, splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", params...)
}
rb.AddFromClient(splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", params...)
Expand All @@ -915,12 +945,14 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
}
}

channel.AddHistoryItem(history.Item{
Type: history.Part,
Nick: details.nickMask,
AccountName: details.accountName,
Message: splitMessage,
}, details.account)
if !respectAuditorium {
channel.AddHistoryItem(history.Item{
Type: history.Part,
Nick: details.nickMask,
AccountName: details.accountName,
Message: splitMessage,
}, details.account)
}

client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", details.nick, chname))
}
Expand Down Expand Up @@ -951,20 +983,24 @@ func (channel *Channel) resumeAndAnnounce(session *Session) {
// send join for old clients
chname := channel.Name()
details := session.client.Details()
for _, member := range channel.Members() {
for _, session := range member.Sessions() {
if session.capabilities.Has(caps.Resume) {
continue
}
// TODO: for now, skip this entirely for auditoriums,
// but really we should send it to voiced clients
if !channel.flags.HasMode(modes.Auditorium) {
for _, member := range channel.Members() {
for _, session := range member.Sessions() {
if session.capabilities.Has(caps.Resume) {
continue
}

if session.capabilities.Has(caps.ExtendedJoin) {
session.Send(nil, details.nickMask, "JOIN", chname, details.accountName, details.realname)
} else {
session.Send(nil, details.nickMask, "JOIN", chname)
}
if session.capabilities.Has(caps.ExtendedJoin) {
session.Send(nil, details.nickMask, "JOIN", chname, details.accountName, details.realname)
} else {
session.Send(nil, details.nickMask, "JOIN", chname)
}

if 0 < len(oldModes) {
session.Send(nil, channel.server.name, "MODE", chname, oldModes, details.nick)
if 0 < len(oldModes) {
session.Send(nil, channel.server.name, "MODE", chname, oldModes, details.nick)
}
}
}
}
Expand Down Expand Up @@ -1451,6 +1487,30 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuf
}
}

// returns who the client can "see" in the channel, respecting the auditorium mode
func (channel *Channel) auditoriumFriends(client *Client) (friends []*Client) {
channel.stateMutex.RLock()
defer channel.stateMutex.RUnlock()

clientModes := channel.members[client]
if clientModes == nil {
return // non-members have no friends
}
if !channel.flags.HasMode(modes.Auditorium) {
return channel.membersCache // default behavior for members
}
if clientModes.HighestChannelUserMode() != modes.Mode(0) {
return channel.membersCache // +v and up can see everyone in the auditorium
}
// without +v, your friends are those with +v and up
for member, memberModes := range channel.members {
if memberModes.HighestChannelUserMode() != modes.Mode(0) {
friends = append(friends, member)
}
}
return
}

// data for RPL_LIST
func (channel *Channel) listData() (memberCount int, name, topic string) {
channel.stateMutex.RLock()
Expand Down
8 changes: 4 additions & 4 deletions irc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,7 @@ func (session *Session) playResume() {
// work out how much time, if any, is not covered by history buffers
// assume that a persistent buffer covers the whole resume period
for _, channel := range client.Channels() {
for _, member := range channel.Members() {
for _, member := range channel.auditoriumFriends(client) {
friends.Add(member)
}
status, _ := channel.historyStatus(config)
Expand Down Expand Up @@ -1161,7 +1161,7 @@ func (client *Client) Friends(capabs ...caps.Capability) (result map[*Session]em
addFriendsToSet(result, client, capabs...)

for _, channel := range client.Channels() {
for _, member := range channel.Members() {
for _, member := range channel.auditoriumFriends(client) {
addFriendsToSet(result, member, capabs...)
}
}
Expand Down Expand Up @@ -1512,10 +1512,10 @@ func (client *Client) destroy(session *Session) {
friends := make(ClientSet)
channels = client.Channels()
for _, channel := range channels {
channel.Quit(client)
for _, member := range channel.Members() {
for _, member := range channel.auditoriumFriends(client) {
friends.Add(member)
}
channel.Quit(client)
}
friends.Remove(client)

Expand Down
11 changes: 10 additions & 1 deletion irc/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3051,7 +3051,13 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
if channel != nil {
isJoined := channel.hasClient(client)
if !channel.flags.HasMode(modes.Secret) || isJoined || isOper {
for _, member := range channel.Members() {
var members []*Client
if isOper {
members = channel.Members()
} else {
members = channel.auditoriumFriends(client)
}
for _, member := range members {
if !member.HasMode(modes.Invisible) || isJoined || isOper {
client.rplWhoReply(channel, member, rb, isWhox, fields, whoType)
}
Expand All @@ -3072,6 +3078,9 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
}

for _, channel := range otherClient.Channels() {
if channel.flags.HasMode(modes.Auditorium) {
return false // TODO this should respect +v etc.
}
if _, present := userChannels[channel]; present {
return true
}
Expand Down
4 changes: 3 additions & 1 deletion irc/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Oragono supports the following channel modes:
+t | Only channel opers can modify the topic.
+E | Roleplaying commands are enabled in the channel.
+C | Clients are blocked from sending CTCP messages in the channel.
+u | Auditorium mode: JOIN, PART, QUIT, NAMES, and WHO are hidden
hidden from unvoiced clients.

= Prefixes =

Expand All @@ -74,7 +76,7 @@ Oragono supports the following user modes:
+Z | User is connected via TLS.
+B | User is a bot.
+E | User can receive roleplaying commands.
+T | User is blocked from sending CTCP messages.`
+T | CTCP messages to the user are blocked.`
snomaskHelpText = `== Server Notice Masks ==

Oragono supports the following server notice masks for operators:
Expand Down
3 changes: 2 additions & 1 deletion irc/modes/modes.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var (
SupportedChannelModes = Modes{
BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, RegisteredOnlySpeak,
Secret, UserLimit, NoCTCP,
Secret, UserLimit, NoCTCP, Auditorium,
}
)

Expand Down Expand Up @@ -113,6 +113,7 @@ const (

// Channel Modes
const (
Auditorium Mode = 'u' // flag
BanMask Mode = 'b' // arg
ChanRoleplaying Mode = 'E' // flag
ExceptMask Mode = 'e' // arg
Expand Down
2 changes: 1 addition & 1 deletion irctest