summaryrefslogtreecommitdiff
path: root/src/rfc822.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/rfc822.rs')
-rw-r--r--src/rfc822.rs365
1 files changed, 166 insertions, 199 deletions
diff --git a/src/rfc822.rs b/src/rfc822.rs
index 658b167..a8fa5c3 100644
--- a/src/rfc822.rs
+++ b/src/rfc822.rs
@@ -1,14 +1,15 @@
use chrono::DateTime;
-use mailparse::{addrparse_header, body::Body, dateparse, DispositionType, ParsedMail};
-
-use crate::error::{Error, Result};
-use crate::pb3::jwebmail::mimeheader::ContentDisposition::*;
-use crate::pb3::jwebmail::{
- mail_body::Multipart, mail_header::MailAddr, ListMailHeader, MIMEHeader, MIMEPart, Mail,
- MailBody, MailHeader,
+use maildir::MailEntryError;
+use mailparse::{
+ addrparse_header, body::Body, dateparse, DispositionType, MailParseError, ParsedMail,
};
-fn parse_mail_addrs(inp: &mailparse::MailHeader) -> Result<Vec<MailAddr>> {
+use crate::de_jmhoffmann_jwebmail_mailstorage::MIMEHeader_content_dispo as CD;
+use crate::de_jmhoffmann_jwebmail_mailstorage::*;
+
+fn parse_mail_addrs(
+ inp: &mailparse::MailHeader,
+) -> std::result::Result<Vec<MailAddr>, MailParseError> {
let mut mal = addrparse_header(inp)?;
Ok(mal
@@ -17,17 +18,16 @@ fn parse_mail_addrs(inp: &mailparse::MailHeader) -> Result<Vec<MailAddr>> {
mailparse::MailAddr::Group(mut g) => g
.addrs
.drain(..)
- .map(|s| {
- let mut r = MailAddr::new();
- r.name = Some(s.display_name.unwrap_or_default());
- r.address = s.addr;
- r
+ .map(|s| MailAddr {
+ name: Some(s.display_name.unwrap_or_default()),
+ address: s.addr,
})
.collect(),
mailparse::MailAddr::Single(s) => {
- let mut addr = MailAddr::new();
- addr.name = Some(s.display_name.unwrap_or_default());
- addr.address = s.addr;
+ let addr = MailAddr {
+ name: Some(s.display_name.unwrap_or_default()),
+ address: s.addr,
+ };
vec![addr]
}
})
@@ -44,43 +44,44 @@ fn get_received(me: &mut maildir::MailEntry) -> i64 {
})
}
-pub fn me_to_lmh(mut me: maildir::MailEntry) -> Result<ListMailHeader> {
- let mut lmh = ListMailHeader::new();
- lmh.byte_size = me.path().metadata()?.len();
- lmh.unread = !me.is_seen();
- lmh.rec_date = DateTime::from_timestamp(get_received(&mut me), 0)
- .unwrap()
- .to_rfc3339();
- lmh.mid = me.id().to_owned();
- lmh.header = Some(parse_mail_header(&me.parsed()?)?).into();
+pub fn me_to_lmh(
+ mut me: maildir::MailEntry,
+) -> std::result::Result<ListMailHeader, MailEntryError> {
+ let lmh = ListMailHeader {
+ byte_size: me.path().metadata()?.len() as i64,
+ unread: !me.is_seen(),
+ rec_date: DateTime::from_timestamp(get_received(&mut me), 0)
+ .unwrap()
+ .to_rfc3339(),
+ mid: me.id().to_owned(),
+ header: parse_mail_header(&me.parsed()?)?,
+ };
Ok(lmh)
}
-pub fn parse_mail_content(v: &ParsedMail) -> Result<MIMEHeader> {
- let mut c = MIMEHeader::new();
-
- {
- let mut val = v.ctype.mimetype.clone();
- if let Some(i) = val.find(';') {
- val.truncate(i);
- }
- let j = val.find('/').unwrap();
- c.subtype = val.split_off(j + 1);
- val.pop();
- c.maintype = val;
+pub fn parse_mail_content(v: &ParsedMail) -> MIMEHeader {
+ let mut val = v.ctype.mimetype.clone();
+ if let Some(i) = val.find(';') {
+ val.truncate(i);
}
+ let j = val.find('/').unwrap();
+ let subtype = val.split_off(j + 1);
+ val.pop();
+ let maintype = val;
+
+ let mut file_name = None;
- match v.get_content_disposition().disposition {
- DispositionType::Inline => c.contentdispo = CONTENT_DISPOSITION_INLINE.into(),
+ let cd = match v.get_content_disposition().disposition {
+ DispositionType::Inline => CD::inline,
DispositionType::Attachment => {
- c.contentdispo = CONTENT_DISPOSITION_ATTACHMENT.into();
if let Some(fname) = v.get_content_disposition().params.remove("filename") {
- c.file_name = Some(fname);
+ file_name = Some(fname);
}
+ CD::attachment
}
- _ => {}
- }
+ _ => CD::none,
+ };
for h in &v.headers {
let mut key = h.get_key();
@@ -89,29 +90,44 @@ pub fn parse_mail_content(v: &ParsedMail) -> Result<MIMEHeader> {
key.make_ascii_lowercase();
if key == "filename" {
- c.file_name = Some(val);
+ file_name = Some(val);
}
}
- Ok(c)
+ MIMEHeader {
+ mime_type: MIMEHeader_mime_type {
+ main_type: maintype,
+ sub_type: subtype,
+ },
+ content_dispo: cd,
+ file_name,
+ }
}
-fn parse_mail_header(pm: &ParsedMail) -> Result<MailHeader> {
+fn parse_mail_header(pm: &ParsedMail) -> std::result::Result<MailHeader, MailParseError> {
let v = &pm.headers;
- let mut mh = MailHeader::new();
- let mut mimeh = MIMEHeader::new();
-
- {
- let mut val = pm.ctype.mimetype.clone();
- if let Some(i) = val.find(';') {
- val.truncate(i);
- }
- let j = val.find('/').unwrap();
- mimeh.subtype = val.split_off(j + 1);
- val.pop();
- mimeh.maintype = val;
+ let mut val = pm.ctype.mimetype.clone();
+ if let Some(i) = val.find(';') {
+ val.truncate(i);
}
+ let j = val.find('/').unwrap();
+ let sub_type = val.split_off(j + 1);
+ val.pop();
+ let main_type = val;
+
+ let mut file_name = None;
+ let mut content_dispo = CD::none;
+ let mut cc = vec![];
+ let mut bcc = vec![];
+ let mut comments = vec![];
+ let mut keywords = vec![];
+ let mut reply_to = vec![];
+ let mut written_from = vec![];
+ let mut send_to = vec![];
+ let mut subject = String::new();
+ let mut sender = None;
+ let mut send_date = String::new();
let mut key = String::new();
@@ -123,102 +139,130 @@ fn parse_mail_header(pm: &ParsedMail) -> Result<MailHeader> {
match key.as_str() {
"date" => {
- mh.send_date = DateTime::from_timestamp(dateparse(&val)?, 0)
+ send_date = DateTime::from_timestamp(dateparse(&val)?, 0)
.unwrap()
.to_rfc3339()
}
"from" => {
- if !mh.written_from.is_empty() {
- return Err(Error::SortOrder("from already set".into()));
+ if !written_from.is_empty() {
+ const FROM_MULTIPLE_TIMES_ERROR: &str = "from already set";
+ return Err(MailParseError::Generic(FROM_MULTIPLE_TIMES_ERROR));
}
- mh.written_from = parse_mail_addrs(y)?
+ written_from = parse_mail_addrs(y)?
}
- "sender" => mh.sender = parse_mail_addrs(y)?.drain(0..1).next().into(),
- "reply-to" => mh.reply_to = parse_mail_addrs(y)?,
- "to" => mh.send_to = parse_mail_addrs(y)?,
- "cc" => mh.cc = parse_mail_addrs(y)?,
- "bcc" => mh.bcc = parse_mail_addrs(y)?,
+ "sender" => sender = parse_mail_addrs(y)?.drain(0..1).next(),
+ "reply-to" => reply_to = parse_mail_addrs(y)?,
+ "to" => send_to = parse_mail_addrs(y)?,
+ "cc" => cc = parse_mail_addrs(y)?,
+ "bcc" => bcc = parse_mail_addrs(y)?,
"subject" => {
- mh.subject = val;
+ subject = val;
}
"comments" => {
- mh.comments.push(val);
+ comments.push(val);
}
"keywords" => {
- mh.keywords.push(val);
+ keywords.push(val);
}
"mime-version" => {
strip_comments(&mut val);
if val.trim() != "1.0" {
- return Err(Error::MailEntryError(maildir::MailEntryError::DateError(
- "unknown mime version",
- )));
+ const UNKNOWN_MIME_VERSION_ERROR: &str = "unknown mime version";
+ return Err(MailParseError::Generic(UNKNOWN_MIME_VERSION_ERROR));
}
}
"content-disposition" => {
let cd = val.to_ascii_lowercase();
match cd.as_ref() {
- "inline" => mimeh.contentdispo = CONTENT_DISPOSITION_INLINE.into(),
- "attachment" => mimeh.contentdispo = CONTENT_DISPOSITION_ATTACHMENT.into(),
+ "inline" => content_dispo = CD::inline,
+ "attachment" => content_dispo = CD::attachment,
_ => {}
};
}
"filename" => {
- mimeh.file_name = Some(val);
+ file_name = Some(val);
}
_ => {}
};
key.clear();
}
- mh.mime = Some(mimeh).into();
- Ok(mh)
+ Ok(MailHeader {
+ written_from,
+ sender,
+ send_to,
+ cc,
+ bcc,
+ reply_to,
+ subject,
+ send_date,
+ keywords,
+ comments,
+ mime: MIMEHeader {
+ mime_type: MIMEHeader_mime_type {
+ main_type,
+ sub_type,
+ },
+ content_dispo,
+ file_name,
+ },
+ })
}
-fn parse_mail_body(pm: &ParsedMail) -> Result<MailBody> {
+fn parse_mail_body(pm: &ParsedMail) -> std::result::Result<MailBody, MailParseError> {
let body = if pm.ctype.mimetype.starts_with("message/") {
- let mut mb = MailBody::new();
- mb.set_mail(parsed_mail_to_mail(mailparse::parse_mail(
- pm.get_body()?.as_ref(),
- )?)?);
- mb
+ MailBody {
+ mail: Some(Box::new(parsed_mail_to_mail(mailparse::parse_mail(
+ pm.get_body()?.as_ref(),
+ )?)?)),
+ discrete: None,
+ multipart: None,
+ }
} else if pm.subparts.is_empty() && pm.ctype.mimetype.starts_with("text/") {
- let mut mb = MailBody::new();
- mb.set_discrete(pm.get_body()?);
- mb
+ MailBody {
+ discrete: Some(pm.get_body()?),
+ multipart: None,
+ mail: None,
+ }
} else if pm.subparts.is_empty() {
- let b = match pm.get_body_encoded() {
- Body::Base64(eb) => {
- let db = eb.get_raw();
- if db.len() < 512 * 1024 {
- String::from_utf8_lossy(db).into_owned()
- } else {
- String::new()
+ MailBody {
+ discrete: Some(match pm.get_body_encoded() {
+ Body::Base64(eb) => {
+ let db = eb.get_raw();
+ if db.len() < 512 * 1024 {
+ String::from_utf8_lossy(db).into_owned()
+ } else {
+ String::new()
+ }
}
- }
- Body::SevenBit(eb) => eb.get_as_string()?,
- Body::QuotedPrintable(eb) => eb.get_decoded_as_string()?,
- _ => todo!(),
- };
- let mut mb = MailBody::new();
- mb.set_discrete(b);
- mb
+ Body::SevenBit(eb) => eb.get_as_string()?,
+ Body::QuotedPrintable(eb) => eb.get_decoded_as_string()?,
+ _ => todo!(),
+ }),
+ multipart: None,
+ mail: None,
+ }
} else {
- let mut mb = MailBody::new();
- let mut mp = Multipart::new();
- mp.parts = pm
- .subparts
- .iter()
- .map(|part| -> Result<MIMEPart> {
- let mut mp = MIMEPart::new();
- mp.mime_header = Some(parse_mail_content(part)?).into();
- mp.body = Some(parse_mail_body(part)?).into();
- Ok(mp)
- })
- .filter_map(|p| p.ok())
- .collect();
- mb.set_multipart(mp);
- mb
+ let mp = Multipart {
+ parts: pm
+ .subparts
+ .iter()
+ .map(|part| -> std::result::Result<MIMEPart, MailParseError> {
+ Ok(MIMEPart {
+ mime_header: parse_mail_content(part),
+ body: parse_mail_body(part)?,
+ })
+ })
+ .filter_map(|p| p.ok())
+ .collect(),
+ preamble: None,
+ epilogue: None,
+ };
+ MailBody {
+ multipart: Some(mp),
+ discrete: None,
+ mail: None,
+ }
};
Ok(body)
}
@@ -316,86 +360,9 @@ fn strip_comments(s: &mut String) {
}
}
-pub fn parsed_mail_to_mail(pm: ParsedMail) -> Result<Mail> {
- let mut m = Mail::new();
- m.head = Some(parse_mail_header(&pm)?).into();
- m.body = Some(parse_mail_body(&pm)?).into();
-
- Ok(m)
-}
-
-/*
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn comment() {
- let mut x = r#"(this is ((some) text)) a "some text with (comment \" in) quotes)(" (example) \( included) (xx)b()"#.to_owned();
- strip_comments(&mut x);
- assert_eq!(
- &x,
- r#" a "some text with (comment \" in) quotes)(" \( included) b"#
- );
- }
-
- #[test]
- fn unclosed_comment() {
- let mut x = "(this is (some text) example b".to_owned();
- strip_comments(&mut x);
- assert_eq!(&x, "(this is example b");
- }
-
- #[test]
- fn find_first_pair() {
- let mut r = find_pair(0, "abc def");
- assert_eq!(r, None);
-
- r = find_pair(0, "abc ( def");
- assert_eq!(r, None);
-
- r = find_pair(0, "abc ) def");
- assert_eq!(r, None);
-
- let s = "(abc) def";
- if let Some(i) = find_pair(0, s) {
- assert_eq!(i, 0..5);
- assert_eq!(&s[i], "(abc)");
- } else {
- assert!(false, "Got None expected Some!");
- }
-
- let s = "abc (def) ghi";
- if let Some(i) = find_pair(0, s) {
- assert_eq!(i, 4..9);
- assert_eq!(&s[i], "(def)");
- } else {
- assert!(false, "Got None expected Some!");
- }
-
- let s = "(abc (def) ghi";
- if let Some(i) = find_pair(0, s) {
- assert_eq!(i, 5..10);
- assert_eq!(&s[i], "(def)");
- } else {
- assert!(false, "Got None expected Some!");
- }
-
- let s = "abc ((def) ghi)";
- if let Some(i) = find_pair(0, s) {
- assert_eq!(i, 4..15);
- assert_eq!(&s[i], "((def) ghi)");
- } else {
- assert!(false, "Got None expected Some!");
- }
-
- let s = r#" a "some text with (comment \" in) quotes)(" (example)"#;
- if let Some(i) = find_pair(0, s) {
- assert_eq!(i, 45..54);
- assert_eq!(&s[i], "(example)");
- } else {
- assert!(false, "Got None expected Some!");
- }
- }
+pub fn parsed_mail_to_mail(pm: ParsedMail) -> std::result::Result<Mail, MailParseError> {
+ Ok(Mail {
+ head: parse_mail_header(&pm)?,
+ body: parse_mail_body(&pm)?,
+ })
}
-*/