use std::io::Write;
use ansi_term::Colour::{Blue as ColorServer, Red as ColorClient};
use imap_codec::rfc3501::command::command;
fn main() {
welcome();
let mut buffer = Vec::new();
loop {
match command(&buffer) {
Ok((remaining, command)) => {
println!("{:#?}", command);
buffer = remaining.to_vec();
}
Err(nom::Err::Incomplete(_needed)) => {
read_more(&mut buffer);
}
Err(nom::Err::Failure(failure)) if failure.code == nom::error::ErrorKind::Fix => {
println!("S: {}", ColorServer.paint("+ "));
read_more(&mut buffer);
}
Err(nom::Err::Error(error)) | Err(nom::Err::Failure(error)) => {
println!("Error parsing command. Is it correct? ({:?})", error);
println!("Clearing buffer.");
buffer.clear();
}
}
}
}
fn welcome() {
let welcome = r#"
# Parsing of IMAP commands.
As a user, you are in the role of an IMAP client. Thus, you type IMAP commands. However, the example code shows typical server code, i.e., how to rfc3501 received commands.
"C:" denotes the client, "S:" denotes the server, and ".." denotes the continuation of an (incomplete) command, e.g., due to the use of IMAP literals.
Enter command (or "exit").
"#;
println!("{}", welcome);
}
fn read_more(buffer: &mut Vec<u8>) {
let prompt = if buffer.is_empty() { "C: " } else { ".. " };
let line = read_line(prompt);
if line.trim() == "exit" || line.trim() == "" {
std::process::exit(0);
}
buffer.extend_from_slice(line.as_bytes());
}
pub fn read_line(prompt: &str) -> String {
print!("{}{}", prompt, ColorClient.prefix());
std::io::stdout().flush().unwrap();
let mut line = String::new();
std::io::stdin().read_line(&mut line).unwrap();
print!("{}", ColorClient.suffix());
line.replace("\n", "\r\n")
}