diff options
| author | EuAndreh <eu@euandre.org> | 2026-04-25 06:34:56 -0300 |
|---|---|---|
| committer | EuAndreh <eu@euandre.org> | 2026-04-25 06:34:56 -0300 |
| commit | 7b1572e68f886d4b4eadb16a9193b968c86fbc74 (patch) | |
| tree | a6688c7274643a02c61419b6ac8e403c7db07dee | |
| parent | Add unit+integration tests for WHOIS, WHO, MODE, TOPIC, KICK, AWAY, (diff) | |
| download | papod-7b1572e68f886d4b4eadb16a9193b968c86fbc74.tar.gz papod-7b1572e68f886d4b4eadb16a9193b968c86fbc74.tar.xz | |
Implement LUSERS, WHOWAS, INFO, INVITE; fix AWAY, LIST, WHO
New commands:
- LUSERS: return 251-255 with user/channel counts (only counts
registered clients to avoid stale-state inflation)
- WHOWAS: return 406 (no such nickname) + 369 (end of WHOWAS)
for all queries (no history tracking yet)
- INFO: return 371 (server info) + 374 (end of INFO)
- INVITE: send invite to target, return 341 (inviting) or
443 (already on channel)
Fixes:
- AWAY: empty trailing param (AWAY :) now unsets away status
- LIST: only show channels with active members; support
LIST #specific filtering
- WHO: include away flag (H=here, G=gone) in 352 replies
irctest: 214 passed, 440 failed, 218 skipped (up from 205).
Unit: 260 assertions, Integration: 38 assertions — all pass.
| -rw-r--r-- | src/papod.clj | 141 |
1 files changed, 113 insertions, 28 deletions
diff --git a/src/papod.clj b/src/papod.clj index f29b3f6..94c7bb2 100644 --- a/src/papod.clj +++ b/src/papod.clj @@ -2432,16 +2432,17 @@ (defn- handle-away [params client] - (if (empty? params) - (do (swap! client dissoc :away) - [(numeric-reply client "305" - ":You are no longer marked as being away")]) - (let [msg (string/join " " params) - msg (cond-> msg - (string/starts-with? msg ":") (subs 1))] - (swap! client assoc :away msg) - [(numeric-reply client "306" - ":You have been marked as being away")]))) + (let [msg (when (seq params) + (let [raw (string/join " " params)] + (cond-> raw + (string/starts-with? raw ":") (subs 1))))] + (if (or (empty? params) (string/blank? msg)) + (do (swap! client dissoc :away) + [(numeric-reply client "305" + ":You are no longer marked as being away")]) + (do (swap! client assoc :away msg) + [(numeric-reply client "306" + ":You have been marked as being away")])))) (defn- replies-for! [message client components] @@ -2566,38 +2567,107 @@ (for [mn members :let [m (when clients (get @clients mn))] - :when m] + :when m + :let [ca (:client-atom m) + away (when ca (:away @ca)) + flag (if away "G" "H") + uname (or (some-> ca deref + :user :username) + mn)]] (numeric-reply client "352" - (str target " " - (or (some-> (:client-atom m) deref - :user :username) - mn) + (str target " " uname " localhost " +server-name+ - " " mn " H :0 " mn)))) + " " mn " " flag " :0 " mn)))) [(numeric-reply client "315" (str target " :End of /WHO list"))])) ;; WHO <nick> :else (let [m (when clients (get @clients target))] (if m - [(numeric-reply client "352" - (str "* " - (or (some-> (:client-atom m) deref - :user :username) - target) - " localhost " +server-name+ - " " target " H :0 " target)) - (numeric-reply client "315" - (str target " :End of /WHO list"))] + (let [ca (:client-atom m) + away (when ca (:away @ca)) + flag (if away "G" "H") + uname (or (some-> ca deref + :user :username) + target)] + [(numeric-reply client "352" + (str "* " uname + " localhost " +server-name+ + " " target " " flag + " :0 " target)) + (numeric-reply client "315" + (str target " :End of /WHO list"))]) [(numeric-reply client "315" (str target " :End of /WHO list"))])))) (= command "LUSERS") - [] + (let [{:keys [clients channels]} components + n-users (if clients + (count + (filter + (fn [[_ m]] + (some-> (:client-atom m) deref + :registered?)) + @clients)) + 0) + n-chans (if channels (count @channels) 0)] + [(numeric-reply client "251" + (str ":There are " n-users + " users and 0 invisible on 1 servers")) + (numeric-reply client "252" + "0 :operator(s) online") + (numeric-reply client "253" + "0 :unknown connection(s)") + (numeric-reply client "254" + (str n-chans " :channels formed")) + (numeric-reply client "255" + (str ":I have " n-users + " clients and 0 servers"))]) (= command "MOTD") [(numeric-reply client "422" ":MOTD File is missing")] + (= command "WHOWAS") + (if (empty? params) + [(numeric-reply client "431" ":No nickname given")] + (let [target (first params)] + [(numeric-reply client "406" + (str target " :There was no such nickname")) + (numeric-reply client "369" + (str target " :End of WHOWAS"))])) + + (= command "INFO") + [(numeric-reply client "371" + (str ":papod " +version+ + " - IRC server")) + (numeric-reply client "374" + ":End of /INFO list")] + + (= command "INVITE") + (let [{:keys [clients channels]} components + target (first params) + handle (second params)] + (cond + (< (count params) 2) + [(numeric-reply client "461" + "INVITE :Not enough parameters")] + + (and channels handle + (contains? (get @channels handle) target)) + [(numeric-reply client "443" + (str target " " handle + " :is already on channel"))] + + :else + (let [nick (client-target client)] + (when-let [m (and clients + (get @clients target))] + (deliver-to-client! (:w m) + (str ":" nick " INVITE " target + " " handle))) + [(numeric-reply client "341" + (str target " " handle))]))) + ;; Network-scoped commands (not (:network-id @client)) [(numeric-reply client "451" @@ -2616,8 +2686,23 @@ "EDIT" (handle-edit params client components) "TAGMSG" (handle-tagmsg message client components) "MARKREAD" (handle-markread params client components) - "LIST" [(numeric-reply client "323" - ":End of /LIST")] + "LIST" (let [filter-ch (first params) + chans (when (:channels components) + @(:channels components)) + active (filter + (fn [[ch members]] + (and (seq members) + (or (nil? filter-ch) + (= ch filter-ch)))) + chans)] + (conj + (vec + (for [[ch members] active] + (numeric-reply client "322" + (str ch " " + (count members) " :")))) + (numeric-reply client "323" + ":End of /LIST"))) "NAMES" (let [handle (first params)] (if (and handle (:channels components) |
