Skip to content

Commit

Permalink
NAMES/WHO: Only send multiple prefixes after negotiating multi-prefix
Browse files Browse the repository at this point in the history
It is incorrect without this capability, and may break clients.
  • Loading branch information
progval authored and spb committed Apr 14, 2024
1 parent 51df31c commit 12111eb
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 19 deletions.
1 change: 1 addition & 0 deletions sable_ircd/src/capability/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ define_capabilities! (
UserhostInNames: 0x40 => ("userhost-in-names", true),
AwayNotify: 0x80 => ("away-notify", true),
AccountTag: 0x100 => ("account-tag", true),
MultiPrefix: 0x200 => ("multi-prefix", true),

// Draft and experimental caps
ChatHistory: 0x1_0000 => ("draft/chathistory", true),
Expand Down
46 changes: 28 additions & 18 deletions sable_ircd/src/command/handlers/who.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use crate::capability::ClientCapability;
use crate::utils::make_numeric;

#[command_handler("WHO")]
Expand All @@ -20,19 +21,15 @@ fn handle_who(
continue;
}

response.numeric(make_who_reply(
&member.user()?,
Some(&channel),
Some(&member),
));
send_who_reply(response, &member.user()?, Some(&channel), Some(&member));
}
}
} else if let Ok(nick) = Nickname::from_str(target) {
if let Ok(user) = network.user_by_nick(&nick) {
response.numeric(make_who_reply(
&user, None, // channel
send_who_reply(
response, &user, None, // channel
None, // membership
));
);
}
}

Expand All @@ -42,22 +39,35 @@ fn handle_who(
Ok(())
}

fn make_who_reply(
fn send_who_reply(
response: &dyn CommandResponse,
target: &wrapper::User,
channel: Option<&wrapper::Channel>,
membership: Option<&wrapper::Membership>,
) -> UntargetedNumeric {
) {
let chname = channel.map(|c| c.name().value() as &str).unwrap_or("*");
let away_letter = match target.away_reason() {
None => 'H', // Here
Some(_) => 'G', // Gone
};
let status = format!(
"{}{}",
away_letter,
membership
.map(|m| m.permissions().to_prefixes())
.unwrap_or_else(|| "".to_string())
);
make_numeric!(WhoReply, chname, target, &status, 0)
let status = if response.capabilities().has(ClientCapability::MultiPrefix) {
format!(
"{}{}",
away_letter,
membership
.map(|m| m.permissions().to_prefixes())
.unwrap_or_else(|| "".to_string())
)
} else {
format!(
"{}{}",
away_letter,
membership
.and_then(|m| m.permissions().to_highest_prefix())
.as_ref()
.map(char::to_string)
.unwrap_or_else(|| "".to_string())
)
};
response.numeric(make_numeric!(WhoReply, chname, target, &status, 0))
}
12 changes: 11 additions & 1 deletion sable_ircd/src/utils/channel_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub fn send_channel_names(
let user_is_on_chan = to_user.is_in_channel(channel.id()).is_some();

let with_userhost = to.capabilities().has(ClientCapability::UserhostInNames);
let with_multiprefix = to.capabilities().has(ClientCapability::MultiPrefix);

for member in channel.members() {
if !user_is_on_chan
Expand All @@ -38,7 +39,16 @@ pub fn send_channel_names(
continue;
}

let p = member.permissions().to_prefixes();
let p = if with_multiprefix {
member.permissions().to_prefixes()
} else {
member
.permissions()
.to_highest_prefix()
.as_ref()
.map(char::to_string)
.unwrap_or_else(|| "".to_string())
};
let user = member.user()?;
let n = if with_userhost {
format!("{}!{}@{}", user.nick(), user.user(), user.visible_host())
Expand Down
14 changes: 14 additions & 0 deletions sable_macros/src/modeflags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,20 @@ pub fn mode_flags(input: TokenStream) -> TokenStream {
return s;
}

/// [`to_prefixes`] fallback for clients without
/// [`multi-prefix`](https://ircv3.net/specs/extensions/multi-prefix)
pub fn to_highest_prefix(&self) -> Option<char>
{
for v in Self::ALL
{
if (self.is_set(v.0))
{
return Some(v.2)
}
}
return None;
}

pub fn prefix_for(flag: #name_one) -> char
{
for v in Self::ALL
Expand Down

0 comments on commit 12111eb

Please sign in to comment.