From b500698e82ef61dc96a8b4966d0a0479053e4464 Mon Sep 17 00:00:00 2001 From: Jean Date: Mon, 20 Jul 2026 19:40:02 +0000 Subject: [PATCH] Add AJOIN ADDALL to auto-join every channel you are currently in --- api/src/lib.rs | 1 + lang/de.json | 5 ++++- lang/es-ar.json | 5 ++++- lang/es.json | 5 ++++- lang/fr.json | 5 ++++- lang/pt-br.json | 5 ++++- lang/pt.json | 5 ++++- modules/nickserv/src/ajoin.rs | 27 +++++++++++++++++++++++---- modules/nickserv/src/lib.rs | 2 +- src/engine/state.rs | 3 +++ 10 files changed, 52 insertions(+), 11 deletions(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index 70534c6..8bb262c 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -2318,6 +2318,7 @@ pub trait NetView { // A user's identity for extban / AKICK matching, if known. fn ban_target(&self, uid: &str) -> Option>; fn uids_logged_into(&self, account: &str) -> Vec; + fn channels_of(&self, uid: &str) -> Vec; fn is_op(&self, channel: &str, uid: &str) -> bool; fn channel_members(&self, channel: &str) -> Vec; fn channel_key(&self, channel: &str) -> Option<&str>; diff --git a/lang/de.json b/lang/de.json index 81e5eec..503a0e6 100644 --- a/lang/de.json +++ b/lang/de.json @@ -1360,5 +1360,8 @@ "\u0002{by}\u0002 removed you from \u0002{chan}\u0002's {word} list.": "\u0002{by}\u0002 hat dich von der {word}-Liste von \u0002{chan}\u0002 entfernt.", "\u0002{by}\u0002 set your access on \u0002{chan}\u0002 to \u0002{letters}\u0002.": "\u0002{by}\u0002 hat deinen Zugang in \u0002{chan}\u0002 auf \u0002{letters}\u0002 gesetzt.", "\u0002{by}\u0002 transferred the \u0002{chan}\u0002 founder to you.": "\u0002{by}\u0002 hat dir die Gründerrolle von \u0002{chan}\u0002 übertragen.", - "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 hat dich als Nachfolger von \u0002{chan}\u0002 festgelegt." + "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 hat dich als Nachfolger von \u0002{chan}\u0002 festgelegt.", + "Added \u0002{count}\u0002 channel to your auto-join list.": "\u0002{count}\u0002 Kanal zu deiner Auto-Join-Liste hinzugefügt.", + "Added \u0002{count}\u0002 channels to your auto-join list.": "\u0002{count}\u0002 Kanäle zu deiner Auto-Join-Liste hinzugefügt.", + "Unknown AJOIN command \u0002{other}\u0002. Use \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 or \u0002LIST\u0002.": "Unbekannter AJOIN-Befehl \u0002{other}\u0002. Nutze \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 oder \u0002LIST\u0002." } \ No newline at end of file diff --git a/lang/es-ar.json b/lang/es-ar.json index 6cb0ba6..29a0460 100644 --- a/lang/es-ar.json +++ b/lang/es-ar.json @@ -1360,5 +1360,8 @@ "\u0002{by}\u0002 removed you from \u0002{chan}\u0002's {word} list.": "\u0002{by}\u0002 te sacó de la lista {word} de \u0002{chan}\u0002.", "\u0002{by}\u0002 set your access on \u0002{chan}\u0002 to \u0002{letters}\u0002.": "\u0002{by}\u0002 estableció tu acceso en \u0002{chan}\u0002 a \u0002{letters}\u0002.", "\u0002{by}\u0002 transferred the \u0002{chan}\u0002 founder to you.": "\u0002{by}\u0002 te transfirió el estatus de fundador de \u0002{chan}\u0002.", - "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 te estableció como sucesor de \u0002{chan}\u0002." + "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 te estableció como sucesor de \u0002{chan}\u0002.", + "Added \u0002{count}\u0002 channel to your auto-join list.": "\u0002{count}\u0002 canal agregado a tu lista de auto-unión.", + "Added \u0002{count}\u0002 channels to your auto-join list.": "\u0002{count}\u0002 canales agregados a tu lista de auto-unión.", + "Unknown AJOIN command \u0002{other}\u0002. Use \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 or \u0002LIST\u0002.": "Comando AJOIN desconocido \u0002{other}\u0002. Usá \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 o \u0002LIST\u0002." } \ No newline at end of file diff --git a/lang/es.json b/lang/es.json index 4f4dab5..0bb31cf 100644 --- a/lang/es.json +++ b/lang/es.json @@ -1360,5 +1360,8 @@ "\u0002{by}\u0002 removed you from \u0002{chan}\u0002's {word} list.": "\u0002{by}\u0002 te quitó de la lista {word} de \u0002{chan}\u0002.", "\u0002{by}\u0002 set your access on \u0002{chan}\u0002 to \u0002{letters}\u0002.": "\u0002{by}\u0002 estableció tu acceso en \u0002{chan}\u0002 a \u0002{letters}\u0002.", "\u0002{by}\u0002 transferred the \u0002{chan}\u0002 founder to you.": "\u0002{by}\u0002 te transfirió el estatus de fundador de \u0002{chan}\u0002.", - "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 te estableció como sucesor de \u0002{chan}\u0002." + "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 te estableció como sucesor de \u0002{chan}\u0002.", + "Added \u0002{count}\u0002 channel to your auto-join list.": "\u0002{count}\u0002 canal añadido a tu lista de auto-unión.", + "Added \u0002{count}\u0002 channels to your auto-join list.": "\u0002{count}\u0002 canales añadidos a tu lista de auto-unión.", + "Unknown AJOIN command \u0002{other}\u0002. Use \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 or \u0002LIST\u0002.": "Comando AJOIN desconocido \u0002{other}\u0002. Usa \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 o \u0002LIST\u0002." } \ No newline at end of file diff --git a/lang/fr.json b/lang/fr.json index 3afa643..954f096 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -1360,5 +1360,8 @@ "\u0002{by}\u0002 removed you from \u0002{chan}\u0002's {word} list.": "\u0002{by}\u0002 vous a retiré de la liste {word} de \u0002{chan}\u0002.", "\u0002{by}\u0002 set your access on \u0002{chan}\u0002 to \u0002{letters}\u0002.": "\u0002{by}\u0002 a défini votre accès sur \u0002{chan}\u0002 à \u0002{letters}\u0002.", "\u0002{by}\u0002 transferred the \u0002{chan}\u0002 founder to you.": "\u0002{by}\u0002 vous a transféré le statut de fondateur de \u0002{chan}\u0002.", - "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 vous a défini comme successeur de \u0002{chan}\u0002." + "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 vous a défini comme successeur de \u0002{chan}\u0002.", + "Added \u0002{count}\u0002 channel to your auto-join list.": "\u0002{count}\u0002 salon ajouté à votre liste d'auto-join.", + "Added \u0002{count}\u0002 channels to your auto-join list.": "\u0002{count}\u0002 salons ajoutés à votre liste d'auto-join.", + "Unknown AJOIN command \u0002{other}\u0002. Use \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 or \u0002LIST\u0002.": "Commande AJOIN inconnue \u0002{other}\u0002. Utilisez \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 ou \u0002LIST\u0002." } \ No newline at end of file diff --git a/lang/pt-br.json b/lang/pt-br.json index 20e6831..de58b44 100644 --- a/lang/pt-br.json +++ b/lang/pt-br.json @@ -1360,5 +1360,8 @@ "\u0002{by}\u0002 removed you from \u0002{chan}\u0002's {word} list.": "\u0002{by}\u0002 removeu você da lista {word} de \u0002{chan}\u0002.", "\u0002{by}\u0002 set your access on \u0002{chan}\u0002 to \u0002{letters}\u0002.": "\u0002{by}\u0002 definiu seu acesso em \u0002{chan}\u0002 como \u0002{letters}\u0002.", "\u0002{by}\u0002 transferred the \u0002{chan}\u0002 founder to you.": "\u0002{by}\u0002 transferiu a fundação de \u0002{chan}\u0002 para você.", - "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 definiu você como sucessor de \u0002{chan}\u0002." + "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 definiu você como sucessor de \u0002{chan}\u0002.", + "Added \u0002{count}\u0002 channel to your auto-join list.": "\u0002{count}\u0002 canal adicionado à sua lista de auto-entrada.", + "Added \u0002{count}\u0002 channels to your auto-join list.": "\u0002{count}\u0002 canais adicionados à sua lista de auto-entrada.", + "Unknown AJOIN command \u0002{other}\u0002. Use \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 or \u0002LIST\u0002.": "Comando AJOIN desconhecido \u0002{other}\u0002. Use \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 ou \u0002LIST\u0002." } \ No newline at end of file diff --git a/lang/pt.json b/lang/pt.json index 27e6ce3..cdc4687 100644 --- a/lang/pt.json +++ b/lang/pt.json @@ -1360,5 +1360,8 @@ "\u0002{by}\u0002 removed you from \u0002{chan}\u0002's {word} list.": "\u0002{by}\u0002 removeu-o da lista {word} de \u0002{chan}\u0002.", "\u0002{by}\u0002 set your access on \u0002{chan}\u0002 to \u0002{letters}\u0002.": "\u0002{by}\u0002 definiu o seu acesso em \u0002{chan}\u0002 como \u0002{letters}\u0002.", "\u0002{by}\u0002 transferred the \u0002{chan}\u0002 founder to you.": "\u0002{by}\u0002 transferiu-lhe a fundação de \u0002{chan}\u0002.", - "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 definiu-o como sucessor de \u0002{chan}\u0002." + "\u0002{by}\u0002 set you as successor of \u0002{chan}\u0002.": "\u0002{by}\u0002 definiu-o como sucessor de \u0002{chan}\u0002.", + "Added \u0002{count}\u0002 channel to your auto-join list.": "\u0002{count}\u0002 canal adicionado à sua lista de auto-entrada.", + "Added \u0002{count}\u0002 channels to your auto-join list.": "\u0002{count}\u0002 canais adicionados à sua lista de auto-entrada.", + "Unknown AJOIN command \u0002{other}\u0002. Use \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 or \u0002LIST\u0002.": "Comando AJOIN desconhecido \u0002{other}\u0002. Use \u0002ADD\u0002, \u0002ADDALL\u0002, \u0002DEL\u0002 ou \u0002LIST\u0002." } \ No newline at end of file diff --git a/modules/nickserv/src/ajoin.rs b/modules/nickserv/src/ajoin.rs index c4a0531..ce4da44 100644 --- a/modules/nickserv/src/ajoin.rs +++ b/modules/nickserv/src/ajoin.rs @@ -1,5 +1,4 @@ -use echo_api::Store; -use echo_api::{Sender, ServiceCtx}; +use echo_api::{NetView, Sender, ServiceCtx, Store}; use echo_api::t; // A sane cap so a runaway list can't bloat an account or flood a user on identify. @@ -7,7 +6,7 @@ const MAX_AJOIN: usize = 25; // AJOIN [ADD <#channel> [key] | DEL <#channel> | LIST]: manage your auto-join // list — the channels NickServ joins you to each time you identify. -pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) { +pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView, db: &mut dyn Store) { let Some(account) = from.account else { ctx.notice(me, from.uid, "You must identify to NickServ to use \x02AJOIN\x02."); return; @@ -33,6 +32,26 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."), } } + Some("ADDALL") => { + let existing: std::collections::HashSet = + db.ajoin_list(account).into_iter().map(|e| e.channel.to_ascii_lowercase()).collect(); + let mut count = existing.len(); + let mut added = 0u64; + for channel in net.channels_of(from.uid) { + if count >= MAX_AJOIN { + break; + } + if existing.contains(&channel.to_ascii_lowercase()) { + continue; + } + let key = net.channel_key(&channel).unwrap_or(""); + if let Ok(true) = db.ajoin_add(account, &channel, key) { + added += 1; + count += 1; + } + } + ctx.notice(me, from.uid, echo_api::plural!(ctx, added, one = "Added \x02{count}\x02 channel to your auto-join list.", other = "Added \x02{count}\x02 channels to your auto-join list.", count = added)); + } Some("DEL") => { let Some(&channel) = args.get(2) else { ctx.notice(me, from.uid, "Syntax: AJOIN DEL <#channel>"); @@ -59,6 +78,6 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: } } } - Some(other) => ctx.notice(me, from.uid, t!(ctx, "Unknown AJOIN command \x02{other}\x02. Use \x02ADD\x02, \x02DEL\x02 or \x02LIST\x02.", other = other)), + Some(other) => ctx.notice(me, from.uid, t!(ctx, "Unknown AJOIN command \x02{other}\x02. Use \x02ADD\x02, \x02ADDALL\x02, \x02DEL\x02 or \x02LIST\x02.", other = other)), } } diff --git a/modules/nickserv/src/lib.rs b/modules/nickserv/src/lib.rs index cf6aac2..75c3ad8 100644 --- a/modules/nickserv/src/lib.rs +++ b/modules/nickserv/src/lib.rs @@ -126,7 +126,7 @@ impl Service for NickServ { Some("RECOVER") => ghost::handle(me, &self.guest_nick, &mut self.guest_seq, from, args, ctx, net, db, true), Some("RESETPASS") => resetpass::handle(me, from, args, ctx, db), Some("CONFIRM") => confirm::handle(me, from, args, ctx, db), - Some("AJOIN") => ajoin::handle(me, from, args, ctx, db), + Some("AJOIN") => ajoin::handle(me, from, args, ctx, net, db), Some("SUSPEND") => suspend::handle(me, from, args, ctx, net, db, true), Some("UNSUSPEND") => suspend::handle(me, from, args, ctx, net, db, false), Some("NOEXPIRE") => noexpire::handle(me, from, args, ctx, db), diff --git a/src/engine/state.rs b/src/engine/state.rs index 694d984..0cda915 100644 --- a/src/engine/state.rs +++ b/src/engine/state.rs @@ -615,6 +615,9 @@ impl NetView for Network { fn uids_logged_into(&self, account: &str) -> Vec { Network::uids_logged_into(self, account) } + fn channels_of(&self, uid: &str) -> Vec { + Network::channels_of(self, uid) + } fn is_op(&self, channel: &str, uid: &str) -> bool { Network::is_op(self, channel, uid) }