///|
pub fn decode_header_value(value : String) -> String {
let mut out = ""
let chars : Array[Char] = []
for ch in value {
chars.push(ch)
}
let mut i = 0
while i < chars.length() {
if i + 1 < chars.length() && chars[i] == '=' && chars[i + 1] == '?' {
let parsed = try_decode_word(chars, i)
match parsed {
Some((text, next)) => {
out = out + text
i = next
}
None => {
out = out + chars[i].to_string()
i = i + 1
}
}
} else {
out = out + chars[i].to_string()
i = i + 1
}
}
out
}
///|
fn try_decode_word(chars : Array[Char], start : Int) -> (String, Int)? {
let first_q = find_char(chars, start + 2, '?')
if first_q < 0 {
return None
}
let second_q = find_char(chars, first_q + 1, '?')
if second_q < 0 {
return None
}
let end = find_encoded_end(chars, second_q + 1)
if end < 0 {
return None
}
let charset = lower_ascii(chars_to_string(chars, start + 2, first_q))
let encoding = lower_ascii(chars_to_string(chars, first_q + 1, second_q))
let payload = chars_to_string(chars, second_q + 1, end)
let decoded = if encoding == "b" {
decode_base64_text(payload)
} else if encoding == "q" {
decode_rfc2047_q(payload)
} else {
payload
}
let final_text = if charset == "utf-8" || charset == "us-ascii" {
decoded
} else {
decoded
}
Some((final_text, end + 2))
}
///|
fn find_char(chars : Array[Char], start : Int, target : Char) -> Int {
let mut i = start
while i < chars.length() {
if chars[i] == target {
return i
}
i = i + 1
}
-1
}
///|
fn find_encoded_end(chars : Array[Char], start : Int) -> Int {
let mut i = start
while i + 1 < chars.length() {
if chars[i] == '?' && chars[i + 1] == '=' {
return i
}
i = i + 1
}
-1
}
///|
fn chars_to_string(chars : Array[Char], start : Int, end : Int) -> String {
let mut out = ""
let mut i = start
while i < end {
out = out + chars[i].to_string()
i = i + 1
}
out
}
///|
fn decode_rfc2047_q(input : String) -> String {
let normalized = replace_underscores(input)
decode_quoted_printable(normalized)
}
///|
fn replace_underscores(input : String) -> String {
let mut out = ""
for ch in input {
if ch == '_' {
out = out + " "
} else {
out = out + ch.to_string()
}
}
out
}
///|
pub fn normalize_subject(value : String) -> String {
trim_ascii(decode_header_value(value))
}
///|
pub fn normalize_display_name(value : String) -> String {
remove_quotes(trim_ascii(decode_header_value(value)))
}