///|
/// Boundary generation for multipart messages (RFC 2046 section 5.1.1).
/// The boundary is derived from a caller-supplied seed so that rendering is
/// deterministic and reproducible in tests.
pub fn generate_boundary(seed : String) -> String {
let digest = bytes_to_hex(string_to_bytes(seed))
"=_moonmail_" + digest
}
///|
/// Characters permitted inside a boundary value: `[0-9a-zA-Z'()+_,-./:=?]`
/// (MM_MIME_003, RFC 2046).
pub fn is_valid_boundary(boundary : String) -> Bool {
if boundary.is_empty() || boundary.length() > 70 {
return false
}
for ch in boundary {
let c = ch.to_int()
let ok = (c >= 0x30 && c <= 0x39) ||
(c >= 0x41 && c <= 0x5A) ||
(c >= 0x61 && c <= 0x7A) ||
c == 0x27 ||
c == 0x28 ||
c == 0x29 ||
c == 0x2B ||
c == 0x2C ||
c == 0x2D ||
c == 0x2E ||
c == 0x2F ||
c == 0x3A ||
c == 0x3D ||
c == 0x3F ||
c == 0x5F
if !ok {
return false
}
}
true
}
///|
/// Check that `boundary` does not occur anywhere inside `body` (MM_MIME_002).
/// A boundary line is `--boundary` at the start of a line; to be safe we
/// search for `--boundary` anywhere in the body.
pub fn boundary_collides(boundary : String, body : String) -> Bool {
body.contains("--" + boundary)
}
///|
/// Generate a boundary that is valid and does not collide with `body`.
/// The seed can be reused: a counter is appended until no collision occurs.
pub fn unique_boundary(seed : String, body : String) -> String {
let mut counter = 0
let mut boundary = generate_boundary(seed)
while boundary_collides(boundary, body) {
counter += 1
boundary = generate_boundary(seed + "#\{counter}")
}
boundary
}