diff options
| author | EuAndreh <eu@euandre.org> | 2026-04-27 22:53:03 -0300 |
|---|---|---|
| committer | EuAndreh <eu@euandre.org> | 2026-04-27 22:53:03 -0300 |
| commit | 27f27e08f3f3d6ac6d29bcf7010a7fc8a5ab6f93 (patch) | |
| tree | a1b3686b0574f97ee9cedfc32fb23162237f3041 /src/papod.clj | |
| parent | MONITOR command and online-state notifications (diff) | |
| download | papod-27f27e08f3f3d6ac6d29bcf7010a7fc8a5ab6f93.tar.gz papod-27f27e08f3f3d6ac6d29bcf7010a7fc8a5ab6f93.tar.xz | |
extended-monitor capability
Watchers that negotiate extended-monitor (alongside the appropriate
gating cap) now receive AWAY, SETNAME, and ACCOUNT events for
monitored nicks even when they don't share a channel. The channel-
member broadcast and the extended-monitor fan-out share a `seen` set
so a watcher never gets a line twice.
Implementation: notify-extended-monitors\! looks up the nick's watchers
in :nick-monitors, filters by both extended-monitor and the gating cap
(away-notify / setname / account-notify), and skips anyone already
delivered to. handle-away, handle-setname, and broadcast-account-
notify\! each call it after the existing channel-member loop.
Diffstat (limited to 'src/papod.clj')
| -rw-r--r-- | src/papod.clj | 119 |
1 files changed, 76 insertions, 43 deletions
diff --git a/src/papod.clj b/src/papod.clj index 9f148c3..96530a8 100644 --- a/src/papod.clj +++ b/src/papod.clj @@ -1030,26 +1030,30 @@ (when (cracha/user-by-email c nick) nick))) +(declare notify-extended-monitors!) + (defn- broadcast-account-notify! "Send :nick ACCOUNT <account-or-*> to every other member of every channel `nick` is in, gated on the recipient negotiating account- - notify." + notify. Also fans out to extended-monitor watchers." [components nick account] (let [{:keys [clients channels]} components - line (str ":" nick " ACCOUNT " (or account "*"))] + line (str ":" nick " ACCOUNT " (or account "*")) + seen (atom #{nick})] (when (and clients channels) - (let [seen (volatile! #{})] - (doseq [[handle members] @channels - :when (contains? members nick) - mn members - :when (and (not= mn nick) - (not (@seen mn)))] - (vswap! seen conj mn) - (when-let [m (get @clients mn)] - (let [ca (:client-atom m) - caps (when ca (or (:caps @ca) #{}))] - (when (caps "account-notify") - (deliver-to-client! (:w m) line))))))))) + (doseq [[handle members] @channels + :when (contains? members nick) + mn members + :when (and (not= mn nick) + (not (@seen mn)))] + (swap! seen conj mn) + (when-let [m (get @clients mn)] + (let [ca (:client-atom m) + caps (when ca (or (:caps @ca) #{}))] + (when (caps "account-notify") + (deliver-to-client! (:w m) line)))))) + (notify-extended-monitors! + components nick "account-notify" line seen))) (defn- authenticate! [client _components] @@ -1400,6 +1404,7 @@ " away-notify utf8only" " account-notify account-tag chghost" " setname invite-notify" + " extended-monitor" " draft/multiline=max-bytes=4096" ",max-lines=32" " draft/read-marker" @@ -1415,6 +1420,7 @@ " away-notify utf8only" " account-notify account-tag chghost" " setname invite-notify" + " extended-monitor" " draft/multiline draft/read-marker" " draft/message-redaction" " draft/message-editing" @@ -1432,6 +1438,7 @@ "away-notify" "utf8only" "account-notify" "account-tag" "chghost" "setname" "invite-notify" + "extended-monitor" "draft/multiline" "draft/read-marker" "draft/message-redaction" "draft/message-editing" @@ -3761,23 +3768,27 @@ src (client-prefix client) notify! (fn [line] - (let [{:keys [clients channels]} components] + (let [{:keys [clients channels]} components + seen (atom #{nick})] (when (and clients channels) - (let [seen (atom #{nick})] - (doseq [[ch members] @channels - :when (contains? members nick) - mn members - :when (not (contains? @seen mn)) - :let [m (get @clients mn) - ca (:client-atom m) - caps (or (when ca - (:caps @ca)) - #{})] - :when (and m - (contains? - caps "away-notify"))] - (deliver-to-client! (:w m) line) - (swap! seen conj mn))))))] + (doseq [[ch members] @channels + :when (contains? members nick) + mn members + :when (not (contains? @seen mn)) + :let [m (get @clients mn) + ca (:client-atom m) + caps (or (when ca + (:caps @ca)) + #{})] + :when (and m + (contains? + caps "away-notify"))] + (deliver-to-client! (:w m) line) + (swap! seen conj mn))) + ;; extended-monitor: AWAY also goes to watchers + ;; that negotiated extended-monitor + away-notify + (notify-extended-monitors! + components nick "away-notify" line seen)))] (if (or (empty? params) (string/blank? msg)) (do (swap! client dissoc :away) (notify! (str ":" src " AWAY")) @@ -3912,6 +3923,24 @@ (str ":" +server-name+ " " numeric " " wn " :" nick)))))) +(defn- notify-extended-monitors! + "Deliver `line` to each watcher of `nick` that negotiated + extended-monitor and the given gating cap (away-notify, setname, + account-notify, chghost), excluding any watcher already in `seen`." + [components nick gating-cap line seen] + (when-let [nm (:nick-monitors components)] + (let [low (string/lower-case nick)] + (doseq [watcher (get @nm low #{}) + :let [w (:w @watcher) + caps (or (:caps @watcher) #{}) + wn (:nick @watcher)] + :when (and w + (caps "extended-monitor") + (caps gating-cap) + (not (contains? @seen wn)))] + (deliver-to-client! w line) + (swap! seen conj wn))))) + (defn- handle-setname [params client components] (let [{:keys [clients channels]} components @@ -3927,21 +3956,25 @@ [(str "FAIL SETNAME INVALID_REALNAME :Invalid realname")] :else - (let [line (str ":" src " SETNAME :" new-name)] + (let [line (str ":" src " SETNAME :" new-name) + seen (atom #{nick})] (swap! client assoc-in [:user :realname] new-name) (when (and clients channels) - (let [seen (atom #{nick})] - (doseq [[ch members] @channels - :when (contains? members nick) - mn members - :when (not (contains? @seen mn)) - :let [m (get @clients mn) - ca (:client-atom m) - caps (or (when ca (:caps @ca)) - #{})] - :when (and m (caps "setname"))] - (deliver-to-client! (:w m) line) - (swap! seen conj mn)))) + (doseq [[ch members] @channels + :when (contains? members nick) + mn members + :when (not (contains? @seen mn)) + :let [m (get @clients mn) + ca (:client-atom m) + caps (or (when ca (:caps @ca)) + #{})] + :when (and m (caps "setname"))] + (deliver-to-client! (:w m) line) + (swap! seen conj mn))) + ;; extended-monitor: SETNAME also goes to watchers + ;; with extended-monitor + setname. + (notify-extended-monitors! + components nick "setname" line seen) [line])))) (defn- handle-batch-open! |
