Implementing the USER command

Since we have a name in our Client structure, it'd be nice to have some use for it, right? So, as the title says, let's implement the USER command. Since this command takes an argument, I'll go through the command implementation steps once again, so you'll have an example of a command taking a parameter.

First, let's update the enumĀ Command:

enum Command {
    Auth,
    Syst,
    User(String),
    Unknown(String),
}

Then, we update the as_ref implementation:

impl AsRef<str> for Command {
    fn as_ref(&self) -> &str {
        match *self {
            Command::Auth => "AUTH",
            Command::Syst => "SYST",
            Command::User => "USER",
            Command::Unknown(_) => "UNKN",
        }
    }
}

Finally, we update the Command::new method:

impl Command {
    pub fn new(input: Vec<u8>) -> io::Result<Self> {
        let mut iter = input.split(|&byte| byte == b' ');
        let mut command = iter.next().expect("command in input").to_vec();
        to_uppercase(&mut command);
        let data = iter.next();
        let command =
            match command.as_slice() {
                b"AUTH" => Command::Auth,
                b"SYST" => Command::Syst,
                b"USER" => Command::User(data.map(|bytes| 
String::from_utf8(bytes.to_vec()).expect("cannot
convert bytes to String")).unwrap_or_default()), s => Command::Unknown(str::from_utf8(s).unwrap_or("").to_owned()), }; Ok(command) } }

Phew, all done! Now we just need to implement the function (which is quite simple, I promise):

fn handle_cmd(&mut self, cmd: Command) {
    println!("====> {:?}", cmd);
    match cmd {
        Command::Auth => send_cmd(&mut self.stream, 
ResultCode::CommandNotImplemented, "Not implemented"), Command::Syst => send_cmd(&mut self.stream, ResultCode::Ok,
"I won't tell"), Command::User(username) => { if username.is_empty() { send_cmd(&mut self.stream, ResultCode::InvalidParameterOrArgument, "Invalid username") } else { self.name = username.to_owned(); send_cmd(&mut self.stream, ResultCode::UserLoggedIn, &format!("Welcome {}!", username)), } } Command::Unknown(s) => send_cmd(&mut self.stream,
ResultCode::UnknownCommand, "Not implemented"), } }

Here's a little explanation just in case you need it; if we receive an empty username (or no username at all), we consider this as an invalid parameter and return InvalidParameterOrArgument. Otherwise, everything is fine and we return UserLoggedIn.

If you're wondering why we didn't return ResultCode::Ok, it's because the RFC states as such. Once again, every command, what it does, and what it should return is described there. If you feel lost, don't hesitate to read it again!