66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
-
|
/// validates all required configuration values.
///
/// # Arguments
/// * `settings` - Parsed application configuration.
///
/// # Errors
/// Returns an error if required configuration values are missing or invalid.
/// server fails to start.
pub fn new (settings: config::Config) -> Result<MailServer> {
let api_key = settings.get_string("api_key")
.context("[smtp2tg.toml] missing \"api_key\" parameter.\n")?;
let mut recipients = HashMap::new();
for (name, value) in settings.get_table("recipients")
.context("[smtp2tg.toml] missing table \"recipients\".\n")?
{
|
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
+
+
-
-
+
+
-
-
+
-
+
|
let mut domains: HashSet<String> = HashSet::new();
let extra_domains = settings.get_array("domains").stack()?;
for domain in extra_domains {
let domain = domain.to_string().to_lowercase();
if RE_DOMAIN.is_match(&domain) {
domains.insert(domain);
} else {
bail!("Invalid domain in configuration: '{domain}'\n\
Domains must be valid (e.g., 'example.com', 'localhost').\n\
bail!("[smtp2tg.toml] can't check domains in \"domains\": {domain}");
}
Check 'domains' array in smtp2tg.toml.");
} }
}
if domains.is_empty() {
bail!("No domains, need at least one: default `localhost` would do.");
}
let domains = domains.into_iter().map(|s| escape(&s))
let re_domains = domains.iter().map(|s| escape(s))
.collect::<Vec<String>>().join("|");
let address = RegexBuilder::new(&format!("^[a-z0-9][a-z0-9.-]*(@({domains}))?$"))
let address = RegexBuilder::new(&format!("^[a-z0-9][a-z0-9.-]*(@({re_domains}))?$"))
.case_insensitive(true).build().stack()?;
Ok(MailServer {
data: vec!(),
headers: None,
tg,
fields,
|
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
-
-
+
+
-
|
/// # Returns
/// * `Result<ChatPeerId>` - Telegram chat ID for the address, or default if
/// not found.
pub fn get_id (&self, name: &str) -> Result<&ChatPeerId> {
if self.address.is_match(name) {
Ok(self.tg.get(name).unwrap_or(&self.tg.default))
} else {
bail!("Doesn't look like address from one of our domains.");
}
bail!("Email address {name:?} is not from an allowed domain.");
} }
}
/// Attempt to deliver one message
async fn relay_mail (&self) -> Result<()> {
if let Some(headers) = &self.headers {
let mail = mail_parser::MessageParser::new().parse(&self.data)
.context("Failed to parse mail.")?;
|