f5ed284f8c 2025-06-21 1: use crate::Cursor;
f5ed284f8c 2025-06-21 2:
85fa6bddaa 2026-01-18 3: use std::borrow::Cow;
85fa6bddaa 2026-01-18 4:
85fa6bddaa 2026-01-18 5: use html_escape::encode_text;
f5ed284f8c 2025-06-21 6: use lazy_static::lazy_static;
f5ed284f8c 2025-06-21 7: use regex::Regex;
0f47e23e21 2026-01-12 8: use stacked_errors::{
0f47e23e21 2026-01-12 9: bail,
0f47e23e21 2026-01-12 10: Result,
0f47e23e21 2026-01-12 11: };
f5ed284f8c 2025-06-21 12:
f5ed284f8c 2025-06-21 13: lazy_static! {
3c858ed7c4 2026-07-31 14: pub static ref RE_DOMAIN: Regex = Regex::new(r"^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$").expect("Invalid domain regex");
3c858ed7c4 2026-07-31 15: pub static ref RE_CLOSING: Regex = Regex::new(r"</[ \t]*(pre|code)[ \t]*>").expect("Invalid cloding tag regex");
f5ed284f8c 2025-06-21 16: }
f5ed284f8c 2025-06-21 17:
3c858ed7c4 2026-07-31 18: /// Stores binary attachment data and metadata for Telegram messages.
3c858ed7c4 2026-07-31 19: /// The data is wrapped in a `Cursor<Vec<u8>>` for efficient streaming,
3c858ed7c4 2026-07-31 20: /// while `name` holds the filename or display name of the attachment.
f5ed284f8c 2025-06-21 21: #[derive(Debug)]
f5ed284f8c 2025-06-21 22: pub struct Attachment {
f5ed284f8c 2025-06-21 23: pub data: Cursor<Vec<u8>>,
f5ed284f8c 2025-06-21 24: pub name: String,
0f47e23e21 2026-01-12 25: }
0f47e23e21 2026-01-12 26:
dafeec0481 2026-01-18 27: /// Pass any text here to be validated as not breaking from Telegram preformatted blocks
85fa6bddaa 2026-01-18 28: /// escape all HTML chars afterwards
3c858ed7c4 2026-07-31 29: pub fn validate <'a>(text: &'a str) -> Result<Cow<'a, str>> {
dafeec0481 2026-01-18 30: if RE_CLOSING.is_match(text) {
dafeec0481 2026-01-18 31: bail!("Telegram closing tag found.");
dafeec0481 2026-01-18 32: } else {
85fa6bddaa 2026-01-18 33: Ok(encode_text(text))
dafeec0481 2026-01-18 34: }
f5ed284f8c 2025-06-21 35: }