Add MIME support
- Wrap encrypted mails into a mime structure - Add 'protected headers'
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
//! CHeader struct
|
||||
//!
|
||||
//! This struct is for collecting header lines from the milter.
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::fmt;
|
||||
|
||||
pub struct CHeader {
|
||||
lines: Vec<(CString, CString)>
|
||||
}
|
||||
|
||||
impl CHeader {
|
||||
pub fn new() -> Self {
|
||||
CHeader {
|
||||
lines: Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(mut self, key: CString, value: CString) -> Self {
|
||||
self.lines.push((key, value));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn append(&mut self, key: CString, value: CString) {
|
||||
self.lines.push((key, value));
|
||||
}
|
||||
|
||||
pub fn find(&self, key: &str) -> Option<(&str, &str)> {
|
||||
let lower_key = key.to_lowercase();
|
||||
for (line_key, line_value) in self.lines.iter() {
|
||||
if let Ok(line_compare) = line_key.to_str() {
|
||||
if line_compare.to_ascii_lowercase() == lower_key {
|
||||
if let Ok(line_value_as_str) = line_value.to_str() {
|
||||
return Some(
|
||||
(line_compare, line_value_as_str)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_value_or<'ch>(&'ch self, key: &str, default: &'ch str) -> &'ch str {
|
||||
if let Some((_, value)) = self.find(key) {
|
||||
value
|
||||
} else {
|
||||
default
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_lines(&self) -> std::slice::Iter<'_, (CString, CString)> {
|
||||
self.lines.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CHeader {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", [
|
||||
self.iter_lines()
|
||||
.filter_map(|(k, v)| {
|
||||
match (k.to_str(), v.to_str()) {
|
||||
(Ok(k), Ok(v)) => Some([k, v].join(": ")),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\r\n"),
|
||||
"\r\n".to_string()]
|
||||
.join("")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use std::ffi::CString;
|
||||
use super::CHeader;
|
||||
|
||||
|
||||
#[test]
|
||||
pub fn basic_functionality() {
|
||||
let cheader = CHeader::new()
|
||||
.add(CString::new("Content-Type").unwrap(), CString::new("text/plain").unwrap())
|
||||
.add(CString::new("Content-Transfer-Encoding").unwrap(), CString::new("7bit").unwrap());
|
||||
|
||||
assert_eq!("Content-Type: text/plain\r\nContent-Transfer-Encoding: 7bit\r\n", cheader.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn find() {
|
||||
let cheader = CHeader::new()
|
||||
.add(CString::new("Content-Type").unwrap(), CString::new("text/plain").unwrap())
|
||||
.add(CString::new("Content-Transfer-Encoding").unwrap(), CString::new("7bit").unwrap());
|
||||
|
||||
let line = cheader.find("content-type");
|
||||
|
||||
assert!(line.is_some());
|
||||
|
||||
let (key, value) = line.unwrap();
|
||||
|
||||
assert_eq!("Content-Type", key);
|
||||
assert_eq!("text/plain", value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn find_none() {
|
||||
let cheader = CHeader::new()
|
||||
.add(CString::new("Content-Type").unwrap(), CString::new("text/plain").unwrap())
|
||||
.add(CString::new("Content-Transfer-Encoding").unwrap(), CString::new("7bit").unwrap());
|
||||
|
||||
let line = cheader.find("foo-bar");
|
||||
|
||||
assert!(line.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn find_with_default() {
|
||||
let cheader = CHeader::new()
|
||||
.add(CString::new("Content-Type").unwrap(), CString::new("text/plain").unwrap())
|
||||
.add(CString::new("Content-Transfer-Encoding").unwrap(), CString::new("7bit").unwrap());
|
||||
|
||||
let value = cheader.get_value_or("foo-bar", "baaz");
|
||||
|
||||
assert_eq!(value, "baaz");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user