SWHOIS (320), SETIDLE, UNINVITE
This commit is contained in:
parent
2aec23c5f9
commit
68fdd91eaa
4 changed files with 140 additions and 0 deletions
|
|
@ -15,6 +15,7 @@ pub fn commands() -> Vec<Box<dyn Command>> {
|
||||||
Box::new(TopicCmd),
|
Box::new(TopicCmd),
|
||||||
Box::new(Names),
|
Box::new(Names),
|
||||||
Box::new(Invite),
|
Box::new(Invite),
|
||||||
|
Box::new(Uninvite),
|
||||||
Box::new(Knock),
|
Box::new(Knock),
|
||||||
Box::new(Cycle),
|
Box::new(Cycle),
|
||||||
Box::new(Remove),
|
Box::new(Remove),
|
||||||
|
|
@ -243,6 +244,76 @@ impl Command for Invite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// UNINVITE — revoke a pending invite (InspIRCd `m_uninvite`). `UNINVITE <nick>
|
||||||
|
/// <#chan>`; a channel op cancels an invite they (or another op) issued.
|
||||||
|
struct Uninvite;
|
||||||
|
impl Command for Uninvite {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"UNINVITE"
|
||||||
|
}
|
||||||
|
fn min_params(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
fn handle(&self, s: &mut Server, uid: Uid, params: &[String]) -> CmdResult {
|
||||||
|
let (tnick, chan) = (¶ms[0], ¶ms[1]);
|
||||||
|
let key = chan.to_ascii_lowercase();
|
||||||
|
if !s.channels.contains_key(&key) {
|
||||||
|
s.numeric(uid, ERR_NOSUCHCHANNEL, &format!("{chan} :No such channel"));
|
||||||
|
return CmdResult::Fail;
|
||||||
|
}
|
||||||
|
if !s.is_member(uid, &key) {
|
||||||
|
s.numeric(
|
||||||
|
uid,
|
||||||
|
ERR_NOTONCHANNEL,
|
||||||
|
&format!("{chan} :You're not on that channel"),
|
||||||
|
);
|
||||||
|
return CmdResult::Fail;
|
||||||
|
}
|
||||||
|
if !s.is_op(uid, &key) {
|
||||||
|
s.numeric(
|
||||||
|
uid,
|
||||||
|
ERR_CHANOPRIVSNEEDED,
|
||||||
|
&format!("{chan} :You're not a channel operator"),
|
||||||
|
);
|
||||||
|
return CmdResult::Fail;
|
||||||
|
}
|
||||||
|
let Some(tuid) = s.find_nick(tnick) else {
|
||||||
|
s.numeric(
|
||||||
|
uid,
|
||||||
|
ERR_NOSUCHNICK,
|
||||||
|
&format!("{tnick} :No such nick/channel"),
|
||||||
|
);
|
||||||
|
return CmdResult::Fail;
|
||||||
|
};
|
||||||
|
let removed = s
|
||||||
|
.channels
|
||||||
|
.get_mut(&key)
|
||||||
|
.map(|ch| ch.invites.remove(&tuid))
|
||||||
|
.unwrap_or(false);
|
||||||
|
let who = s.users[&tuid].nick.clone();
|
||||||
|
let word = if removed {
|
||||||
|
"is no longer invited to"
|
||||||
|
} else {
|
||||||
|
"was not invited to"
|
||||||
|
};
|
||||||
|
let nick = s.users[&uid].nick.clone();
|
||||||
|
s.send(
|
||||||
|
uid,
|
||||||
|
format!(":{} NOTICE {nick} :{who} {word} {chan}", s.name),
|
||||||
|
);
|
||||||
|
if removed {
|
||||||
|
s.send(
|
||||||
|
tuid,
|
||||||
|
format!(
|
||||||
|
":{} NOTICE {who} :Your invite to {chan} was revoked",
|
||||||
|
s.name
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
CmdResult::Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Join;
|
struct Join;
|
||||||
impl Command for Join {
|
impl Command for Join {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ impl Command for Whois {
|
||||||
last_active,
|
last_active,
|
||||||
signon,
|
signon,
|
||||||
certfp,
|
certfp,
|
||||||
|
swhois,
|
||||||
) = {
|
) = {
|
||||||
let u = &s.users[&tuid];
|
let u = &s.users[&tuid];
|
||||||
(
|
(
|
||||||
|
|
@ -136,6 +137,9 @@ impl Command for Whois {
|
||||||
u.last_active,
|
u.last_active,
|
||||||
u.signon,
|
u.signon,
|
||||||
u.certfp.clone(),
|
u.certfp.clone(),
|
||||||
|
u.ext
|
||||||
|
.get::<crate::coremods::core_oper::Swhois>()
|
||||||
|
.map(|w| w.0.clone()),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let chans: Vec<String> = keys
|
let chans: Vec<String> = keys
|
||||||
|
|
@ -171,6 +175,10 @@ impl Command for Whois {
|
||||||
&format!("{nick} :is an IRC operator"),
|
&format!("{nick} :is an IRC operator"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// 320: oper-set SWHOIS line
|
||||||
|
if let Some(line) = &swhois {
|
||||||
|
s.numeric(uid, RPL_WHOISSPECIAL, &format!("{nick} :{line}"));
|
||||||
|
}
|
||||||
// opers can see through the cloak to the real host/ip
|
// opers can see through the cloak to the real host/ip
|
||||||
if asker_oper && disp != realhost {
|
if asker_oper && disp != realhost {
|
||||||
s.numeric(
|
s.numeric(
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,15 @@ pub fn commands() -> Vec<Box<dyn Command>> {
|
||||||
Box::new(ClearChan),
|
Box::new(ClearChan),
|
||||||
Box::new(Check),
|
Box::new(Check),
|
||||||
Box::new(AllTime),
|
Box::new(AllTime),
|
||||||
|
Box::new(SwhoisCmd),
|
||||||
|
Box::new(SetIdle),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An oper-set WHOIS line, stored per-user in `User.ext` and rendered by WHOIS
|
||||||
|
/// (RPL_WHOISSPECIAL 320). InspIRCd `m_swhois`.
|
||||||
|
pub struct Swhois(pub String);
|
||||||
|
|
||||||
/// Reject non-opers with 481; returns whether the caller is an oper.
|
/// Reject non-opers with 481; returns whether the caller is an oper.
|
||||||
fn require_oper(s: &mut Server, uid: Uid) -> bool {
|
fn require_oper(s: &mut Server, uid: Uid) -> bool {
|
||||||
if s.is_oper(uid) {
|
if s.is_oper(uid) {
|
||||||
|
|
@ -1185,6 +1191,60 @@ impl Command for Check {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SWHOIS — attach (or clear) an extra WHOIS line on a user (InspIRCd `m_swhois`).
|
||||||
|
/// `SWHOIS <nick> :<text>`; an empty text removes it. Shown as RPL_WHOISSPECIAL.
|
||||||
|
struct SwhoisCmd;
|
||||||
|
impl Command for SwhoisCmd {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"SWHOIS"
|
||||||
|
}
|
||||||
|
fn min_params(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
fn handle(&self, s: &mut Server, uid: Uid, params: &[String]) -> CmdResult {
|
||||||
|
if !require_oper(s, uid) {
|
||||||
|
return CmdResult::Fail;
|
||||||
|
}
|
||||||
|
let Some(t) = oper_target(s, uid, ¶ms[0]) else {
|
||||||
|
return CmdResult::Fail;
|
||||||
|
};
|
||||||
|
let text = params[1].clone();
|
||||||
|
if let Some(u) = s.users.get_mut(&t) {
|
||||||
|
if text.is_empty() {
|
||||||
|
u.ext.take::<Swhois>();
|
||||||
|
} else {
|
||||||
|
u.ext.set(Swhois(text.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let by = oper_nick(s, uid);
|
||||||
|
s.snotice(&format!("{by} used SWHOIS on {}: {text}", params[0]));
|
||||||
|
CmdResult::Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SETIDLE — reset your own idle time (InspIRCd `m_setidle`). `SETIDLE <seconds>`
|
||||||
|
/// backdates the last-activity clock so WHOIS shows that idle time.
|
||||||
|
struct SetIdle;
|
||||||
|
impl Command for SetIdle {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"SETIDLE"
|
||||||
|
}
|
||||||
|
fn min_params(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
fn handle(&self, s: &mut Server, uid: Uid, params: &[String]) -> CmdResult {
|
||||||
|
if !require_oper(s, uid) {
|
||||||
|
return CmdResult::Fail;
|
||||||
|
}
|
||||||
|
let secs: u64 = params[0].parse().unwrap_or(0);
|
||||||
|
if let Some(u) = s.users.get_mut(&uid) {
|
||||||
|
u.last_active = now().saturating_sub(secs);
|
||||||
|
}
|
||||||
|
onotice(s, uid, &format!("*** SETIDLE: idle time set to {secs}s"));
|
||||||
|
CmdResult::Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// ALLTIME — show the current server time to the requesting oper (InspIRCd
|
/// ALLTIME — show the current server time to the requesting oper (InspIRCd
|
||||||
/// `m_alltime`; on a single server there's just the one time to report).
|
/// `m_alltime`; on a single server there's just the one time to report).
|
||||||
struct AllTime;
|
struct AllTime;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ pub const RPL_ADMINEMAIL: u16 = 259;
|
||||||
pub const RPL_USERHOST: u16 = 302;
|
pub const RPL_USERHOST: u16 = 302;
|
||||||
pub const RPL_ISON: u16 = 303;
|
pub const RPL_ISON: u16 = 303;
|
||||||
pub const RPL_WHOISIDLE: u16 = 317;
|
pub const RPL_WHOISIDLE: u16 = 317;
|
||||||
|
pub const RPL_WHOISSPECIAL: u16 = 320; // SWHOIS oper-set whois line
|
||||||
pub const RPL_LISTSTART: u16 = 321;
|
pub const RPL_LISTSTART: u16 = 321;
|
||||||
pub const RPL_LIST: u16 = 322;
|
pub const RPL_LIST: u16 = 322;
|
||||||
pub const RPL_LISTEND: u16 = 323;
|
pub const RPL_LISTEND: u16 = 323;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue