mod config;
mod store;
mod transport;
mod editor;
mod tui;
mod display;
use std::env;
use anyhow::{Context, Result};
use config::Config;
use store::MailStore;
#[tokio::main]
async fn main() -> Result<()> {
let cfg = Config::load().context("Failed to load config")?;
let store = MailStore::new(&cfg).context("Failed to initialize mail store")?;
let args: Vec<String> = env::args().collect();
match args.get(1).map(String::as_str) {
Some("send") => {
let input = args.get(2).unwrap_or_else(|| {
eprintln!("Usage: mail send <username|id>");
std::process::exit(1);
});
handle_send(&cfg, &store, input).await?;
}
Some("inbox") => {
display::show_inbox(&store);
}
Some("read") => {
let index: usize = args
.get(2)
.and_then(|s| s.parse().ok())
.unwrap_or_else(|| {
eprintln!("Usage: mail read <inbox_index>");
std::process::exit(1);
});
display::read_message(&store, index);
}
Some("sync") => {
println!("Syncing mail...");
transport::fetch_imap(&cfg, &store).await?;
println!("Sync complete. {} unread.", store.unread_count());
}
None => {
tui::run(&cfg, &store).await?;
}
Some(cmd) => {
eprintln!("Unknown command: {}", cmd);
eprintln!();
eprintln!("Usage:");
eprintln!(" mail send <username|id> Compose and send a message");
eprintln!(" mail inbox List inbox messages");
eprintln!(" mail read <index> Read message by inbox index");
eprintln!(" mail sync Fetch new mail via IMAP");
eprintln!(" mail Launch interactive TUI");
std::process::exit(1);
}
}
Ok(())
}
async fn handle_send(cfg: &Config, store: &MailStore, input: &str) -> Result<()> {
let resolved = if input.chars().all(|c| c.is_ascii_digit()) {
store
.resolve_contact_id(input)
.with_context(|| format!("No contact with ID {}", input))?
} else {
let addr = cfg.resolve_address(input);
store.ensure_contact(&addr)?;
addr
};
println!("Composing mail to: {}", resolved);
match editor::compose()? {
Some(body) if !body.trim().is_empty() => {
transport::send_smtp(cfg, &resolved, &body, &[]).await?;
store.record_sent(&resolved, &body)?;
println!("✓ Message sent to {}", resolved);
}
_ => {
println!("Aborted: empty message, nothing sent.");
}
}
Ok(())
}