79 lines
2.4 KiB
Rust
79 lines
2.4 KiB
Rust
//! operprefix — network staff (IRC opers) get a distinct `!` prefix (prefix mode
|
|
//! `y`, ranked above channel owner) in every channel, so users can see who's staff
|
|
//! and ops can't kick/deop them. Enabled with `operprefix = yes`. Also provides the
|
|
//! shared grant/clear primitive used by [`crate::modules::ojoin`].
|
|
|
|
use crate::module::Module;
|
|
use crate::server::Server;
|
|
use crate::Uid;
|
|
|
|
pub fn enabled(s: &Server) -> bool {
|
|
s.conf_bool("operprefix", false)
|
|
}
|
|
|
|
/// Set/clear the oper prefix for `uid` in one channel and broadcast `MODE ±y`.
|
|
fn set(s: &mut Server, uid: Uid, key: &str, on: bool) {
|
|
let Some(nick) = s.users.get(&uid).map(|u| u.nick.clone()) else {
|
|
return;
|
|
};
|
|
let changed = match s.channels.get_mut(key).and_then(|c| c.members.get_mut(&uid)) {
|
|
Some(m) if m.oprefix != on => {
|
|
m.oprefix = on;
|
|
true
|
|
}
|
|
_ => false,
|
|
};
|
|
if !changed {
|
|
return;
|
|
}
|
|
let sign = if on { '+' } else { '-' };
|
|
let name = s.channels.get(key).map(|c| c.name.clone()).unwrap_or_default();
|
|
s.to_channel(key, &format!(":{} MODE {name} {sign}y {nick}", s.name), None);
|
|
s.propagate(&format!(":{} MODE {name} {sign}y {nick}", s.sid), None);
|
|
}
|
|
|
|
/// Grant the oper prefix in `key` (used by ojoin and on-join auto-grant).
|
|
pub fn grant(s: &mut Server, uid: Uid, key: &str) {
|
|
set(s, uid, key, true);
|
|
}
|
|
|
|
fn all_channels(s: &Server, uid: Uid) -> Vec<String> {
|
|
s.users
|
|
.get(&uid)
|
|
.map(|u| u.channels.iter().cloned().collect())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
/// Auto-grant to opers on join when the feature is enabled.
|
|
fn join_grant(s: &mut Server, uid: Uid, key: &str) {
|
|
if enabled(s) && s.is_oper(uid) {
|
|
grant(s, uid, key);
|
|
}
|
|
}
|
|
|
|
/// Grant across all of `uid`'s channels — on oper-up.
|
|
pub fn grant_all(s: &mut Server, uid: Uid) {
|
|
if !enabled(s) {
|
|
return;
|
|
}
|
|
for key in all_channels(s, uid) {
|
|
grant(s, uid, &key);
|
|
}
|
|
}
|
|
|
|
/// Clear across all of `uid`'s channels — on de-oper (safe no-op if never granted).
|
|
pub fn clear_all(s: &mut Server, uid: Uid) {
|
|
for key in all_channels(s, uid) {
|
|
set(s, uid, &key, false);
|
|
}
|
|
}
|
|
|
|
pub struct OperPrefix;
|
|
impl Module for OperPrefix {
|
|
fn name(&self) -> &'static str {
|
|
"operprefix"
|
|
}
|
|
fn on_join(&mut self, s: &mut Server, uid: Uid, chan: &str) {
|
|
join_grant(s, uid, &chan.to_ascii_lowercase());
|
|
}
|
|
}
|