use std::ffi::{CStr, CString}; use std::io::{stdin, stdout, Read, Write}; use clap::Parser as _; mod arguments; mod cmd; mod error; mod pb3; mod rfc822; use arguments::{Arguments, Mode}; use error::{Error, Result}; fn switch_to_user(sys_user: &str) -> Result<()> { unsafe { *libc::__errno_location() = 0; } let c_sys_user = CString::new(sys_user).map_err(|e| Error::Setuid(format!("nul char in user, {}", e)))?; let user_info: *const libc::passwd = unsafe { libc::getpwnam(c_sys_user.as_ptr()) }; let err = unsafe { *libc::__errno_location() }; if err != 0 { return Err(Error::Setuid(format!( "error calling getpwnam {:?}", unsafe { libc::strerror(err) } ))); }; if user_info.is_null() { return Err(Error::Setuid(format!("user {:?} does not exist", sys_user))); }; let rc = unsafe { libc::setuid((*user_info).pw_uid) }; if rc != 0 { let err = unsafe { *libc::__errno_location() }; return Err(Error::Setuid(format!( "error calling setuid {:?}", unsafe { CStr::from_ptr(libc::strerror(err)) } ))); } Ok(()) } fn main() -> Result<()> { simplelog::TermLogger::init( simplelog::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr, simplelog::ColorChoice::Never, ) .unwrap(); let args = Arguments::parse(); switch_to_user(&args.sys_user)?; let path = args.maildir_path.join(args.mail_user); stdout().write_all(b"OPEN\n")?; stdout().flush()?; let mut req = Vec::with_capacity(2048); stdin().read_to_end(&mut req)?; let res = match args.mode { Mode::Read => cmd::read(path, &req), Mode::Raw => cmd::raw(path, &req), Mode::List => cmd::list(path, &req), Mode::Folders => cmd::folders(path, &req), Mode::Count => cmd::count(path, &req), //Mode::Search => cmd::search(&path, &req), Mode::Move => cmd::move_mail(path, &req), Mode::Remove => cmd::remove(path, &req), Mode::AddFolder => cmd::add_folder(path, &req), _ => todo!(), }?; stdout().write_all(&res).map_err(|e| e.into()) }