summaryrefslogtreecommitdiff
path: root/src/papod.clj
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2026-04-26 20:38:06 -0300
committerEuAndreh <eu@euandre.org>2026-04-26 20:38:06 -0300
commit5a9f800c604b5d59bf71bd077be1c5434cee1715 (patch)
tree3073c43e9418c5658836074c777b967af501f8d6 /src/papod.clj
parentReject non-UTF-8 messages with FAIL INVALID_UTF8 (diff)
downloadpapod-5a9f800c604b5d59bf71bd077be1c5434cee1715.tar.gz
papod-5a9f800c604b5d59bf71bd077be1c5434cee1715.tar.xz
Implement +b channel ban mode with glob mask matching
- Track per-channel ban masks in :chan-bans atom - MODE +b <mask> adds, -b removes (case-insensitive) - MODE +b without mask returns RPL_BANLIST + RPL_ENDOFBANLIST - JOIN checks ban list and returns ERR_BANNEDFROMCHAN (474) - Update CHANMODES isupport to b,k,l,nt
Diffstat (limited to 'src/papod.clj')
-rw-r--r--src/papod.clj76
1 files changed, 73 insertions, 3 deletions
diff --git a/src/papod.clj b/src/papod.clj
index 316b65a..8e1851c 100644
--- a/src/papod.clj
+++ b/src/papod.clj
@@ -1064,7 +1064,7 @@
(numeric-reply client "005"
(str "AWAYLEN=200 CASEMAPPING=ascii"
" CHANLIMIT=#:100"
- " CHANMODES=,,l,nt"
+ " CHANMODES=b,k,l,nt"
" CHANNELLEN=64 CHANTYPES=#"
" ELIST= HOSTLEN=64"
" KICKLEN=300 MAXLIST=b:50"
@@ -2236,6 +2236,34 @@
(get @(:chan-modes components) handle))
"+nt"))
+(defn- glob-pattern
+ [^String mask]
+ (re-pattern
+ (str "^"
+ (->> mask
+ (map (fn [c]
+ (case c
+ \* ".*"
+ \? "."
+ (java.util.regex.Pattern/quote
+ (str c)))))
+ (apply str))
+ "$")))
+
+(defn- nuh-mask
+ [nick]
+ (str nick "!" nick "@localhost"))
+
+(defn- ban-matches?
+ [bans nick]
+ (let [nuh (nuh-mask nick)]
+ (some (fn [mask]
+ (boolean
+ (re-matches (glob-pattern
+ (string/lower-case mask))
+ (string/lower-case nuh))))
+ bans)))
+
(defn- chan-symbol
[components handle]
(let [m (chan-modes-for components handle)]
@@ -2304,6 +2332,16 @@
(str handle
" :Cannot join channel (+l)"))]
+ ;; +b: banned
+ (and existing?
+ (not (contains? (get @channels handle) nick))
+ (let [bans-atom (:chan-bans components)
+ bans (when bans-atom
+ (get @bans-atom handle #{}))]
+ (and (seq bans) (ban-matches? bans nick))))
+ [(numeric-reply client "474"
+ (str handle " :Cannot join channel (+b)"))]
+
:else
(let [db (when conn (d/db conn))
channel-eid (when db (resolve-channel db handle))
@@ -3811,10 +3849,41 @@
(:w m) line)))
[])))
+ ;; +b/-b with mask: add/remove ban
+ (and (= \b mode-char) mode-arg)
+ (let [bans-atom (:chan-bans components)
+ mask mode-arg
+ mask-key (string/lower-case mask)
+ line (str ":" nick " MODE " target
+ " " mode-str " " mask)]
+ (when bans-atom
+ (if adding?
+ (swap! bans-atom update target
+ (fnil conj #{}) mask-key)
+ (swap! bans-atom update target
+ (fnil disj #{}) mask-key)))
+ (when (and clients channels)
+ (doseq [mn (get @channels target)
+ :let [m (get @clients mn)]
+ :when m]
+ (deliver-to-client! (:w m) line)))
+ [])
+
;; +b: ban list query
(and (= \b mode-char) (nil? mode-arg))
- [(numeric-reply client "368"
- (str target " :End of channel ban list"))]
+ (let [bans-atom (:chan-bans components)
+ cur-bans (when bans-atom
+ (get @bans-atom target #{}))]
+ (concat
+ (mapv (fn [mask]
+ (numeric-reply client "367"
+ (str target " " mask " " nick
+ " " (quot
+ (System/currentTimeMillis)
+ 1000))))
+ (sort cur-bans))
+ [(numeric-reply client "368"
+ (str target " :End of channel ban list"))]))
:else []))))
@@ -4495,6 +4564,7 @@
:chan-modes (atom {})
:chan-keys (atom {})
:chan-limits (atom {})
+ :chan-bans (atom {})
:invites (atom {})
:whowas (atom [])
:max-users (atom 0)