///|
/// Content-Disposition disposition type (RFC 2183).
pub(all) enum Disposition {
Inline
Attachment
} derive(Eq, Debug)
///|
pub fn Disposition::to_string(self : Disposition) -> String {
match self {
Inline => "inline"
Attachment => "attachment"
}
}
///|
pub impl Show for Disposition with fn output(self, logger) {
logger.write_string(self.to_string())
}
///|
/// Build a `Content-Disposition` header value. The filename is sanitized
/// (MM_INJ_003); ASCII filenames use `filename="..."`, non-ASCII filenames use
/// RFC 2231 extended notation `filename*=utf-8''...` (MM_MIME_006).
pub fn make_disposition(
disposition : Disposition,
filename : String,
) -> String raise MailFailure {
let safe = sanitize_filename(filename)
reject_crlf(safe, "filename")
let buf = Buffer::Buffer()
buf.write_string_utf16le(disposition.to_string())
if !safe.is_empty() {
if is_pure_ascii(safe) {
buf.write_string_utf16le("; filename=\"\{safe}\"")
} else {
buf.write_string_utf16le("; filename*=utf-8''\{rfc2231_encode(safe)}")
}
}
buf.to_string()
}
///|
/// Percent-encode a UTF-8 filename per RFC 2231 section 4.
fn rfc2231_encode(s : String) -> String {
let bytes = string_to_bytes(s)
let out = FixedArray::make(bytes.length() * 3, b'\x00')
let mut j = 0
for b in bytes {
let c = b.to_int()
let safe = (c >= 0x30 && c <= 0x39) ||
(c >= 0x41 && c <= 0x5A) ||
(c >= 0x61 && c <= 0x7A) ||
c == 0x2D ||
c == 0x2E ||
c == 0x5F
if safe {
out[j] = b
j += 1
} else {
out[j] = b'%'
out[j + 1] = to_hex_upper(c >> 4)
out[j + 2] = to_hex_upper(c & 0xf)
j += 3
}
}
bytes_to_string(Bytes::from_iter(out.iter())[0:j].to_owned())
}