Annotation For src/main.rs
Logged in as anonymous

Origin for each line in src/main.rs from check-in 61238a3618:

7620f854a7 2024-05-21    1: use anyhow::Result;
7620f854a7 2024-05-21    2: use async_std::task;
7620f854a7 2024-05-21    3: use samotop::{
7620f854a7 2024-05-21    4: 	mail::{
7620f854a7 2024-05-21    5: 		Builder,
7620f854a7 2024-05-21    6: 		DebugService,
7620f854a7 2024-05-21    7: 		MailDir,
7620f854a7 2024-05-21    8: 		Name
7620f854a7 2024-05-21    9: 	},
7620f854a7 2024-05-21   10: 	smtp::Prudence,
7620f854a7 2024-05-21   11: };
7620f854a7 2024-05-21   12: use telegram_bot::{
7620f854a7 2024-05-21   13: 	Api,
7620f854a7 2024-05-21   14: 	ParseMode,
7620f854a7 2024-05-21   15: 	SendMessage,
7620f854a7 2024-05-21   16: 	UserId,
7620f854a7 2024-05-21   17: };
7620f854a7 2024-05-21   18: 
7620f854a7 2024-05-21   19: use std::{
7620f854a7 2024-05-21   20: 	borrow::Cow,
61238a3618 2024-05-22   21: 	collections::{
61238a3618 2024-05-22   22: 		HashMap,
61238a3618 2024-05-22   23: 		HashSet,
61238a3618 2024-05-22   24: 	},
7620f854a7 2024-05-21   25: 	io::Read,
7620f854a7 2024-05-21   26: 	path::{
7620f854a7 2024-05-21   27: 		Path,
7620f854a7 2024-05-21   28: 		PathBuf
7620f854a7 2024-05-21   29: 	},
7620f854a7 2024-05-21   30: 	time::Duration,
7620f854a7 2024-05-21   31: 	vec::Vec,
7620f854a7 2024-05-21   32: };
7620f854a7 2024-05-21   33: 
61238a3618 2024-05-22   34: fn address_into_iter<'a>(addr: &'a mail_parser::Address<'a, >) -> impl Iterator<Item = Cow<'a, str>> {
61238a3618 2024-05-22   35: 	addr.clone().into_list().into_iter().map(|a| a.address.unwrap())
61238a3618 2024-05-22   36: }
7620f854a7 2024-05-21   37: 
61238a3618 2024-05-22   38: fn relay_mails(maildir: &Path, core: &TelegramTransport) -> Result<()> {
7620f854a7 2024-05-21   39: 	let new_dir = maildir.join("new");
7620f854a7 2024-05-21   40: 
7620f854a7 2024-05-21   41: 	std::fs::create_dir_all(&new_dir)?;
7620f854a7 2024-05-21   42: 
7620f854a7 2024-05-21   43: 	let files = std::fs::read_dir(new_dir)?;
7620f854a7 2024-05-21   44: 	for file in files {
7620f854a7 2024-05-21   45: 		let file = file?;
7620f854a7 2024-05-21   46: 		let mut buf = Vec::new();
7620f854a7 2024-05-21   47: 		std::fs::File::open(file.path())?.read_to_end(&mut buf)?;
7620f854a7 2024-05-21   48: 
7620f854a7 2024-05-21   49: 		task::block_on(async move {
61238a3618 2024-05-22   50: 			match mail_parser::MessageParser::default().parse(&buf[..]) {
7620f854a7 2024-05-21   51: 				Some(mail) => {
61238a3618 2024-05-22   52: 					let mail = mail.clone();
61238a3618 2024-05-22   53: 
61238a3618 2024-05-22   54: 					// Fetching address lists from fields we know
61238a3618 2024-05-22   55: 					let mut to = HashSet::new();
61238a3618 2024-05-22   56: 					if let Some(addr) = mail.to() {
61238a3618 2024-05-22   57: 						let _ = address_into_iter(addr).map(|x| to.insert(x));
61238a3618 2024-05-22   58: 					};
61238a3618 2024-05-22   59: 					if let Some(addr) = mail.header("X-Samotop-To") {
61238a3618 2024-05-22   60: 						match addr {
61238a3618 2024-05-22   61: 							mail_parser::HeaderValue::Address(addr) => {
61238a3618 2024-05-22   62: 								let _ = address_into_iter(addr).map(|x| to.insert(x));
61238a3618 2024-05-22   63: 							},
61238a3618 2024-05-22   64: 							mail_parser::HeaderValue::Text(text) => {
61238a3618 2024-05-22   65: 								to.insert(text.clone());
61238a3618 2024-05-22   66: 							},
61238a3618 2024-05-22   67: 							_ => {}
61238a3618 2024-05-22   68: 						}
61238a3618 2024-05-22   69: 					};
61238a3618 2024-05-22   70: 
61238a3618 2024-05-22   71: 					// Adding all known addresses to recipient list, for anyone else adding default
61238a3618 2024-05-22   72: 					// Also if list is empty also adding default
61238a3618 2024-05-22   73: 					let mut rcpt: HashSet<UserId> = HashSet::new();
61238a3618 2024-05-22   74: 					for item in to {
61238a3618 2024-05-22   75: 						let item = item.into_owned();
61238a3618 2024-05-22   76: 						if core.recipients.contains_key(&item) {
61238a3618 2024-05-22   77: 							rcpt.insert(core.recipients[&item]);
61238a3618 2024-05-22   78: 						} else {
61238a3618 2024-05-22   79: 							core.debug(format!("Recipient [{}] not found.", &item)).await.unwrap();
61238a3618 2024-05-22   80: 							rcpt.insert(core.default);
61238a3618 2024-05-22   81: 						}
61238a3618 2024-05-22   82: 					};
61238a3618 2024-05-22   83: 					if rcpt.is_empty() {
61238a3618 2024-05-22   84: 						rcpt.insert(core.default);
61238a3618 2024-05-22   85: 						core.debug("No recipient or envelope address.").await.unwrap();
61238a3618 2024-05-22   86: 					};
61238a3618 2024-05-22   87: 
61238a3618 2024-05-22   88: 					// prepating message header
61238a3618 2024-05-22   89: 					let mut reply: Vec<Cow<str>> = vec![];
61238a3618 2024-05-22   90: 					if let Some(subject) = mail.subject() {
61238a3618 2024-05-22   91: 						reply.push(format!("<b>Subject:</b> {}", subject).into());
61238a3618 2024-05-22   92: 					} else if let Some(thread) = mail.thread_name() {
61238a3618 2024-05-22   93: 						reply.push(format!("<b>Thread:</b> {}", thread).into());
61238a3618 2024-05-22   94: 					}
61238a3618 2024-05-22   95: 					if let Some(from) = mail.from() {
61238a3618 2024-05-22   96: 						reply.push(format!("<b>From:</b> {:?}", from).into());
61238a3618 2024-05-22   97: 					}
61238a3618 2024-05-22   98: 					if let Some(sender) = mail.sender() {
61238a3618 2024-05-22   99: 						reply.push(format!("<b>Sender:</b> {:?}", sender).into());
61238a3618 2024-05-22  100: 					}
61238a3618 2024-05-22  101: 					reply.push("".into());
61238a3618 2024-05-22  102: 					let header_size = reply.join("\n").len() + 1;
61238a3618 2024-05-22  103: 
61238a3618 2024-05-22  104: 					let html_parts = mail.html_body_count();
61238a3618 2024-05-22  105: 					let text_parts = mail.text_body_count();
61238a3618 2024-05-22  106: 					let attachments = mail.attachment_count();
61238a3618 2024-05-22  107: 					if html_parts != text_parts {
61238a3618 2024-05-22  108: 						core.debug(format!("Hm, we have {} HTML parts and {} text parts.", html_parts, text_parts)).await.unwrap();
61238a3618 2024-05-22  109: 					}
61238a3618 2024-05-22  110: 					//let mut html_num = 0;
61238a3618 2024-05-22  111: 					let mut text_num = 0;
61238a3618 2024-05-22  112: 					let mut file_num = 0;
61238a3618 2024-05-22  113: 					// let's display first html or text part as body
61238a3618 2024-05-22  114: 					let mut body = "".into();
7620f854a7 2024-05-21  115: 					/*
61238a3618 2024-05-22  116: 					 * actually I don't wanna parse that html stuff
61238a3618 2024-05-22  117: 					if html_parts > 0 {
61238a3618 2024-05-22  118: 						let text = mail.body_html(0).unwrap();
61238a3618 2024-05-22  119: 						if text.len() < 4096 - header_size {
61238a3618 2024-05-22  120: 							body = text;
61238a3618 2024-05-22  121: 							html_num = 1;
61238a3618 2024-05-22  122: 						}
61238a3618 2024-05-22  123: 					};
61238a3618 2024-05-22  124: 					*/
61238a3618 2024-05-22  125: 					if body == "" && text_parts > 0 {
61238a3618 2024-05-22  126: 						let text = mail.body_text(0).unwrap();
61238a3618 2024-05-22  127: 						if text.len() < 4096 - header_size {
61238a3618 2024-05-22  128: 							body = text;
61238a3618 2024-05-22  129: 							text_num = 1;
61238a3618 2024-05-22  130: 						}
7620f854a7 2024-05-21  131: 					};
61238a3618 2024-05-22  132: 					reply.push(body);
61238a3618 2024-05-22  133: 
61238a3618 2024-05-22  134: 					// and let's coillect all other attachment parts
61238a3618 2024-05-22  135: 					let mut files_to_send = vec![];
61238a3618 2024-05-22  136: 					/*
61238a3618 2024-05-22  137: 					 * let's just skip html parts for now, they just duplicate text?
61238a3618 2024-05-22  138: 					while html_num < html_parts {
61238a3618 2024-05-22  139: 						files_to_send.push(mail.html_part(html_num).unwrap());
61238a3618 2024-05-22  140: 						html_num += 1;
61238a3618 2024-05-22  141: 					}
7620f854a7 2024-05-21  142: 					*/
61238a3618 2024-05-22  143: 					while text_num < text_parts {
61238a3618 2024-05-22  144: 						files_to_send.push(mail.text_part(text_num).unwrap());
61238a3618 2024-05-22  145: 						text_num += 1;
61238a3618 2024-05-22  146: 					}
61238a3618 2024-05-22  147: 					while file_num < attachments {
61238a3618 2024-05-22  148: 						files_to_send.push(mail.attachment(file_num).unwrap());
61238a3618 2024-05-22  149: 						file_num += 1;
61238a3618 2024-05-22  150: 					}
61238a3618 2024-05-22  151: 
61238a3618 2024-05-22  152: 					for chat in rcpt {
61238a3618 2024-05-22  153: 						core.send(chat, reply.join("\n")).await.unwrap();
61238a3618 2024-05-22  154: 						for chunk in &files_to_send {
61238a3618 2024-05-22  155: 							task::sleep(Duration::from_secs(5)).await;
61238a3618 2024-05-22  156: 							let data = chunk.contents().to_vec();
61238a3618 2024-05-22  157: 							let obj = telegram_bot::types::InputFileUpload::with_data(data, "Attachment");
61238a3618 2024-05-22  158: 							core.sendfile(chat, obj).await.unwrap();
61238a3618 2024-05-22  159: 						}
61238a3618 2024-05-22  160: 					}
7620f854a7 2024-05-21  161: 				},
7620f854a7 2024-05-21  162: 				None => { core.debug("None mail.").await.unwrap(); },
7620f854a7 2024-05-21  163: 				//send_to_sendgrid(mail, sendgrid_api_key).await;
7620f854a7 2024-05-21  164: 			};
7620f854a7 2024-05-21  165: 		});
7620f854a7 2024-05-21  166: 
7620f854a7 2024-05-21  167: 		std::fs::remove_file(file.path())?;
7620f854a7 2024-05-21  168: 	}
7620f854a7 2024-05-21  169: 	Ok(())
7620f854a7 2024-05-21  170: }
7620f854a7 2024-05-21  171: 
7620f854a7 2024-05-21  172: fn my_prudence() -> Prudence {
7620f854a7 2024-05-21  173: 	Prudence::default().with_read_timeout(Duration::from_secs(60)).with_banner_delay(Duration::from_secs(1))
7620f854a7 2024-05-21  174: }
7620f854a7 2024-05-21  175: 
61238a3618 2024-05-22  176: pub struct TelegramTransport {
7620f854a7 2024-05-21  177: 	default: UserId,
7620f854a7 2024-05-21  178: 	tg: Api,
7620f854a7 2024-05-21  179: 	recipients: HashMap<String, UserId>,
7620f854a7 2024-05-21  180: }
7620f854a7 2024-05-21  181: 
61238a3618 2024-05-22  182: impl TelegramTransport {
61238a3618 2024-05-22  183: 	pub fn new(settings: &config::Config) -> TelegramTransport {
7620f854a7 2024-05-21  184: 		let api_key = settings.get_string("api_key").unwrap();
7620f854a7 2024-05-21  185: 		let tg = Api::new(api_key);
61238a3618 2024-05-22  186: 		let default_recipient = settings.get_string("default").unwrap();
61238a3618 2024-05-22  187: 		let recipients: HashMap<String, UserId> = settings.get_table("recipients").unwrap().into_iter().map(|(a, b)| (a, UserId::new(b.into_int().unwrap()))).collect();
61238a3618 2024-05-22  188: 		// Barf if no default
7620f854a7 2024-05-21  189: 		let default = recipients[&default_recipient];
7620f854a7 2024-05-21  190: 
61238a3618 2024-05-22  191: 		TelegramTransport {
7620f854a7 2024-05-21  192: 			default,
7620f854a7 2024-05-21  193: 			tg,
7620f854a7 2024-05-21  194: 			recipients,
61238a3618 2024-05-22  195: 		}
7620f854a7 2024-05-21  196: 	}
7620f854a7 2024-05-21  197: 
7620f854a7 2024-05-21  198: 	pub async fn debug<'b, S>(&self, msg: S) -> Result<()>
7620f854a7 2024-05-21  199: 	where S: Into<Cow<'b, str>> {
7620f854a7 2024-05-21  200: 		self.tg.send(SendMessage::new(self.default, msg)
61238a3618 2024-05-22  201: 			.parse_mode(ParseMode::Html)).await?;
61238a3618 2024-05-22  202: 		Ok(())
61238a3618 2024-05-22  203: 	}
61238a3618 2024-05-22  204: 
61238a3618 2024-05-22  205: 	pub async fn send<'b, S>(&self, to: UserId, msg: S) -> Result<()>
61238a3618 2024-05-22  206: 	where S: Into<Cow<'b, str>> {
61238a3618 2024-05-22  207: 		self.tg.send(SendMessage::new(to, msg)
61238a3618 2024-05-22  208: 			.parse_mode(ParseMode::Html)).await?;
7620f854a7 2024-05-21  209: 		Ok(())
7620f854a7 2024-05-21  210: 	}
7620f854a7 2024-05-21  211: 
61238a3618 2024-05-22  212: 	pub async fn sendfile<V>(&self, to: UserId, chunk: V) -> Result<()>
61238a3618 2024-05-22  213: 	where V: Into<telegram_bot::InputFile> {
61238a3618 2024-05-22  214: 		self.tg.send(telegram_bot::SendDocument::new(to, chunk)).await?;
7620f854a7 2024-05-21  215: 		Ok(())
7620f854a7 2024-05-21  216: 	}
7620f854a7 2024-05-21  217: }
7620f854a7 2024-05-21  218: 
7620f854a7 2024-05-21  219: #[async_std::main]
7620f854a7 2024-05-21  220: async fn main() {
7620f854a7 2024-05-21  221: 	let settings: config::Config = config::Config::builder()
7620f854a7 2024-05-21  222: 		.add_source(config::File::with_name("smtp2tg.toml"))
7620f854a7 2024-05-21  223: 		.build().unwrap();
7620f854a7 2024-05-21  224: 
61238a3618 2024-05-22  225: 	let core = TelegramTransport::new(&settings);
7620f854a7 2024-05-21  226: 	let maildir: PathBuf = settings.get_string("maildir").unwrap().into();
7620f854a7 2024-05-21  227: 	let listen_on = settings.get_string("listen_on").unwrap();
7620f854a7 2024-05-21  228: 	let sink = Builder + Name::new("smtp2tg") + DebugService +
7620f854a7 2024-05-21  229: 		samotop::smtp::Esmtp.with(samotop::smtp::SmtpParser) + my_prudence() +
61238a3618 2024-05-22  230: 		//TelegramTransport::new(&settings);
7620f854a7 2024-05-21  231: 		MailDir::new(maildir.clone()).unwrap();
7620f854a7 2024-05-21  232: 
7620f854a7 2024-05-21  233: 	task::spawn(async move {
7620f854a7 2024-05-21  234: 		loop {
7620f854a7 2024-05-21  235: 			relay_mails(&maildir, &core).unwrap();
61238a3618 2024-05-22  236: 			task::sleep(Duration::from_secs(5)).await;
7620f854a7 2024-05-21  237: 		}
7620f854a7 2024-05-21  238: 	});
7620f854a7 2024-05-21  239: 
7620f854a7 2024-05-21  240: 	match listen_on.as_str() {
7620f854a7 2024-05-21  241: 		"socket" => samotop::server::UnixServer::on("./smtp2tg.sock")
7620f854a7 2024-05-21  242: 			.serve(sink.build()).await.unwrap(),
7620f854a7 2024-05-21  243: 		_ => samotop::server::TcpServer::on(listen_on)
7620f854a7 2024-05-21  244: 			.serve(sink.build()).await.unwrap(),
7620f854a7 2024-05-21  245: 	};
7620f854a7 2024-05-21  246: }