diff --git a/melib/src/datetime.rs b/melib/src/datetime.rs index 1d12ada21..88cf08a8c 100644 --- a/melib/src/datetime.rs +++ b/melib/src/datetime.rs @@ -50,6 +50,7 @@ pub const RFC822_FMT_WITH_TIME: &str = "%a, %e %h %Y %H:%M:%S \0"; pub const RFC822_FMT: &str = "%e %h %Y %H:%M:%S \0"; pub const DEFAULT_FMT: &str = "%a, %d %b %Y %R\0"; //"Tue May 21 13:46:22 1991\n" +//"Wed Sep 9 00:27:54 2020\n" pub const ASCTIME_FMT: &str = "%a %b %d %H:%M:%S %Y\n\0"; extern "C" { @@ -301,7 +302,7 @@ where { let s = CString::new(s)?; let mut new_tm: libc::tm = unsafe { std::mem::zeroed() }; - for fmt in &[RFC822_FMT_WITH_TIME, RFC822_FMT] { + for fmt in &[RFC822_FMT_WITH_TIME, RFC822_FMT, ASCTIME_FMT] { let fmt = unsafe { CStr::from_bytes_with_nul_unchecked(fmt.as_bytes()) }; let ret = { let _with_locale = Locale::new( diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index 29f754462..ba360707c 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -443,6 +443,65 @@ pub mod dates { } } + ///e.g Wed Sep 9 00:27:54 2020 + ///day-of-week month day time year + ///date-time = [ day-of-week "," ] date time [CFWS] + ///date = day month year + ///time = time-of-day zone + ///time-of-day = hour ":" minute [ ":" second ] + ///hour = 2DIGIT / obs-hour + ///minute = 2DIGIT / obs-minute + ///second = 2DIGIT / obs-second + pub fn mbox_date_time(input: &[u8]) -> IResult<&[u8], UnixTimestamp> { + let orig_input = input; + let mut accum: SmallVec<[u8; 32]> = SmallVec::new(); + let (input, _) = opt(cfws)(input)?; + let (input, day_of_week) = day_of_week(input)?; + let (input, _) = opt(cfws)(input)?; + let (input, month) = month(input)?; + let (input, _) = opt(cfws)(input)?; + let (input, day) = day(input)?; + let (input, _) = opt(cfws)(input)?; + let (input, hour) = take_n_digits(2)(input)?; + let (input, _) = tag(":")(input)?; + let (input, minute) = take_n_digits(2)(input)?; + let (input, second) = opt(preceded(tag(":"), take_n_digits(2)))(input)?; + let (input, _) = fws(input)?; + let (input, zone) = opt(zone)(input)?; + let (input, _) = opt(cfws)(input)?; + let (input, year) = year(input)?; + accum.extend_from_slice(&day_of_week); + accum.extend_from_slice(b", "); + accum.extend_from_slice(&day); + accum.extend_from_slice(b" "); + accum.extend_from_slice(&month); + accum.extend_from_slice(b" "); + accum.extend_from_slice(&year); + accum.extend_from_slice(b" "); + accum.extend_from_slice(&hour); + accum.extend_from_slice(b":"); + accum.extend_from_slice(&minute); + if let Some(second) = second { + accum.extend_from_slice(b":"); + accum.extend_from_slice(&second); + } + if let Some((sign, zone)) = zone { + accum.extend_from_slice(b" "); + accum.extend_from_slice(&sign); + accum.extend_from_slice(&zone); + } + match crate::datetime::rfc822_to_timestamp(accum.to_vec()) { + Ok(t) => Ok((input, t)), + Err(_err) => Err(nom::Err::Error( + ( + orig_input, + "mbox_date_time(): could not convert date from rfc822", + ) + .into(), + )), + } + } + ///`day-of-week = ([FWS] day-name) / obs-day-of-week` ///day-name = "Mon" / "Tue" / "Wed" / "Thu" / /// "Fri" / "Sat" / "Sun" @@ -490,9 +549,9 @@ pub mod dates { ///year = (FWS 4*DIGIT FWS) / obs-year fn year(input: &[u8]) -> IResult<&[u8], &[u8]> { - let (input, _) = fws(input)?; + let (input, _) = opt(fws)(input)?; let (input, ret) = take_n_digits(4)(input)?; - let (input, _) = fws(input)?; + let (input, _) = opt(fws)(input)?; Ok((input, ret)) } @@ -511,6 +570,17 @@ pub mod dates { }; Ok((rest, ret)) }) + .or_else(|_| { + let (rest, ret) = match mbox_date_time(&input) { + Ok(v) => v, + Err(_) => { + return Err(nom::Err::Error( + (input, "rfc5322_date(): invalid input").into(), + )); + } + }; + Ok((rest, ret)) + }) .map(|(_, r)| r) .map_err(|err: nom::Err>| err.into()) /* @@ -532,6 +602,8 @@ pub mod dates { assert_eq!(rfc5322_date(_s).unwrap(), rfc5322_date(__s).unwrap()); let val = b"Fri, 23 Dec 0001 21:20:36 -0800 (PST)"; assert_eq!(rfc5322_date(val).unwrap(), 0); + let val = b"Wed Sep 9 00:27:54 2020"; + assert_eq!(rfc5322_date(val).unwrap(), 1599611274); } }