mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-29 15:40:02 +01:00
fix #484
This commit is contained in:
parent
4a7ca14bdc
commit
8c99dcb2c7
@ -439,8 +439,12 @@ func (channel *Channel) regenerateMembersCache() {
|
|||||||
|
|
||||||
// Names sends the list of users joined to the channel to the given client.
|
// Names sends the list of users joined to the channel to the given client.
|
||||||
func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
|
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)
|
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)
|
isMultiPrefix := rb.session.capabilities.Has(caps.MultiPrefix)
|
||||||
isUserhostInNames := rb.session.capabilities.Has(caps.UserhostInNames)
|
isUserhostInNames := rb.session.capabilities.Has(caps.UserhostInNames)
|
||||||
|
|
||||||
@ -464,6 +468,9 @@ func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
|
|||||||
if !isJoined && target.HasMode(modes.Invisible) && !isOper {
|
if !isJoined && target.HasMode(modes.Invisible) && !isOper {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if respectAuditorium && modeSet.HighestChannelUserMode() == modes.Mode(0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
prefix := modeSet.Prefixes(isMultiPrefix)
|
prefix := modeSet.Prefixes(isMultiPrefix)
|
||||||
if buffer.Len()+len(nick)+len(prefix)+1 > maxNamLen {
|
if buffer.Len()+len(nick)+len(prefix)+1 > maxNamLen {
|
||||||
namesLines = append(namesLines, buffer.String())
|
namesLines = append(namesLines, buffer.String())
|
||||||
@ -748,8 +755,9 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
var message utils.SplitMessage
|
var message utils.SplitMessage
|
||||||
|
respectAuditorium := givenMode == modes.Mode(0) && channel.flags.HasMode(modes.Auditorium)
|
||||||
// no history item for fake persistent joins
|
// no history item for fake persistent joins
|
||||||
if rb != nil {
|
if rb != nil && !respectAuditorium {
|
||||||
message = utils.MakeMessage("")
|
message = utils.MakeMessage("")
|
||||||
histItem := history.Item{
|
histItem := history.Item{
|
||||||
Type: history.Join,
|
Type: history.Join,
|
||||||
@ -772,6 +780,14 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
|||||||
|
|
||||||
isAway, awayMessage := client.Away()
|
isAway, awayMessage := client.Away()
|
||||||
for _, member := range channel.Members() {
|
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() {
|
for _, session := range member.Sessions() {
|
||||||
if session == rb.session {
|
if session == rb.session {
|
||||||
continue
|
continue
|
||||||
@ -889,8 +905,12 @@ func (channel *Channel) playJoinForSession(session *Session) {
|
|||||||
|
|
||||||
// Part parts the given client from this channel, with the given message.
|
// Part parts the given client from this channel, with the given message.
|
||||||
func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
|
func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
|
||||||
chname := channel.Name()
|
channel.stateMutex.RLock()
|
||||||
if !channel.hasClient(client) {
|
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"))
|
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.Nick(), chname, client.t("You're not on that channel"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -905,7 +925,17 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
|
|||||||
if message != "" {
|
if message != "" {
|
||||||
params = append(params, message)
|
params = append(params, message)
|
||||||
}
|
}
|
||||||
|
respectAuditorium := channel.flags.HasMode(modes.Auditorium) &&
|
||||||
|
clientModes.HighestChannelUserMode() == modes.Mode(0)
|
||||||
for _, member := range channel.Members() {
|
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...)
|
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...)
|
rb.AddFromClient(splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", params...)
|
||||||
@ -915,12 +945,14 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !respectAuditorium {
|
||||||
channel.AddHistoryItem(history.Item{
|
channel.AddHistoryItem(history.Item{
|
||||||
Type: history.Part,
|
Type: history.Part,
|
||||||
Nick: details.nickMask,
|
Nick: details.nickMask,
|
||||||
AccountName: details.accountName,
|
AccountName: details.accountName,
|
||||||
Message: splitMessage,
|
Message: splitMessage,
|
||||||
}, details.account)
|
}, details.account)
|
||||||
|
}
|
||||||
|
|
||||||
client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", details.nick, chname))
|
client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", details.nick, chname))
|
||||||
}
|
}
|
||||||
@ -951,6 +983,9 @@ func (channel *Channel) resumeAndAnnounce(session *Session) {
|
|||||||
// send join for old clients
|
// send join for old clients
|
||||||
chname := channel.Name()
|
chname := channel.Name()
|
||||||
details := session.client.Details()
|
details := session.client.Details()
|
||||||
|
// 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 _, member := range channel.Members() {
|
||||||
for _, session := range member.Sessions() {
|
for _, session := range member.Sessions() {
|
||||||
if session.capabilities.Has(caps.Resume) {
|
if session.capabilities.Has(caps.Resume) {
|
||||||
@ -968,6 +1003,7 @@ func (channel *Channel) resumeAndAnnounce(session *Session) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rb := NewResponseBuffer(session)
|
rb := NewResponseBuffer(session)
|
||||||
// use blocking i/o to synchronize with the later history replay
|
// use blocking i/o to synchronize with the later history replay
|
||||||
@ -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
|
// data for RPL_LIST
|
||||||
func (channel *Channel) listData() (memberCount int, name, topic string) {
|
func (channel *Channel) listData() (memberCount int, name, topic string) {
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
|
@ -934,7 +934,7 @@ func (session *Session) playResume() {
|
|||||||
// work out how much time, if any, is not covered by history buffers
|
// work out how much time, if any, is not covered by history buffers
|
||||||
// assume that a persistent buffer covers the whole resume period
|
// assume that a persistent buffer covers the whole resume period
|
||||||
for _, channel := range client.Channels() {
|
for _, channel := range client.Channels() {
|
||||||
for _, member := range channel.Members() {
|
for _, member := range channel.auditoriumFriends(client) {
|
||||||
friends.Add(member)
|
friends.Add(member)
|
||||||
}
|
}
|
||||||
status, _ := channel.historyStatus(config)
|
status, _ := channel.historyStatus(config)
|
||||||
@ -1161,7 +1161,7 @@ func (client *Client) Friends(capabs ...caps.Capability) (result map[*Session]em
|
|||||||
addFriendsToSet(result, client, capabs...)
|
addFriendsToSet(result, client, capabs...)
|
||||||
|
|
||||||
for _, channel := range client.Channels() {
|
for _, channel := range client.Channels() {
|
||||||
for _, member := range channel.Members() {
|
for _, member := range channel.auditoriumFriends(client) {
|
||||||
addFriendsToSet(result, member, capabs...)
|
addFriendsToSet(result, member, capabs...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1512,10 +1512,10 @@ func (client *Client) destroy(session *Session) {
|
|||||||
friends := make(ClientSet)
|
friends := make(ClientSet)
|
||||||
channels = client.Channels()
|
channels = client.Channels()
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
channel.Quit(client)
|
for _, member := range channel.auditoriumFriends(client) {
|
||||||
for _, member := range channel.Members() {
|
|
||||||
friends.Add(member)
|
friends.Add(member)
|
||||||
}
|
}
|
||||||
|
channel.Quit(client)
|
||||||
}
|
}
|
||||||
friends.Remove(client)
|
friends.Remove(client)
|
||||||
|
|
||||||
|
@ -3051,7 +3051,13 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
|
|||||||
if channel != nil {
|
if channel != nil {
|
||||||
isJoined := channel.hasClient(client)
|
isJoined := channel.hasClient(client)
|
||||||
if !channel.flags.HasMode(modes.Secret) || isJoined || isOper {
|
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 {
|
if !member.HasMode(modes.Invisible) || isJoined || isOper {
|
||||||
client.rplWhoReply(channel, member, rb, isWhox, fields, whoType)
|
client.rplWhoReply(channel, member, rb, isWhox, fields, whoType)
|
||||||
}
|
}
|
||||||
@ -3072,6 +3078,9 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, channel := range otherClient.Channels() {
|
for _, channel := range otherClient.Channels() {
|
||||||
|
if channel.flags.HasMode(modes.Auditorium) {
|
||||||
|
return false // TODO this should respect +v etc.
|
||||||
|
}
|
||||||
if _, present := userChannels[channel]; present {
|
if _, present := userChannels[channel]; present {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,8 @@ Oragono supports the following channel modes:
|
|||||||
+t | Only channel opers can modify the topic.
|
+t | Only channel opers can modify the topic.
|
||||||
+E | Roleplaying commands are enabled in the channel.
|
+E | Roleplaying commands are enabled in the channel.
|
||||||
+C | Clients are blocked from sending CTCP messages 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 =
|
= Prefixes =
|
||||||
|
|
||||||
@ -74,7 +76,7 @@ Oragono supports the following user modes:
|
|||||||
+Z | User is connected via TLS.
|
+Z | User is connected via TLS.
|
||||||
+B | User is a bot.
|
+B | User is a bot.
|
||||||
+E | User can receive roleplaying commands.
|
+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 ==
|
snomaskHelpText = `== Server Notice Masks ==
|
||||||
|
|
||||||
Oragono supports the following server notice masks for operators:
|
Oragono supports the following server notice masks for operators:
|
||||||
|
@ -23,7 +23,7 @@ var (
|
|||||||
SupportedChannelModes = Modes{
|
SupportedChannelModes = Modes{
|
||||||
BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
|
BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
|
||||||
Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, RegisteredOnlySpeak,
|
Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, RegisteredOnlySpeak,
|
||||||
Secret, UserLimit, NoCTCP,
|
Secret, UserLimit, NoCTCP, Auditorium,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -113,6 +113,7 @@ const (
|
|||||||
|
|
||||||
// Channel Modes
|
// Channel Modes
|
||||||
const (
|
const (
|
||||||
|
Auditorium Mode = 'u' // flag
|
||||||
BanMask Mode = 'b' // arg
|
BanMask Mode = 'b' // arg
|
||||||
ChanRoleplaying Mode = 'E' // flag
|
ChanRoleplaying Mode = 'E' // flag
|
||||||
ExceptMask Mode = 'e' // arg
|
ExceptMask Mode = 'e' // arg
|
||||||
|
2
irctest
2
irctest
@ -1 +1 @@
|
|||||||
Subproject commit 0287b837971c27ee55bc4dca95d31afc68d2aeea
|
Subproject commit 616785eae403536954f1b1181f74ef51343e33f7
|
Loading…
Reference in New Issue
Block a user