chanserv: SET founder and description

SET <#channel> FOUNDER <account> transfers ownership; SET DESC <text>
stores a description shown in INFO. Both are founder-gated and persisted
to the event log.
This commit is contained in:
Jean Chevronnet 2026-07-12 11:33:33 +00:00
parent ba3803e01c
commit 674f543b40
No known key found for this signature in database
4 changed files with 133 additions and 3 deletions

View file

@ -24,6 +24,8 @@ mod akick;
mod list;
#[path = "status.rs"]
mod status;
#[path = "set.rs"]
mod set;
pub struct ChanServ {
pub uid: String,
@ -78,6 +80,9 @@ impl Service for ChanServ {
Some(info) => {
ctx.notice(me, from.uid, format!("Information for \x02{}\x02:", info.name));
ctx.notice(me, from.uid, format!(" Founder : \x02{}\x02", info.founder));
if !info.desc.is_empty() {
ctx.notice(me, from.uid, format!(" Description: {}", info.desc));
}
ctx.notice(me, from.uid, format!(" Registered : {}", human_time(info.ts)));
}
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered.")),
@ -161,7 +166,8 @@ impl Service for ChanServ {
Some("AKICK") => akick::handle(me, from, args, ctx, db),
Some("STATUS") => status::handle(me, from, args, ctx, net, db),
Some("LIST") => list::handle(me, from, args, ctx, db),
Some("HELP") => ctx.notice(me, from.uid, "ChanServ registers and looks after channels. Commands: \x02REGISTER\x02, \x02INFO\x02, \x02LIST\x02, \x02ACCESS\x02, \x02STATUS\x02, \x02OP\x02/\x02DEOP\x02, \x02VOICE\x02/\x02DEVOICE\x02, \x02KICK\x02, \x02BAN\x02/\x02UNBAN\x02, \x02AKICK\x02, \x02TOPIC\x02, \x02INVITE\x02, \x02MODE\x02, \x02MLOCK\x02, \x02DROP\x02."),
Some("SET") => set::handle(me, from, args, ctx, db),
Some("HELP") => ctx.notice(me, from.uid, "ChanServ registers and looks after channels. Commands: \x02REGISTER\x02, \x02INFO\x02, \x02LIST\x02, \x02SET\x02, \x02ACCESS\x02, \x02STATUS\x02, \x02OP\x02/\x02DEOP\x02, \x02VOICE\x02/\x02DEVOICE\x02, \x02KICK\x02, \x02BAN\x02/\x02UNBAN\x02, \x02AKICK\x02, \x02TOPIC\x02, \x02INVITE\x02, \x02MODE\x02, \x02MLOCK\x02, \x02DROP\x02."),
Some(other) => ctx.notice(me, from.uid, format!("I don't know the command \x02{other}\x02. Try \x02HELP\x02.")),
None => {}
}

45
modules/chanserv/set.rs Normal file
View file

@ -0,0 +1,45 @@
use crate::engine::db::Db;
use crate::engine::service::{Sender, ServiceCtx};
// SET <#channel> FOUNDER <account> | DESC <text>: founder-only channel settings.
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &mut Db) {
let Some(&chan) = args.get(1) else {
ctx.notice(me, from.uid, "Syntax: SET <#channel> FOUNDER <account> | DESC <text>");
return;
};
let founder = match db.channel(chan) {
None => {
ctx.notice(me, from.uid, format!("\x02{chan}\x02 isn't registered."));
return;
}
Some(info) => info.founder.clone(),
};
if from.account != Some(founder.as_str()) {
ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can change its settings."));
return;
}
match args.get(2).map(|s| s.to_ascii_uppercase()).as_deref() {
Some("FOUNDER") => {
let Some(&account) = args.get(3) else {
ctx.notice(me, from.uid, "Syntax: SET <#channel> FOUNDER <account>");
return;
};
if !db.exists(account) {
ctx.notice(me, from.uid, format!("\x02{account}\x02 isn't a registered account."));
return;
}
match db.set_founder(chan, account) {
Ok(()) => ctx.notice(me, from.uid, format!("Founder of \x02{chan}\x02 transferred to \x02{account}\x02.")),
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
}
}
Some("DESC") => {
let desc = if args.len() > 3 { args[3..].join(" ") } else { String::new() };
match db.set_desc(chan, &desc) {
Ok(()) => ctx.notice(me, from.uid, format!("Description for \x02{chan}\x02 updated.")),
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
}
}
_ => ctx.notice(me, from.uid, "Syntax: SET <#channel> FOUNDER <account> | DESC <text>"),
}
}