use imap_codec::{
AuthenticateDataCodec, CommandCodec, IdleDoneCodec,
fragmentizer::{FragmentInfo, Fragmentizer, LiteralAnnouncement},
};
#[path = "common/common.rs"]
mod common;
use common::{COLOR_SERVER, RESET, read_more};
use imap_types::{
IntoStatic,
command::{Command, CommandBody},
core::{LiteralMode, Tag},
};
use crate::common::Role;
enum State {
Command,
Authenticate(Tag<'static>),
Idle,
}
const WELCOME: &str = r#"# Parsing of IMAP commands
"C:" denotes the client,
"S:" denotes the server, and
".." denotes the continuation of an (incomplete) command, e.g., due to the use of an IMAP literal.
Note: "\n" will be automatically replaced by "\r\n".
--------------------------------------------------------------------------------------------------
Enter IMAP commands (or "exit").
"#;
fn main() {
println!("{WELCOME}");
let mut fragmentizer = Fragmentizer::new(10 * 1024);
let mut state = State::Command;
println!("S: {COLOR_SERVER}* OK ...{RESET}");
loop {
let Some(fragment_info) = fragmentizer.progress() else {
let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
fragmentizer.enqueue_bytes(&bytes);
continue;
};
if let FragmentInfo::Line {
announcement:
Some(LiteralAnnouncement {
mode: LiteralMode::Sync,
length,
}),
..
} = fragment_info
{
if length <= 1024 {
println!("S: {COLOR_SERVER}+ {RESET}");
continue;
} else if let Some(tag) = fragmentizer.decode_tag() {
println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
fragmentizer.skip_message();
continue;
} else {
fragmentizer.poison_message();
continue;
}
}
if !fragmentizer.is_message_complete() {
continue;
}
match state {
State::Command => {
match fragmentizer.decode_message(&CommandCodec::default()) {
Ok(Command {
tag,
body: CommandBody::Authenticate { .. },
}) => {
println!("S: {COLOR_SERVER}+ {RESET}");
state = State::Authenticate(tag.into_static());
}
Ok(Command {
body: CommandBody::Idle,
..
}) => {
println!("S: {COLOR_SERVER}+ ...{RESET}");
state = State::Idle;
}
Ok(command) => {
println!("{command:#?}");
}
Err(err) => {
println!("Error parsing command: {err:?}");
}
};
}
State::Authenticate(ref tag) => {
match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
Ok(_authenticate_data) => {
println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
state = State::Command;
}
Err(err) => {
println!("Error parsing authenticate data: {err:?}");
}
};
}
State::Idle => {
match fragmentizer.decode_message(&IdleDoneCodec::default()) {
Ok(_idle_done) => {
state = State::Command;
}
Err(err) => {
println!("Error parsing idle done: {err:?}");
}
};
}
}
}
}