Просмотр исходного кода

ircd: Implement JOIN, PART, and TOPIC.

parazyd 4 лет назад
Родитель
Сommit
f8c5febd2f
2 измененных файлов с 73 добавлено и 35 удалено
  1. 53 12
      bin/ircd/src/server.rs
  2. 20 23
      bin/ircd/src/settings.rs

+ 53 - 12
bin/ircd/src/server.rs

@@ -9,6 +9,9 @@ use darkfi::{Error, Result};
 
 use crate::{crypto::encrypt_message, privmsg::Privmsg, ChannelInfo, SeenMsgIds};
 
+const RPL_NOTOPIC: u32 = 331;
+const RPL_TOPIC: u32 = 332;
+
 pub struct IrcServerConnection {
     write_stream: WriteHalf<TcpStream>,
     is_nick_init: bool,
@@ -34,7 +37,7 @@ impl IrcServerConnection {
             is_nick_init: false,
             is_user_init: false,
             is_registered: false,
-            nickname: "".to_string(),
+            nickname: "anon".to_string(),
             seen_msg_id,
             p2p_sender,
             auto_channels,
@@ -48,6 +51,7 @@ impl IrcServerConnection {
         // that for now to keep the protocol simple and focused.
         let command = tokens.next().ok_or(Error::MalformedPacket)?;
 
+        info!("Received line: {}", line);
         info!("Received command: {}", command);
 
         match command {
@@ -65,14 +69,47 @@ impl IrcServerConnection {
                 self.reply(&nick_reply).await?;
             }
             "JOIN" => {
-                // TODO:
-                // let channel = tokens.next().ok_or(Error::MalformedPacket)?;
-                // self.channels.push(channel.to_string());
+                let channels = tokens.next().ok_or(Error::MalformedPacket)?;
+                for chan in channels.split(',') {
+                    let join_reply = format!(":{}!anon@dark.fi JOIN {}\r\n", self.nickname, chan);
+                    self.reply(&join_reply).await?;
+                    self.configured_chans.insert(chan.to_string(), ChannelInfo::new()?);
+                }
+            }
+            "PART" => {
+                let channels = tokens.next().ok_or(Error::MalformedPacket)?;
+                for chan in channels.split(',') {
+                    let part_reply = format!(":{}!anon@dark.fi PART {}\r\n", self.nickname, chan);
+                    self.reply(&part_reply).await?;
+                    self.configured_chans.remove(chan);
+                }
+            }
+            "TOPIC" => {
+                let channel = tokens.next().ok_or(Error::MalformedPacket)?;
+                if let Some(substr_idx) = line.find(':') {
+                    // Client is setting the topic
+                    if substr_idx >= line.len() {
+                        return Err(Error::MalformedPacket)
+                    }
 
-                // let join_reply = format!(":{}!anon@dark.fi JOIN {}\r\n", self.nickname, channel);
-                // self.reply(&join_reply).await?;
+                    let topic = &line[substr_idx + 1..];
+                    let chan_info = self.configured_chans.get_mut(channel).unwrap();
+                    chan_info.topic = Some(topic.to_string());
 
-                // self.write_stream.write_all(b":f00!f00@127.0.01 PRIVMSG #dev :y0\r\n").await?;
+                    let topic_reply =
+                        format!(":{}!anon@dark.fi TOPIC {} :{}\r\n", self.nickname, channel, topic);
+                    self.reply(&topic_reply).await?;
+                } else {
+                    // Client is asking or the topic
+                    let chan_info = self.configured_chans.get(channel).unwrap();
+                    let topic_reply = if let Some(topic) = &chan_info.topic {
+                        format!("{} {} {} :{}\r\n", RPL_TOPIC, self.nickname, channel, topic)
+                    } else {
+                        const TOPIC: &str = "No topic is set";
+                        format!("{} {} {} :{}\r\n", RPL_NOTOPIC, self.nickname, channel, TOPIC)
+                    };
+                    self.reply(&topic_reply).await?;
+                }
             }
             "PING" => {
                 let line_clone = line.clone();
@@ -148,16 +185,20 @@ impl IrcServerConnection {
 
             for chan in self.auto_channels.clone() {
                 let topic = if self.configured_chans.contains_key(&chan) {
-                    let c = self.configured_chans.get(&chan).unwrap();
-                    if let Some(topic) = &c.topic {
+                    let c = self.configured_chans.get(&chan).unwrap().clone();
+                    if let Some(topic) = c.topic {
                         topic
                     } else {
-                        ""
+                        "".to_string()
                     }
                 } else {
-                    ""
+                    "".to_string()
                 };
-                autojoin!(chan, topic);
+
+                let mut ci = ChannelInfo::new()?;
+                ci.topic = Some(topic.to_string());
+                self.configured_chans.insert(chan.clone(), ci);
+                autojoin!(chan, topic.clone());
             }
         }
 

+ 20 - 23
bin/ircd/src/settings.rs

@@ -82,32 +82,29 @@ pub fn parse_configured_channels(config_file: &PathBuf) -> Result<FxHashMap<Stri
     let toml_contents = std::fs::read_to_string(config_file)?;
     let mut ret = FxHashMap::default();
 
-    match toml::from_str(&toml_contents)? {
-        Value::Table(map) => {
-            if map.contains_key("channel") && map["channel"].is_table() {
-                for chan in map["channel"].as_table().unwrap() {
-                    info!("Found configuration for channel {}", chan.0);
-                    let mut channel_info = ChannelInfo::new()?;
-
-                    if chan.1.as_table().unwrap().contains_key("topic") {
-                        channel_info.topic = Some(chan.1["topic"].as_str().unwrap().to_string());
-                    }
-
-                    if chan.1.as_table().unwrap().contains_key("secret") {
-                        // Build the NaCl box
-                        let s = chan.1["secret"].as_str().unwrap();
-                        let bytes: [u8; 32] = bs58::decode(s).into_vec()?.try_into().unwrap();
-                        let secret = crypto_box::SecretKey::from(bytes);
-                        let public = secret.public_key();
-                        let msg_box = crypto_box::Box::new(&public, &secret);
-                        channel_info.salt_box = Some(msg_box);
-                    }
-
-                    ret.insert(chan.0.to_string(), channel_info);
+    if let Value::Table(map) = toml::from_str(&toml_contents)? {
+        if map.contains_key("channel") && map["channel"].is_table() {
+            for chan in map["channel"].as_table().unwrap() {
+                info!("Found configuration for channel {}", chan.0);
+                let mut channel_info = ChannelInfo::new()?;
+
+                if chan.1.as_table().unwrap().contains_key("topic") {
+                    channel_info.topic = Some(chan.1["topic"].as_str().unwrap().to_string());
                 }
+
+                if chan.1.as_table().unwrap().contains_key("secret") {
+                    // Build the NaCl box
+                    let s = chan.1["secret"].as_str().unwrap();
+                    let bytes: [u8; 32] = bs58::decode(s).into_vec()?.try_into().unwrap();
+                    let secret = crypto_box::SecretKey::from(bytes);
+                    let public = secret.public_key();
+                    let msg_box = crypto_box::Box::new(&public, &secret);
+                    channel_info.salt_box = Some(msg_box);
+                }
+
+                ret.insert(chan.0.to_string(), channel_info);
             }
         }
-        _ => {}
     };
 
     Ok(ret)