From 0ba736615be5ed274430503b6f3a6d7a583e1b6f Mon Sep 17 00:00:00 2001 From: Jean Date: Tue, 14 Jul 2026 14:46:56 +0000 Subject: [PATCH] Split InfoServ into one file per command POST/DEL/LIST each move to their own file (each still parameterised by bulletin kind, so OPOST/ODEL/OLIST route to the same handler); the kind constants stay in lib.rs beside the dispatcher. No behaviour change. --- modules/infoserv/src/del.rs | 21 +++++++++ modules/infoserv/src/lib.rs | 82 ++++++++---------------------------- modules/infoserv/src/list.rs | 19 +++++++++ modules/infoserv/src/post.rs | 18 ++++++++ 4 files changed, 75 insertions(+), 65 deletions(-) create mode 100644 modules/infoserv/src/del.rs create mode 100644 modules/infoserv/src/list.rs create mode 100644 modules/infoserv/src/post.rs diff --git a/modules/infoserv/src/del.rs b/modules/infoserv/src/del.rs new file mode 100644 index 0000000..ebba3b0 --- /dev/null +++ b/modules/infoserv/src/del.rs @@ -0,0 +1,21 @@ +use fedserv_api::{Priv, Sender, ServiceCtx, Store}; + +// DEL/ODEL : remove a bulletin by its listed position. Admin only. +pub fn handle(me: &str, from: &Sender, kind: &str, num: Option<&str>, ctx: &mut ServiceCtx, db: &mut dyn Store) { + if !from.privs.has(Priv::Admin) { + ctx.notice(me, from.uid, "Access denied — that command is for services operators."); + return; + } + let which = if kind == super::OPER { "oper" } else { "public" }; + let Some(n) = num.and_then(|n| n.parse::().ok()) else { + ctx.notice(me, from.uid, format!("Syntax: {} ", if kind == super::OPER { "ODEL" } else { "DEL" })); + return; + }; + match db.news(kind).get(n.wrapping_sub(1)) { + Some(item) if n >= 1 => { + db.news_del(item.id); + ctx.notice(me, from.uid, format!("Removed \x02{which}\x02 bulletin \x02{n}\x02.")); + } + _ => ctx.notice(me, from.uid, format!("There's no \x02{which}\x02 bulletin \x02{n}\x02.")), + } +} diff --git a/modules/infoserv/src/lib.rs b/modules/infoserv/src/lib.rs index fcbbbba..701fb1d 100644 --- a/modules/infoserv/src/lib.rs +++ b/modules/infoserv/src/lib.rs @@ -6,9 +6,17 @@ //! //! POST/LIST/DEL manage public bulletins; OPOST/OLIST/ODEL the oper ones. //! Posting and deleting are admin-only; anyone may LIST the public bulletins, -//! and any operator may OLIST. +//! and any operator may OLIST. `lib.rs` holds the dispatcher; each command +//! (parameterised by bulletin kind) lives in its own file. -use fedserv_api::{NetView, Priv, Sender, Service, ServiceCtx, Store}; +use fedserv_api::{NetView, Sender, Service, ServiceCtx, Store}; + +#[path = "post.rs"] +mod post; +#[path = "del.rs"] +mod del; +#[path = "list.rs"] +mod list; // The two bulletin kinds in the shared news store. const PUBLIC: &str = "logon"; @@ -32,72 +40,16 @@ impl Service for InfoServ { fn on_command(&mut self, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, _net: &dyn NetView, db: &mut dyn Store) { let me = self.uid.as_str(); match args.first().map(|s| s.to_ascii_uppercase()).as_deref() { - Some("POST") | Some("ADD") => post(me, from, PUBLIC, &args[1..], ctx, db), - Some("OPOST") | Some("OADD") => post(me, from, OPER, &args[1..], ctx, db), - Some("DEL") | Some("REMOVE") => del(me, from, PUBLIC, args.get(1).copied(), ctx, db), - Some("ODEL") => del(me, from, OPER, args.get(1).copied(), ctx, db), + Some("POST") | Some("ADD") => post::handle(me, from, PUBLIC, &args[1..], ctx, db), + Some("OPOST") | Some("OADD") => post::handle(me, from, OPER, &args[1..], ctx, db), + Some("DEL") | Some("REMOVE") => del::handle(me, from, PUBLIC, args.get(1).copied(), ctx, db), + Some("ODEL") => del::handle(me, from, OPER, args.get(1).copied(), ctx, db), // Public bulletins are, well, public — anyone may list them. - Some("LIST") | None => list(me, from, PUBLIC, false, ctx, db), + Some("LIST") | None => list::handle(me, from, PUBLIC, false, ctx, db), // Oper bulletins are for operators only. - Some("OLIST") => list(me, from, OPER, true, ctx, db), - Some("HELP") => help(me, from, ctx), + Some("OLIST") => list::handle(me, from, OPER, true, ctx, db), + Some("HELP") => ctx.notice(me, from.uid, "InfoServ holds the network's information bulletins. \x02LIST\x02 shows the public ones. Operators: \x02POST\x02 / \x02DEL\x02 (public, shown on connect), \x02OPOST\x02 / \x02OLIST\x02 / \x02ODEL\x02 (oper-only, shown on login)."), Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02LIST\x02 or \x02HELP\x02.")), } } } - -fn help(me: &str, from: &Sender, ctx: &mut ServiceCtx) { - ctx.notice(me, from.uid, "InfoServ holds the network's information bulletins. \x02LIST\x02 shows the public ones. Operators: \x02POST\x02 / \x02DEL\x02 (public, shown on connect), \x02OPOST\x02 / \x02OLIST\x02 / \x02ODEL\x02 (oper-only, shown on login)."); -} - -fn post(me: &str, from: &Sender, kind: &str, rest: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) { - if !from.privs.has(Priv::Admin) { - ctx.notice(me, from.uid, "Access denied — posting bulletins is for services operators."); - return; - } - let message = rest.join(" "); - if message.trim().is_empty() { - ctx.notice(me, from.uid, format!("Syntax: {} ", if kind == OPER { "OPOST" } else { "POST" })); - return; - } - let setter = from.account.unwrap_or(from.nick); - db.news_add(kind, &message, setter); - let which = if kind == OPER { "oper" } else { "public" }; - ctx.notice(me, from.uid, format!("Added a \x02{which}\x02 bulletin.")); -} - -fn del(me: &str, from: &Sender, kind: &str, num: Option<&str>, ctx: &mut ServiceCtx, db: &mut dyn Store) { - if !from.privs.has(Priv::Admin) { - ctx.notice(me, from.uid, "Access denied — that command is for services operators."); - return; - } - let which = if kind == OPER { "oper" } else { "public" }; - let Some(n) = num.and_then(|n| n.parse::().ok()) else { - ctx.notice(me, from.uid, format!("Syntax: {} ", if kind == OPER { "ODEL" } else { "DEL" })); - return; - }; - match db.news(kind).get(n.wrapping_sub(1)) { - Some(item) if n >= 1 => { - db.news_del(item.id); - ctx.notice(me, from.uid, format!("Removed \x02{which}\x02 bulletin \x02{n}\x02.")); - } - _ => ctx.notice(me, from.uid, format!("There's no \x02{which}\x02 bulletin \x02{n}\x02.")), - } -} - -fn list(me: &str, from: &Sender, kind: &str, oper_only: bool, ctx: &mut ServiceCtx, db: &mut dyn Store) { - if oper_only && !from.privs.any() { - ctx.notice(me, from.uid, "Access denied — oper bulletins are for services operators."); - return; - } - let items = db.news(kind); - let which = if kind == OPER { "oper" } else { "public" }; - if items.is_empty() { - ctx.notice(me, from.uid, format!("There are no {which} bulletins.")); - return; - } - for (i, item) in items.iter().enumerate() { - ctx.notice(me, from.uid, format!("{}. {} — by {}", i + 1, item.text, item.setter)); - } - ctx.notice(me, from.uid, format!("End of {which} bulletins ({} shown).", items.len())); -} diff --git a/modules/infoserv/src/list.rs b/modules/infoserv/src/list.rs new file mode 100644 index 0000000..6a8245d --- /dev/null +++ b/modules/infoserv/src/list.rs @@ -0,0 +1,19 @@ +use fedserv_api::{Sender, ServiceCtx, Store}; + +// LIST/OLIST: show the bulletins of a kind. Public is open; oper is oper-only. +pub fn handle(me: &str, from: &Sender, kind: &str, oper_only: bool, ctx: &mut ServiceCtx, db: &mut dyn Store) { + if oper_only && !from.privs.any() { + ctx.notice(me, from.uid, "Access denied — oper bulletins are for services operators."); + return; + } + let items = db.news(kind); + let which = if kind == super::OPER { "oper" } else { "public" }; + if items.is_empty() { + ctx.notice(me, from.uid, format!("There are no {which} bulletins.")); + return; + } + for (i, item) in items.iter().enumerate() { + ctx.notice(me, from.uid, format!("{}. {} — by {}", i + 1, item.text, item.setter)); + } + ctx.notice(me, from.uid, format!("End of {which} bulletins ({} shown).", items.len())); +} diff --git a/modules/infoserv/src/post.rs b/modules/infoserv/src/post.rs new file mode 100644 index 0000000..71bb6c2 --- /dev/null +++ b/modules/infoserv/src/post.rs @@ -0,0 +1,18 @@ +use fedserv_api::{Priv, Sender, ServiceCtx, Store}; + +// POST/OPOST : add a bulletin (public or oper). Admin only. +pub fn handle(me: &str, from: &Sender, kind: &str, rest: &[&str], ctx: &mut ServiceCtx, db: &mut dyn Store) { + if !from.privs.has(Priv::Admin) { + ctx.notice(me, from.uid, "Access denied — posting bulletins is for services operators."); + return; + } + let message = rest.join(" "); + if message.trim().is_empty() { + ctx.notice(me, from.uid, format!("Syntax: {} ", if kind == super::OPER { "OPOST" } else { "POST" })); + return; + } + let setter = from.account.unwrap_or(from.nick); + db.news_add(kind, &message, setter); + let which = if kind == super::OPER { "oper" } else { "public" }; + ctx.notice(me, from.uid, format!("Added a \x02{which}\x02 bulletin.")); +}