0000: 2f 2f 21 20 53 4d 54 50 20 73 65 72 76 65 72 20 //! SMTP server
0010: 69 6d 70 6c 65 6d 65 6e 74 61 74 69 6f 6e 20 66 implementation f
0020: 6f 72 20 72 65 63 65 69 76 69 6e 67 20 61 6e 64 or receiving and
0030: 20 70 72 6f 63 65 73 73 69 6e 67 20 65 6d 61 69 processing emai
0040: 6c 73 2e 0a 2f 2f 21 0a 2f 2f 21 20 54 68 69 73 ls..//!.//! This
0050: 20 6d 6f 64 75 6c 65 20 68 61 6e 64 6c 65 73 20 module handles
0060: 53 4d 54 50 20 63 6f 6e 6e 65 63 74 69 6f 6e 73 SMTP connections
0070: 2c 20 65 6d 61 69 6c 20 70 61 72 73 69 6e 67 2c , email parsing,
0080: 20 61 6e 64 20 66 6f 72 77 61 72 64 69 6e 67 20 and forwarding
0090: 74 6f 0a 2f 2f 21 20 54 65 6c 65 67 72 61 6d 2e to.//! Telegram.
00a0: 0a 0a 75 73 65 20 63 72 61 74 65 3a 3a 7b 0a 09 ..use crate::{..
00b0: 43 75 72 73 6f 72 2c 0a 09 74 65 6c 65 67 72 61 Cursor,..telegra
00c0: 6d 3a 3a 54 65 6c 65 67 72 61 6d 54 72 61 6e 73 m::TelegramTrans
00d0: 70 6f 72 74 2c 0a 09 75 74 69 6c 73 3a 3a 7b 0a port,..utils::{.
00e0: 09 09 41 74 74 61 63 68 6d 65 6e 74 2c 0a 09 09 ..Attachment,...
00f0: 52 45 5f 44 4f 4d 41 49 4e 2c 0a 09 09 76 61 6c RE_DOMAIN,...val
0100: 69 64 61 74 65 2c 0a 09 7d 2c 0a 7d 3b 0a 0a 75 idate,..},.};..u
0110: 73 65 20 73 74 64 3a 3a 7b 0a 09 63 6f 6c 6c 65 se std::{..colle
0120: 63 74 69 6f 6e 73 3a 3a 7b 0a 09 09 48 61 73 68 ctions::{...Hash
0130: 4d 61 70 2c 0a 09 09 48 61 73 68 53 65 74 2c 0a Map,...HashSet,.
0140: 09 7d 2c 0a 09 69 6f 3a 3a 45 72 72 6f 72 2c 0a .},..io::Error,.
0150: 09 73 79 6e 63 3a 3a 41 72 63 2c 0a 7d 3b 0a 0a .sync::Arc,.};..
0160: 75 73 65 20 61 73 79 6e 63 5f 63 6f 6d 70 61 74 use async_compat
0170: 3a 3a 43 6f 6d 70 61 74 3b 0a 75 73 65 20 6d 61 ::Compat;.use ma
0180: 69 6c 69 6e 5f 65 6d 62 65 64 64 65 64 3a 3a 7b ilin_embedded::{
0190: 0a 09 52 65 73 70 6f 6e 73 65 2c 0a 09 72 65 73 ..Response,..res
01a0: 70 6f 6e 73 65 3a 3a 7b 0a 09 09 49 4e 54 45 52 ponse::{...INTER
01b0: 4e 41 4c 5f 45 52 52 4f 52 2c 0a 09 09 49 4e 56 NAL_ERROR,...INV
01c0: 41 4c 49 44 5f 43 52 45 44 45 4e 54 49 41 4c 53 ALID_CREDENTIALS
01d0: 2c 0a 09 09 4e 4f 5f 4d 41 49 4c 42 4f 58 2c 0a ,...NO_MAILBOX,.
01e0: 09 09 4f 4b 0a 09 7d 2c 0a 7d 3b 0a 75 73 65 20 ..OK..},.};.use
01f0: 72 65 67 65 78 3a 3a 7b 0a 09 52 65 67 65 78 2c regex::{..Regex,
0200: 0a 09 52 65 67 65 78 42 75 69 6c 64 65 72 2c 0a ..RegexBuilder,.
0210: 09 65 73 63 61 70 65 2c 0a 7d 3b 0a 75 73 65 20 .escape,.};.use
0220: 73 74 61 63 6b 65 64 5f 65 72 72 6f 72 73 3a 3a stacked_errors::
0230: 7b 0a 09 52 65 73 75 6c 74 2c 0a 09 53 74 61 63 {..Result,..Stac
0240: 6b 61 62 6c 65 45 72 72 2c 0a 09 62 61 69 6c 2c kableErr,..bail,
0250: 0a 7d 3b 0a 75 73 65 20 74 67 62 6f 74 3a 3a 74 .};.use tgbot::t
0260: 79 70 65 73 3a 3a 43 68 61 74 50 65 65 72 49 64 ypes::ChatPeerId
0270: 3b 0a 0a 2f 2f 2f 20 60 53 6f 6d 65 48 65 61 64 ;../// `SomeHead
0280: 65 72 73 60 20 6f 62 6a 65 63 74 20 74 6f 20 73 ers` object to s
0290: 74 6f 72 65 20 64 61 74 61 20 74 68 72 6f 75 67 tore data throug
02a0: 68 20 53 4d 54 50 20 73 65 73 73 69 6f 6e 0a 23 h SMTP session.#
02b0: 5b 64 65 72 69 76 65 28 43 6c 6f 6e 65 2c 20 44 [derive(Clone, D
02c0: 65 62 75 67 29 5d 0a 73 74 72 75 63 74 20 53 6f ebug)].struct So
02d0: 6d 65 48 65 61 64 65 72 73 20 7b 0a 09 66 72 6f meHeaders {..fro
02e0: 6d 3a 20 53 74 72 69 6e 67 2c 0a 09 74 6f 3a 20 m: String,..to:
02f0: 56 65 63 3c 53 74 72 69 6e 67 3e 2c 0a 7d 0a 0a Vec<String>,.}..
0300: 2f 2f 2f 20 60 4d 61 69 6c 53 65 72 76 65 72 60 /// `MailServer`
0310: 20 43 65 6e 74 72 61 6c 20 6f 62 6a 65 63 74 20 Central object
0320: 77 69 74 68 20 54 47 20 61 70 69 20 61 6e 64 20 with TG api and
0330: 63 6f 6e 66 69 67 75 72 61 74 69 6f 6e 0a 23 5b configuration.#[
0340: 64 65 72 69 76 65 28 43 6c 6f 6e 65 2c 20 44 65 derive(Clone, De
0350: 62 75 67 29 5d 0a 70 75 62 20 73 74 72 75 63 74 bug)].pub struct
0360: 20 4d 61 69 6c 53 65 72 76 65 72 20 7b 0a 09 64 MailServer {..d
0370: 61 74 61 3a 20 56 65 63 3c 75 38 3e 2c 0a 09 68 ata: Vec<u8>,..h
0380: 65 61 64 65 72 73 3a 20 4f 70 74 69 6f 6e 3c 53 eaders: Option<S
0390: 6f 6d 65 48 65 61 64 65 72 73 3e 2c 0a 09 74 67 omeHeaders>,..tg
03a0: 3a 20 41 72 63 3c 54 65 6c 65 67 72 61 6d 54 72 : Arc<TelegramTr
03b0: 61 6e 73 70 6f 72 74 3e 2c 0a 09 66 69 65 6c 64 ansport>,..field
03c0: 73 3a 20 48 61 73 68 53 65 74 3c 53 74 72 69 6e s: HashSet<Strin
03d0: 67 3e 2c 0a 09 61 64 64 72 65 73 73 3a 20 52 65 g>,..address: Re
03e0: 67 65 78 2c 0a 7d 0a 0a 69 6d 70 6c 20 4d 61 69 gex,.}..impl Mai
03f0: 6c 53 65 72 76 65 72 20 7b 0a 09 2f 2f 2f 20 49 lServer {../// I
0400: 6e 69 74 69 61 6c 69 7a 65 73 20 74 68 65 20 6d nitializes the m
0410: 61 69 6c 20 73 65 72 76 65 72 3a 20 73 65 74 73 ail server: sets
0420: 20 75 70 20 74 68 65 20 54 65 6c 65 67 72 61 6d up the Telegram
0430: 20 41 50 49 20 63 6c 69 65 6e 74 20 61 6e 64 0a API client and.
0440: 09 2f 2f 2f 20 76 61 6c 69 64 61 74 65 73 20 61 ./// validates a
0450: 6c 6c 20 72 65 71 75 69 72 65 64 20 63 6f 6e 66 ll required conf
0460: 69 67 75 72 61 74 69 6f 6e 20 76 61 6c 75 65 73 iguration values
0470: 2e 0a 09 2f 2f 2f 0a 09 2f 2f 2f 20 23 20 41 72 ...///../// # Ar
0480: 67 75 6d 65 6e 74 73 0a 09 2f 2f 2f 20 2a 20 60 guments../// * `
0490: 73 65 74 74 69 6e 67 73 60 20 2d 20 50 61 72 73 settings` - Pars
04a0: 65 64 20 61 70 70 6c 69 63 61 74 69 6f 6e 20 63 ed application c
04b0: 6f 6e 66 69 67 75 72 61 74 69 6f 6e 2e 0a 09 2f onfiguration.../
04c0: 2f 2f 0a 09 2f 2f 2f 20 23 20 45 72 72 6f 72 73 //../// # Errors
04d0: 0a 09 2f 2f 2f 20 52 65 74 75 72 6e 73 20 61 6e ../// Returns an
04e0: 20 65 72 72 6f 72 20 69 66 20 72 65 71 75 69 72 error if requir
04f0: 65 64 20 63 6f 6e 66 69 67 75 72 61 74 69 6f 6e ed configuration
0500: 20 76 61 6c 75 65 73 20 61 72 65 20 6d 69 73 73 values are miss
0510: 69 6e 67 20 6f 72 20 69 6e 76 61 6c 69 64 2e 0a ing or invalid..
0520: 09 2f 2f 2f 20 73 65 72 76 65 72 20 66 61 69 6c ./// server fail
0530: 73 20 74 6f 20 73 74 61 72 74 2e 0a 09 70 75 62 s to start...pub
0540: 20 66 6e 20 6e 65 77 20 28 73 65 74 74 69 6e 67 fn new (setting
0550: 73 3a 20 63 6f 6e 66 69 67 3a 3a 43 6f 6e 66 69 s: config::Confi
0560: 67 29 20 2d 3e 20 52 65 73 75 6c 74 3c 4d 61 69 g) -> Result<Mai
0570: 6c 53 65 72 76 65 72 3e 20 7b 0a 09 09 6c 65 74 lServer> {...let
0580: 20 61 70 69 5f 6b 65 79 20 3d 20 73 65 74 74 69 api_key = setti
0590: 6e 67 73 2e 67 65 74 5f 73 74 72 69 6e 67 28 22 ngs.get_string("
05a0: 61 70 69 5f 6b 65 79 22 29 0a 09 09 09 2e 63 6f api_key").....co
05b0: 6e 74 65 78 74 28 22 5b 73 6d 74 70 32 74 67 2e ntext("[smtp2tg.
05c0: 74 6f 6d 6c 5d 20 6d 69 73 73 69 6e 67 20 5c 22 toml] missing \"
05d0: 61 70 69 5f 6b 65 79 5c 22 20 70 61 72 61 6d 65 api_key\" parame
05e0: 74 65 72 2e 5c 6e 22 29 3f 3b 0a 09 09 6c 65 74 ter.\n")?;...let
05f0: 20 6d 75 74 20 72 65 63 69 70 69 65 6e 74 73 20 mut recipients
0600: 3d 20 48 61 73 68 4d 61 70 3a 3a 6e 65 77 28 29 = HashMap::new()
0610: 3b 0a 09 09 66 6f 72 20 28 6e 61 6d 65 2c 20 76 ;...for (name, v
0620: 61 6c 75 65 29 20 69 6e 20 73 65 74 74 69 6e 67 alue) in setting
0630: 73 2e 67 65 74 5f 74 61 62 6c 65 28 22 72 65 63 s.get_table("rec
0640: 69 70 69 65 6e 74 73 22 29 0a 09 09 09 2e 63 6f ipients").....co
0650: 6e 74 65 78 74 28 22 5b 73 6d 74 70 32 74 67 2e ntext("[smtp2tg.
0660: 74 6f 6d 6c 5d 20 6d 69 73 73 69 6e 67 20 74 61 toml] missing ta
0670: 62 6c 65 20 5c 22 72 65 63 69 70 69 65 6e 74 73 ble \"recipients
0680: 5c 22 2e 5c 6e 22 29 3f 0a 09 09 7b 0a 09 09 09 \".\n")?...{....
0690: 6c 65 74 20 76 61 6c 75 65 20 3d 20 76 61 6c 75 let value = valu
06a0: 65 2e 69 6e 74 6f 5f 69 6e 74 28 29 0a 09 09 09 e.into_int()....
06b0: 09 2e 63 6f 6e 74 65 78 74 28 22 5b 73 6d 74 70 ..context("[smtp
06c0: 32 74 67 2e 74 6f 6d 6c 5d 20 5c 22 72 65 63 69 2tg.toml] \"reci
06d0: 70 69 65 6e 74 5c 22 20 74 61 62 6c 65 20 76 61 pient\" table va
06e0: 6c 75 65 73 20 73 68 6f 75 6c 64 20 62 65 20 69 lues should be i
06f0: 6e 74 65 67 65 72 73 2e 5c 6e 22 29 3f 3b 0a 09 ntegers.\n")?;..
0700: 09 09 72 65 63 69 70 69 65 6e 74 73 2e 69 6e 73 ..recipients.ins
0710: 65 72 74 28 6e 61 6d 65 2e 74 6f 5f 6c 6f 77 65 ert(name.to_lowe
0720: 72 63 61 73 65 28 29 2c 20 76 61 6c 75 65 29 3b rcase(), value);
0730: 0a 09 09 7d 0a 0a 09 09 6c 65 74 20 74 67 20 3d ...}....let tg =
0740: 20 41 72 63 3a 3a 6e 65 77 28 54 65 6c 65 67 72 Arc::new(Telegr
0750: 61 6d 54 72 61 6e 73 70 6f 72 74 3a 3a 6e 65 77 amTransport::new
0760: 28 61 70 69 5f 6b 65 79 2c 20 72 65 63 69 70 69 (api_key, recipi
0770: 65 6e 74 73 2c 20 26 73 65 74 74 69 6e 67 73 29 ents, &settings)
0780: 3f 29 3b 0a 09 09 6c 65 74 20 66 69 65 6c 64 73 ?);...let fields
0790: 20 3d 20 48 61 73 68 53 65 74 3a 3a 3c 53 74 72 = HashSet::<Str
07a0: 69 6e 67 3e 3a 3a 66 72 6f 6d 5f 69 74 65 72 28 ing>::from_iter(
07b0: 73 65 74 74 69 6e 67 73 2e 67 65 74 5f 61 72 72 settings.get_arr
07c0: 61 79 28 22 66 69 65 6c 64 73 22 29 0a 09 09 09 ay("fields")....
07d0: 2e 63 6f 6e 74 65 78 74 28 22 5b 73 6d 74 70 32 .context("[smtp2
07e0: 74 67 2e 74 6f 6d 6c 5d 20 5c 22 66 69 65 6c 64 tg.toml] \"field
07f0: 73 5c 22 20 73 68 6f 75 6c 64 20 62 65 20 61 6e s\" should be an
0800: 20 61 72 72 61 79 22 29 3f 0a 09 09 09 2e 69 74 array")?.....it
0810: 65 72 28 29 2e 6d 61 70 28 7c 78 7c 20 78 2e 63 er().map(|x| x.c
0820: 6c 6f 6e 65 28 29 2e 69 6e 74 6f 5f 73 74 72 69 lone().into_stri
0830: 6e 67 28 29 2e 63 6f 6e 74 65 78 74 28 22 73 68 ng().context("sh
0840: 6f 75 6c 64 20 62 65 20 73 74 72 69 6e 67 73 22 ould be strings"
0850: 29 29 0a 09 09 09 2e 63 6f 6c 6c 65 63 74 3a 3a )).....collect::
0860: 3c 52 65 73 75 6c 74 3c 56 65 63 3c 53 74 72 69 <Result<Vec<Stri
0870: 6e 67 3e 3e 3e 28 29 3f 29 3b 0a 09 09 6c 65 74 ng>>>()?);...let
0880: 20 6d 75 74 20 64 6f 6d 61 69 6e 73 3a 20 48 61 mut domains: Ha
0890: 73 68 53 65 74 3c 53 74 72 69 6e 67 3e 20 3d 20 shSet<String> =
08a0: 48 61 73 68 53 65 74 3a 3a 6e 65 77 28 29 3b 0a HashSet::new();.
08b0: 09 09 6c 65 74 20 65 78 74 72 61 5f 64 6f 6d 61 ..let extra_doma
08c0: 69 6e 73 20 3d 20 73 65 74 74 69 6e 67 73 2e 67 ins = settings.g
08d0: 65 74 5f 61 72 72 61 79 28 22 64 6f 6d 61 69 6e et_array("domain
08e0: 73 22 29 2e 73 74 61 63 6b 28 29 3f 3b 0a 09 09 s").stack()?;...
08f0: 66 6f 72 20 64 6f 6d 61 69 6e 20 69 6e 20 65 78 for domain in ex
0900: 74 72 61 5f 64 6f 6d 61 69 6e 73 20 7b 0a 09 09 tra_domains {...
0910: 09 6c 65 74 20 64 6f 6d 61 69 6e 20 3d 20 64 6f .let domain = do
0920: 6d 61 69 6e 2e 74 6f 5f 73 74 72 69 6e 67 28 29 main.to_string()
0930: 2e 74 6f 5f 6c 6f 77 65 72 63 61 73 65 28 29 3b .to_lowercase();
0940: 0a 09 09 09 69 66 20 52 45 5f 44 4f 4d 41 49 4e ....if RE_DOMAIN
0950: 2e 69 73 5f 6d 61 74 63 68 28 26 64 6f 6d 61 69 .is_match(&domai
0960: 6e 29 20 7b 0a 09 09 09 09 64 6f 6d 61 69 6e 73 n) {.....domains
0970: 2e 69 6e 73 65 72 74 28 64 6f 6d 61 69 6e 29 3b .insert(domain);
0980: 0a 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 ....} else {....
0990: 09 62 61 69 6c 21 28 22 5b 73 6d 74 70 32 74 67 .bail!("[smtp2tg
09a0: 2e 74 6f 6d 6c 5d 20 63 61 6e 27 74 20 63 68 65 .toml] can't che
09b0: 63 6b 20 64 6f 6d 61 69 6e 73 20 69 6e 20 5c 22 ck domains in \"
09c0: 64 6f 6d 61 69 6e 73 5c 22 3a 20 7b 64 6f 6d 61 domains\": {doma
09d0: 69 6e 7d 22 29 3b 0a 09 09 09 7d 0a 09 09 7d 0a in}");....}...}.
09e0: 09 09 69 66 20 64 6f 6d 61 69 6e 73 2e 69 73 5f ..if domains.is_
09f0: 65 6d 70 74 79 28 29 20 7b 0a 09 09 09 62 61 69 empty() {....bai
0a00: 6c 21 28 22 4e 6f 20 64 6f 6d 61 69 6e 73 2c 20 l!("No domains,
0a10: 6e 65 65 64 20 61 74 20 6c 65 61 73 74 20 6f 6e need at least on
0a20: 65 3a 20 64 65 66 61 75 6c 74 20 60 6c 6f 63 61 e: default `loca
0a30: 6c 68 6f 73 74 60 20 77 6f 75 6c 64 20 64 6f 2e lhost` would do.
0a40: 22 29 3b 0a 09 09 7d 0a 09 09 6c 65 74 20 64 6f ");...}...let do
0a50: 6d 61 69 6e 73 20 3d 20 64 6f 6d 61 69 6e 73 2e mains = domains.
0a60: 69 6e 74 6f 5f 69 74 65 72 28 29 2e 6d 61 70 28 into_iter().map(
0a70: 7c 73 7c 20 65 73 63 61 70 65 28 26 73 29 29 0a |s| escape(&s)).
0a80: 09 09 09 2e 63 6f 6c 6c 65 63 74 3a 3a 3c 56 65 ....collect::<Ve
0a90: 63 3c 53 74 72 69 6e 67 3e 3e 28 29 2e 6a 6f 69 c<String>>().joi
0aa0: 6e 28 22 7c 22 29 3b 0a 09 09 6c 65 74 20 61 64 n("|");...let ad
0ab0: 64 72 65 73 73 20 3d 20 52 65 67 65 78 42 75 69 dress = RegexBui
0ac0: 6c 64 65 72 3a 3a 6e 65 77 28 26 66 6f 72 6d 61 lder::new(&forma
0ad0: 74 21 28 22 5e 5b 61 2d 7a 30 2d 39 5d 5b 61 2d t!("^[a-z0-9][a-
0ae0: 7a 30 2d 39 2e 2d 5d 2a 28 40 28 7b 64 6f 6d 61 z0-9.-]*(@({doma
0af0: 69 6e 73 7d 29 29 3f 24 22 29 29 0a 09 09 09 2e ins}))?$")).....
0b00: 63 61 73 65 5f 69 6e 73 65 6e 73 69 74 69 76 65 case_insensitive
0b10: 28 74 72 75 65 29 2e 62 75 69 6c 64 28 29 2e 73 (true).build().s
0b20: 74 61 63 6b 28 29 3f 3b 0a 0a 09 09 4f 6b 28 4d tack()?;....Ok(M
0b30: 61 69 6c 53 65 72 76 65 72 20 7b 0a 09 09 09 64 ailServer {....d
0b40: 61 74 61 3a 20 76 65 63 21 28 29 2c 0a 09 09 09 ata: vec!(),....
0b50: 68 65 61 64 65 72 73 3a 20 4e 6f 6e 65 2c 0a 09 headers: None,..
0b60: 09 09 74 67 2c 0a 09 09 09 66 69 65 6c 64 73 2c ..tg,....fields,
0b70: 0a 09 09 09 61 64 64 72 65 73 73 2c 0a 09 09 7d ....address,...}
0b80: 29 0a 09 7d 0a 0a 09 2f 2f 2f 20 52 65 74 72 69 )..}.../// Retri
0b90: 65 76 65 73 20 74 68 65 20 54 65 6c 65 67 72 61 eves the Telegra
0ba0: 6d 20 63 68 61 74 20 49 44 20 66 6f 72 20 61 20 m chat ID for a
0bb0: 67 69 76 65 6e 20 65 6d 61 69 6c 20 61 64 64 72 given email addr
0bc0: 65 73 73 2c 20 63 68 65 63 6b 73 20 74 68 61 74 ess, checks that
0bd0: 0a 09 2f 2f 2f 20 75 73 65 64 20 64 6f 6d 61 69 ../// used domai
0be0: 6e 20 69 73 20 61 6c 6c 6f 77 65 64 2e 0a 09 2f n is allowed.../
0bf0: 2f 2f 0a 09 2f 2f 2f 20 23 20 41 72 67 75 6d 65 //../// # Argume
0c00: 6e 74 73 0a 09 2f 2f 2f 20 2a 20 60 6e 61 6d 65 nts../// * `name
0c10: 60 20 2d 20 45 6d 61 69 6c 20 61 64 64 72 65 73 ` - Email addres
0c20: 73 20 6f 72 20 75 73 65 72 6e 61 6d 65 20 74 6f s or username to
0c30: 20 6c 6f 6f 6b 20 75 70 2e 0a 09 2f 2f 2f 0a 09 look up...///..
0c40: 2f 2f 2f 20 23 20 52 65 74 75 72 6e 73 0a 09 2f /// # Returns../
0c50: 2f 2f 20 2a 20 60 52 65 73 75 6c 74 3c 43 68 61 // * `Result<Cha
0c60: 74 50 65 65 72 49 64 3e 60 20 2d 20 54 65 6c 65 tPeerId>` - Tele
0c70: 67 72 61 6d 20 63 68 61 74 20 49 44 20 66 6f 72 gram chat ID for
0c80: 20 74 68 65 20 61 64 64 72 65 73 73 2c 20 6f 72 the address, or
0c90: 20 64 65 66 61 75 6c 74 20 69 66 0a 09 2f 2f 2f default if..///
0ca0: 20 20 20 6e 6f 74 20 66 6f 75 6e 64 2e 0a 09 70 not found...p
0cb0: 75 62 20 66 6e 20 67 65 74 5f 69 64 20 28 26 73 ub fn get_id (&s
0cc0: 65 6c 66 2c 20 6e 61 6d 65 3a 20 26 73 74 72 29 elf, name: &str)
0cd0: 20 2d 3e 20 52 65 73 75 6c 74 3c 26 43 68 61 74 -> Result<&Chat
0ce0: 50 65 65 72 49 64 3e 20 7b 0a 09 09 69 66 20 73 PeerId> {...if s
0cf0: 65 6c 66 2e 61 64 64 72 65 73 73 2e 69 73 5f 6d elf.address.is_m
0d00: 61 74 63 68 28 6e 61 6d 65 29 20 7b 0a 09 09 09 atch(name) {....
0d10: 4f 6b 28 73 65 6c 66 2e 74 67 2e 67 65 74 28 6e Ok(self.tg.get(n
0d20: 61 6d 65 29 2e 75 6e 77 72 61 70 5f 6f 72 28 26 ame).unwrap_or(&
0d30: 73 65 6c 66 2e 74 67 2e 64 65 66 61 75 6c 74 29 self.tg.default)
0d40: 29 0a 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 )...} else {....
0d50: 62 61 69 6c 21 28 22 44 6f 65 73 6e 27 74 20 6c bail!("Doesn't l
0d60: 6f 6f 6b 20 6c 69 6b 65 20 61 64 64 72 65 73 73 ook like address
0d70: 20 66 72 6f 6d 20 6f 6e 65 20 6f 66 20 6f 75 72 from one of our
0d80: 20 64 6f 6d 61 69 6e 73 2e 22 29 3b 0a 09 09 7d domains.");...}
0d90: 0a 09 7d 0a 0a 09 2f 2f 2f 20 41 74 74 65 6d 70 ..}.../// Attemp
0da0: 74 20 74 6f 20 64 65 6c 69 76 65 72 20 6f 6e 65 t to deliver one
0db0: 20 6d 65 73 73 61 67 65 0a 09 61 73 79 6e 63 20 message..async
0dc0: 66 6e 20 72 65 6c 61 79 5f 6d 61 69 6c 20 28 26 fn relay_mail (&
0dd0: 73 65 6c 66 29 20 2d 3e 20 52 65 73 75 6c 74 3c self) -> Result<
0de0: 28 29 3e 20 7b 0a 09 09 69 66 20 6c 65 74 20 53 ()> {...if let S
0df0: 6f 6d 65 28 68 65 61 64 65 72 73 29 20 3d 20 26 ome(headers) = &
0e00: 73 65 6c 66 2e 68 65 61 64 65 72 73 20 7b 0a 09 self.headers {..
0e10: 09 09 6c 65 74 20 6d 61 69 6c 20 3d 20 6d 61 69 ..let mail = mai
0e20: 6c 5f 70 61 72 73 65 72 3a 3a 4d 65 73 73 61 67 l_parser::Messag
0e30: 65 50 61 72 73 65 72 3a 3a 6e 65 77 28 29 2e 70 eParser::new().p
0e40: 61 72 73 65 28 26 73 65 6c 66 2e 64 61 74 61 29 arse(&self.data)
0e50: 0a 09 09 09 09 2e 63 6f 6e 74 65 78 74 28 22 46 ......context("F
0e60: 61 69 6c 65 64 20 74 6f 20 70 61 72 73 65 20 6d ailed to parse m
0e70: 61 69 6c 2e 22 29 3f 3b 0a 0a 09 09 09 2f 2f 20 ail.")?;.....//
0e80: 41 64 64 69 6e 67 20 61 6c 6c 20 6b 6e 6f 77 6e Adding all known
0e90: 20 61 64 64 72 65 73 73 65 73 20 74 6f 20 72 65 addresses to re
0ea0: 63 69 70 69 65 6e 74 20 6c 69 73 74 2c 20 66 6f cipient list, fo
0eb0: 72 20 61 6e 79 6f 6e 65 20 65 6c 73 65 20 61 64 r anyone else ad
0ec0: 64 69 6e 67 20 64 65 66 61 75 6c 74 0a 09 09 09 ding default....
0ed0: 2f 2f 20 41 6c 73 6f 20 69 66 20 6c 69 73 74 20 // Also if list
0ee0: 69 73 20 65 6d 70 74 79 20 61 6c 73 6f 20 61 64 is empty also ad
0ef0: 64 69 6e 67 20 64 65 66 61 75 6c 74 0a 09 09 09 ding default....
0f00: 6c 65 74 20 6d 75 74 20 72 63 70 74 3a 20 48 61 let mut rcpt: Ha
0f10: 73 68 53 65 74 3c 26 43 68 61 74 50 65 65 72 49 shSet<&ChatPeerI
0f20: 64 3e 20 3d 20 48 61 73 68 53 65 74 3a 3a 6e 65 d> = HashSet::ne
0f30: 77 28 29 3b 0a 09 09 09 69 66 20 68 65 61 64 65 w();....if heade
0f40: 72 73 2e 74 6f 2e 69 73 5f 65 6d 70 74 79 28 29 rs.to.is_empty()
0f50: 20 7b 0a 09 09 09 09 62 61 69 6c 21 28 22 52 65 {.....bail!("Re
0f60: 6c 61 79 69 6e 67 20 69 73 20 64 69 73 61 62 6c laying is disabl
0f70: 65 64 2c 20 61 6e 64 20 74 68 65 72 65 27 73 20 ed, and there's
0f80: 6e 6f 20 64 65 73 74 69 6e 61 74 69 6f 6e 20 61 no destination a
0f90: 64 64 72 65 73 73 22 29 3b 0a 09 09 09 7d 0a 09 ddress");....}..
0fa0: 09 09 66 6f 72 20 69 74 65 6d 20 69 6e 20 26 68 ..for item in &h
0fb0: 65 61 64 65 72 73 2e 74 6f 20 7b 0a 09 09 09 09 eaders.to {.....
0fc0: 72 63 70 74 2e 69 6e 73 65 72 74 28 73 65 6c 66 rcpt.insert(self
0fd0: 2e 67 65 74 5f 69 64 28 69 74 65 6d 29 3f 29 3b .get_id(item)?);
0fe0: 0a 09 09 09 7d 3b 0a 09 09 09 69 66 20 72 63 70 ....};....if rcp
0ff0: 74 2e 69 73 5f 65 6d 70 74 79 28 29 20 7b 0a 09 t.is_empty() {..
1000: 09 09 09 73 65 6c 66 2e 74 67 2e 64 65 62 75 67 ...self.tg.debug
1010: 28 22 4e 6f 20 72 65 63 69 70 69 65 6e 74 20 6f ("No recipient o
1020: 72 20 65 6e 76 65 6c 6f 70 65 20 61 64 64 72 65 r envelope addre
1030: 73 73 2e 22 29 2e 61 77 61 69 74 3f 3b 0a 09 09 ss.").await?;...
1040: 09 09 72 63 70 74 2e 69 6e 73 65 72 74 28 26 73 ..rcpt.insert(&s
1050: 65 6c 66 2e 74 67 2e 64 65 66 61 75 6c 74 29 3b elf.tg.default);
1060: 0a 09 09 09 7d 3b 0a 0a 09 09 09 2f 2f 20 70 72 ....};.....// pr
1070: 65 70 61 72 69 6e 67 20 6d 65 73 73 61 67 65 20 eparing message
1080: 68 65 61 64 65 72 0a 09 09 09 6c 65 74 20 6d 75 header....let mu
1090: 74 20 72 65 70 6c 79 3a 20 56 65 63 3c 53 74 72 t reply: Vec<Str
10a0: 69 6e 67 3e 20 3d 20 76 65 63 21 5b 22 3c 62 6c ing> = vec!["<bl
10b0: 6f 63 6b 71 75 6f 74 65 20 65 78 70 61 6e 64 61 ockquote expanda
10c0: 62 6c 65 3e 22 2e 69 6e 74 6f 28 29 5d 3b 0a 09 ble>".into()];..
10d0: 09 09 69 66 20 73 65 6c 66 2e 66 69 65 6c 64 73 ..if self.fields
10e0: 2e 63 6f 6e 74 61 69 6e 73 28 22 73 75 62 6a 65 .contains("subje
10f0: 63 74 22 29 20 7b 0a 09 09 09 09 69 66 20 6c 65 ct") {.....if le
1100: 74 20 53 6f 6d 65 28 73 75 62 6a 65 63 74 29 20 t Some(subject)
1110: 3d 20 6d 61 69 6c 2e 73 75 62 6a 65 63 74 28 29 = mail.subject()
1120: 20 7b 0a 09 09 09 09 09 72 65 70 6c 79 2e 70 75 {......reply.pu
1130: 73 68 28 66 6f 72 6d 61 74 21 28 22 3c 75 3e 3c sh(format!("<u><
1140: 69 3e 53 75 62 6a 65 63 74 3a 3c 2f 69 3e 3c 2f i>Subject:</i></
1150: 75 3e e2 80 87 3c 63 6f 64 65 3e 7b 7d 3c 2f 63 u> <code>{}</c
1160: 6f 64 65 3e 22 2c 20 76 61 6c 69 64 61 74 65 28 ode>", validate(
1170: 73 75 62 6a 65 63 74 29 2e 73 74 61 63 6b 28 29 subject).stack()
1180: 3f 29 29 3b 0a 09 09 09 09 7d 20 65 6c 73 65 20 ?));.....} else
1190: 69 66 20 6c 65 74 20 53 6f 6d 65 28 74 68 72 65 if let Some(thre
11a0: 61 64 29 20 3d 20 6d 61 69 6c 2e 74 68 72 65 61 ad) = mail.threa
11b0: 64 5f 6e 61 6d 65 28 29 20 7b 0a 09 09 09 09 09 d_name() {......
11c0: 72 65 70 6c 79 2e 70 75 73 68 28 66 6f 72 6d 61 reply.push(forma
11d0: 74 21 28 22 3c 75 3e 3c 69 3e 54 68 72 65 61 64 t!("<u><i>Thread
11e0: 3a 3c 2f 69 3e 3c 2f 75 3e e2 80 87 3c 63 6f 64 :</i></u> <cod
11f0: 65 3e 7b 7d 3c 2f 63 6f 64 65 3e 22 2c 20 76 61 e>{}</code>", va
1200: 6c 69 64 61 74 65 28 74 68 72 65 61 64 29 2e 73 lidate(thread).s
1210: 74 61 63 6b 28 29 3f 29 29 3b 0a 09 09 09 09 7d tack()?));.....}
1220: 0a 09 09 09 7d 0a 09 09 09 2f 2f 20 64 6f 20 77 ....}....// do w
1230: 65 20 6e 65 65 64 20 74 6f 20 72 65 70 6c 61 63 e need to replac
1240: 65 20 73 70 61 63 65 73 20 68 65 72 65 3f 0a 09 e spaces here?..
1250: 09 09 69 66 20 73 65 6c 66 2e 66 69 65 6c 64 73 ..if self.fields
1260: 2e 63 6f 6e 74 61 69 6e 73 28 22 66 72 6f 6d 22 .contains("from"
1270: 29 20 7b 0a 09 09 09 09 72 65 70 6c 79 2e 70 75 ) {.....reply.pu
1280: 73 68 28 66 6f 72 6d 61 74 21 28 22 3c 75 3e 3c sh(format!("<u><
1290: 69 3e 46 72 6f 6d 3a 3c 2f 69 3e 3c 2f 75 3e e2 i>From:</i></u>â
12a0: 80 87 3c 63 6f 64 65 3e 7b 7d 3c 2f 63 6f 64 65 €‡<code>{}</code
12b0: 3e 22 2c 20 76 61 6c 69 64 61 74 65 28 26 68 65 >", validate(&he
12c0: 61 64 65 72 73 2e 66 72 6f 6d 29 2e 73 74 61 63 aders.from).stac
12d0: 6b 28 29 3f 29 29 3b 0a 09 09 09 7d 0a 09 09 09 k()?));....}....
12e0: 69 66 20 73 65 6c 66 2e 66 69 65 6c 64 73 2e 63 if self.fields.c
12f0: 6f 6e 74 61 69 6e 73 28 22 64 61 74 65 22 29 0a ontains("date").
1300: 09 09 09 09 26 26 20 6c 65 74 20 53 6f 6d 65 28 ....&& let Some(
1310: 64 61 74 65 29 20 3d 20 6d 61 69 6c 2e 64 61 74 date) = mail.dat
1320: 65 28 29 0a 09 09 09 7b 0a 09 09 09 09 72 65 70 e()....{.....rep
1330: 6c 79 2e 70 75 73 68 28 66 6f 72 6d 61 74 21 28 ly.push(format!(
1340: 22 3c 75 3e 3c 69 3e 44 61 74 65 3a 3c 2f 69 3e "<u><i>Date:</i>
1350: 3c 2f 75 3e e2 80 87 3c 63 6f 64 65 3e 7b 64 61 </u> <code>{da
1360: 74 65 7d 3c 2f 63 6f 64 65 3e 22 29 29 3b 0a 09 te}</code>"));..
1370: 09 09 7d 0a 09 09 09 72 65 70 6c 79 2e 70 75 73 ..}....reply.pus
1380: 68 28 22 3c 2f 62 6c 6f 63 6b 71 75 6f 74 65 3e h("</blockquote>
1390: 3c 70 72 65 3e 22 2e 69 6e 74 6f 28 29 29 3b 0a <pre>".into());.
13a0: 09 09 09 6c 65 74 20 72 65 70 6c 79 20 3d 20 72 ...let reply = r
13b0: 65 70 6c 79 2e 6a 6f 69 6e 28 22 5c 6e 22 29 3b eply.join("\n");
13c0: 0a 0a 09 09 09 6c 65 74 20 68 74 6d 6c 5f 70 61 .....let html_pa
13d0: 72 74 73 20 3d 20 6d 61 69 6c 2e 68 74 6d 6c 5f rts = mail.html_
13e0: 62 6f 64 79 5f 63 6f 75 6e 74 28 29 3b 0a 09 09 body_count();...
13f0: 09 6c 65 74 20 74 65 78 74 5f 70 61 72 74 73 20 .let text_parts
1400: 3d 20 6d 61 69 6c 2e 74 65 78 74 5f 62 6f 64 79 = mail.text_body
1410: 5f 63 6f 75 6e 74 28 29 3b 0a 09 09 09 6c 65 74 _count();....let
1420: 20 61 74 74 61 63 68 6d 65 6e 74 73 20 3d 20 6d attachments = m
1430: 61 69 6c 2e 61 74 74 61 63 68 6d 65 6e 74 5f 63 ail.attachment_c
1440: 6f 75 6e 74 28 29 3b 0a 09 09 09 69 66 20 68 74 ount();....if ht
1450: 6d 6c 5f 70 61 72 74 73 20 21 3d 20 74 65 78 74 ml_parts != text
1460: 5f 70 61 72 74 73 20 7b 0a 09 09 09 09 73 65 6c _parts {.....sel
1470: 66 2e 74 67 2e 64 65 62 75 67 28 26 66 6f 72 6d f.tg.debug(&form
1480: 61 74 21 28 22 48 6d 2c 20 77 65 20 68 61 76 65 at!("Hm, we have
1490: 20 7b 68 74 6d 6c 5f 70 61 72 74 73 7d 20 48 54 {html_parts} HT
14a0: 4d 4c 20 70 61 72 74 73 20 61 6e 64 20 7b 74 65 ML parts and {te
14b0: 78 74 5f 70 61 72 74 73 7d 20 74 65 78 74 20 70 xt_parts} text p
14c0: 61 72 74 73 2e 22 29 29 2e 61 77 61 69 74 3f 3b arts.")).await?;
14d0: 0a 09 09 09 7d 0a 09 09 09 2f 2f 6c 65 74 20 6d ....}....//let m
14e0: 75 74 20 68 74 6d 6c 5f 6e 75 6d 20 3d 20 30 3b ut html_num = 0;
14f0: 0a 09 09 09 6c 65 74 20 6d 75 74 20 74 65 78 74 ....let mut text
1500: 5f 6e 75 6d 20 3d 20 30 3b 0a 09 09 09 6c 65 74 _num = 0;....let
1510: 20 6d 75 74 20 66 69 6c 65 5f 6e 75 6d 20 3d 20 mut file_num =
1520: 30 3b 0a 09 09 09 2f 2f 20 6c 65 74 27 73 20 64 0;....// let's d
1530: 69 73 70 6c 61 79 20 66 69 72 73 74 20 68 74 6d isplay first htm
1540: 6c 20 6f 72 20 74 65 78 74 20 70 61 72 74 20 61 l or text part a
1550: 73 20 62 6f 64 79 0a 09 09 09 6c 65 74 20 6d 75 s body....let mu
1560: 74 20 62 6f 64 79 3a 20 53 74 72 69 6e 67 20 3d t body: String =
1570: 20 22 22 2e 69 6e 74 6f 28 29 3b 0a 09 09 09 2f "".into();..../
1580: 2a 0a 09 09 09 20 2a 20 61 63 74 75 61 6c 6c 79 *.... * actually
1590: 20 49 20 64 6f 6e 27 74 20 77 61 6e 6e 61 20 70 I don't wanna p
15a0: 61 72 73 65 20 74 68 61 74 20 68 74 6d 6c 20 73 arse that html s
15b0: 74 75 66 66 0a 09 09 09 69 66 20 68 74 6d 6c 5f tuff....if html_
15c0: 70 61 72 74 73 20 3e 20 30 20 7b 0a 09 09 09 09 parts > 0 {.....
15d0: 6c 65 74 20 74 65 78 74 20 3d 20 6d 61 69 6c 2e let text = mail.
15e0: 62 6f 64 79 5f 68 74 6d 6c 28 30 29 2e 73 74 61 body_html(0).sta
15f0: 63 6b 28 29 3f 3b 0a 09 09 09 09 69 66 20 74 65 ck()?;.....if te
1600: 78 74 2e 6c 65 6e 28 29 20 3c 20 34 30 39 36 20 xt.len() < 4096
1610: 2d 20 68 65 61 64 65 72 5f 73 69 7a 65 20 7b 0a - header_size {.
1620: 09 09 09 09 09 62 6f 64 79 20 3d 20 74 65 78 74 .....body = text
1630: 3b 0a 09 09 09 09 09 68 74 6d 6c 5f 6e 75 6d 20 ;......html_num
1640: 3d 20 31 3b 0a 09 09 09 09 7d 0a 09 09 09 7d 3b = 1;.....}....};
1650: 0a 09 09 09 2a 2f 0a 09 09 09 69 66 20 62 6f 64 ....*/....if bod
1660: 79 2e 69 73 5f 65 6d 70 74 79 28 29 20 26 26 20 y.is_empty() &&
1670: 74 65 78 74 5f 70 61 72 74 73 20 3e 20 30 20 7b text_parts > 0 {
1680: 0a 09 09 09 09 6c 65 74 20 74 65 78 74 20 3d 20 .....let text =
1690: 6d 61 69 6c 2e 62 6f 64 79 5f 74 65 78 74 28 30 mail.body_text(0
16a0: 29 0a 09 09 09 09 09 2e 63 6f 6e 74 65 78 74 28 ).......context(
16b0: 22 46 61 69 6c 65 64 20 74 6f 20 65 78 74 72 61 "Failed to extra
16c0: 63 74 20 74 65 78 74 20 66 72 6f 6d 20 6d 65 73 ct text from mes
16d0: 73 61 67 65 22 29 3f 0a 09 09 09 09 09 2e 72 65 sage")?.......re
16e0: 70 6c 61 63 65 28 22 5c 72 5c 6e 22 2c 20 22 5c place("\r\n", "\
16f0: 6e 22 29 3b 0a 09 09 09 09 6c 65 74 20 74 65 78 n");.....let tex
1700: 74 20 3d 20 76 61 6c 69 64 61 74 65 28 26 74 65 t = validate(&te
1710: 78 74 29 2e 73 74 61 63 6b 28 29 3f 3b 0a 09 09 xt).stack()?;...
1720: 09 09 2f 2f 20 36 3a 0a 09 09 09 09 2f 2f 20 2d ..// 6:.....// -
1730: 20 28 68 65 61 64 65 72 73 29 0a 09 09 09 09 2f (headers)...../
1740: 2f 20 2d 20 28 6d 61 69 6c 20 74 65 78 74 29 0a / - (mail text).
1750: 09 09 09 09 2f 2f 20 2d 20 36 3a 20 3c 2f 70 72 ....// - 6: </pr
1760: 65 3e 0a 09 09 09 09 69 66 20 74 65 78 74 2e 6c e>.....if text.l
1770: 65 6e 28 29 20 3c 20 34 30 39 36 20 2d 20 28 20 en() < 4096 - (
1780: 72 65 70 6c 79 2e 6c 65 6e 28 29 20 2b 20 36 20 reply.len() + 6
1790: 29 20 7b 0a 09 09 09 09 09 62 6f 64 79 20 3d 20 ) {......body =
17a0: 74 65 78 74 2e 74 6f 5f 73 74 72 69 6e 67 28 29 text.to_string()
17b0: 3b 0a 09 09 09 09 09 74 65 78 74 5f 6e 75 6d 20 ;......text_num
17c0: 3d 20 31 3b 0a 09 09 09 09 7d 0a 09 09 09 7d 3b = 1;.....}....};
17d0: 0a 09 09 09 6c 65 74 20 6d 73 67 20 3d 20 66 6f ....let msg = fo
17e0: 72 6d 61 74 21 28 22 7b 7d 7b 7d 3c 2f 70 72 65 rmat!("{}{}</pre
17f0: 3e 22 2c 20 72 65 70 6c 79 2c 20 62 6f 64 79 29 >", reply, body)
1800: 3b 0a 0a 09 09 09 2f 2f 20 61 6e 64 20 6c 65 74 ;.....// and let
1810: 27 73 20 63 6f 6c 6c 65 63 74 20 61 6c 6c 20 6f 's collect all o
1820: 74 68 65 72 20 61 74 74 61 63 68 6d 65 6e 74 20 ther attachment
1830: 70 61 72 74 73 0a 09 09 09 6c 65 74 20 6d 75 74 parts....let mut
1840: 20 66 69 6c 65 73 5f 74 6f 5f 73 65 6e 64 20 3d files_to_send =
1850: 20 76 65 63 21 5b 5d 3b 0a 09 09 09 2f 2a 0a 09 vec![];..../*..
1860: 09 09 20 2a 20 6c 65 74 27 73 20 6a 75 73 74 20 .. * let's just
1870: 73 6b 69 70 20 68 74 6d 6c 20 70 61 72 74 73 20 skip html parts
1880: 66 6f 72 20 6e 6f 77 2c 20 74 68 65 79 20 6a 75 for now, they ju
1890: 73 74 20 64 75 70 6c 69 63 61 74 65 20 74 65 78 st duplicate tex
18a0: 74 3f 0a 09 09 09 77 68 69 6c 65 20 68 74 6d 6c t?....while html
18b0: 5f 6e 75 6d 20 3c 20 68 74 6d 6c 5f 70 61 72 74 _num < html_part
18c0: 73 20 7b 0a 09 09 09 09 66 69 6c 65 73 5f 74 6f s {.....files_to
18d0: 5f 73 65 6e 64 2e 70 75 73 68 28 6d 61 69 6c 2e _send.push(mail.
18e0: 68 74 6d 6c 5f 70 61 72 74 28 68 74 6d 6c 5f 6e html_part(html_n
18f0: 75 6d 29 2e 73 74 61 63 6b 28 29 3f 29 3b 0a 09 um).stack()?);..
1900: 09 09 09 68 74 6d 6c 5f 6e 75 6d 20 2b 3d 20 31 ...html_num += 1
1910: 3b 0a 09 09 09 7d 0a 09 09 09 2a 2f 0a 09 09 09 ;....}....*/....
1920: 77 68 69 6c 65 20 74 65 78 74 5f 6e 75 6d 20 3c while text_num <
1930: 20 74 65 78 74 5f 70 61 72 74 73 20 7b 0a 09 09 text_parts {...
1940: 09 09 66 69 6c 65 73 5f 74 6f 5f 73 65 6e 64 2e ..files_to_send.
1950: 70 75 73 68 28 6d 61 69 6c 2e 74 65 78 74 5f 70 push(mail.text_p
1960: 61 72 74 28 74 65 78 74 5f 6e 75 6d 2e 74 72 79 art(text_num.try
1970: 5f 69 6e 74 6f 28 29 2e 73 74 61 63 6b 28 29 3f _into().stack()?
1980: 29 0a 09 09 09 09 09 2e 63 6f 6e 74 65 78 74 28 ).......context(
1990: 22 46 61 69 6c 65 64 20 74 6f 20 67 65 74 20 74 "Failed to get t
19a0: 65 78 74 20 70 61 72 74 20 66 72 6f 6d 20 6d 65 ext part from me
19b0: 73 73 61 67 65 2e 22 29 3f 29 3b 0a 09 09 09 09 ssage.")?);.....
19c0: 74 65 78 74 5f 6e 75 6d 20 2b 3d 20 31 3b 0a 09 text_num += 1;..
19d0: 09 09 7d 0a 09 09 09 77 68 69 6c 65 20 66 69 6c ..}....while fil
19e0: 65 5f 6e 75 6d 20 3c 20 61 74 74 61 63 68 6d 65 e_num < attachme
19f0: 6e 74 73 20 7b 0a 09 09 09 09 66 69 6c 65 73 5f nts {.....files_
1a00: 74 6f 5f 73 65 6e 64 2e 70 75 73 68 28 6d 61 69 to_send.push(mai
1a10: 6c 2e 61 74 74 61 63 68 6d 65 6e 74 28 66 69 6c l.attachment(fil
1a20: 65 5f 6e 75 6d 2e 74 72 79 5f 69 6e 74 6f 28 29 e_num.try_into()
1a30: 2e 73 74 61 63 6b 28 29 3f 29 0a 09 09 09 09 09 .stack()?)......
1a40: 2e 63 6f 6e 74 65 78 74 28 22 46 61 69 6c 65 64 .context("Failed
1a50: 20 74 6f 20 67 65 74 20 66 69 6c 65 20 70 61 72 to get file par
1a60: 74 20 66 72 6f 6d 20 6d 65 73 73 61 67 65 2e 22 t from message."
1a70: 29 3f 29 3b 0a 09 09 09 09 66 69 6c 65 5f 6e 75 )?);.....file_nu
1a80: 6d 20 2b 3d 20 31 3b 0a 09 09 09 7d 0a 0a 09 09 m += 1;....}....
1a90: 09 66 6f 72 20 63 68 61 74 20 69 6e 20 72 63 70 .for chat in rcp
1aa0: 74 20 7b 0a 09 09 09 09 69 66 20 21 66 69 6c 65 t {.....if !file
1ab0: 73 5f 74 6f 5f 73 65 6e 64 2e 69 73 5f 65 6d 70 s_to_send.is_emp
1ac0: 74 79 28 29 20 7b 0a 09 09 09 09 09 6c 65 74 20 ty() {......let
1ad0: 6d 75 74 20 66 69 6c 65 73 20 3d 20 76 65 63 21 mut files = vec!
1ae0: 5b 5d 3b 0a 09 09 09 09 09 2f 2f 20 6c 65 74 20 [];......// let
1af0: 6d 75 74 20 66 69 72 73 74 5f 6f 6e 65 20 3d 20 mut first_one =
1b00: 74 72 75 65 3b 0a 09 09 09 09 09 66 6f 72 20 63 true;......for c
1b10: 68 75 6e 6b 20 69 6e 20 26 66 69 6c 65 73 5f 74 hunk in &files_t
1b20: 6f 5f 73 65 6e 64 20 7b 0a 09 09 09 09 09 09 6c o_send {.......l
1b30: 65 74 20 64 61 74 61 3a 20 56 65 63 3c 75 38 3e et data: Vec<u8>
1b40: 20 3d 20 63 68 75 6e 6b 2e 63 6f 6e 74 65 6e 74 = chunk.content
1b50: 73 28 29 2e 74 6f 5f 76 65 63 28 29 3b 0a 09 09 s().to_vec();...
1b60: 09 09 09 09 6c 65 74 20 6d 75 74 20 66 69 6c 65 ....let mut file
1b70: 6e 61 6d 65 3a 20 4f 70 74 69 6f 6e 3c 53 74 72 name: Option<Str
1b80: 69 6e 67 3e 20 3d 20 4e 6f 6e 65 3b 0a 09 09 09 ing> = None;....
1b90: 09 09 09 66 6f 72 20 68 65 61 64 65 72 20 69 6e ...for header in
1ba0: 20 63 68 75 6e 6b 2e 68 65 61 64 65 72 73 28 29 chunk.headers()
1bb0: 20 7b 0a 09 09 09 09 09 09 09 69 66 20 68 65 61 {........if hea
1bc0: 64 65 72 2e 6e 61 6d 65 28 29 20 3d 3d 20 22 43 der.name() == "C
1bd0: 6f 6e 74 65 6e 74 2d 54 79 70 65 22 20 7b 0a 09 ontent-Type" {..
1be0: 09 09 09 09 09 09 09 6d 61 74 63 68 20 68 65 61 .......match hea
1bf0: 64 65 72 2e 76 61 6c 75 65 28 29 20 7b 0a 09 09 der.value() {...
1c00: 09 09 09 09 09 09 09 6d 61 69 6c 5f 70 61 72 73 .......mail_pars
1c10: 65 72 3a 3a 48 65 61 64 65 72 56 61 6c 75 65 3a er::HeaderValue:
1c20: 3a 43 6f 6e 74 65 6e 74 54 79 70 65 28 63 6f 6e :ContentType(con
1c30: 74 65 6e 74 74 79 70 65 29 20 3d 3e 20 7b 0a 09 tenttype) => {..
1c40: 09 09 09 09 09 09 09 09 09 69 66 20 6c 65 74 20 .........if let
1c50: 53 6f 6d 65 28 66 6e 61 6d 65 29 20 3d 20 63 6f Some(fname) = co
1c60: 6e 74 65 6e 74 74 79 70 65 2e 61 74 74 72 69 62 ntenttype.attrib
1c70: 75 74 65 28 22 6e 61 6d 65 22 29 20 7b 0a 09 09 ute("name") {...
1c80: 09 09 09 09 09 09 09 09 09 66 69 6c 65 6e 61 6d .........filenam
1c90: 65 20 3d 20 53 6f 6d 65 28 66 6e 61 6d 65 2e 74 e = Some(fname.t
1ca0: 6f 5f 6f 77 6e 65 64 28 29 29 3b 0a 09 09 09 09 o_owned());.....
1cb0: 09 09 09 09 09 09 7d 0a 09 09 09 09 09 09 09 09 ......}.........
1cc0: 09 7d 2c 0a 09 09 09 09 09 09 09 09 09 5f 20 3d .},.........._ =
1cd0: 3e 20 7b 0a 09 09 09 09 09 09 09 09 09 09 73 65 > {...........se
1ce0: 6c 66 2e 74 67 2e 64 65 62 75 67 28 22 41 74 74 lf.tg.debug("Att
1cf0: 61 63 68 6d 65 6e 74 20 68 61 73 20 62 61 64 20 achment has bad
1d00: 43 6f 6e 74 65 6e 74 54 79 70 65 20 68 65 61 64 ContentType head
1d10: 65 72 2e 22 29 2e 61 77 61 69 74 3f 3b 0a 09 09 er.").await?;...
1d20: 09 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09 09 .......},.......
1d30: 09 09 7d 3b 0a 09 09 09 09 09 09 09 7d 3b 0a 09 ..};........};..
1d40: 09 09 09 09 09 7d 3b 0a 09 09 09 09 09 09 6c 65 .....};.......le
1d50: 74 20 66 69 6c 65 6e 61 6d 65 20 3d 20 69 66 20 t filename = if
1d60: 6c 65 74 20 53 6f 6d 65 28 66 6e 61 6d 65 29 20 let Some(fname)
1d70: 3d 20 66 69 6c 65 6e 61 6d 65 20 7b 0a 09 09 09 = filename {....
1d80: 09 09 09 09 66 6e 61 6d 65 0a 09 09 09 09 09 09 ....fname.......
1d90: 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 09 09 } else {........
1da0: 22 41 74 74 61 63 68 6d 65 6e 74 2e 74 78 74 22 "Attachment.txt"
1db0: 2e 69 6e 74 6f 28 29 0a 09 09 09 09 09 09 7d 3b .into().......};
1dc0: 0a 09 09 09 09 09 09 66 69 6c 65 73 2e 70 75 73 .......files.pus
1dd0: 68 28 41 74 74 61 63 68 6d 65 6e 74 20 7b 0a 09 h(Attachment {..
1de0: 09 09 09 09 09 09 64 61 74 61 3a 20 43 75 72 73 ......data: Curs
1df0: 6f 72 3a 3a 6e 65 77 28 64 61 74 61 29 2c 0a 09 or::new(data),..
1e00: 09 09 09 09 09 09 6e 61 6d 65 3a 20 66 69 6c 65 ......name: file
1e10: 6e 61 6d 65 2c 0a 09 09 09 09 09 09 7d 29 3b 0a name,.......});.
1e20: 09 09 09 09 09 7d 0a 09 09 09 09 09 73 65 6c 66 .....}......self
1e30: 2e 74 67 2e 73 65 6e 64 67 72 6f 75 70 28 63 68 .tg.sendgroup(ch
1e40: 61 74 2c 20 66 69 6c 65 73 2c 20 26 6d 73 67 29 at, files, &msg)
1e50: 2e 61 77 61 69 74 3f 3b 0a 09 09 09 09 7d 20 65 .await?;.....} e
1e60: 6c 73 65 20 7b 0a 09 09 09 09 09 73 65 6c 66 2e lse {......self.
1e70: 74 67 2e 73 65 6e 64 28 63 68 61 74 2c 20 26 6d tg.send(chat, &m
1e80: 73 67 29 2e 61 77 61 69 74 3f 3b 0a 09 09 09 09 sg).await?;.....
1e90: 7d 0a 09 09 09 7d 0a 09 09 7d 20 65 6c 73 65 20 }....}...} else
1ea0: 7b 0a 09 09 09 62 61 69 6c 21 28 22 52 65 71 75 {....bail!("Requ
1eb0: 69 72 65 64 20 68 65 61 64 65 72 73 20 77 65 72 ired headers wer
1ec0: 65 20 6e 6f 74 20 66 6f 75 6e 64 2e 22 29 3b 0a e not found.");.
1ed0: 09 09 7d 0a 09 09 4f 6b 28 28 29 29 0a 09 7d 0a ..}...Ok(())..}.
1ee0: 7d 0a 0a 2f 2f 2f 20 53 4d 54 50 20 68 61 6e 64 }../// SMTP hand
1ef0: 6c 65 72 20 69 6d 70 6c 65 6d 65 6e 74 61 74 69 ler implementati
1f00: 6f 6e 20 66 6f 72 20 6d 61 69 6c 69 6e 2d 65 6d on for mailin-em
1f10: 62 65 64 64 65 64 2e 0a 69 6d 70 6c 20 6d 61 69 bedded..impl mai
1f20: 6c 69 6e 5f 65 6d 62 65 64 64 65 64 3a 3a 48 61 lin_embedded::Ha
1f30: 6e 64 6c 65 72 20 66 6f 72 20 4d 61 69 6c 53 65 ndler for MailSe
1f40: 72 76 65 72 20 7b 0a 09 2f 2f 2f 20 4a 75 73 74 rver {../// Just
1f50: 20 64 65 6e 79 20 6c 6f 67 69 6e 20 61 75 74 68 deny login auth
1f60: 0a 09 66 6e 20 61 75 74 68 5f 6c 6f 67 69 6e 20 ..fn auth_login
1f70: 28 26 6d 75 74 20 73 65 6c 66 2c 20 5f 75 73 65 (&mut self, _use
1f80: 72 6e 61 6d 65 3a 20 26 73 74 72 2c 20 5f 70 61 rname: &str, _pa
1f90: 73 73 77 6f 72 64 3a 20 26 73 74 72 29 20 2d 3e ssword: &str) ->
1fa0: 20 52 65 73 70 6f 6e 73 65 20 7b 0a 09 09 49 4e Response {...IN
1fb0: 56 41 4c 49 44 5f 43 52 45 44 45 4e 54 49 41 4c VALID_CREDENTIAL
1fc0: 53 0a 09 7d 0a 0a 09 2f 2f 2f 20 4a 75 73 74 20 S..}.../// Just
1fd0: 64 65 6e 79 20 70 6c 61 69 6e 20 61 75 74 68 0a deny plain auth.
1fe0: 09 66 6e 20 61 75 74 68 5f 70 6c 61 69 6e 20 28 .fn auth_plain (
1ff0: 26 6d 75 74 20 73 65 6c 66 2c 20 5f 61 75 74 68 &mut self, _auth
2000: 6f 72 69 7a 61 74 69 6f 6e 5f 69 64 3a 20 26 73 orization_id: &s
2010: 74 72 2c 20 5f 61 75 74 68 65 6e 74 69 63 61 74 tr, _authenticat
2020: 69 6f 6e 5f 69 64 3a 20 26 73 74 72 2c 20 5f 70 ion_id: &str, _p
2030: 61 73 73 77 6f 72 64 3a 20 26 73 74 72 29 20 2d assword: &str) -
2040: 3e 20 52 65 73 70 6f 6e 73 65 20 7b 0a 09 09 49 > Response {...I
2050: 4e 56 41 4c 49 44 5f 43 52 45 44 45 4e 54 49 41 NVALID_CREDENTIA
2060: 4c 53 0a 09 7d 0a 0a 09 2f 2f 2f 20 56 65 72 69 LS..}.../// Veri
2070: 66 79 20 77 68 65 74 68 65 72 20 61 64 64 72 65 fy whether addre
2080: 73 73 20 69 73 20 64 65 6c 69 76 65 72 61 62 6c ss is deliverabl
2090: 65 0a 09 66 6e 20 72 63 70 74 20 28 26 6d 75 74 e..fn rcpt (&mut
20a0: 20 73 65 6c 66 2c 20 74 6f 3a 20 26 73 74 72 29 self, to: &str)
20b0: 20 2d 3e 20 52 65 73 70 6f 6e 73 65 20 7b 0a 09 -> Response {..
20c0: 09 69 66 20 73 65 6c 66 2e 67 65 74 5f 69 64 28 .if self.get_id(
20d0: 74 6f 29 2e 69 73 5f 6f 6b 28 29 20 7b 0a 09 09 to).is_ok() {...
20e0: 09 4f 4b 0a 09 09 7d 20 65 6c 73 65 20 7b 0a 09 .OK...} else {..
20f0: 09 09 4e 4f 5f 4d 41 49 4c 42 4f 58 0a 09 09 7d ..NO_MAILBOX...}
2100: 0a 09 7d 0a 0a 09 2f 2f 2f 20 53 61 76 65 20 68 ..}.../// Save h
2110: 65 61 64 65 72 73 20 77 65 20 6e 65 65 64 0a 09 eaders we need..
2120: 66 6e 20 64 61 74 61 5f 73 74 61 72 74 20 28 26 fn data_start (&
2130: 6d 75 74 20 73 65 6c 66 2c 20 5f 64 6f 6d 61 69 mut self, _domai
2140: 6e 3a 20 26 73 74 72 2c 20 66 72 6f 6d 3a 20 26 n: &str, from: &
2150: 73 74 72 2c 20 5f 69 73 38 62 69 74 3a 20 62 6f str, _is8bit: bo
2160: 6f 6c 2c 20 74 6f 3a 20 26 5b 53 74 72 69 6e 67 ol, to: &[String
2170: 5d 29 20 2d 3e 20 52 65 73 70 6f 6e 73 65 20 7b ]) -> Response {
2180: 0a 09 09 73 65 6c 66 2e 68 65 61 64 65 72 73 20 ...self.headers
2190: 3d 20 53 6f 6d 65 28 53 6f 6d 65 48 65 61 64 65 = Some(SomeHeade
21a0: 72 73 7b 0a 09 09 09 66 72 6f 6d 3a 20 66 72 6f rs{....from: fro
21b0: 6d 2e 74 6f 5f 73 74 72 69 6e 67 28 29 2c 0a 09 m.to_string(),..
21c0: 09 09 74 6f 3a 20 74 6f 2e 74 6f 5f 76 65 63 28 ..to: to.to_vec(
21d0: 29 2c 0a 09 09 7d 29 3b 0a 09 09 4f 4b 0a 09 7d ),...});...OK..}
21e0: 0a 0a 09 2f 2f 2f 20 53 61 76 65 20 63 68 75 6e .../// Save chun
21f0: 6b 28 3f 29 20 6f 66 20 64 61 74 61 0a 09 66 6e k(?) of data..fn
2200: 20 64 61 74 61 20 28 26 6d 75 74 20 73 65 6c 66 data (&mut self
2210: 2c 20 62 75 66 3a 20 26 5b 75 38 5d 29 20 2d 3e , buf: &[u8]) ->
2220: 20 73 74 64 3a 3a 72 65 73 75 6c 74 3a 3a 52 65 std::result::Re
2230: 73 75 6c 74 3c 28 29 2c 20 45 72 72 6f 72 3e 20 sult<(), Error>
2240: 7b 0a 09 09 73 65 6c 66 2e 64 61 74 61 2e 61 70 {...self.data.ap
2250: 70 65 6e 64 28 62 75 66 2e 74 6f 5f 76 65 63 28 pend(buf.to_vec(
2260: 29 2e 61 73 5f 6d 75 74 28 29 29 3b 0a 09 09 4f ).as_mut());...O
2270: 6b 28 28 29 29 0a 09 7d 0a 0a 09 2f 2f 2f 20 41 k(())..}.../// A
2280: 74 74 65 6d 70 74 20 74 6f 20 73 65 6e 64 20 65 ttempt to send e
2290: 6d 61 69 6c 2c 20 72 65 74 75 72 6e 20 74 65 6d mail, return tem
22a0: 70 6f 72 61 72 79 20 65 72 72 6f 72 20 69 66 20 porary error if
22b0: 74 68 61 74 20 66 61 69 6c 73 0a 09 66 6e 20 64 that fails..fn d
22c0: 61 74 61 5f 65 6e 64 20 28 26 6d 75 74 20 73 65 ata_end (&mut se
22d0: 6c 66 29 20 2d 3e 20 52 65 73 70 6f 6e 73 65 20 lf) -> Response
22e0: 7b 0a 09 09 6c 65 74 20 6d 75 74 20 72 65 73 75 {...let mut resu
22f0: 6c 74 20 3d 20 4f 4b 3b 0a 09 09 73 6d 6f 6c 3a lt = OK;...smol:
2300: 3a 62 6c 6f 63 6b 5f 6f 6e 28 43 6f 6d 70 61 74 :block_on(Compat
2310: 3a 3a 6e 65 77 28 61 73 79 6e 63 20 7b 0a 09 09 ::new(async {...
2320: 09 2f 2f 20 72 65 6c 61 79 20 6d 61 69 6c 0a 09 .// relay mail..
2330: 09 09 69 66 20 6c 65 74 20 45 72 72 28 65 72 72 ..if let Err(err
2340: 29 20 3d 20 73 65 6c 66 2e 72 65 6c 61 79 5f 6d ) = self.relay_m
2350: 61 69 6c 28 29 2e 61 77 61 69 74 20 7b 0a 09 09 ail().await {...
2360: 09 09 72 65 73 75 6c 74 20 3d 20 49 4e 54 45 52 ..result = INTER
2370: 4e 41 4c 5f 45 52 52 4f 52 3b 0a 09 09 09 09 2f NAL_ERROR;...../
2380: 2f 20 69 6e 20 63 61 73 65 20 74 68 61 74 20 66 / in case that f
2390: 61 69 6c 73 20 2d 20 69 6e 66 6f 72 6d 20 64 65 ails - inform de
23a0: 66 61 75 6c 74 20 72 65 63 69 70 69 65 6e 74 0a fault recipient.
23b0: 09 09 09 09 69 66 20 6c 65 74 20 45 72 72 28 65 ....if let Err(e
23c0: 72 72 29 20 3d 20 73 65 6c 66 2e 74 67 2e 64 65 rr) = self.tg.de
23d0: 62 75 67 28 26 66 6f 72 6d 61 74 21 28 22 53 65 bug(&format!("Se
23e0: 6e 64 69 6e 67 20 65 6d 61 69 6c 73 20 66 61 69 nding emails fai
23f0: 6c 65 64 3a 5c 6e 7b 65 72 72 3a 7d 22 29 29 2e led:\n{err:}")).
2400: 61 77 61 69 74 20 7b 0a 09 09 09 09 09 2f 2f 20 await {......//
2410: 69 6e 20 63 61 73 65 20 74 68 61 74 20 61 6c 73 in case that als
2420: 6f 20 66 61 69 6c 73 20 2d 20 77 72 69 74 65 20 o fails - write
2430: 73 6f 6d 65 20 6c 6f 67 73 20 61 6e 64 20 62 61 some logs and ba
2440: 69 6c 0a 09 09 09 09 09 65 70 72 69 6e 74 6c 6e il......eprintln
2450: 21 28 22 7b 65 72 72 3a 3f 7d 22 29 3b 0a 09 09 !("{err:?}");...
2460: 09 09 7d 3b 0a 09 09 09 7d 3b 0a 09 09 7d 29 29 ..};....};...}))
2470: 3b 0a 09 09 2f 2f 20 63 6c 65 61 72 20 2d 20 6a ;...// clear - j
2480: 75 73 74 20 69 6e 20 63 61 73 65 0a 09 09 73 65 ust in case...se
2490: 6c 66 2e 64 61 74 61 20 3d 20 76 65 63 21 5b 5d lf.data = vec![]
24a0: 3b 0a 09 09 73 65 6c 66 2e 68 65 61 64 65 72 73 ;...self.headers
24b0: 20 3d 20 4e 6f 6e 65 3b 0a 09 09 72 65 73 75 6c = None;...resul
24c0: 74 0a 09 7d 0a 7d 0a t..}.}.