Allow admins to broadcast message to all bouncer users
Typically done via: /notice $<bouncer> <message> Or, for a connection not bound to a specific network: /notice $* <message> The message is broadcast as BouncerServ, because that's the only user that can be trusted to belong to the bouncer by users. Any other prefix would conflict with the upstream network.
This commit is contained in:
parent
eca4c41223
commit
d7b1c5a9a2
@ -1913,6 +1913,33 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
|||||||
tags := copyClientTags(msg.Tags)
|
tags := copyClientTags(msg.Tags)
|
||||||
|
|
||||||
for _, name := range strings.Split(targetsStr, ",") {
|
for _, name := range strings.Split(targetsStr, ",") {
|
||||||
|
if name == "$"+dc.srv.Hostname || (name == "$*" && dc.network == nil) {
|
||||||
|
// "$" means a server mask follows. If it's the bouncer's
|
||||||
|
// hostname, broadcast the message to all bouncer users.
|
||||||
|
if !dc.user.Admin {
|
||||||
|
return ircError{&irc.Message{
|
||||||
|
Prefix: dc.srv.prefix(),
|
||||||
|
Command: irc.ERR_BADMASK,
|
||||||
|
Params: []string{dc.nick, name, "Permission denied to broadcast message to all bouncer users"},
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
dc.logger.Printf("broadcasting bouncer-wide %v: %v", msg.Command, text)
|
||||||
|
|
||||||
|
broadcastTags := tags.Copy()
|
||||||
|
broadcastTags["time"] = irc.TagValue(time.Now().UTC().Format(serverTimeLayout))
|
||||||
|
broadcastMsg := &irc.Message{
|
||||||
|
Tags: broadcastTags,
|
||||||
|
Prefix: servicePrefix,
|
||||||
|
Command: msg.Command,
|
||||||
|
Params: []string{name, text},
|
||||||
|
}
|
||||||
|
dc.srv.forEachUser(func(u *user) {
|
||||||
|
u.events <- eventBroadcast{broadcastMsg}
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if dc.network == nil && casemapASCII(name) == dc.nickCM {
|
if dc.network == nil && casemapASCII(name) == dc.nickCM {
|
||||||
dc.SendMessage(msg)
|
dc.SendMessage(msg)
|
||||||
continue
|
continue
|
||||||
|
@ -124,6 +124,14 @@ func (s *Server) createUser(user *User) (*user, error) {
|
|||||||
return s.addUserLocked(user), nil
|
return s.addUserLocked(user), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) forEachUser(f func(*user)) {
|
||||||
|
s.lock.Lock()
|
||||||
|
for _, u := range s.users {
|
||||||
|
f(u)
|
||||||
|
}
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) getUser(name string) *user {
|
func (s *Server) getUser(name string) *user {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
u := s.users[name]
|
u := s.users[name]
|
||||||
|
@ -1768,6 +1768,11 @@ func (uc *upstreamConn) appendLog(entity string, msg *irc.Message) (msgID string
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't store messages with a server mask target
|
||||||
|
if strings.HasPrefix(entity, "$") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
entityCM := uc.network.casemap(entity)
|
entityCM := uc.network.casemap(entity)
|
||||||
if entityCM == "nickserv" {
|
if entityCM == "nickserv" {
|
||||||
// The messages sent/received from NickServ may contain
|
// The messages sent/received from NickServ may contain
|
||||||
|
9
user.go
9
user.go
@ -53,6 +53,10 @@ type eventChannelDetach struct {
|
|||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type eventBroadcast struct {
|
||||||
|
msg *irc.Message
|
||||||
|
}
|
||||||
|
|
||||||
type eventStop struct{}
|
type eventStop struct{}
|
||||||
|
|
||||||
type deliveredClientMap map[string]string // client name -> msg ID
|
type deliveredClientMap map[string]string // client name -> msg ID
|
||||||
@ -633,6 +637,11 @@ func (u *user) run() {
|
|||||||
dc.logger.Printf("failed to handle message %q: %v", msg, err)
|
dc.logger.Printf("failed to handle message %q: %v", msg, err)
|
||||||
dc.Close()
|
dc.Close()
|
||||||
}
|
}
|
||||||
|
case eventBroadcast:
|
||||||
|
msg := e.msg
|
||||||
|
u.forEachDownstream(func(dc *downstreamConn) {
|
||||||
|
dc.SendMessage(msg)
|
||||||
|
})
|
||||||
case eventStop:
|
case eventStop:
|
||||||
u.forEachDownstream(func(dc *downstreamConn) {
|
u.forEachDownstream(func(dc *downstreamConn) {
|
||||||
dc.Close()
|
dc.Close()
|
||||||
|
Loading…
Reference in New Issue
Block a user