showfile: serve a text file as its own command (e.g. /RULES), config-driven like aliases
This commit is contained in:
parent
61584a545b
commit
e0d849b4c9
4 changed files with 51 additions and 0 deletions
|
|
@ -117,6 +117,10 @@ amu_target = both
|
||||||
# hidewhois_hide_server = yes # hide 312
|
# hidewhois_hide_server = yes # hide 312
|
||||||
# hidewhois_hide_idle = yes # hide 317
|
# hidewhois_hide_idle = yes # hide 317
|
||||||
# hidewhois_hide_secure = yes # hide 671
|
# hidewhois_hide_secure = yes # hide 671
|
||||||
|
# --- showfile (m_showfile): serve a text file as its own command. One line per
|
||||||
|
# file: `showfile = <COMMAND> <path>`. The file is read fresh each use, so
|
||||||
|
# edits show without a rehash. e.g. make /RULES stream a rules file:
|
||||||
|
# showfile = RULES /etc/echoircd/rules.txt
|
||||||
# --- geoip (m_geo_maxmind): native MaxMind .mmdb country lookup. Enables the
|
# --- geoip (m_geo_maxmind): native MaxMind .mmdb country lookup. Enables the
|
||||||
# G:<cc> ban extban (e.g. +b G:CN,RU), the oper GEOIP <nick|ip> command and
|
# G:<cc> ban extban (e.g. +b G:CN,RU), the oper GEOIP <nick|ip> command and
|
||||||
# a country line in WHOIS (opers). Point at a GeoLite2-Country.mmdb file:
|
# a country line in WHOIS (opers). Point at a GeoLite2-Country.mmdb file:
|
||||||
|
|
|
||||||
|
|
@ -283,6 +283,11 @@ impl Ircd {
|
||||||
|
|
||||||
let Some(handler) = self.commands.get(cmd) else {
|
let Some(handler) = self.commands.get(cmd) else {
|
||||||
if registered {
|
if registered {
|
||||||
|
// showfile (m_showfile): config `showfile = <CMD> <path>` streams a
|
||||||
|
// text file as its own command (e.g. /RULES), like a config-named alias.
|
||||||
|
if crate::modules::showfile::maybe_show(&mut self.server, uid, cmd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// command aliases (m_alias): config `alias = <CMD> <target-nick>`
|
// command aliases (m_alias): config `alias = <CMD> <target-nick>`
|
||||||
// e.g. `alias = NS NickServ` makes `/NS help` -> PRIVMSG NickServ :help
|
// e.g. `alias = NS NickServ` makes `/NS help` -> PRIVMSG NickServ :help
|
||||||
if let Some(target) = self.server.conf_all("alias").iter().find_map(|line| {
|
if let Some(target) = self.server.conf_all("alias").iter().find_map(|line| {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ pub mod rpc;
|
||||||
pub mod securelist;
|
pub mod securelist;
|
||||||
pub mod securitygroups;
|
pub mod securitygroups;
|
||||||
pub mod serverban;
|
pub mod serverban;
|
||||||
|
pub mod showfile;
|
||||||
pub mod snoop;
|
pub mod snoop;
|
||||||
pub mod tline;
|
pub mod tline;
|
||||||
pub mod whoisport;
|
pub mod whoisport;
|
||||||
|
|
|
||||||
41
src/modules/showfile.rs
Normal file
41
src/modules/showfile.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
//! showfile — serve a text file as its own command (InspIRCd's `m_showfile`).
|
||||||
|
//! Config, one line per file:
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! showfile = <COMMAND> <path> # e.g. showfile = RULES /etc/echoircd/rules.txt
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! makes `/RULES` stream the file to the client. Dispatched from the same place as
|
||||||
|
//! command aliases (an unknown, config-named command), so no static registration is
|
||||||
|
//! needed. The file is read fresh on each use, so edits show without a REHASH.
|
||||||
|
//! Original native Rust.
|
||||||
|
|
||||||
|
use crate::server::Server;
|
||||||
|
use crate::Uid;
|
||||||
|
|
||||||
|
/// If `cmd` names a configured `showfile`, stream that file to `uid` (one NOTICE
|
||||||
|
/// per line) and return `true`. Returns `false` if no showfile matches `cmd`, so
|
||||||
|
/// the caller can fall through to the normal unknown-command handling.
|
||||||
|
pub fn maybe_show(s: &mut Server, uid: Uid, cmd: &str) -> bool {
|
||||||
|
let path = s.conf_all("showfile").iter().find_map(|line| {
|
||||||
|
let (name, path) = line.split_once(char::is_whitespace)?;
|
||||||
|
name.eq_ignore_ascii_case(cmd)
|
||||||
|
.then(|| path.trim().to_string())
|
||||||
|
});
|
||||||
|
let Some(path) = path else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let nick = s.users.get(&uid).map(|u| u.nick.clone()).unwrap_or_default();
|
||||||
|
match std::fs::read_to_string(&path) {
|
||||||
|
Ok(body) => {
|
||||||
|
for line in body.lines() {
|
||||||
|
s.send(uid, format!(":{} NOTICE {nick} :{line}", s.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => s.send(
|
||||||
|
uid,
|
||||||
|
format!(":{} NOTICE {nick} :*** {cmd}: file not available.", s.name),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue