use super::extract::{document_to_markdown, parse_message_bytes};
const FROM_SEP: &[u8] = b"From ";
pub fn split_mbox(raw: &[u8]) -> Vec<Vec<u8>> {
let mut messages: Vec<Vec<u8>> = Vec::new();
let mut current: Vec<u8> = Vec::new();
let mut started = false;
for line in split_keep_eol(raw) {
if line_starts_with(line, FROM_SEP) {
if started && !current.is_empty() {
messages.push(std::mem::take(&mut current));
}
started = true;
current.clear();
continue; }
if !started {
started = true;
}
if is_escaped_from(line) {
current.extend_from_slice(&line[1..]);
} else {
current.extend_from_slice(line);
}
}
if !current.is_empty() {
messages.push(current);
}
messages
}
fn line_starts_with(line: &[u8], prefix: &[u8]) -> bool {
line.len() >= prefix.len() && &line[..prefix.len()] == prefix
}
fn is_escaped_from(line: &[u8]) -> bool {
let mut i = 0;
while i < line.len() && line[i] == b'>' {
i += 1;
}
i > 0 && line_starts_with(&line[i..], FROM_SEP)
}
fn split_keep_eol(raw: &[u8]) -> Vec<&[u8]> {
let mut out = Vec::new();
let mut start = 0usize;
for (i, &b) in raw.iter().enumerate() {
if b == b'\n' {
out.push(&raw[start..=i]);
start = i + 1;
}
}
if start < raw.len() {
out.push(&raw[start..]);
}
out
}
pub fn mbox_to_markdown(raw: &[u8]) -> (String, Vec<(String, Vec<u8>)>, usize) {
let messages = split_mbox(raw);
let count = messages.len();
let mut out = String::new();
let mut images: Vec<(String, Vec<u8>)> = Vec::new();
out.push_str(&format!(
"# Mailbox — {count} message{}\n\n",
if count == 1 { "" } else { "s" }
));
for (i, msg_bytes) in messages.iter().enumerate() {
let doc = parse_message_bytes(msg_bytes);
out.push_str(&format!("## Message {}\n\n", i + 1));
out.push_str(&document_to_markdown(&doc, 3));
out.push_str("\n\n");
for (name, bytes) in doc.images {
images.push((format!("msg{}_{name}", i + 1), bytes));
}
}
(out.trim().to_string(), images, count)
}