Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added notify-away support #175

Merged
merged 12 commits into from
Jul 26, 2023
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ to ensure future breakages won't occur.**

Added:

- Away-notify extension added for supported servers
- SASL support for PLAIN & EXTERNAL. The following per-server config keys have been added:
- PLAIN - `sasl.plain.username` & `sasl.plain.password`
- EXTERNAL - `sasl.external.cert` is a path to the PEM encoded X509 cert
Expand All @@ -16,6 +17,7 @@ Added:

Changed:

- Away users will be appear slightly transparent in nicklist
- Configuration option `new_buffer` has been renamed to `buffer`. `new_buffer` key will still work for backwards compatibility.
- Migrated to our own internal IRC backend. This should allow for quicker development against extensions and bug fixes.

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ cargo run --release

Halloy supports the following IRCv3.2 capabilities

- `away-notify`
- `batch`
- `server-time`
- `sasl=PLAIN,EXTERNAL`
Expand Down
42 changes: 42 additions & 0 deletions data/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub struct Client {
registration_step: RegistrationStep,
listed_caps: Vec<String>,
supports_labels: bool,
supports_away_notify: bool,
}

impl fmt::Debug for Client {
Expand Down Expand Up @@ -111,6 +112,7 @@ impl Client {
registration_step,
listed_caps: vec![],
supports_labels: false,
supports_away_notify: false,
}
}

Expand Down Expand Up @@ -268,6 +270,9 @@ impl Client {

let contains = |s| self.listed_caps.iter().any(|cap| cap == s);

if contains("away-notify") {
requested.push("away-notify");
}
if contains("server-time") {
requested.push("server-time");
}
Expand Down Expand Up @@ -308,6 +313,9 @@ impl Client {
if caps.contains(&"labeled-response") {
self.supports_labels = true;
}
if caps.contains(&"away-notify") {
self.supports_away_notify = true;
}

let supports_sasl = caps.iter().any(|cap| cap.contains("sasl"));

Expand Down Expand Up @@ -461,6 +469,11 @@ impl Client {
}
}
Command::JOIN(channel, _) => {
if self.supports_away_notify {
// Sends WHO to get away state on users.
let _ = self.sender.try_send(command!("WHO", channel));
}
casperstorm marked this conversation as resolved.
Show resolved Hide resolved

let user = message.user()?;

if user.nickname() == self.nickname() {
Expand All @@ -469,6 +482,35 @@ impl Client {
list.insert(user);
}
}
Command::Numeric(RPL_WHOREPLY, args) => {
if self.supports_away_notify {
// H = Here, G = gone (away)
let flags = args.get(6)?.chars().collect::<Vec<char>>();
let away = *(flags.first()?) == 'G';

if let Some(list) = self.chanmap.get_mut(&args[1]) {
let lookup = User::from(Nick::from(args[5].clone()));

if let Some(mut user) = list.take(&lookup) {
user.update_away(away);
list.insert(user);
}
}
}
}
Command::AWAY(args) => {
let away = args.is_some();
let user = message.user()?;
let channels = self.user_channels(user.nickname());
for channel in channels.iter() {
casperstorm marked this conversation as resolved.
Show resolved Hide resolved
if let Some(list) = self.chanmap.get_mut(channel) {
if let Some(mut user) = list.take(&user) {
user.update_away(away);
list.insert(user);
}
}
}
}
Command::MODE(target, Some(modes), args) if proto::is_channel(target) => {
let modes = mode::parse::<mode::Channel>(modes, args);

Expand Down
12 changes: 12 additions & 0 deletions data/src/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct User {
username: Option<String>,
hostname: Option<String>,
access_levels: HashSet<AccessLevel>,
away: bool,
}

impl PartialEq for User {
Expand Down Expand Up @@ -88,6 +89,7 @@ impl<'a> TryFrom<&'a str> for User {
username,
hostname,
access_levels,
away: false,
})
}
}
Expand All @@ -112,6 +114,7 @@ impl From<Nick> for User {
username: None,
hostname: None,
access_levels: HashSet::default(),
away: false,
}
}
}
Expand All @@ -128,6 +131,10 @@ impl User {
}
}

pub fn is_away(&self) -> bool {
self.away
}

pub fn username(&self) -> Option<&str> {
self.username.as_deref()
}
Expand Down Expand Up @@ -165,6 +172,10 @@ impl User {
}
}

pub fn update_away(&mut self, away: bool) {
self.away = away;
}

pub fn formatted(&self) -> String {
let user = self.username();
let host = self.hostname();
Expand All @@ -186,6 +197,7 @@ impl From<proto::User> for User {
username: user.username,
hostname: user.hostname,
access_levels: HashSet::default(),
away: false,
}
}
}
Expand Down
19 changes: 14 additions & 5 deletions src/buffer/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,20 @@ mod nick_list {
users
.iter()
.map(|user| {
let content = container(row![].padding([0, 4]).push(text(format!(
"{}{}",
user.highest_access_level(),
user.nickname()
))));
let content = container(
row![].padding([0, 4]).push(
text(format!(
"{}{}",
user.highest_access_level(),
user.nickname()
))
.style(if user.is_away() {
theme::Text::Transparent
} else {
theme::Text::Default
}),
),
);

user_context::view(content, user.clone())
})
Expand Down