Diff
Logged in as anonymous

Differences From Artifact [2d1a8f5193]:

To Artifact [7f35ba3c51]:











1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36






37
38
39
40

41
42
43
44
45
46









47
48
49
50




51
52

53
54
55
56
57
58
59
60
61
62
63
1
2
3
4
5
6
7
8
9
10
11
12
13




14
15
16
17
18
19
20
21

22




23
24
25
26
27
28
29
30
31






32
33
34
35
36
37




38






39
40
41
42
43
44
45
46
47




48
49
50
51


52




53
54
55
56
57
58
59
+
+
+
+
+
+
+
+
+




-
-
-
-








-
+
-
-
-
-









-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
+
-
-
-
-







//! SMTP-to-Telegram gateway main library.
//!
//! This module provides the core functionality for receiving emails via SMTP
//! and forwarding them to Telegram chats.
//!
//! As we are not actually exporting this lib there would be no local Error's
//! for now, everything will be just .stack()?'ed and propagated like in real
//! bin The lib here is just to separate all tests from main code into tests/

pub mod mail;
mod telegram;
pub mod utils;

// As we are not actually exporting this lib there would be no local Error's for
// now, everything will be just .stack()?'ed and propagated like in real bin
// The lib here is just to separate all tests from main code into tests/

use crate::mail::MailServer;

use std::{
	io::Cursor,
	os::unix::fs::PermissionsExt,
	path::Path,
};

use just_getopt::{
use clap::Parser;
	OptFlags,
	OptSpecs,
	OptValue,
};
use smol::{
	fs::metadata,
};
use stacked_errors::{
	Result,
	StackableErr,
	bail,
};

/// Actual main function running async with Error propagation support
pub async fn async_main () -> Result<()> {
	let specs = OptSpecs::new()
		.option("help", "h", OptValue::None)
		.option("help", "help", OptValue::None)
		.option("config", "c", OptValue::Required)
/// SMTP-to-Telegram gateway
#[derive(Parser, Debug)]
#[command(name = "smtp2tg")]
#[command(about = format!("SMTP-to-Telegram gateway v{}, (C) 2024 - 2026", env!("CARGO_PKG_VERSION")), long_about = None)]
struct Args {
	/// Set configuration file location
		.option("config", "config", OptValue::Required)
		.flag(OptFlags::OptionsEverywhere);
	let mut args = std::env::args();
	args.next();
	#[arg(short, long, default_value = "smtp2tg.toml")]
	let parsed = specs.getopt(args);
	for u in &parsed.unknown {
		println!("Unknown option: {u}");
	}
	if !(parsed.unknown.is_empty()) || parsed.options_first("help").is_some() {
		println!("SMTP2TG v{}, (C) 2024 - 2026\n\n\
	config: String,
}

/// Main asynchronous entry point for the application.
///
/// Parses command-line arguments, loads configuration, and starts the SMTP
/// server.
///
/// # Errors
			\t-h|--help\tDisplay this help\n\
			\t-c|--config …\tSet configuration file location.",
			env!("CARGO_PKG_VERSION"));
		return Ok(());
/// Returns an error if configuration is invalid, files are inaccessible, or
/// server fails to start.
pub async fn async_main () -> Result<()> {
	let args = Args::parse();
	};
	let config_file = Path::new(if let Some(path) = parsed.options_value_last("config") {
	let config_file = Path::new(&args.config);
		&path[..]
	} else {
		"smtp2tg.toml"
	});
	if !config_file.exists() {
		bail!("can't read configuration from {config_file:?}");
	};
	{
		let meta = metadata(config_file).await.stack()?;
		if (!0o100600 & meta.permissions().mode()) > 0 {
			bail!("other users can read or write config file {config_file:?}\n\