use std::io::{BufRead, BufReader}; use std::net::Shutdown; use std::os::fd::FromRawFd; use std::os::unix::net::UnixStream; use std::str::FromStr; use varlink::{ConnectionHandler, ErrorKind, Stream, VarlinkService}; mod cmd; #[path = "de_jmhoffmann_jwebmail_mail-storage.rs"] mod de_jmhoffmann_jwebmail_mailstorage; mod rfc822; use cmd::MailStorage; fn main() { simplelog::TermLogger::init( simplelog::LevelFilter::Info, simplelog::Config::default(), simplelog::TerminalMode::Stderr, simplelog::ColorChoice::Never, ) .unwrap(); let mail_storage = MailStorage::default(); let myinterface = de_jmhoffmann_jwebmail_mailstorage::new(Box::new(mail_storage)); let service = VarlinkService::new( "de.jmhoffmann.jwebmail.mail-storage.varlink", "jwebmails storage service", "1.0.1", "https://fehcom.de/cgit/jwebmail2/", vec![Box::new(myinterface)], ); if let Ok(listen_fds) = std::env::var("LISTEN_FDS") { let lfds = u8::from_str(&listen_fds).expect("env variable `LISTEN_FDS` must be an integer"); if lfds < 1 { log::error!("No file descriptor to receive commands from!"); return; } else if lfds == 1 { let uds = unsafe { UnixStream::from_raw_fd(3) }; accept_con(&service, uds); } else { let listen_fdnames = std::env::var("LISTEN_FDNAMES") .expect("when multiple `LISTEN_FDS` are available `LISTEN_FDNAMES` must be set"); listen_fdnames .split(':') .enumerate() .filter(|(_, name)| *name == "varlink") .for_each(|(i, _)| { accept_con(&service, unsafe { UnixStream::from_raw_fd(3 + i as i32) }) }); } } else { log::error!("No file descriptor to receive commands from!"); } } /// mostly a copy from varlink::listen fn accept_con(service: &VarlinkService, mut uds: UnixStream) { let (r, mut w) = uds.split().unwrap(); let mut br = BufReader::new(r); let mut iface: Option = None; loop { match service.handle(&mut br, &mut w, iface.clone()) { Ok((_, i)) => { iface = i; match br.fill_buf() { Err(_) => break, Ok(buf) if buf.is_empty() => break, _ => {} } } Err(err) => { match err.kind() { ErrorKind::ConnectionClosed | ErrorKind::SerdeJsonDe(_) => {} _ => { eprintln!("Worker error: {:?}", err); } } let _ = uds.shutdown(Shutdown::Both); break; } } } }