Full implementation of the LIST command

Now that we know how to play with paths nicely, it'd be a shame not fully implement the LIST command, right?

To complete it, you'll need to update the Command::List variant in order to make it accept PathBuf as an argument.

So, we currently have the following code:

Command::List => {
    if let Some(ref mut data_writer) = self.data_writer {
        let mut tmp = PathBuf::from(".");
        send_cmd(&mut self.stream, ResultCode::DataConnectionAlreadyOpen,
                 "Starting to list directory...");
        let mut out = String::new();
        for entry in read_dir(tmp).unwrap() {
            for entry in dir {
                if let Ok(entry) = entry {
                    add_file_info(entry.path(), &mut out);
                }
            }
            send_data(data_writer, &out)
        }
    } else {
        send_cmd(&mut self.stream, ResultCode::ConnectionClosed, "No opened data  
connection"); } if self.data_writer.is_some() { self.data_writer = None; send_cmd(&mut self.stream, ResultCode::ClosingDataConnection, "Transfer
done"); } }

Let's update it as follows:

Command::List(path) => {
    if let Some(ref mut data_writer) = self.data_writer {
        let server_root = env::current_dir().unwrap();
        let path = self.cwd.join(path.unwrap_or_default());
        let directory = PathBuf::from(&path);
        if let Ok(path) = self.complete_path(directory, 
&server_root) { send_cmd(&mut self.stream,
ResultCode::DataConnectionAlreadyOpen,
"Starting to list directory..."); let mut out = String::new(); for entry in read_dir(path).unwrap() { for entry in dir { if let Ok(entry) = entry { add_file_info(entry.path(), &mut out); } } send_data(data_writer, &out) } } else { send_cmd(&mut self.stream, ResultCode::InvalidParameterOrArgument, "No such file or directory..."); } } else { send_cmd(&mut self.stream, ResultCode::ConnectionClosed,
"No opened data connection"); } if self.data_writer.is_some() { self.data_writer = None; send_cmd(&mut self.stream,
ResultCode::ClosingDataConnection, "Transfer done"); } }

To put it simply, we just added the following line:

let path = self.cwd.join(path.unwrap_or_default());
let directory = PathBuf::from(&path);
if let Ok(path) = self.complete_path(directory, &server_root) {
    // ...
} else {
    send_cmd(&mut self.stream, ResultCode::InvalidParameterOrArgument,
             "No such file or directory...");
}

Thanks to the Client::complete_path method, things were pretty easy with the path manipulation. So, what happens if the given path is a file? We don't check such a case but we should! Let's replace the following lines:

for entry in read_dir(path).unwrap() {
    for entry in dir {
        if let Ok(entry) = entry {
            add_file_info(entry.path(), &mut out);
        }
    }
    send_data(data_writer, &out)
}

With:

if path.is_dir() {
    for entry in read_dir(path).unwrap() {
        for entry in dir {
            if let Ok(entry) = entry {
                add_file_info(entry.path(), &mut out);
            }
        }
        send_data(data_writer, &out)
    }
} else {
    add_file_info(path, &mut out);
}

And that's it! Luckily for us, we did things correctly the first time, so it just works.