Lines of
src/main.rs
from check-in a044f68fa7
that are changed by the sequence of edits moving toward
check-in 072229b5bf:
1: //! Simple SMTP-to-Telegram gateway. Can parse email and send them as telegram
2: //! messages to specified chats, generally you specify which email address is
3: //! available in configuration, everything else is sent to default address.
4:
5: mod mail;
6: mod telegram;
7: mod utils;
8:
9: #[cfg(test)]
10: mod tests;
11:
12: use crate::mail::MailServer;
13:
a044f68fa7 2025-08-23 14: use async_std::fs::metadata;
15: use just_getopt::{
16: OptFlags,
17: OptSpecs,
18: OptValue,
19: };
20: use stacked_errors::{
21: Result,
22: StackableErr,
23: bail,
24: };
25:
26: use std::{
27: io::Cursor,
28: os::unix::fs::PermissionsExt,
29: path::Path,
30: };
31:
a044f68fa7 2025-08-23 32: #[async_std::main]
a044f68fa7 2025-08-23 33: async fn main () -> Result<()> {
a044f68fa7 2025-08-23 34: let specs = OptSpecs::new()
a044f68fa7 2025-08-23 35: .option("help", "h", OptValue::None)
a044f68fa7 2025-08-23 36: .option("help", "help", OptValue::None)
a044f68fa7 2025-08-23 37: .option("config", "c", OptValue::Required)
a044f68fa7 2025-08-23 38: .option("config", "config", OptValue::Required)
a044f68fa7 2025-08-23 39: .flag(OptFlags::OptionsEverywhere);
a044f68fa7 2025-08-23 40: let mut args = std::env::args();
a044f68fa7 2025-08-23 41: args.next();
a044f68fa7 2025-08-23 42: let parsed = specs.getopt(args);
a044f68fa7 2025-08-23 43: for u in &parsed.unknown {
a044f68fa7 2025-08-23 44: println!("Unknown option: {u}");
a044f68fa7 2025-08-23 45: }
a044f68fa7 2025-08-23 46: if !(parsed.unknown.is_empty()) || parsed.options_first("help").is_some() {
a044f68fa7 2025-08-23 47: println!("SMTP2TG v{}, (C) 2024 - 2025\n\n\
a044f68fa7 2025-08-23 48: \t-h|--help\tDisplay this help\n\
a044f68fa7 2025-08-23 49: \t-c|--config …\tSet configuration file location.",
a044f68fa7 2025-08-23 50: env!("CARGO_PKG_VERSION"));
a044f68fa7 2025-08-23 51: return Ok(());
a044f68fa7 2025-08-23 52: };
a044f68fa7 2025-08-23 53: let config_file = Path::new(if let Some(path) = parsed.options_value_last("config") {
a044f68fa7 2025-08-23 54: &path[..]
a044f68fa7 2025-08-23 55: } else {
a044f68fa7 2025-08-23 56: "smtp2tg.toml"
a044f68fa7 2025-08-23 57: });
a044f68fa7 2025-08-23 58: if !config_file.exists() {
a044f68fa7 2025-08-23 59: bail!("can't read configuration from {config_file:?}");
a044f68fa7 2025-08-23 60: };
a044f68fa7 2025-08-23 61: {
a044f68fa7 2025-08-23 62: let meta = metadata(config_file).await.stack()?;
a044f68fa7 2025-08-23 63: if (!0o100600 & meta.permissions().mode()) > 0 {
a044f68fa7 2025-08-23 64: bail!("other users can read or write config file {config_file:?}\n\
a044f68fa7 2025-08-23 65: File permissions: {:o}", meta.permissions().mode());
a044f68fa7 2025-08-23 66: }
a044f68fa7 2025-08-23 67: }
a044f68fa7 2025-08-23 68: let settings: config::Config = config::Config::builder()
a044f68fa7 2025-08-23 69: .set_default("fields", vec!["date", "from", "subject"]).stack()?
a044f68fa7 2025-08-23 70: .set_default("hostname", "smtp.2.tg").stack()?
a044f68fa7 2025-08-23 71: .set_default("listen_on", "0.0.0.0:1025").stack()?
a044f68fa7 2025-08-23 72: .set_default("unknown", "relay").stack()?
a044f68fa7 2025-08-23 73: .set_default("domains", vec!["localhost", hostname::get().stack()?.to_str().expect("Failed to get current hostname")]).stack()?
a044f68fa7 2025-08-23 74: .add_source(config::File::from(config_file))
a044f68fa7 2025-08-23 75: .build()
a044f68fa7 2025-08-23 76: .with_context(|| format!("[{config_file:?}] there was an error reading config\n\
a044f68fa7 2025-08-23 77: \tplease consult \"smtp2tg.toml.example\" for details"))?;
a044f68fa7 2025-08-23 78:
a044f68fa7 2025-08-23 79: let listen_on = settings.get_string("listen_on").stack()?;
a044f68fa7 2025-08-23 80: let server_name = settings.get_string("hostname").stack()?;
a044f68fa7 2025-08-23 81: let core = MailServer::new(settings)?;
a044f68fa7 2025-08-23 82: let mut server = mailin_embedded::Server::new(core);
a044f68fa7 2025-08-23 83:
a044f68fa7 2025-08-23 84: server.with_name(server_name)
a044f68fa7 2025-08-23 85: .with_ssl(mailin_embedded::SslConfig::None).unwrap()
a044f68fa7 2025-08-23 86: .with_addr(listen_on).unwrap();
a044f68fa7 2025-08-23 87: server.serve().unwrap();
a044f68fa7 2025-08-23 88:
a044f68fa7 2025-08-23 89: Ok(())
90: }