bin/ircd: implement CAP command

This commit is contained in:
ghassmo
2022-06-30 02:09:46 +03:00
parent 231e9dbfab
commit d97e1d8bae

View File

@@ -31,9 +31,11 @@ pub struct IrcServerConnection {
is_nick_init: bool,
is_user_init: bool,
is_registered: bool,
is_cap_end: bool,
nickname: String,
auto_channels: Vec<String>,
pub configured_chans: FxHashMap<String, ChannelInfo>,
capabilities: FxHashMap<String, bool>,
// p2p
p2p: P2pPtr,
senders: SubscriberPtr<Privmsg>,
@@ -53,6 +55,8 @@ impl IrcServerConnection {
senders: SubscriberPtr<Privmsg>,
subscriber_id: u64,
) -> Self {
let mut capabilities = FxHashMap::default();
capabilities.insert("no-history".to_string(), false);
Self {
write_stream,
peer_address,
@@ -61,9 +65,11 @@ impl IrcServerConnection {
is_nick_init: false,
is_user_init: false,
is_registered: false,
is_cap_end: false,
nickname: "anon".to_string(),
auto_channels,
configured_chans,
capabilities,
p2p,
senders,
subscriber_id,
@@ -199,7 +205,78 @@ impl IrcServerConnection {
self.on_receive_privmsg(&message, target).await?;
}
"CAP" => {}
"CAP" => {
let subcommand = tokens.next().ok_or(Error::MalformedPacket)?.to_uppercase();
let capabilities_keys: Vec<String> = self.capabilities.keys().cloned().collect();
if subcommand == "LS" {
let cap_ls_reply = format!(
":{}!anon@dark.fi CAP * LS :{}\r\n",
self.nickname,
capabilities_keys.join(" ")
);
self.reply(&cap_ls_reply).await?;
}
if subcommand == "REQ" {
let substr_idx = line.find(':').ok_or(Error::MalformedPacket)?;
if substr_idx >= line.len() {
return Err(Error::MalformedPacket)
}
let cap: Vec<&str> = line[substr_idx + 1..].split(" ").collect();
let mut ack_list = vec![];
let mut nak_list = vec![];
for c in cap {
if self.capabilities.contains_key(c) {
self.capabilities.insert(c.to_string(), true);
ack_list.push(c);
} else {
nak_list.push(c);
}
}
let cap_ack_reply = format!(
":{}!anon@dark.fi CAP * ACK :{}\r\n",
self.nickname,
ack_list.join(" ")
);
let cap_nak_reply = format!(
":{}!anon@dark.fi CAP * NAK :{}\r\n",
self.nickname,
nak_list.join(" ")
);
self.reply(&cap_ack_reply).await?;
self.reply(&cap_nak_reply).await?;
}
if subcommand == "LIST" {
let enabled_capabilities: Vec<String> = self
.capabilities
.clone()
.into_iter()
.filter(|(_, v)| *v)
.map(|(k, _)| k)
.collect();
let cap_list_reply = format!(
":{}!anon@dark.fi CAP * LIST :{}\r\n",
self.nickname,
enabled_capabilities.join(" ")
);
self.reply(&cap_list_reply).await?;
}
if subcommand == "END" {
self.is_cap_end = true;
}
}
"QUIT" => {
// Close the connection
return Err(Error::NetworkServiceStopped)
@@ -210,7 +287,7 @@ impl IrcServerConnection {
}
// on registration
if !self.is_registered && self.is_nick_init && self.is_user_init {
if !self.is_registered && self.is_cap_end && self.is_nick_init && self.is_user_init {
debug!("Initializing peer connection");
let register_reply = format!(":darkfi 001 {} :Let there be dark\r\n", self.nickname);
self.reply(&register_reply).await?;
@@ -221,13 +298,13 @@ impl IrcServerConnection {
}
// Send dm messages in buffer
for msg in self.privmsgs_buffer.lock().await.to_vec() {
if msg.target == self.nickname || msg.nickname == self.nickname {
self.senders.notify_by_id(msg, self.subscriber_id).await;
if !self.capabilities.get("no-history").unwrap() {
for msg in self.privmsgs_buffer.lock().await.to_vec() {
if msg.target == self.nickname || msg.nickname == self.nickname {
self.senders.notify_by_id(msg, self.subscriber_id).await;
}
}
}
// send names command
}
Ok(())
@@ -282,7 +359,6 @@ impl IrcServerConnection {
(*self.seen_msg_ids.lock().await).push(random_id);
(*self.privmsgs_buffer.lock().await).push(protocol_msg.clone())
}
self.senders.notify_with_exclude(protocol_msg.clone(), &[self.subscriber_id]).await;
debug!(target: "ircd", "PRIVMSG to be sent: {:?}", protocol_msg);
@@ -312,9 +388,11 @@ impl IrcServerConnection {
}
// Send messages in buffer
for msg in self.privmsgs_buffer.lock().await.to_vec() {
if msg.target == chan {
self.senders.notify_by_id(msg, self.subscriber_id).await;
if !self.capabilities.get("no-history").unwrap() {
for msg in self.privmsgs_buffer.lock().await.to_vec() {
if msg.target == chan {
self.senders.notify_by_id(msg, self.subscriber_id).await;
}
}
}
@@ -355,7 +433,10 @@ impl IrcServerConnection {
return Ok(())
}
if self.is_nick_init && (self.nickname == msg.target || self.nickname == msg.nickname) {
if self.is_cap_end &&
self.is_nick_init &&
(self.nickname == msg.target || self.nickname == msg.nickname)
{
self.reply(&msg.to_irc_msg()).await?;
}