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.
This commit is contained in:
Jean Chevronnet 2026-07-14 14:19:43 +00:00
parent 6f76f9722c
commit ad2a623120
No known key found for this signature in database
116 changed files with 69 additions and 46 deletions

View file

@ -0,0 +1,38 @@
use fedserv_api::{NetView, Priv, Sender, ServiceCtx, Store};
use std::collections::HashSet;
// CHANKILL <#channel> [reason]: AKILL every user in a channel by host, clearing
// a spam or attack channel in one shot. The G-lines the ircd applies also kill
// the matching sessions. Admin-only, and never bans the operator running it.
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView, db: &mut dyn Store) {
if !from.privs.has(Priv::Admin) {
ctx.notice(me, from.uid, "Access denied — CHANKILL needs the \x02admin\x02 privilege.");
return;
}
let Some(&chan) = args.get(1).filter(|c| c.starts_with('#') || c.starts_with('&')) else {
ctx.notice(me, from.uid, "Syntax: CHANKILL <#channel> [reason]");
return;
};
let members = net.channel_members(chan);
if members.is_empty() {
ctx.notice(me, from.uid, format!("No one is in \x02{chan}\x02 (or it isn't tracked)."));
return;
}
let reason = if args.len() > 2 { args[2..].join(" ") } else { "Channel cleared by services".to_string() };
let setter = from.account.unwrap_or(from.nick);
let mut seen: HashSet<String> = HashSet::new();
let mut banned = 0;
for uid in &members {
if uid.as_str() == from.uid {
continue; // never ban yourself
}
let Some(host) = net.host_of(uid) else { continue };
if seen.insert(host.to_string()) {
let mask = format!("*@{host}");
let _ = db.akill_add("G", &mask, setter, &reason, None);
ctx.add_line("G", &mask, from.nick, 0, &reason);
banned += 1;
}
}
ctx.notice(me, from.uid, format!("CHANKILL on \x02{chan}\x02: \x02{banned}\x02 host(s) AKILL'd."));
}