use std::{io::BufRead, num::NonZeroU32};
use imap_next::{
imap_types::{
core::Text,
response::{
CommandContinuationRequest, Data, Greeting, Status, StatusBody, StatusKind, Tagged,
},
},
server::{Event, Options, Server},
stream::Stream,
};
use tokio::{net::TcpListener, sync::mpsc::Receiver};
#[tokio::main(flavor = "current_thread")]
async fn main() {
let listener = TcpListener::bind("127.0.0.1:12345").await.unwrap();
let (stream, _) = listener.accept().await.unwrap();
let mut stream = Stream::insecure(stream);
let mut server = Server::new(
Options::default(),
Greeting::ok(None, "server_idle (example)").unwrap(),
);
loop {
match stream.next(&mut server).await.unwrap() {
Event::GreetingSent { .. } => break,
event => println!("unexpected event: {event:?}"),
}
}
println!("Please enter 'ok', 'no', or 'expunge'");
let mut lines = Lines::new();
let mut current_idle_tag = None;
loop {
tokio::select! {
event = stream.next(&mut server) => {
match event.unwrap() {
Event::IdleCommandReceived { tag } => {
println!("IDLE received");
current_idle_tag = Some(tag);
},
Event::IdleDoneReceived => {
println!("IDLE DONE received");
if let Some(tag) = current_idle_tag.take() {
let status = Status::Tagged(Tagged {
tag,
body: StatusBody {
kind: StatusKind::Ok,
code: None,
text: Text::try_from("...").unwrap()
},
});
server.enqueue_status(status);
}
},
event => {
println!("Event received: {event:?}");
}
}
}
line = lines.next() => {
match line.as_ref() {
"ok" => {
let cont = CommandContinuationRequest::basic(None, "...").unwrap();
if server.idle_accept(cont).is_ok() {
println!("IDLE accepted");
} else {
println!("IDLE can't be accepted now");
}
}
"no" => {
let Some(tag) = current_idle_tag.clone() else {
println!("IDLE can't be rejected now");
continue;
};
let status = Status::Tagged(Tagged {
tag,
body: StatusBody {
kind: StatusKind::No,
code: None,
text: Text::try_from("...").unwrap()
},
});
if server.idle_reject(status).is_ok() {
println!("IDLE rejected");
} else {
println!("IDLE can't be rejected now");
}
}
"expunge" => {
let data = Data::Expunge(NonZeroU32::new(1).unwrap());
server.enqueue_data(data);
println!("Send EXPUNGE");
}
_ => println!("Please enter 'ok', 'no', or 'expunge'"),
}
}
}
}
}
struct Lines {
receiver: Receiver<String>,
}
impl Lines {
pub fn new() -> Self {
let (sender, receiver) = tokio::sync::mpsc::channel(1);
tokio::task::spawn_blocking(move || loop {
for line in std::io::stdin().lock().lines() {
sender.blocking_send(line.unwrap()).unwrap();
}
});
Self { receiver }
}
pub async fn next(&mut self) -> String {
self.receiver.recv().await.unwrap()
}
}