From 258af017d4465eb74f2b3c8aa0ff715d23678371 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Mon, 15 Dec 2025 21:57:42 -0500 Subject: [PATCH 1/4] fix #2309 If bob is monitoring alice, bob should get METADATA lines for alice even if bob doesn't have extended-monitor. The four caps that explicitly require extended-monitor are: away-notify, chghost, setname, account-notify. --- irc/client.go | 2 +- irc/handlers.go | 6 +++--- irc/monitor.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/irc/client.go b/irc/client.go index 42a6dc95..c20886ce 100644 --- a/irc/client.go +++ b/irc/client.go @@ -1121,7 +1121,7 @@ func (client *Client) SetOper(oper *Oper) { func (client *Client) sendChghost(oldNickMask string, vhost string) { details := client.Details() isBot := client.HasMode(modes.Bot) - for fClient := range client.FriendsMonitors(caps.ChgHost) { + for fClient := range client.FriendsMonitors(caps.ExtendedMonitor, caps.ChgHost) { fClient.sendFromClientInternal(false, time.Time{}, "", oldNickMask, details.accountName, isBot, nil, "CHGHOST", details.username, vhost) } } diff --git a/irc/handlers.go b/irc/handlers.go index b74800f0..449add65 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -114,7 +114,7 @@ func sendSuccessfulAccountAuth(service *ircService, client *Client, rb *Response if client.Registered() { // dispatch account-notify - for friend := range client.FriendsMonitors(caps.AccountNotify) { + for friend := range client.FriendsMonitors(caps.ExtendedMonitor, caps.AccountNotify) { if friend != rb.session { friend.Send(nil, details.nickMask, "ACCOUNT", details.accountName) } @@ -531,7 +531,7 @@ func dispatchAwayNotify(client *Client, awayMessage string) { // dispatch away-notify details := client.Details() isBot := client.HasMode(modes.Bot) - for session := range client.FriendsMonitors(caps.AwayNotify) { + for session := range client.FriendsMonitors(caps.ExtendedMonitor, caps.AwayNotify) { if awayMessage != "" { session.sendFromClientInternal(false, time.Time{}, "", details.nickMask, details.accountName, isBot, nil, "AWAY", awayMessage) } else { @@ -3650,7 +3650,7 @@ func setnameHandler(server *Server, client *Client, msg ircmsg.Message, rb *Resp // alert friends now := time.Now().UTC() - friends := client.FriendsMonitors(caps.SetName) + friends := client.FriendsMonitors(caps.ExtendedMonitor, caps.SetName) delete(friends, rb.session) isBot := client.HasMode(modes.Bot) for session := range friends { diff --git a/irc/monitor.go b/irc/monitor.go index 46ab46e6..b0ab566f 100644 --- a/irc/monitor.go +++ b/irc/monitor.go @@ -31,7 +31,7 @@ func (manager *MonitorManager) AddMonitors(users utils.HashSet[*Session], cfnick manager.RLock() defer manager.RUnlock() for session := range manager.watchedby[cfnick] { - if session.capabilities.Has(caps.ExtendedMonitor) && session.capabilities.HasAll(capabs...) { + if session.capabilities.HasAll(capabs...) { users.Add(session) } } From 623735c757fb55554245eb37652d9765eb8e69e3 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Mon, 15 Dec 2025 22:52:15 -0500 Subject: [PATCH 2/4] Revert "fix #2309" This reverts commit 258af017d4465eb74f2b3c8aa0ff715d23678371. --- irc/client.go | 2 +- irc/handlers.go | 6 +++--- irc/monitor.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/irc/client.go b/irc/client.go index c20886ce..42a6dc95 100644 --- a/irc/client.go +++ b/irc/client.go @@ -1121,7 +1121,7 @@ func (client *Client) SetOper(oper *Oper) { func (client *Client) sendChghost(oldNickMask string, vhost string) { details := client.Details() isBot := client.HasMode(modes.Bot) - for fClient := range client.FriendsMonitors(caps.ExtendedMonitor, caps.ChgHost) { + for fClient := range client.FriendsMonitors(caps.ChgHost) { fClient.sendFromClientInternal(false, time.Time{}, "", oldNickMask, details.accountName, isBot, nil, "CHGHOST", details.username, vhost) } } diff --git a/irc/handlers.go b/irc/handlers.go index 449add65..b74800f0 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -114,7 +114,7 @@ func sendSuccessfulAccountAuth(service *ircService, client *Client, rb *Response if client.Registered() { // dispatch account-notify - for friend := range client.FriendsMonitors(caps.ExtendedMonitor, caps.AccountNotify) { + for friend := range client.FriendsMonitors(caps.AccountNotify) { if friend != rb.session { friend.Send(nil, details.nickMask, "ACCOUNT", details.accountName) } @@ -531,7 +531,7 @@ func dispatchAwayNotify(client *Client, awayMessage string) { // dispatch away-notify details := client.Details() isBot := client.HasMode(modes.Bot) - for session := range client.FriendsMonitors(caps.ExtendedMonitor, caps.AwayNotify) { + for session := range client.FriendsMonitors(caps.AwayNotify) { if awayMessage != "" { session.sendFromClientInternal(false, time.Time{}, "", details.nickMask, details.accountName, isBot, nil, "AWAY", awayMessage) } else { @@ -3650,7 +3650,7 @@ func setnameHandler(server *Server, client *Client, msg ircmsg.Message, rb *Resp // alert friends now := time.Now().UTC() - friends := client.FriendsMonitors(caps.ExtendedMonitor, caps.SetName) + friends := client.FriendsMonitors(caps.SetName) delete(friends, rb.session) isBot := client.HasMode(modes.Bot) for session := range friends { diff --git a/irc/monitor.go b/irc/monitor.go index b0ab566f..46ab46e6 100644 --- a/irc/monitor.go +++ b/irc/monitor.go @@ -31,7 +31,7 @@ func (manager *MonitorManager) AddMonitors(users utils.HashSet[*Session], cfnick manager.RLock() defer manager.RUnlock() for session := range manager.watchedby[cfnick] { - if session.capabilities.HasAll(capabs...) { + if session.capabilities.Has(caps.ExtendedMonitor) && session.capabilities.HasAll(capabs...) { users.Add(session) } } From eda5c01b2d81eef3b3bf2b659e126c4ae9b96d1e Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Mon, 15 Dec 2025 22:58:07 -0500 Subject: [PATCH 3/4] fix #2309, take 2 --- irc/monitor.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/irc/monitor.go b/irc/monitor.go index 46ab46e6..617648b7 100644 --- a/irc/monitor.go +++ b/irc/monitor.go @@ -28,12 +28,26 @@ func (mm *MonitorManager) Initialize() { // AddMonitors adds clients using extended-monitor monitoring `client`'s nick to the passed user set. func (manager *MonitorManager) AddMonitors(users utils.HashSet[*Session], cfnick string, capabs ...caps.Capability) { + var requireExtendedMonitor bool + for _, c := range capabs { + // these are the four capabilities that explicitly require extended-monitor; + // draft/metadata-2 does not + if c == caps.AccountNotify || c == caps.AwayNotify || c == caps.ChgHost || c == caps.SetName { + requireExtendedMonitor = true + break + } + } + manager.RLock() defer manager.RUnlock() for session := range manager.watchedby[cfnick] { - if session.capabilities.Has(caps.ExtendedMonitor) && session.capabilities.HasAll(capabs...) { - users.Add(session) + if requireExtendedMonitor && !session.capabilities.Has(caps.ExtendedMonitor) { + continue } + if !session.capabilities.HasAll(capabs...) { + continue + } + users.Add(session) } } From 385f606d6705173a1a3c749401362b09ec685dea Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Fri, 19 Dec 2025 04:43:22 -0500 Subject: [PATCH 4/4] don't check extended-monitor --- irc/monitor.go | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/irc/monitor.go b/irc/monitor.go index 617648b7..7019f64a 100644 --- a/irc/monitor.go +++ b/irc/monitor.go @@ -28,26 +28,16 @@ func (mm *MonitorManager) Initialize() { // AddMonitors adds clients using extended-monitor monitoring `client`'s nick to the passed user set. func (manager *MonitorManager) AddMonitors(users utils.HashSet[*Session], cfnick string, capabs ...caps.Capability) { - var requireExtendedMonitor bool - for _, c := range capabs { - // these are the four capabilities that explicitly require extended-monitor; - // draft/metadata-2 does not - if c == caps.AccountNotify || c == caps.AwayNotify || c == caps.ChgHost || c == caps.SetName { - requireExtendedMonitor = true - break - } - } + // technically, we should check extended-monitor here, but it's not really necessary + // since clients will ignore AWAY, ACCOUNT, CHGHOST, and SETNAME for users + // they're not tracking manager.RLock() defer manager.RUnlock() for session := range manager.watchedby[cfnick] { - if requireExtendedMonitor && !session.capabilities.Has(caps.ExtendedMonitor) { - continue + if session.capabilities.HasAll(capabs...) { + users.Add(session) } - if !session.capabilities.HasAll(capabs...) { - continue - } - users.Add(session) } }