echo/modules/operserv/src/jupe.rs
Jean ad2a623120
Group the module crates under modules/
The service pseudo-clients and the ircd protocol link sat flat at the
repo root, mixed in with the daemon core and the SDK. Move them all
under modules/ so the tree separates concerns cleanly: the daemon in
src/, the SDK every module links against in api/, and the loadable
modules — the pseudo-clients plus the protocol link — in modules/.

Workspace members, the daemon's per-crate dependency paths, and each
module's api path are updated to match; the docs follow. No code change.
2026-07-14 14:19:43 +00:00

49 lines
2.2 KiB
Rust

use fedserv_api::{Priv, Sender, ServiceCtx, Store};
// JUPE <server.name> [reason] | JUPE DEL <server.name> | JUPE LIST: hold a
// server name with a fake server so a rogue one can't link (or lift it). Admin-
// only. Node-local: the introducing node owns the jupe.
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) {
if !from.privs.has(Priv::Admin) {
ctx.notice(me, from.uid, "Access denied — JUPE needs the \x02admin\x02 privilege.");
return;
}
match args.get(1) {
Some(&sub) if sub.eq_ignore_ascii_case("DEL") || sub.eq_ignore_ascii_case("REMOVE") => del(me, from, args.get(2).copied(), ctx, db),
Some(&sub) if sub.eq_ignore_ascii_case("LIST") => list(me, from, ctx, db),
Some(&name) if name.contains('.') => {
let reason = if args.len() > 2 { args[2..].join(" ") } else { "Juped by services".to_string() };
let by = from.account.unwrap_or(from.nick);
let sid = db.jupe_add(name, &format!("({by}) {reason}"));
ctx.jupe(name, &sid, &format!("({by}) {reason}"));
ctx.notice(me, from.uid, format!("\x02{name}\x02 is now juped."));
}
_ => ctx.notice(me, from.uid, "Syntax: JUPE <server.name> [reason] | JUPE DEL <server.name> | JUPE LIST"),
}
}
fn del(me: &str, from: &Sender, name: Option<&str>, ctx: &mut ServiceCtx, db: &mut dyn Store) {
let Some(name) = name else {
ctx.notice(me, from.uid, "Syntax: JUPE DEL <server.name>");
return;
};
match db.jupe_del(name) {
Some(sid) => {
ctx.squit(&sid, "Jupe lifted");
ctx.notice(me, from.uid, format!("The jupe on \x02{name}\x02 has been lifted."));
}
None => ctx.notice(me, from.uid, format!("\x02{name}\x02 isn't juped.")),
}
}
fn list(me: &str, from: &Sender, ctx: &mut ServiceCtx, db: &mut dyn Store) {
let jupes = db.jupes();
if jupes.is_empty() {
ctx.notice(me, from.uid, "No servers are juped.");
return;
}
for (name, sid, reason) in &jupes {
ctx.notice(me, from.uid, format!(" \x02{name}\x02 ({sid}) — {reason}"));
}
ctx.notice(me, from.uid, format!("End of jupe list ({} shown).", jupes.len()));
}