Hex Artifact Content
Logged in as anonymous

Artifact c0b6f524948411af4895101bd9dbdfc957779cd018e05e7b782fc4e6f53293ca:


0000: 75 73 65 20 63 72 61 74 65 3a 3a 7b 0a 09 43 75  use crate::{..Cu
0010: 72 73 6f 72 2c 0a 09 74 65 6c 65 67 72 61 6d 3a  rsor,..telegram:
0020: 3a 7b 0a 09 09 65 6e 63 6f 64 65 2c 0a 09 09 54  :{...encode,...T
0030: 65 6c 65 67 72 61 6d 54 72 61 6e 73 70 6f 72 74  elegramTransport
0040: 2c 0a 09 7d 2c 0a 09 75 74 69 6c 73 3a 3a 7b 0a  ,..},..utils::{.
0050: 09 09 41 74 74 61 63 68 6d 65 6e 74 2c 0a 09 09  ..Attachment,...
0060: 52 45 5f 44 4f 4d 41 49 4e 2c 0a 09 7d 2c 0a 7d  RE_DOMAIN,..},.}
0070: 3b 0a 0a 75 73 65 20 73 74 64 3a 3a 7b 0a 09 62  ;..use std::{..b
0080: 6f 72 72 6f 77 3a 3a 43 6f 77 2c 0a 09 63 6f 6c  orrow::Cow,..col
0090: 6c 65 63 74 69 6f 6e 73 3a 3a 7b 0a 09 09 48 61  lections::{...Ha
00a0: 73 68 4d 61 70 2c 0a 09 09 48 61 73 68 53 65 74  shMap,...HashSet
00b0: 2c 0a 09 7d 2c 0a 09 69 6f 3a 3a 45 72 72 6f 72  ,..},..io::Error
00c0: 2c 0a 09 73 79 6e 63 3a 3a 41 72 63 2c 0a 7d 3b  ,..sync::Arc,.};
00d0: 0a 0a 75 73 65 20 6d 61 69 6c 69 6e 5f 65 6d 62  ..use mailin_emb
00e0: 65 64 64 65 64 3a 3a 7b 0a 09 52 65 73 70 6f 6e  edded::{..Respon
00f0: 73 65 2c 0a 09 72 65 73 70 6f 6e 73 65 3a 3a 7b  se,..response::{
0100: 0a 09 09 49 4e 54 45 52 4e 41 4c 5f 45 52 52 4f  ...INTERNAL_ERRO
0110: 52 2c 0a 09 09 49 4e 56 41 4c 49 44 5f 43 52 45  R,...INVALID_CRE
0120: 44 45 4e 54 49 41 4c 53 2c 0a 09 09 4e 4f 5f 4d  DENTIALS,...NO_M
0130: 41 49 4c 42 4f 58 2c 0a 09 09 4f 4b 0a 09 7d 2c  AILBOX,...OK..},
0140: 0a 7d 3b 0a 75 73 65 20 72 65 67 65 78 3a 3a 7b  .};.use regex::{
0150: 0a 09 52 65 67 65 78 2c 0a 09 65 73 63 61 70 65  ..Regex,..escape
0160: 2c 0a 7d 3b 0a 75 73 65 20 73 74 61 63 6b 65 64  ,.};.use stacked
0170: 5f 65 72 72 6f 72 73 3a 3a 7b 0a 09 52 65 73 75  _errors::{..Resu
0180: 6c 74 2c 0a 09 53 74 61 63 6b 61 62 6c 65 45 72  lt,..StackableEr
0190: 72 2c 0a 09 62 61 69 6c 2c 0a 7d 3b 0a 75 73 65  r,..bail,.};.use
01a0: 20 74 67 62 6f 74 3a 3a 74 79 70 65 73 3a 3a 43   tgbot::types::C
01b0: 68 61 74 50 65 65 72 49 64 3b 0a 0a 2f 2f 2f 20  hatPeerId;../// 
01c0: 60 53 6f 6d 65 48 65 61 64 65 72 73 60 20 6f 62  `SomeHeaders` ob
01d0: 6a 65 63 74 20 74 6f 20 73 74 6f 72 65 20 64 61  ject to store da
01e0: 74 61 20 74 68 72 6f 75 67 68 20 53 4d 54 50 20  ta through SMTP 
01f0: 73 65 73 73 69 6f 6e 0a 23 5b 64 65 72 69 76 65  session.#[derive
0200: 28 43 6c 6f 6e 65 2c 20 44 65 62 75 67 29 5d 0a  (Clone, Debug)].
0210: 73 74 72 75 63 74 20 53 6f 6d 65 48 65 61 64 65  struct SomeHeade
0220: 72 73 20 7b 0a 09 66 72 6f 6d 3a 20 53 74 72 69  rs {..from: Stri
0230: 6e 67 2c 0a 09 74 6f 3a 20 56 65 63 3c 53 74 72  ng,..to: Vec<Str
0240: 69 6e 67 3e 2c 0a 7d 0a 0a 2f 2f 2f 20 60 4d 61  ing>,.}../// `Ma
0250: 69 6c 53 65 72 76 65 72 60 20 43 65 6e 74 72 61  ilServer` Centra
0260: 6c 20 6f 62 6a 65 63 74 20 77 69 74 68 20 54 47  l object with TG
0270: 20 61 70 69 20 61 6e 64 20 63 6f 6e 66 69 67 75   api and configu
0280: 72 61 74 69 6f 6e 0a 23 5b 64 65 72 69 76 65 28  ration.#[derive(
0290: 43 6c 6f 6e 65 2c 20 44 65 62 75 67 29 5d 0a 70  Clone, Debug)].p
02a0: 75 62 20 73 74 72 75 63 74 20 4d 61 69 6c 53 65  ub struct MailSe
02b0: 72 76 65 72 20 7b 0a 09 64 61 74 61 3a 20 56 65  rver {..data: Ve
02c0: 63 3c 75 38 3e 2c 0a 09 68 65 61 64 65 72 73 3a  c<u8>,..headers:
02d0: 20 4f 70 74 69 6f 6e 3c 53 6f 6d 65 48 65 61 64   Option<SomeHead
02e0: 65 72 73 3e 2c 0a 09 72 65 6c 61 79 3a 20 62 6f  ers>,..relay: bo
02f0: 6f 6c 2c 0a 09 74 67 3a 20 41 72 63 3c 54 65 6c  ol,..tg: Arc<Tel
0300: 65 67 72 61 6d 54 72 61 6e 73 70 6f 72 74 3e 2c  egramTransport>,
0310: 0a 09 66 69 65 6c 64 73 3a 20 48 61 73 68 53 65  ..fields: HashSe
0320: 74 3c 53 74 72 69 6e 67 3e 2c 0a 09 61 64 64 72  t<String>,..addr
0330: 65 73 73 3a 20 52 65 67 65 78 2c 0a 7d 0a 0a 69  ess: Regex,.}..i
0340: 6d 70 6c 20 4d 61 69 6c 53 65 72 76 65 72 20 7b  mpl MailServer {
0350: 0a 09 2f 2f 2f 20 49 6e 69 74 69 61 6c 69 7a 65  ../// Initialize
0360: 20 41 50 49 20 61 6e 64 20 72 65 61 64 20 63 6f   API and read co
0370: 6e 66 69 67 75 72 61 74 69 6f 6e 0a 09 70 75 62  nfiguration..pub
0380: 20 66 6e 20 6e 65 77 28 73 65 74 74 69 6e 67 73   fn new(settings
0390: 3a 20 63 6f 6e 66 69 67 3a 3a 43 6f 6e 66 69 67  : config::Config
03a0: 29 20 2d 3e 20 52 65 73 75 6c 74 3c 4d 61 69 6c  ) -> Result<Mail
03b0: 53 65 72 76 65 72 3e 20 7b 0a 09 09 6c 65 74 20  Server> {...let 
03c0: 61 70 69 5f 6b 65 79 20 3d 20 73 65 74 74 69 6e  api_key = settin
03d0: 67 73 2e 67 65 74 5f 73 74 72 69 6e 67 28 22 61  gs.get_string("a
03e0: 70 69 5f 6b 65 79 22 29 0a 09 09 09 2e 63 6f 6e  pi_key").....con
03f0: 74 65 78 74 28 22 5b 73 6d 74 70 32 74 67 2e 74  text("[smtp2tg.t
0400: 6f 6d 6c 5d 20 6d 69 73 73 69 6e 67 20 5c 22 61  oml] missing \"a
0410: 70 69 5f 6b 65 79 5c 22 20 70 61 72 61 6d 65 74  pi_key\" paramet
0420: 65 72 2e 5c 6e 22 29 3f 3b 0a 09 09 6c 65 74 20  er.\n")?;...let 
0430: 6d 75 74 20 72 65 63 69 70 69 65 6e 74 73 20 3d  mut recipients =
0440: 20 48 61 73 68 4d 61 70 3a 3a 6e 65 77 28 29 3b   HashMap::new();
0450: 0a 09 09 66 6f 72 20 28 6e 61 6d 65 2c 20 76 61  ...for (name, va
0460: 6c 75 65 29 20 69 6e 20 73 65 74 74 69 6e 67 73  lue) in settings
0470: 2e 67 65 74 5f 74 61 62 6c 65 28 22 72 65 63 69  .get_table("reci
0480: 70 69 65 6e 74 73 22 29 0a 09 09 09 2e 65 78 70  pients").....exp
0490: 65 63 74 28 22 5b 73 6d 74 70 32 74 67 2e 74 6f  ect("[smtp2tg.to
04a0: 6d 6c 5d 20 6d 69 73 73 69 6e 67 20 74 61 62 6c  ml] missing tabl
04b0: 65 20 5c 22 72 65 63 69 70 69 65 6e 74 73 5c 22  e \"recipients\"
04c0: 2e 5c 6e 22 29 0a 09 09 7b 0a 09 09 09 6c 65 74  .\n")...{....let
04d0: 20 76 61 6c 75 65 20 3d 20 76 61 6c 75 65 2e 69   value = value.i
04e0: 6e 74 6f 5f 69 6e 74 28 29 0a 09 09 09 09 2e 63  nto_int()......c
04f0: 6f 6e 74 65 78 74 28 22 5b 73 6d 74 70 32 74 67  ontext("[smtp2tg
0500: 2e 74 6f 6d 6c 5d 20 5c 22 72 65 63 69 70 69 65  .toml] \"recipie
0510: 6e 74 5c 22 20 74 61 62 6c 65 20 76 61 6c 75 65  nt\" table value
0520: 73 20 73 68 6f 75 6c 64 20 62 65 20 69 6e 74 65  s should be inte
0530: 67 65 72 73 2e 5c 6e 22 29 3f 3b 0a 09 09 09 72  gers.\n")?;....r
0540: 65 63 69 70 69 65 6e 74 73 2e 69 6e 73 65 72 74  ecipients.insert
0550: 28 6e 61 6d 65 2c 20 76 61 6c 75 65 29 3b 0a 09  (name, value);..
0560: 09 7d 0a 09 09 6c 65 74 20 64 65 66 61 75 6c 74  .}...let default
0570: 20 3d 20 73 65 74 74 69 6e 67 73 2e 67 65 74 5f   = settings.get_
0580: 69 6e 74 28 22 64 65 66 61 75 6c 74 22 29 0a 09  int("default")..
0590: 09 09 2e 63 6f 6e 74 65 78 74 28 22 5b 73 6d 74  ...context("[smt
05a0: 70 32 74 67 2e 74 6f 6d 6c 5d 20 6d 69 73 73 69  p2tg.toml] missi
05b0: 6e 67 20 5c 22 64 65 66 61 75 6c 74 5c 22 20 72  ng \"default\" r
05c0: 65 63 69 70 69 65 6e 74 2e 5c 6e 22 29 3f 3b 0a  ecipient.\n")?;.
05d0: 0a 09 09 6c 65 74 20 74 67 20 3d 20 41 72 63 3a  ...let tg = Arc:
05e0: 3a 6e 65 77 28 54 65 6c 65 67 72 61 6d 54 72 61  :new(TelegramTra
05f0: 6e 73 70 6f 72 74 3a 3a 6e 65 77 28 61 70 69 5f  nsport::new(api_
0600: 6b 65 79 2c 20 72 65 63 69 70 69 65 6e 74 73 2c  key, recipients,
0610: 20 64 65 66 61 75 6c 74 29 3f 29 3b 0a 09 09 6c   default)?);...l
0620: 65 74 20 66 69 65 6c 64 73 20 3d 20 48 61 73 68  et fields = Hash
0630: 53 65 74 3a 3a 3c 53 74 72 69 6e 67 3e 3a 3a 66  Set::<String>::f
0640: 72 6f 6d 5f 69 74 65 72 28 73 65 74 74 69 6e 67  rom_iter(setting
0650: 73 2e 67 65 74 5f 61 72 72 61 79 28 22 66 69 65  s.get_array("fie
0660: 6c 64 73 22 29 0a 09 09 09 2e 65 78 70 65 63 74  lds").....expect
0670: 28 22 5b 73 6d 74 70 32 74 67 2e 74 6f 6d 6c 5d  ("[smtp2tg.toml]
0680: 20 5c 22 66 69 65 6c 64 73 5c 22 20 73 68 6f 75   \"fields\" shou
0690: 6c 64 20 62 65 20 61 6e 20 61 72 72 61 79 22 29  ld be an array")
06a0: 0a 09 09 09 2e 69 74 65 72 28 29 2e 6d 61 70 28  .....iter().map(
06b0: 7c 78 7c 20 78 2e 63 6c 6f 6e 65 28 29 2e 69 6e  |x| x.clone().in
06c0: 74 6f 5f 73 74 72 69 6e 67 28 29 2e 65 78 70 65  to_string().expe
06d0: 63 74 28 22 73 68 6f 75 6c 64 20 62 65 20 73 74  ct("should be st
06e0: 72 69 6e 67 73 22 29 29 29 3b 0a 09 09 6c 65 74  rings")));...let
06f0: 20 6d 75 74 20 64 6f 6d 61 69 6e 73 3a 20 48 61   mut domains: Ha
0700: 73 68 53 65 74 3c 53 74 72 69 6e 67 3e 20 3d 20  shSet<String> = 
0710: 48 61 73 68 53 65 74 3a 3a 6e 65 77 28 29 3b 0a  HashSet::new();.
0720: 09 09 6c 65 74 20 65 78 74 72 61 5f 64 6f 6d 61  ..let extra_doma
0730: 69 6e 73 20 3d 20 73 65 74 74 69 6e 67 73 2e 67  ins = settings.g
0740: 65 74 5f 61 72 72 61 79 28 22 64 6f 6d 61 69 6e  et_array("domain
0750: 73 22 29 2e 73 74 61 63 6b 28 29 3f 3b 0a 09 09  s").stack()?;...
0760: 66 6f 72 20 64 6f 6d 61 69 6e 20 69 6e 20 65 78  for domain in ex
0770: 74 72 61 5f 64 6f 6d 61 69 6e 73 20 7b 0a 09 09  tra_domains {...
0780: 09 6c 65 74 20 64 6f 6d 61 69 6e 20 3d 20 64 6f  .let domain = do
0790: 6d 61 69 6e 2e 74 6f 5f 73 74 72 69 6e 67 28 29  main.to_string()
07a0: 2e 74 6f 5f 6c 6f 77 65 72 63 61 73 65 28 29 3b  .to_lowercase();
07b0: 0a 09 09 09 69 66 20 52 45 5f 44 4f 4d 41 49 4e  ....if RE_DOMAIN
07c0: 2e 69 73 5f 6d 61 74 63 68 28 26 64 6f 6d 61 69  .is_match(&domai
07d0: 6e 29 20 7b 0a 09 09 09 09 64 6f 6d 61 69 6e 73  n) {.....domains
07e0: 2e 69 6e 73 65 72 74 28 64 6f 6d 61 69 6e 29 3b  .insert(domain);
07f0: 0a 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09  ....} else {....
0800: 09 70 61 6e 69 63 21 28 22 5b 73 6d 74 70 32 74  .panic!("[smtp2t
0810: 67 2e 74 6f 6d 6c 5d 20 63 61 6e 27 74 20 63 68  g.toml] can't ch
0820: 65 63 6b 20 6f 66 20 64 6f 6d 61 69 6e 73 20 69  eck of domains i
0830: 6e 20 5c 22 64 6f 6d 61 69 6e 73 5c 22 3a 20 7b  n \"domains\": {
0840: 64 6f 6d 61 69 6e 7d 22 29 3b 0a 09 09 09 7d 0a  domain}");....}.
0850: 09 09 7d 0a 09 09 6c 65 74 20 64 6f 6d 61 69 6e  ..}...let domain
0860: 73 20 3d 20 64 6f 6d 61 69 6e 73 2e 69 6e 74 6f  s = domains.into
0870: 5f 69 74 65 72 28 29 2e 6d 61 70 28 7c 73 7c 20  _iter().map(|s| 
0880: 65 73 63 61 70 65 28 26 73 29 29 0a 09 09 09 2e  escape(&s)).....
0890: 63 6f 6c 6c 65 63 74 3a 3a 3c 56 65 63 3c 53 74  collect::<Vec<St
08a0: 72 69 6e 67 3e 3e 28 29 2e 6a 6f 69 6e 28 22 7c  ring>>().join("|
08b0: 22 29 3b 0a 09 09 6c 65 74 20 61 64 64 72 65 73  ");...let addres
08c0: 73 20 3d 20 52 65 67 65 78 3a 3a 6e 65 77 28 26  s = Regex::new(&
08d0: 66 6f 72 6d 61 74 21 28 22 5e 28 3f 50 3c 75 73  format!("^(?P<us
08e0: 65 72 3e 5b 61 2d 7a 30 2d 39 5d 5b 2d 61 2d 7a  er>[a-z0-9][-a-z
08f0: 30 2d 39 5d 29 28 40 28 7b 64 6f 6d 61 69 6e 73  0-9])(@({domains
0900: 7d 29 29 24 22 29 29 2e 73 74 61 63 6b 28 29 3f  }))$")).stack()?
0910: 3b 0a 09 09 6c 65 74 20 72 65 6c 61 79 20 3d 20  ;...let relay = 
0920: 6d 61 74 63 68 20 73 65 74 74 69 6e 67 73 2e 67  match settings.g
0930: 65 74 5f 73 74 72 69 6e 67 28 22 75 6e 6b 6e 6f  et_string("unkno
0940: 77 6e 22 29 0a 09 09 09 2e 63 6f 6e 74 65 78 74  wn").....context
0950: 28 22 5b 73 6d 74 70 32 74 67 2e 74 6f 6d 6c 5d  ("[smtp2tg.toml]
0960: 20 63 61 6e 27 74 20 67 65 74 20 5c 22 75 6e 6b   can't get \"unk
0970: 6e 6f 77 6e 5c 22 20 70 6f 6c 69 63 79 2e 5c 6e  nown\" policy.\n
0980: 22 29 3f 2e 61 73 5f 73 74 72 28 29 0a 09 09 7b  ")?.as_str()...{
0990: 0a 09 09 09 22 72 65 6c 61 79 22 20 3d 3e 20 74  ...."relay" => t
09a0: 72 75 65 2c 0a 09 09 09 22 64 65 6e 79 22 20 3d  rue,...."deny" =
09b0: 3e 20 66 61 6c 73 65 2c 0a 09 09 09 5f 20 3d 3e  > false,...._ =>
09c0: 20 7b 0a 09 09 09 09 62 61 69 6c 21 28 22 5b 73   {.....bail!("[s
09d0: 6d 74 70 32 74 67 2e 74 6f 6d 6c 5d 20 5c 22 75  mtp2tg.toml] \"u
09e0: 6e 6b 6e 6f 77 6e 5c 22 20 73 68 6f 75 6c 64 20  nknown\" should 
09f0: 62 65 20 65 69 74 68 65 72 20 5c 22 72 65 6c 61  be either \"rela
0a00: 79 5c 22 20 6f 72 20 5c 22 64 65 6e 79 5c 22 2e  y\" or \"deny\".
0a10: 5c 6e 22 29 3b 0a 09 09 09 7d 2c 0a 09 09 7d 3b  \n");....},...};
0a20: 0a 0a 09 09 4f 6b 28 4d 61 69 6c 53 65 72 76 65  ....Ok(MailServe
0a30: 72 20 7b 0a 09 09 09 64 61 74 61 3a 20 76 65 63  r {....data: vec
0a40: 21 28 29 2c 0a 09 09 09 68 65 61 64 65 72 73 3a  !(),....headers:
0a50: 20 4e 6f 6e 65 2c 0a 09 09 09 72 65 6c 61 79 2c   None,....relay,
0a60: 0a 09 09 09 74 67 2c 0a 09 09 09 66 69 65 6c 64  ....tg,....field
0a70: 73 2c 0a 09 09 09 61 64 64 72 65 73 73 2c 0a 09  s,....address,..
0a80: 09 7d 29 0a 09 7d 0a 0a 09 2f 2f 2f 20 52 65 74  .})..}.../// Ret
0a90: 75 72 6e 73 20 69 64 20 66 6f 72 20 70 72 6f 76  urns id for prov
0aa0: 69 64 65 64 20 65 6d 61 69 6c 20 61 64 64 72 65  ided email addre
0ab0: 73 73 0a 09 66 6e 20 67 65 74 5f 69 64 20 28 26  ss..fn get_id (&
0ac0: 73 65 6c 66 2c 20 6e 61 6d 65 3a 20 26 73 74 72  self, name: &str
0ad0: 29 20 2d 3e 20 52 65 73 75 6c 74 3c 26 43 68 61  ) -> Result<&Cha
0ae0: 74 50 65 65 72 49 64 3e 20 7b 0a 09 09 2f 2f 20  tPeerId> {...// 
0af0: 68 65 72 65 20 77 65 20 6e 65 65 64 20 74 6f 20  here we need to 
0b00: 73 74 6f 72 65 20 53 74 72 69 6e 67 20 6c 6f 63  store String loc
0b10: 61 6c 6c 79 20 74 6f 20 62 6f 72 72 6f 77 20 69  ally to borrow i
0b20: 74 20 61 66 74 65 72 0a 09 09 6c 65 74 20 6d 75  t after...let mu
0b30: 74 20 6c 69 6e 6b 20 3d 20 6e 61 6d 65 3b 0a 09  t link = name;..
0b40: 09 6c 65 74 20 6e 61 6d 65 3a 20 53 74 72 69 6e  .let name: Strin
0b50: 67 3b 0a 09 09 69 66 20 6c 65 74 20 53 6f 6d 65  g;...if let Some
0b60: 28 63 61 70 73 29 20 3d 20 73 65 6c 66 2e 61 64  (caps) = self.ad
0b70: 64 72 65 73 73 2e 63 61 70 74 75 72 65 73 28 6c  dress.captures(l
0b80: 69 6e 6b 29 20 7b 0a 09 09 09 6e 61 6d 65 20 3d  ink) {....name =
0b90: 20 63 61 70 73 5b 22 6e 61 6d 65 22 5d 2e 74 6f   caps["name"].to
0ba0: 5f 73 74 72 69 6e 67 28 29 3b 0a 09 09 09 6c 69  _string();....li
0bb0: 6e 6b 20 3d 20 26 6e 61 6d 65 3b 0a 09 09 7d 0a  nk = &name;...}.
0bc0: 09 09 6d 61 74 63 68 20 73 65 6c 66 2e 74 67 2e  ..match self.tg.
0bd0: 67 65 74 28 6c 69 6e 6b 29 20 7b 0a 09 09 09 4f  get(link) {....O
0be0: 6b 28 61 64 64 72 29 20 3d 3e 20 4f 6b 28 61 64  k(addr) => Ok(ad
0bf0: 64 72 29 2c 0a 09 09 09 45 72 72 28 5f 29 20 3d  dr),....Err(_) =
0c00: 3e 20 4f 6b 28 26 73 65 6c 66 2e 74 67 2e 64 65  > Ok(&self.tg.de
0c10: 66 61 75 6c 74 29 2c 0a 09 09 7d 0a 09 7d 0a 0a  fault),...}..}..
0c20: 09 2f 2f 2f 20 41 74 74 65 6d 70 74 20 74 6f 20  ./// Attempt to 
0c30: 64 65 6c 69 76 65 72 20 6f 6e 65 20 6d 65 73 73  deliver one mess
0c40: 61 67 65 0a 09 61 73 79 6e 63 20 66 6e 20 72 65  age..async fn re
0c50: 6c 61 79 5f 6d 61 69 6c 20 28 26 73 65 6c 66 29  lay_mail (&self)
0c60: 20 2d 3e 20 52 65 73 75 6c 74 3c 28 29 3e 20 7b   -> Result<()> {
0c70: 0a 09 09 69 66 20 6c 65 74 20 53 6f 6d 65 28 68  ...if let Some(h
0c80: 65 61 64 65 72 73 29 20 3d 20 26 73 65 6c 66 2e  eaders) = &self.
0c90: 68 65 61 64 65 72 73 20 7b 0a 09 09 09 6c 65 74  headers {....let
0ca0: 20 6d 61 69 6c 20 3d 20 6d 61 69 6c 5f 70 61 72   mail = mail_par
0cb0: 73 65 72 3a 3a 4d 65 73 73 61 67 65 50 61 72 73  ser::MessagePars
0cc0: 65 72 3a 3a 6e 65 77 28 29 2e 70 61 72 73 65 28  er::new().parse(
0cd0: 26 73 65 6c 66 2e 64 61 74 61 29 0a 09 09 09 09  &self.data).....
0ce0: 2e 63 6f 6e 74 65 78 74 28 22 46 61 69 6c 65 64  .context("Failed
0cf0: 20 74 6f 20 70 61 72 73 65 20 6d 61 69 6c 2e 22   to parse mail."
0d00: 29 3f 3b 0a 0a 09 09 09 2f 2f 20 41 64 64 69 6e  )?;.....// Addin
0d10: 67 20 61 6c 6c 20 6b 6e 6f 77 6e 20 61 64 64 72  g all known addr
0d20: 65 73 73 65 73 20 74 6f 20 72 65 63 69 70 69 65  esses to recipie
0d30: 6e 74 20 6c 69 73 74 2c 20 66 6f 72 20 61 6e 79  nt list, for any
0d40: 6f 6e 65 20 65 6c 73 65 20 61 64 64 69 6e 67 20  one else adding 
0d50: 64 65 66 61 75 6c 74 0a 09 09 09 2f 2f 20 41 6c  default....// Al
0d60: 73 6f 20 69 66 20 6c 69 73 74 20 69 73 20 65 6d  so if list is em
0d70: 70 74 79 20 61 6c 73 6f 20 61 64 64 69 6e 67 20  pty also adding 
0d80: 64 65 66 61 75 6c 74 0a 09 09 09 6c 65 74 20 6d  default....let m
0d90: 75 74 20 72 63 70 74 3a 20 48 61 73 68 53 65 74  ut rcpt: HashSet
0da0: 3c 26 43 68 61 74 50 65 65 72 49 64 3e 20 3d 20  <&ChatPeerId> = 
0db0: 48 61 73 68 53 65 74 3a 3a 6e 65 77 28 29 3b 0a  HashSet::new();.
0dc0: 09 09 09 69 66 20 68 65 61 64 65 72 73 2e 74 6f  ...if headers.to
0dd0: 2e 69 73 5f 65 6d 70 74 79 28 29 20 26 26 20 21  .is_empty() && !
0de0: 73 65 6c 66 2e 72 65 6c 61 79 20 7b 0a 09 09 09  self.relay {....
0df0: 09 62 61 69 6c 21 28 22 52 65 6c 61 79 69 6e 67  .bail!("Relaying
0e00: 20 69 73 20 64 69 73 61 62 6c 65 64 2c 20 61 6e   is disabled, an
0e10: 64 20 74 68 65 72 65 27 73 20 6e 6f 20 64 65 73  d there's no des
0e20: 74 69 6e 61 74 69 6f 6e 20 61 64 64 72 65 73 73  tination address
0e30: 22 29 3b 0a 09 09 09 7d 0a 09 09 09 66 6f 72 20  ");....}....for 
0e40: 69 74 65 6d 20 69 6e 20 26 68 65 61 64 65 72 73  item in &headers
0e50: 2e 74 6f 20 7b 0a 09 09 09 09 72 63 70 74 2e 69  .to {.....rcpt.i
0e60: 6e 73 65 72 74 28 73 65 6c 66 2e 67 65 74 5f 69  nsert(self.get_i
0e70: 64 28 69 74 65 6d 29 3f 29 3b 0a 09 09 09 7d 3b  d(item)?);....};
0e80: 0a 09 09 09 69 66 20 72 63 70 74 2e 69 73 5f 65  ....if rcpt.is_e
0e90: 6d 70 74 79 28 29 20 7b 0a 09 09 09 09 73 65 6c  mpty() {.....sel
0ea0: 66 2e 74 67 2e 64 65 62 75 67 28 22 4e 6f 20 72  f.tg.debug("No r
0eb0: 65 63 69 70 69 65 6e 74 20 6f 72 20 65 6e 76 65  ecipient or enve
0ec0: 6c 6f 70 65 20 61 64 64 72 65 73 73 2e 22 29 2e  lope address.").
0ed0: 61 77 61 69 74 3f 3b 0a 09 09 09 09 72 63 70 74  await?;.....rcpt
0ee0: 2e 69 6e 73 65 72 74 28 26 73 65 6c 66 2e 74 67  .insert(&self.tg
0ef0: 2e 64 65 66 61 75 6c 74 29 3b 0a 09 09 09 7d 3b  .default);....};
0f00: 0a 0a 09 09 09 2f 2f 20 70 72 65 70 61 74 69 6e  .....// prepatin
0f10: 67 20 6d 65 73 73 61 67 65 20 68 65 61 64 65 72  g message header
0f20: 0a 09 09 09 6c 65 74 20 6d 75 74 20 72 65 70 6c  ....let mut repl
0f30: 79 3a 20 56 65 63 3c 53 74 72 69 6e 67 3e 20 3d  y: Vec<String> =
0f40: 20 76 65 63 21 5b 5d 3b 0a 09 09 09 69 66 20 73   vec![];....if s
0f50: 65 6c 66 2e 66 69 65 6c 64 73 2e 63 6f 6e 74 61  elf.fields.conta
0f60: 69 6e 73 28 22 73 75 62 6a 65 63 74 22 29 20 7b  ins("subject") {
0f70: 0a 09 09 09 09 69 66 20 6c 65 74 20 53 6f 6d 65  .....if let Some
0f80: 28 73 75 62 6a 65 63 74 29 20 3d 20 6d 61 69 6c  (subject) = mail
0f90: 2e 73 75 62 6a 65 63 74 28 29 20 7b 0a 09 09 09  .subject() {....
0fa0: 09 09 72 65 70 6c 79 2e 70 75 73 68 28 66 6f 72  ..reply.push(for
0fb0: 6d 61 74 21 28 22 5f 5f 2a 53 75 62 6a 65 63 74  mat!("__*Subject
0fc0: 3a 2a 5f 5f e2 80 87 60 7b 7d 60 22 2c 20 65 6e  :*__ `{}`", en
0fd0: 63 6f 64 65 28 73 75 62 6a 65 63 74 29 29 29 3b  code(subject)));
0fe0: 0a 09 09 09 09 7d 20 65 6c 73 65 20 69 66 20 6c  .....} else if l
0ff0: 65 74 20 53 6f 6d 65 28 74 68 72 65 61 64 29 20  et Some(thread) 
1000: 3d 20 6d 61 69 6c 2e 74 68 72 65 61 64 5f 6e 61  = mail.thread_na
1010: 6d 65 28 29 20 7b 0a 09 09 09 09 09 72 65 70 6c  me() {......repl
1020: 79 2e 70 75 73 68 28 66 6f 72 6d 61 74 21 28 22  y.push(format!("
1030: 5f 5f 2a 54 68 72 65 61 64 3a 2a 5f 5f e2 80 87  __*Thread:*__ 
1040: 60 7b 7d 60 22 2c 20 65 6e 63 6f 64 65 28 74 68  `{}`", encode(th
1050: 72 65 61 64 29 29 29 3b 0a 09 09 09 09 7d 0a 09  read)));.....}..
1060: 09 09 7d 0a 09 09 09 6c 65 74 20 6d 75 74 20 73  ..}....let mut s
1070: 68 6f 72 74 5f 68 65 61 64 65 72 73 3a 20 56 65  hort_headers: Ve
1080: 63 3c 53 74 72 69 6e 67 3e 20 3d 20 76 65 63 21  c<String> = vec!
1090: 5b 5d 3b 0a 09 09 09 2f 2f 20 64 6f 20 77 65 20  [];....// do we 
10a0: 6e 65 65 64 20 74 6f 20 72 65 70 6c 61 63 65 20  need to replace 
10b0: 73 70 61 63 65 73 20 68 65 72 65 3f 0a 09 09 09  spaces here?....
10c0: 69 66 20 73 65 6c 66 2e 66 69 65 6c 64 73 2e 63  if self.fields.c
10d0: 6f 6e 74 61 69 6e 73 28 22 66 72 6f 6d 22 29 20  ontains("from") 
10e0: 7b 0a 09 09 09 09 73 68 6f 72 74 5f 68 65 61 64  {.....short_head
10f0: 65 72 73 2e 70 75 73 68 28 66 6f 72 6d 61 74 21  ers.push(format!
1100: 28 22 5f 5f 2a 46 72 6f 6d 3a 2a 5f 5f e2 80 87  ("__*From:*__ 
1110: 60 7b 7d 60 22 2c 20 65 6e 63 6f 64 65 28 26 68  `{}`", encode(&h
1120: 65 61 64 65 72 73 2e 66 72 6f 6d 29 29 29 3b 0a  eaders.from)));.
1130: 09 09 09 7d 0a 09 09 09 69 66 20 73 65 6c 66 2e  ...}....if self.
1140: 66 69 65 6c 64 73 2e 63 6f 6e 74 61 69 6e 73 28  fields.contains(
1150: 22 64 61 74 65 22 29 20 7b 0a 09 09 09 09 69 66  "date") {.....if
1160: 20 6c 65 74 20 53 6f 6d 65 28 64 61 74 65 29 20   let Some(date) 
1170: 3d 20 6d 61 69 6c 2e 64 61 74 65 28 29 20 7b 0a  = mail.date() {.
1180: 09 09 09 09 09 73 68 6f 72 74 5f 68 65 61 64 65  .....short_heade
1190: 72 73 2e 70 75 73 68 28 66 6f 72 6d 61 74 21 28  rs.push(format!(
11a0: 22 5f 5f 2a 44 61 74 65 3a 2a 5f 5f e2 80 87 60  "__*Date:*__ `
11b0: 7b 64 61 74 65 7d 60 22 29 29 3b 0a 09 09 09 09  {date}`"));.....
11c0: 7d 0a 09 09 09 7d 0a 09 09 09 72 65 70 6c 79 2e  }....}....reply.
11d0: 70 75 73 68 28 73 68 6f 72 74 5f 68 65 61 64 65  push(short_heade
11e0: 72 73 2e 6a 6f 69 6e 28 22 20 22 29 29 3b 0a 09  rs.join(" "));..
11f0: 09 09 6c 65 74 20 68 65 61 64 65 72 5f 73 69 7a  ..let header_siz
1200: 65 20 3d 20 72 65 70 6c 79 2e 6a 6f 69 6e 28 22  e = reply.join("
1210: 20 22 29 2e 6c 65 6e 28 29 20 2b 20 31 3b 0a 0a   ").len() + 1;..
1220: 09 09 09 6c 65 74 20 68 74 6d 6c 5f 70 61 72 74  ...let html_part
1230: 73 20 3d 20 6d 61 69 6c 2e 68 74 6d 6c 5f 62 6f  s = mail.html_bo
1240: 64 79 5f 63 6f 75 6e 74 28 29 3b 0a 09 09 09 6c  dy_count();....l
1250: 65 74 20 74 65 78 74 5f 70 61 72 74 73 20 3d 20  et text_parts = 
1260: 6d 61 69 6c 2e 74 65 78 74 5f 62 6f 64 79 5f 63  mail.text_body_c
1270: 6f 75 6e 74 28 29 3b 0a 09 09 09 6c 65 74 20 61  ount();....let a
1280: 74 74 61 63 68 6d 65 6e 74 73 20 3d 20 6d 61 69  ttachments = mai
1290: 6c 2e 61 74 74 61 63 68 6d 65 6e 74 5f 63 6f 75  l.attachment_cou
12a0: 6e 74 28 29 3b 0a 09 09 09 69 66 20 68 74 6d 6c  nt();....if html
12b0: 5f 70 61 72 74 73 20 21 3d 20 74 65 78 74 5f 70  _parts != text_p
12c0: 61 72 74 73 20 7b 0a 09 09 09 09 73 65 6c 66 2e  arts {.....self.
12d0: 74 67 2e 64 65 62 75 67 28 26 66 6f 72 6d 61 74  tg.debug(&format
12e0: 21 28 22 48 6d 2c 20 77 65 20 68 61 76 65 20 7b  !("Hm, we have {
12f0: 68 74 6d 6c 5f 70 61 72 74 73 7d 20 48 54 4d 4c  html_parts} HTML
1300: 20 70 61 72 74 73 20 61 6e 64 20 7b 74 65 78 74   parts and {text
1310: 5f 70 61 72 74 73 7d 20 74 65 78 74 20 70 61 72  _parts} text par
1320: 74 73 2e 22 29 29 2e 61 77 61 69 74 3f 3b 0a 09  ts.")).await?;..
1330: 09 09 7d 0a 09 09 09 2f 2f 6c 65 74 20 6d 75 74  ..}....//let mut
1340: 20 68 74 6d 6c 5f 6e 75 6d 20 3d 20 30 3b 0a 09   html_num = 0;..
1350: 09 09 6c 65 74 20 6d 75 74 20 74 65 78 74 5f 6e  ..let mut text_n
1360: 75 6d 20 3d 20 30 3b 0a 09 09 09 6c 65 74 20 6d  um = 0;....let m
1370: 75 74 20 66 69 6c 65 5f 6e 75 6d 20 3d 20 30 3b  ut file_num = 0;
1380: 0a 09 09 09 2f 2f 20 6c 65 74 27 73 20 64 69 73  ....// let's dis
1390: 70 6c 61 79 20 66 69 72 73 74 20 68 74 6d 6c 20  play first html 
13a0: 6f 72 20 74 65 78 74 20 70 61 72 74 20 61 73 20  or text part as 
13b0: 62 6f 64 79 0a 09 09 09 6c 65 74 20 6d 75 74 20  body....let mut 
13c0: 62 6f 64 79 3a 20 43 6f 77 3c 27 5f 2c 20 73 74  body: Cow<'_, st
13d0: 72 3e 20 3d 20 22 22 2e 69 6e 74 6f 28 29 3b 0a  r> = "".into();.
13e0: 09 09 09 2f 2a 0a 09 09 09 20 2a 20 61 63 74 75  .../*.... * actu
13f0: 61 6c 6c 79 20 49 20 64 6f 6e 27 74 20 77 61 6e  ally I don't wan
1400: 6e 61 20 70 61 72 73 65 20 74 68 61 74 20 68 74  na parse that ht
1410: 6d 6c 20 73 74 75 66 66 0a 09 09 09 69 66 20 68  ml stuff....if h
1420: 74 6d 6c 5f 70 61 72 74 73 20 3e 20 30 20 7b 0a  tml_parts > 0 {.
1430: 09 09 09 09 6c 65 74 20 74 65 78 74 20 3d 20 6d  ....let text = m
1440: 61 69 6c 2e 62 6f 64 79 5f 68 74 6d 6c 28 30 29  ail.body_html(0)
1450: 2e 73 74 61 63 6b 28 29 3f 3b 0a 09 09 09 09 69  .stack()?;.....i
1460: 66 20 74 65 78 74 2e 6c 65 6e 28 29 20 3c 20 34  f text.len() < 4
1470: 30 39 36 20 2d 20 68 65 61 64 65 72 5f 73 69 7a  096 - header_siz
1480: 65 20 7b 0a 09 09 09 09 09 62 6f 64 79 20 3d 20  e {......body = 
1490: 74 65 78 74 3b 0a 09 09 09 09 09 68 74 6d 6c 5f  text;......html_
14a0: 6e 75 6d 20 3d 20 31 3b 0a 09 09 09 09 7d 0a 09  num = 1;.....}..
14b0: 09 09 7d 3b 0a 09 09 09 2a 2f 0a 09 09 09 69 66  ..};....*/....if
14c0: 20 62 6f 64 79 2e 69 73 5f 65 6d 70 74 79 28 29   body.is_empty()
14d0: 20 26 26 20 74 65 78 74 5f 70 61 72 74 73 20 3e   && text_parts >
14e0: 20 30 20 7b 0a 09 09 09 09 6c 65 74 20 74 65 78   0 {.....let tex
14f0: 74 20 3d 20 6d 61 69 6c 2e 62 6f 64 79 5f 74 65  t = mail.body_te
1500: 78 74 28 30 29 0a 09 09 09 09 09 2e 63 6f 6e 74  xt(0).......cont
1510: 65 78 74 28 22 46 61 69 6c 65 64 20 74 6f 20 65  ext("Failed to e
1520: 78 74 72 61 63 74 20 74 65 78 74 20 66 72 6f 6d  xtract text from
1530: 20 6d 65 73 73 61 67 65 22 29 3f 3b 0a 09 09 09   message")?;....
1540: 09 69 66 20 74 65 78 74 2e 6c 65 6e 28 29 20 3c  .if text.len() <
1550: 20 34 30 39 36 20 2d 20 68 65 61 64 65 72 5f 73   4096 - header_s
1560: 69 7a 65 20 7b 0a 09 09 09 09 09 62 6f 64 79 20  ize {......body 
1570: 3d 20 74 65 78 74 3b 0a 09 09 09 09 09 74 65 78  = text;......tex
1580: 74 5f 6e 75 6d 20 3d 20 31 3b 0a 09 09 09 09 7d  t_num = 1;.....}
1590: 0a 09 09 09 7d 3b 0a 09 09 09 72 65 70 6c 79 2e  ....};....reply.
15a0: 70 75 73 68 28 22 60 60 60 22 2e 69 6e 74 6f 28  push("```".into(
15b0: 29 29 3b 0a 09 09 09 72 65 70 6c 79 2e 65 78 74  ));....reply.ext
15c0: 65 6e 64 28 62 6f 64 79 2e 6c 69 6e 65 73 28 29  end(body.lines()
15d0: 2e 6d 61 70 28 7c 78 7c 20 78 2e 69 6e 74 6f 28  .map(|x| x.into(
15e0: 29 29 29 3b 0a 09 09 09 72 65 70 6c 79 2e 70 75  )));....reply.pu
15f0: 73 68 28 22 60 60 60 22 2e 69 6e 74 6f 28 29 29  sh("```".into())
1600: 3b 0a 0a 09 09 09 2f 2f 20 61 6e 64 20 6c 65 74  ;.....// and let
1610: 27 73 20 63 6f 6c 6c 65 63 74 20 61 6c 6c 20 6f  's collect all o
1620: 74 68 65 72 20 61 74 74 61 63 68 6d 65 6e 74 20  ther attachment 
1630: 70 61 72 74 73 0a 09 09 09 6c 65 74 20 6d 75 74  parts....let mut
1640: 20 66 69 6c 65 73 5f 74 6f 5f 73 65 6e 64 20 3d   files_to_send =
1650: 20 76 65 63 21 5b 5d 3b 0a 09 09 09 2f 2a 0a 09   vec![];..../*..
1660: 09 09 20 2a 20 6c 65 74 27 73 20 6a 75 73 74 20  .. * let's just 
1670: 73 6b 69 70 20 68 74 6d 6c 20 70 61 72 74 73 20  skip html parts 
1680: 66 6f 72 20 6e 6f 77 2c 20 74 68 65 79 20 6a 75  for now, they ju
1690: 73 74 20 64 75 70 6c 69 63 61 74 65 20 74 65 78  st duplicate tex
16a0: 74 3f 0a 09 09 09 77 68 69 6c 65 20 68 74 6d 6c  t?....while html
16b0: 5f 6e 75 6d 20 3c 20 68 74 6d 6c 5f 70 61 72 74  _num < html_part
16c0: 73 20 7b 0a 09 09 09 09 66 69 6c 65 73 5f 74 6f  s {.....files_to
16d0: 5f 73 65 6e 64 2e 70 75 73 68 28 6d 61 69 6c 2e  _send.push(mail.
16e0: 68 74 6d 6c 5f 70 61 72 74 28 68 74 6d 6c 5f 6e  html_part(html_n
16f0: 75 6d 29 2e 73 74 61 63 6b 28 29 3f 29 3b 0a 09  um).stack()?);..
1700: 09 09 09 68 74 6d 6c 5f 6e 75 6d 20 2b 3d 20 31  ...html_num += 1
1710: 3b 0a 09 09 09 7d 0a 09 09 09 2a 2f 0a 09 09 09  ;....}....*/....
1720: 77 68 69 6c 65 20 74 65 78 74 5f 6e 75 6d 20 3c  while text_num <
1730: 20 74 65 78 74 5f 70 61 72 74 73 20 7b 0a 09 09   text_parts {...
1740: 09 09 66 69 6c 65 73 5f 74 6f 5f 73 65 6e 64 2e  ..files_to_send.
1750: 70 75 73 68 28 6d 61 69 6c 2e 74 65 78 74 5f 70  push(mail.text_p
1760: 61 72 74 28 74 65 78 74 5f 6e 75 6d 2e 74 72 79  art(text_num.try
1770: 5f 69 6e 74 6f 28 29 2e 73 74 61 63 6b 28 29 3f  _into().stack()?
1780: 29 0a 09 09 09 09 09 2e 63 6f 6e 74 65 78 74 28  ).......context(
1790: 22 46 61 69 6c 65 64 20 74 6f 20 67 65 74 20 74  "Failed to get t
17a0: 65 78 74 20 70 61 72 74 20 66 72 6f 6d 20 6d 65  ext part from me
17b0: 73 73 61 67 65 2e 22 29 3f 29 3b 0a 09 09 09 09  ssage.")?);.....
17c0: 74 65 78 74 5f 6e 75 6d 20 2b 3d 20 31 3b 0a 09  text_num += 1;..
17d0: 09 09 7d 0a 09 09 09 77 68 69 6c 65 20 66 69 6c  ..}....while fil
17e0: 65 5f 6e 75 6d 20 3c 20 61 74 74 61 63 68 6d 65  e_num < attachme
17f0: 6e 74 73 20 7b 0a 09 09 09 09 66 69 6c 65 73 5f  nts {.....files_
1800: 74 6f 5f 73 65 6e 64 2e 70 75 73 68 28 6d 61 69  to_send.push(mai
1810: 6c 2e 61 74 74 61 63 68 6d 65 6e 74 28 66 69 6c  l.attachment(fil
1820: 65 5f 6e 75 6d 2e 74 72 79 5f 69 6e 74 6f 28 29  e_num.try_into()
1830: 2e 73 74 61 63 6b 28 29 3f 29 0a 09 09 09 09 09  .stack()?)......
1840: 2e 63 6f 6e 74 65 78 74 28 22 46 61 69 6c 65 64  .context("Failed
1850: 20 74 6f 20 67 65 74 20 66 69 6c 65 20 70 61 72   to get file par
1860: 74 20 66 72 6f 6d 20 6d 65 73 73 61 67 65 2e 22  t from message."
1870: 29 3f 29 3b 0a 09 09 09 09 66 69 6c 65 5f 6e 75  )?);.....file_nu
1880: 6d 20 2b 3d 20 31 3b 0a 09 09 09 7d 0a 0a 09 09  m += 1;....}....
1890: 09 6c 65 74 20 6d 73 67 20 3d 20 72 65 70 6c 79  .let msg = reply
18a0: 2e 6a 6f 69 6e 28 22 5c 6e 22 29 3b 0a 09 09 09  .join("\n");....
18b0: 66 6f 72 20 63 68 61 74 20 69 6e 20 72 63 70 74  for chat in rcpt
18c0: 20 7b 0a 09 09 09 09 69 66 20 21 66 69 6c 65 73   {.....if !files
18d0: 5f 74 6f 5f 73 65 6e 64 2e 69 73 5f 65 6d 70 74  _to_send.is_empt
18e0: 79 28 29 20 7b 0a 09 09 09 09 09 6c 65 74 20 6d  y() {......let m
18f0: 75 74 20 66 69 6c 65 73 20 3d 20 76 65 63 21 5b  ut files = vec![
1900: 5d 3b 0a 09 09 09 09 09 2f 2f 20 6c 65 74 20 6d  ];......// let m
1910: 75 74 20 66 69 72 73 74 5f 6f 6e 65 20 3d 20 74  ut first_one = t
1920: 72 75 65 3b 0a 09 09 09 09 09 66 6f 72 20 63 68  rue;......for ch
1930: 75 6e 6b 20 69 6e 20 26 66 69 6c 65 73 5f 74 6f  unk in &files_to
1940: 5f 73 65 6e 64 20 7b 0a 09 09 09 09 09 09 6c 65  _send {.......le
1950: 74 20 64 61 74 61 3a 20 56 65 63 3c 75 38 3e 20  t data: Vec<u8> 
1960: 3d 20 63 68 75 6e 6b 2e 63 6f 6e 74 65 6e 74 73  = chunk.contents
1970: 28 29 2e 74 6f 5f 76 65 63 28 29 3b 0a 09 09 09  ().to_vec();....
1980: 09 09 09 6c 65 74 20 6d 75 74 20 66 69 6c 65 6e  ...let mut filen
1990: 61 6d 65 3a 20 4f 70 74 69 6f 6e 3c 53 74 72 69  ame: Option<Stri
19a0: 6e 67 3e 20 3d 20 4e 6f 6e 65 3b 0a 09 09 09 09  ng> = None;.....
19b0: 09 09 66 6f 72 20 68 65 61 64 65 72 20 69 6e 20  ..for header in 
19c0: 63 68 75 6e 6b 2e 68 65 61 64 65 72 73 28 29 20  chunk.headers() 
19d0: 7b 0a 09 09 09 09 09 09 09 69 66 20 68 65 61 64  {........if head
19e0: 65 72 2e 6e 61 6d 65 28 29 20 3d 3d 20 22 43 6f  er.name() == "Co
19f0: 6e 74 65 6e 74 2d 54 79 70 65 22 20 7b 0a 09 09  ntent-Type" {...
1a00: 09 09 09 09 09 09 6d 61 74 63 68 20 68 65 61 64  ......match head
1a10: 65 72 2e 76 61 6c 75 65 28 29 20 7b 0a 09 09 09  er.value() {....
1a20: 09 09 09 09 09 09 6d 61 69 6c 5f 70 61 72 73 65  ......mail_parse
1a30: 72 3a 3a 48 65 61 64 65 72 56 61 6c 75 65 3a 3a  r::HeaderValue::
1a40: 43 6f 6e 74 65 6e 74 54 79 70 65 28 63 6f 6e 74  ContentType(cont
1a50: 65 6e 74 74 79 70 65 29 20 3d 3e 20 7b 0a 09 09  enttype) => {...
1a60: 09 09 09 09 09 09 09 09 69 66 20 6c 65 74 20 53  ........if let S
1a70: 6f 6d 65 28 66 6e 61 6d 65 29 20 3d 20 63 6f 6e  ome(fname) = con
1a80: 74 65 6e 74 74 79 70 65 2e 61 74 74 72 69 62 75  tenttype.attribu
1a90: 74 65 28 22 6e 61 6d 65 22 29 20 7b 0a 09 09 09  te("name") {....
1aa0: 09 09 09 09 09 09 09 09 66 69 6c 65 6e 61 6d 65  ........filename
1ab0: 20 3d 20 53 6f 6d 65 28 66 6e 61 6d 65 2e 74 6f   = Some(fname.to
1ac0: 5f 6f 77 6e 65 64 28 29 29 3b 0a 09 09 09 09 09  _owned());......
1ad0: 09 09 09 09 09 7d 0a 09 09 09 09 09 09 09 09 09  .....}..........
1ae0: 7d 2c 0a 09 09 09 09 09 09 09 09 09 5f 20 3d 3e  },.........._ =>
1af0: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 73 65 6c   {...........sel
1b00: 66 2e 74 67 2e 64 65 62 75 67 28 22 41 74 74 61  f.tg.debug("Atta
1b10: 63 68 6d 65 6e 74 20 68 61 73 20 62 61 64 20 43  chment has bad C
1b20: 6f 6e 74 65 6e 74 54 79 70 65 20 68 65 61 64 65  ontentType heade
1b30: 72 2e 22 29 2e 61 77 61 69 74 3f 3b 0a 09 09 09  r.").await?;....
1b40: 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09 09 09  ......},........
1b50: 09 7d 3b 0a 09 09 09 09 09 09 09 7d 3b 0a 09 09  .};........};...
1b60: 09 09 09 09 7d 3b 0a 09 09 09 09 09 09 6c 65 74  ....};.......let
1b70: 20 66 69 6c 65 6e 61 6d 65 20 3d 20 69 66 20 6c   filename = if l
1b80: 65 74 20 53 6f 6d 65 28 66 6e 61 6d 65 29 20 3d  et Some(fname) =
1b90: 20 66 69 6c 65 6e 61 6d 65 20 7b 0a 09 09 09 09   filename {.....
1ba0: 09 09 09 66 6e 61 6d 65 0a 09 09 09 09 09 09 7d  ...fname.......}
1bb0: 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 09 09 22   else {........"
1bc0: 41 74 74 61 63 68 6d 65 6e 74 2e 74 78 74 22 2e  Attachment.txt".
1bd0: 69 6e 74 6f 28 29 0a 09 09 09 09 09 09 7d 3b 0a  into().......};.
1be0: 09 09 09 09 09 09 66 69 6c 65 73 2e 70 75 73 68  ......files.push
1bf0: 28 41 74 74 61 63 68 6d 65 6e 74 20 7b 0a 09 09  (Attachment {...
1c00: 09 09 09 09 09 64 61 74 61 3a 20 43 75 72 73 6f  .....data: Curso
1c10: 72 3a 3a 6e 65 77 28 64 61 74 61 29 2c 0a 09 09  r::new(data),...
1c20: 09 09 09 09 09 6e 61 6d 65 3a 20 66 69 6c 65 6e  .....name: filen
1c30: 61 6d 65 2c 0a 09 09 09 09 09 09 7d 29 3b 0a 09  ame,.......});..
1c40: 09 09 09 09 7d 0a 09 09 09 09 09 73 65 6c 66 2e  ....}......self.
1c50: 74 67 2e 73 65 6e 64 67 72 6f 75 70 28 63 68 61  tg.sendgroup(cha
1c60: 74 2c 20 66 69 6c 65 73 2c 20 26 6d 73 67 29 2e  t, files, &msg).
1c70: 61 77 61 69 74 3f 3b 0a 09 09 09 09 7d 20 65 6c  await?;.....} el
1c80: 73 65 20 7b 0a 09 09 09 09 09 73 65 6c 66 2e 74  se {......self.t
1c90: 67 2e 73 65 6e 64 28 63 68 61 74 2c 20 26 6d 73  g.send(chat, &ms
1ca0: 67 29 2e 61 77 61 69 74 3f 3b 0a 09 09 09 09 7d  g).await?;.....}
1cb0: 0a 09 09 09 7d 0a 09 09 7d 20 65 6c 73 65 20 7b  ....}...} else {
1cc0: 0a 09 09 09 62 61 69 6c 21 28 22 52 65 71 75 69  ....bail!("Requi
1cd0: 72 65 64 20 68 65 61 64 65 72 73 20 77 65 72 65  red headers were
1ce0: 20 6e 6f 74 20 66 6f 75 6e 64 2e 22 29 3b 0a 09   not found.");..
1cf0: 09 7d 0a 09 09 4f 6b 28 28 29 29 0a 09 7d 0a 7d  .}...Ok(())..}.}
1d00: 0a 0a 69 6d 70 6c 20 6d 61 69 6c 69 6e 5f 65 6d  ..impl mailin_em
1d10: 62 65 64 64 65 64 3a 3a 48 61 6e 64 6c 65 72 20  bedded::Handler 
1d20: 66 6f 72 20 4d 61 69 6c 53 65 72 76 65 72 20 7b  for MailServer {
1d30: 0a 09 2f 2f 2f 20 4a 75 73 74 20 64 65 6e 79 20  ../// Just deny 
1d40: 6c 6f 67 69 6e 20 61 75 74 68 0a 09 66 6e 20 61  login auth..fn a
1d50: 75 74 68 5f 6c 6f 67 69 6e 20 28 26 6d 75 74 20  uth_login (&mut 
1d60: 73 65 6c 66 2c 20 5f 75 73 65 72 6e 61 6d 65 3a  self, _username:
1d70: 20 26 73 74 72 2c 20 5f 70 61 73 73 77 6f 72 64   &str, _password
1d80: 3a 20 26 73 74 72 29 20 2d 3e 20 52 65 73 70 6f  : &str) -> Respo
1d90: 6e 73 65 20 7b 0a 09 09 49 4e 56 41 4c 49 44 5f  nse {...INVALID_
1da0: 43 52 45 44 45 4e 54 49 41 4c 53 0a 09 7d 0a 0a  CREDENTIALS..}..
1db0: 09 2f 2f 2f 20 4a 75 73 74 20 64 65 6e 79 20 70  ./// Just deny p
1dc0: 6c 61 69 6e 20 61 75 74 68 0a 09 66 6e 20 61 75  lain auth..fn au
1dd0: 74 68 5f 70 6c 61 69 6e 20 28 26 6d 75 74 20 73  th_plain (&mut s
1de0: 65 6c 66 2c 20 5f 61 75 74 68 6f 72 69 7a 61 74  elf, _authorizat
1df0: 69 6f 6e 5f 69 64 3a 20 26 73 74 72 2c 20 5f 61  ion_id: &str, _a
1e00: 75 74 68 65 6e 74 69 63 61 74 69 6f 6e 5f 69 64  uthentication_id
1e10: 3a 20 26 73 74 72 2c 20 5f 70 61 73 73 77 6f 72  : &str, _passwor
1e20: 64 3a 20 26 73 74 72 29 20 2d 3e 20 52 65 73 70  d: &str) -> Resp
1e30: 6f 6e 73 65 20 7b 0a 09 09 49 4e 56 41 4c 49 44  onse {...INVALID
1e40: 5f 43 52 45 44 45 4e 54 49 41 4c 53 0a 09 7d 0a  _CREDENTIALS..}.
1e50: 0a 09 2f 2f 2f 20 56 65 72 69 66 79 20 77 68 65  ../// Verify whe
1e60: 74 68 65 72 20 61 64 64 72 65 73 73 20 69 73 20  ther address is 
1e70: 64 65 6c 69 76 65 72 61 62 6c 65 0a 09 66 6e 20  deliverable..fn 
1e80: 72 63 70 74 20 28 26 6d 75 74 20 73 65 6c 66 2c  rcpt (&mut self,
1e90: 20 74 6f 3a 20 26 73 74 72 29 20 2d 3e 20 52 65   to: &str) -> Re
1ea0: 73 70 6f 6e 73 65 20 7b 0a 09 09 69 66 20 73 65  sponse {...if se
1eb0: 6c 66 2e 72 65 6c 61 79 20 7b 0a 09 09 09 4f 4b  lf.relay {....OK
1ec0: 0a 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 6d  ...} else {....m
1ed0: 61 74 63 68 20 73 65 6c 66 2e 67 65 74 5f 69 64  atch self.get_id
1ee0: 28 74 6f 29 20 7b 0a 09 09 09 09 4f 6b 28 5f 29  (to) {.....Ok(_)
1ef0: 20 3d 3e 20 4f 4b 2c 0a 09 09 09 09 45 72 72 28   => OK,.....Err(
1f00: 5f 29 20 3d 3e 20 7b 0a 09 09 09 09 09 69 66 20  _) => {......if 
1f10: 73 65 6c 66 2e 72 65 6c 61 79 20 7b 0a 09 09 09  self.relay {....
1f20: 09 09 09 4f 4b 0a 09 09 09 09 09 7d 20 65 6c 73  ...OK......} els
1f30: 65 20 7b 0a 09 09 09 09 09 09 4e 4f 5f 4d 41 49  e {.......NO_MAI
1f40: 4c 42 4f 58 0a 09 09 09 09 09 7d 0a 09 09 09 09  LBOX......}.....
1f50: 7d 0a 09 09 09 7d 0a 09 09 7d 0a 09 7d 0a 0a 09  }....}...}..}...
1f60: 2f 2f 2f 20 53 61 76 65 20 68 65 61 64 65 72 73  /// Save headers
1f70: 20 77 65 20 6e 65 65 64 0a 09 66 6e 20 64 61 74   we need..fn dat
1f80: 61 5f 73 74 61 72 74 20 28 26 6d 75 74 20 73 65  a_start (&mut se
1f90: 6c 66 2c 20 5f 64 6f 6d 61 69 6e 3a 20 26 73 74  lf, _domain: &st
1fa0: 72 2c 20 66 72 6f 6d 3a 20 26 73 74 72 2c 20 5f  r, from: &str, _
1fb0: 69 73 38 62 69 74 3a 20 62 6f 6f 6c 2c 20 74 6f  is8bit: bool, to
1fc0: 3a 20 26 5b 53 74 72 69 6e 67 5d 29 20 2d 3e 20  : &[String]) -> 
1fd0: 52 65 73 70 6f 6e 73 65 20 7b 0a 09 09 73 65 6c  Response {...sel
1fe0: 66 2e 68 65 61 64 65 72 73 20 3d 20 53 6f 6d 65  f.headers = Some
1ff0: 28 53 6f 6d 65 48 65 61 64 65 72 73 7b 0a 09 09  (SomeHeaders{...
2000: 09 66 72 6f 6d 3a 20 66 72 6f 6d 2e 74 6f 5f 73  .from: from.to_s
2010: 74 72 69 6e 67 28 29 2c 0a 09 09 09 74 6f 3a 20  tring(),....to: 
2020: 74 6f 2e 74 6f 5f 76 65 63 28 29 2c 0a 09 09 7d  to.to_vec(),...}
2030: 29 3b 0a 09 09 4f 4b 0a 09 7d 0a 0a 09 2f 2f 2f  );...OK..}...///
2040: 20 53 61 76 65 20 63 68 75 6e 6b 28 3f 29 20 6f   Save chunk(?) o
2050: 66 20 64 61 74 61 0a 09 66 6e 20 64 61 74 61 20  f data..fn data 
2060: 28 26 6d 75 74 20 73 65 6c 66 2c 20 62 75 66 3a  (&mut self, buf:
2070: 20 26 5b 75 38 5d 29 20 2d 3e 20 73 74 64 3a 3a   &[u8]) -> std::
2080: 72 65 73 75 6c 74 3a 3a 52 65 73 75 6c 74 3c 28  result::Result<(
2090: 29 2c 20 45 72 72 6f 72 3e 20 7b 0a 09 09 73 65  ), Error> {...se
20a0: 6c 66 2e 64 61 74 61 2e 61 70 70 65 6e 64 28 62  lf.data.append(b
20b0: 75 66 2e 74 6f 5f 76 65 63 28 29 2e 61 73 5f 6d  uf.to_vec().as_m
20c0: 75 74 28 29 29 3b 0a 09 09 4f 6b 28 28 29 29 0a  ut());...Ok(()).
20d0: 09 7d 0a 0a 09 2f 2f 2f 20 41 74 74 65 6d 70 74  .}.../// Attempt
20e0: 20 74 6f 20 73 65 6e 64 20 65 6d 61 69 6c 2c 20   to send email, 
20f0: 72 65 74 75 72 6e 20 74 65 6d 70 6f 72 61 72 79  return temporary
2100: 20 65 72 72 6f 72 20 69 66 20 74 68 61 74 20 66   error if that f
2110: 61 69 6c 73 0a 09 66 6e 20 64 61 74 61 5f 65 6e  ails..fn data_en
2120: 64 20 28 26 6d 75 74 20 73 65 6c 66 29 20 2d 3e  d (&mut self) ->
2130: 20 52 65 73 70 6f 6e 73 65 20 7b 0a 09 09 6c 65   Response {...le
2140: 74 20 6d 75 74 20 72 65 73 75 6c 74 20 3d 20 4f  t mut result = O
2150: 4b 3b 0a 09 09 73 6d 6f 6c 3a 3a 62 6c 6f 63 6b  K;...smol::block
2160: 5f 6f 6e 28 61 73 79 6e 63 20 7b 0a 09 09 09 2f  _on(async {..../
2170: 2f 20 72 65 6c 61 79 20 6d 61 69 6c 0a 09 09 09  / relay mail....
2180: 69 66 20 6c 65 74 20 45 72 72 28 65 72 72 29 20  if let Err(err) 
2190: 3d 20 73 65 6c 66 2e 72 65 6c 61 79 5f 6d 61 69  = self.relay_mai
21a0: 6c 28 29 2e 61 77 61 69 74 20 7b 0a 09 09 09 09  l().await {.....
21b0: 72 65 73 75 6c 74 20 3d 20 49 4e 54 45 52 4e 41  result = INTERNA
21c0: 4c 5f 45 52 52 4f 52 3b 0a 09 09 09 09 2f 2f 20  L_ERROR;.....// 
21d0: 69 6e 20 63 61 73 65 20 74 68 61 74 20 66 61 69  in case that fai
21e0: 6c 73 20 2d 20 69 6e 66 6f 72 6d 20 64 65 66 61  ls - inform defa
21f0: 75 6c 74 20 72 65 63 69 70 69 65 6e 74 0a 09 09  ult recipient...
2200: 09 09 69 66 20 6c 65 74 20 45 72 72 28 65 72 72  ..if let Err(err
2210: 29 20 3d 20 73 65 6c 66 2e 74 67 2e 64 65 62 75  ) = self.tg.debu
2220: 67 28 26 66 6f 72 6d 61 74 21 28 22 53 65 6e 64  g(&format!("Send
2230: 69 6e 67 20 65 6d 61 69 6c 73 20 66 61 69 6c 65  ing emails faile
2240: 64 3a 5c 6e 7b 65 72 72 3a 3f 7d 22 29 29 2e 61  d:\n{err:?}")).a
2250: 77 61 69 74 20 7b 0a 09 09 09 09 09 2f 2f 20 69  wait {......// i
2260: 6e 20 63 61 73 65 20 74 68 61 74 20 61 6c 73 6f  n case that also
2270: 20 66 61 69 6c 73 20 2d 20 77 72 69 74 65 20 73   fails - write s
2280: 6f 6d 65 20 6c 6f 67 73 20 61 6e 64 20 62 61 69  ome logs and bai
2290: 6c 0a 09 09 09 09 09 65 70 72 69 6e 74 6c 6e 21  l......eprintln!
22a0: 28 22 7b 65 72 72 3a 3f 7d 22 29 3b 0a 09 09 09  ("{err:?}");....
22b0: 09 7d 3b 0a 09 09 09 7d 3b 0a 09 09 7d 29 3b 0a  .};....};...});.
22c0: 09 09 2f 2f 20 63 6c 65 61 72 20 2d 20 6a 75 73  ..// clear - jus
22d0: 74 20 69 6e 20 63 61 73 65 0a 09 09 73 65 6c 66  t in case...self
22e0: 2e 64 61 74 61 20 3d 20 76 65 63 21 5b 5d 3b 0a  .data = vec![];.
22f0: 09 09 73 65 6c 66 2e 68 65 61 64 65 72 73 20 3d  ..self.headers =
2300: 20 4e 6f 6e 65 3b 0a 09 09 72 65 73 75 6c 74 0a   None;...result.
2310: 09 7d 0a 7d 0a                                   .}.}.