modules: port rmode (bulk-remove channel list-mode entries)
This commit is contained in:
parent
3186af07e8
commit
e7976a76d3
2 changed files with 107 additions and 0 deletions
|
|
@ -41,6 +41,7 @@ pub mod reputation;
|
|||
pub mod restrictchans;
|
||||
pub mod restrictcommands;
|
||||
pub mod restrictmsg;
|
||||
pub mod rmode;
|
||||
pub mod rpc;
|
||||
pub mod securelist;
|
||||
pub mod securitygroups;
|
||||
|
|
@ -109,5 +110,6 @@ pub fn module_commands() -> Vec<Box<dyn Command>> {
|
|||
.chain(filehost::commands())
|
||||
.chain(extended_isupport::commands())
|
||||
.chain(tline::commands())
|
||||
.chain(rmode::commands())
|
||||
.collect()
|
||||
}
|
||||
|
|
|
|||
105
src/modules/rmode.rs
Normal file
105
src/modules/rmode.rs
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
//! rmode — `RMODE <channel> <listmode> [pattern]`, bulk-remove entries from a
|
||||
//! channel list mode (`b` bans, `e` ban exceptions, `I` invite exceptions). With a
|
||||
//! `pattern` glob only matching entries are cleared; without one, all are. Needs
|
||||
//! half-op+ (opers bypass). The removals go through the normal mode engine (chunked
|
||||
//! to keep each `MODE` line legal), so they broadcast and propagate like any other.
|
||||
//!
|
||||
//! Behaviour reference: InspIRCd's `m_rmode`. Original native Rust.
|
||||
|
||||
use crate::channels::{glob_match, RANK_HALFOP};
|
||||
use crate::command::{CmdResult, Command};
|
||||
use crate::coremods::core_mode::apply_mode;
|
||||
use crate::numeric::{ERR_CHANOPRIVSNEEDED, ERR_NOSUCHCHANNEL};
|
||||
use crate::server::Server;
|
||||
use crate::Uid;
|
||||
|
||||
pub fn commands() -> Vec<Box<dyn Command>> {
|
||||
vec![Box::new(RMode)]
|
||||
}
|
||||
|
||||
struct RMode;
|
||||
impl Command for RMode {
|
||||
fn name(&self) -> &'static str {
|
||||
"RMODE"
|
||||
}
|
||||
fn min_params(&self) -> usize {
|
||||
2
|
||||
}
|
||||
fn handle(&self, s: &mut Server, uid: Uid, params: &[String]) -> CmdResult {
|
||||
let chan = params[0].clone();
|
||||
let key = chan.to_ascii_lowercase();
|
||||
let Some(mode) = params[1].chars().find(|c| c.is_ascii_alphabetic()) else {
|
||||
return CmdResult::Fail;
|
||||
};
|
||||
if !s.channels.contains_key(&key) {
|
||||
s.numeric(uid, ERR_NOSUCHCHANNEL, &format!("{chan} :No such channel"));
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
let is_oper = s.is_oper(uid);
|
||||
if !is_oper && s.rank(uid, &key) < RANK_HALFOP {
|
||||
s.numeric(
|
||||
uid,
|
||||
ERR_CHANOPRIVSNEEDED,
|
||||
&format!("{chan} :You're not a channel operator"),
|
||||
);
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
// collect the matching masks from the requested list mode
|
||||
let pattern = params.get(2).map(|p| p.as_str()).unwrap_or("*");
|
||||
let masks: Vec<String> = {
|
||||
let ch = &s.channels[&key];
|
||||
let list = match mode {
|
||||
'b' => &ch.bans,
|
||||
'e' => &ch.excepts,
|
||||
'I' => &ch.invex,
|
||||
_ => {
|
||||
let nick = s
|
||||
.users
|
||||
.get(&uid)
|
||||
.map(|u| u.nick.clone())
|
||||
.unwrap_or_default();
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :RMODE only supports list modes b, e, I",
|
||||
s.name
|
||||
),
|
||||
);
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
};
|
||||
list.iter()
|
||||
.filter(|b| glob_match(pattern, &b.mask))
|
||||
.map(|b| b.mask.clone())
|
||||
.collect()
|
||||
};
|
||||
let removed = masks.len();
|
||||
// apply in chunks so each MODE line stays within limits
|
||||
for chunk in masks.chunks(6) {
|
||||
let mut p = vec![
|
||||
chan.clone(),
|
||||
format!("-{}", mode.to_string().repeat(chunk.len())),
|
||||
];
|
||||
p.extend(chunk.iter().cloned());
|
||||
if is_oper {
|
||||
s.mode_sudo = true;
|
||||
}
|
||||
apply_mode(s, uid, &p);
|
||||
s.mode_sudo = false;
|
||||
}
|
||||
let nick = s
|
||||
.users
|
||||
.get(&uid)
|
||||
.map(|u| u.nick.clone())
|
||||
.unwrap_or_default();
|
||||
let plural = if removed == 1 { "y" } else { "ies" };
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :RMODE: removed {removed} +{mode} entr{plural} from {chan}",
|
||||
s.name
|
||||
),
|
||||
);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue