helpserv: HELP EXTBANS lists the network live extban set with a friendly example for each
This commit is contained in:
parent
7f5b37efd6
commit
8c77016aed
6 changed files with 112 additions and 9 deletions
|
|
@ -61,7 +61,7 @@ const TOPICS: &[HelpEntry] = &[
|
|||
HelpEntry { cmd: "OWNER/PROTECT/HALFOP", summary: "give or take higher status", detail: "Syntax: \x02OWNER|PROTECT|HALFOP <#channel> [nick]\x02 (and \x02DEOWNER|DEPROTECT|DEHALFOP\x02)\nSets +q/+a/+h. OWNER is founder-only; PROTECT and HALFOP need op access." },
|
||||
HelpEntry { cmd: "KICK", summary: "kick from the channel", detail: "Syntax: \x02KICK <#channel> <nick> [reason]\x02\nKicks a user from the channel." },
|
||||
HelpEntry { cmd: "BAN/UNBAN", summary: "ban or unban a user", detail: "Syntax: \x02BAN <#channel> <nick> [reason]\x02, \x02UNBAN <#channel> [nick]\x02\nBans or unbans a user by host." },
|
||||
HelpEntry { cmd: "AKICK", summary: "manage the auto-kick list", detail: "Syntax: \x02AKICK <#channel> ADD <mask> [reason] | DEL <mask> | LIST | CLEAR\x02\nManages the auto-kick list; matches are banned and kicked on join. CLEAR empties it." },
|
||||
HelpEntry { cmd: "AKICK", summary: "manage the auto-kick list", detail: "Syntax: \x02AKICK <#channel> ADD <mask> [reason] | DEL <mask> | LIST | CLEAR\x02\nManages the auto-kick list; matches are banned and kicked on join. CLEAR empties it.\nA mask is a nick!user@host glob or an extban — type \x02/msg HelpServ HELP EXTBANS\x02 for the list." },
|
||||
HelpEntry { cmd: "ENFORCE", summary: "re-apply lock and access", detail: "Syntax: \x02ENFORCE <#channel>\x02\nRe-applies the mode-lock, access, and akick list to everyone present. \x02SYNC\x02 is an alias." },
|
||||
HelpEntry { cmd: "SYNC", summary: "re-apply access to members", detail: "Syntax: \x02SYNC <#channel>\x02\nRe-applies everyone's access status modes. An alias for \x02ENFORCE\x02." },
|
||||
HelpEntry { cmd: "TOPIC", summary: "set the topic", detail: "Syntax: \x02TOPIC <#channel> <text>\x02\nSets the channel topic." },
|
||||
|
|
@ -70,7 +70,7 @@ const TOPICS: &[HelpEntry] = &[
|
|||
HelpEntry { cmd: "GETKEY", summary: "show the channel key", detail: "Syntax: \x02GETKEY <#channel>\x02\nShows the channel key (+k), if one is set." },
|
||||
HelpEntry { cmd: "SEEN", summary: "when a nick was last seen", detail: "Syntax: \x02SEEN <nick>\x02\nShows when a nick was last seen." },
|
||||
HelpEntry { cmd: "CLONE", summary: "copy channel settings", detail: "Syntax: \x02CLONE <source> <target>\x02\nCopies one channel's settings to another you own." },
|
||||
HelpEntry { cmd: "MODE", summary: "set channel modes", detail: "Syntax: \x02MODE <#channel> <modes>\x02\nSets modes on the channel, e.g. MODE #chan +nt." },
|
||||
HelpEntry { cmd: "MODE", summary: "set channel modes", detail: "Syntax: \x02MODE <#channel> <modes>\x02\nSets modes on the channel, e.g. MODE #chan +nt. For extban ban types, see \x02/msg HelpServ HELP EXTBANS\x02." },
|
||||
HelpEntry { cmd: "MLOCK", summary: "lock channel modes", detail: "Syntax: \x02MLOCK <#channel> [modes]\x02\nLocks modes set or unset, e.g. MLOCK #chan +nt-s." },
|
||||
HelpEntry { cmd: "DROP", summary: "delete the registration", detail: "Syntax: \x02DROP <#channel>\x02\nDeletes the channel registration." },
|
||||
HelpEntry { cmd: "SUSPEND/UNSUSPEND", summary: "suspend a channel (operator)", detail: "Syntax: \x02SUSPEND <#channel> [+expiry] [reason]\x02, \x02UNSUSPEND <#channel>\x02\nSuspends or unsuspends a channel. Operators only." },
|
||||
|
|
|
|||
82
modules/helpserv/src/extbans.rs
Normal file
82
modules/helpserv/src/extbans.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use echo_api::{Sender, ServiceCtx, Store};
|
||||
|
||||
// A friendly one-liner (with an example) for each extban, keyed by its ircd name.
|
||||
// The letter and whether it's offered come live from the ircd's CAPAB set, so this
|
||||
// only supplies the human description; names the ircd offers but we have no blurb
|
||||
// for are still listed, just without the sentence.
|
||||
const DESC: &[(&str, &str)] = &[
|
||||
// Matching extbans — they match *who* a user is.
|
||||
("account", "a logged-in account. e.g. +b account:baddie"),
|
||||
("unauthed", "users NOT logged in whose mask matches. e.g. +b unauthed:*!*@*.example"),
|
||||
("realname", "the real name (gecos). e.g. +b realname:*viagra*"),
|
||||
("realmask", "host and real name together, joined by +. e.g. +b realmask:*!*@*.tor+*bot*"),
|
||||
("server", "everyone on a server. e.g. +b server:leaf2.example.net"),
|
||||
("fingerprint", "a TLS client-certificate fingerprint. e.g. +b fingerprint:<hash>"),
|
||||
("channel", "users also in another channel. e.g. +b channel:#trolls"),
|
||||
("banlist", "users banned in another channel. e.g. +b banlist:#other"),
|
||||
("country", "users connecting from a country (GeoIP). e.g. +b country:RU"),
|
||||
("asn", "users on a network operator, by AS number. e.g. +b asn:12345"),
|
||||
("class", "users in a connect class. e.g. +b class:webchat"),
|
||||
("gateway", "users behind a web gateway. e.g. +b gateway:kiwiirc"),
|
||||
("bot", "users flagged as bots (+B). e.g. +b bot:*!*@*"),
|
||||
("oper", "IRC operators. e.g. +b oper:*"),
|
||||
("opertype", "a specific oper type. e.g. +b opertype:NetAdmin"),
|
||||
("securitygroup", "members of a security group. e.g. +b securitygroup:trusted"),
|
||||
("score", "users over a connection-score threshold. e.g. +b score:10"),
|
||||
("team", "members of an account team. e.g. +b team:staff"),
|
||||
("redirect", "ban and send them to another channel. e.g. +b redirect:#overflow:*!*@lots"),
|
||||
// Acting extbans — they restrict *what* a user can do.
|
||||
("mute", "can stay and read but not speak. e.g. +b mute:*!*@spam.host"),
|
||||
("nonick", "cannot change nick in the channel. e.g. +b nonick:*!*@*"),
|
||||
("noctcp", "cannot send CTCPs. e.g. +b noctcp:*!*@*"),
|
||||
("nonotice", "cannot send channel notices. e.g. +b nonotice:*!*@*"),
|
||||
("nokick", "cannot use KICK. e.g. +b nokick:*!*@*"),
|
||||
("blockcolor", "colour/formatting in their messages is blocked. e.g. +b blockcolor:*!*@*"),
|
||||
("stripcolor", "colour is stripped from their messages. e.g. +b stripcolor:*!*@*"),
|
||||
("blockinvite", "cannot invite others. e.g. +b blockinvite:*!*@*"),
|
||||
("opmoderated", "their messages reach only ops. e.g. +b opmoderated:*!*@*"),
|
||||
];
|
||||
|
||||
// HELP EXTBANS: explain extended bans and list the ones this network actually
|
||||
// offers, each with an example, split into matching (who) and acting (what).
|
||||
pub fn handle(me: &str, from: &Sender, ctx: &mut ServiceCtx, db: &dyn Store) {
|
||||
let say = |ctx: &mut ServiceCtx, s: String| ctx.notice(me, from.uid, s);
|
||||
|
||||
say(ctx, "Extended bans (\x02extbans\x02) match users by more than nick!user@host.".to_string());
|
||||
say(ctx, "Use one where a ban mask goes: \x02/mode #chan +b <extban>\x02 (also +e/+I), or in \x02ChanServ AKICK\x02 (matching types only).".to_string());
|
||||
say(ctx, "Write them by name or letter — \x02account:bad\x02 is the same as \x02R:bad\x02 — and prefix \x02!\x02 to invert (match everyone except).".to_string());
|
||||
|
||||
let mut offered = db.extbans();
|
||||
offered.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
let (acting, matching): (Vec<_>, Vec<_>) = offered.into_iter().partition(|e| e.acting);
|
||||
|
||||
let line = |ctx: &mut ServiceCtx, e: &echo_api::ExtbanCap| {
|
||||
let letter = e.letter.map_or_else(|| "-".to_string(), |c| c.to_string());
|
||||
match DESC.iter().find(|(n, _)| n.eq_ignore_ascii_case(&e.name)) {
|
||||
Some((_, desc)) => say(ctx, format!(" \x02{}\x02 (\x02{}\x02) — {}", e.name, letter, desc)),
|
||||
None => say(ctx, format!(" \x02{}\x02 (\x02{}\x02)", e.name, letter)),
|
||||
}
|
||||
};
|
||||
|
||||
if matching.is_empty() && acting.is_empty() {
|
||||
// We haven't learned the ircd's set yet — show the reference from DESC.
|
||||
say(ctx, "\x02Extban types\x02 (your network's exact set is confirmed on link):".to_string());
|
||||
for (name, desc) in DESC {
|
||||
say(ctx, format!(" \x02{name}\x02 — {desc}"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if !matching.is_empty() {
|
||||
say(ctx, "\x02Matching\x02 — match who a user is (work in AKICK and bans):".to_string());
|
||||
for e in &matching {
|
||||
line(ctx, e);
|
||||
}
|
||||
}
|
||||
if !acting.is_empty() {
|
||||
say(ctx, "\x02Acting\x02 — restrict what a user can do (bans only):".to_string());
|
||||
for e in &acting {
|
||||
line(ctx, e);
|
||||
}
|
||||
}
|
||||
say(ctx, "ChanServ accepts only the extbans this network offers and hasn't disabled.".to_string());
|
||||
}
|
||||
|
|
@ -23,6 +23,8 @@ mod take;
|
|||
mod next;
|
||||
#[path = "close.rs"]
|
||||
mod close;
|
||||
#[path = "extbans.rs"]
|
||||
mod extbans;
|
||||
|
||||
const BLURB: &str = "HelpServ is the help desk and the network's help index. Open a ticket with \x02REQUEST\x02; operators work the queue.";
|
||||
|
||||
|
|
@ -65,16 +67,22 @@ impl Service for HelpServ {
|
|||
Some("TAKE") | Some("ASSIGN") => take::handle(me, from, args.get(1).copied(), ctx, db),
|
||||
Some("NEXT") => next::handle(me, from, ctx, db),
|
||||
Some("CLOSE") | Some("RESOLVE") => close::handle(me, from, args.get(1).copied(), ctx, db),
|
||||
// The extended-ban reference, listing this network's live extban set.
|
||||
Some("EXTBANS") | Some("EXTBAN") => extbans::handle(me, from, ctx, db),
|
||||
// HELP [service [command]]: bare HELP is HelpServ's own; HELP <service>
|
||||
// [command] fronts any other service's help through the shared renderer.
|
||||
Some("HELP") | None => match args.get(1).and_then(|&s| net.service_help(s)) {
|
||||
Some((blurb, topics)) => echo_api::help(me, from, ctx, blurb, topics, args.get(2).copied()),
|
||||
None => {
|
||||
echo_api::help(me, from, ctx, BLURB, TOPICS, args.get(1).copied());
|
||||
if args.get(1).is_none() {
|
||||
ctx.notice(me, from.uid, format!("For a service's own commands, type \x02HELP <service>\x02. Services: {}.", net.help_services().join(", ")));
|
||||
Some("HELP") | None => match args.get(1).copied() {
|
||||
Some(t) if t.eq_ignore_ascii_case("extbans") || t.eq_ignore_ascii_case("extban") => extbans::handle(me, from, ctx, db),
|
||||
other => match other.and_then(|s| net.service_help(s)) {
|
||||
Some((blurb, topics)) => echo_api::help(me, from, ctx, blurb, topics, args.get(2).copied()),
|
||||
None => {
|
||||
echo_api::help(me, from, ctx, BLURB, TOPICS, other);
|
||||
if other.is_none() {
|
||||
ctx.notice(me, from.uid, format!("For a service's own commands, type \x02HELP <service>\x02. Services: {}.", net.help_services().join(", ")));
|
||||
ctx.notice(me, from.uid, "For the extended ban types you can use, type \x02HELP EXTBANS\x02.");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
// Not a HelpServ command — maybe the name of a service to get help for.
|
||||
Some(_) => match net.service_help(args[0]) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue