simplemailclient 0.1.1

A simple terminal mail client (SMTP send, IMAP fetch) with a TUI.
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<()> {
    // Numeric ID → look up contact; bare name → append domain; full address → use as-is
    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(())
}