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.
49 lines
2.2 KiB
Rust
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()));
|
|
}
|