diff --git a/downstream.go b/downstream.go index 238f4eb..8de1152 100644 --- a/downstream.go +++ b/downstream.go @@ -1913,6 +1913,33 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error { tags := copyClientTags(msg.Tags) 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 { dc.SendMessage(msg) continue diff --git a/server.go b/server.go index be91152..db08a73 100644 --- a/server.go +++ b/server.go @@ -124,6 +124,14 @@ func (s *Server) createUser(user *User) (*user, error) { 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 { s.lock.Lock() u := s.users[name] diff --git a/upstream.go b/upstream.go index 6c46814..e033410 100644 --- a/upstream.go +++ b/upstream.go @@ -1768,6 +1768,11 @@ func (uc *upstreamConn) appendLog(entity string, msg *irc.Message) (msgID string return "" } + // Don't store messages with a server mask target + if strings.HasPrefix(entity, "$") { + return "" + } + entityCM := uc.network.casemap(entity) if entityCM == "nickserv" { // The messages sent/received from NickServ may contain diff --git a/user.go b/user.go index adb315d..1b5f4f2 100644 --- a/user.go +++ b/user.go @@ -53,6 +53,10 @@ type eventChannelDetach struct { name string } +type eventBroadcast struct { + msg *irc.Message +} + type eventStop struct{} 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.Close() } + case eventBroadcast: + msg := e.msg + u.forEachDownstream(func(dc *downstreamConn) { + dc.SendMessage(msg) + }) case eventStop: u.forEachDownstream(func(dc *downstreamConn) { dc.Close()