Initial commit

This commit is contained in:
Maurus Decimus
2026-05-29 18:02:15 +02:00
commit 576073f8c9
263 changed files with 78638 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
use crate::error::Error;
pub fn imap_internaldate_to_rfc3339(s: &str) -> Result<String, Error> {
let s = s.trim_start_matches(' ').trim_end();
let (day, rest) = s
.split_once('-')
.ok_or_else(|| Error::Partial(format!("INTERNALDATE: missing day in {s:?}")))?;
let (mon, rest) = rest
.split_once('-')
.ok_or_else(|| Error::Partial(format!("INTERNALDATE: missing month in {s:?}")))?;
let (year, rest) = rest
.split_once(' ')
.ok_or_else(|| Error::Partial(format!("INTERNALDATE: missing year in {s:?}")))?;
let (time, zone) = rest
.split_once(' ')
.ok_or_else(|| Error::Partial(format!("INTERNALDATE: missing zone in {s:?}")))?;
let (h, ms) = time
.split_once(':')
.ok_or_else(|| Error::Partial(format!("INTERNALDATE: bad time {time:?}")))?;
let (m, sec) = ms
.split_once(':')
.ok_or_else(|| Error::Partial(format!("INTERNALDATE: bad time {time:?}")))?;
let day: u32 = day
.trim()
.parse()
.map_err(|e| Error::Partial(format!("INTERNALDATE day {day:?}: {e}")))?;
let mon_idx = month_to_num(mon)?;
let year: i32 = year
.parse()
.map_err(|e| Error::Partial(format!("INTERNALDATE year {year:?}: {e}")))?;
let h: u32 = h
.parse()
.map_err(|e| Error::Partial(format!("INTERNALDATE hour {h:?}: {e}")))?;
let m: u32 = m
.parse()
.map_err(|e| Error::Partial(format!("INTERNALDATE minute {m:?}: {e}")))?;
let sec: u32 = sec
.parse()
.map_err(|e| Error::Partial(format!("INTERNALDATE second {sec:?}: {e}")))?;
let (sign, hh, mm) = parse_zone(zone)?;
let mut out = String::with_capacity(32);
use std::fmt::Write;
let _ = write!(
&mut out,
"{year:04}-{mon_idx:02}-{day:02}T{h:02}:{m:02}:{sec:02}"
);
if hh == 0 && mm == 0 {
out.push('Z');
} else {
let _ = write!(&mut out, "{sign}{hh:02}:{mm:02}");
}
Ok(out)
}
fn month_to_num(s: &str) -> Result<u32, Error> {
let m = match s {
"Jan" => 1,
"Feb" => 2,
"Mar" => 3,
"Apr" => 4,
"May" => 5,
"Jun" => 6,
"Jul" => 7,
"Aug" => 8,
"Sep" => 9,
"Oct" => 10,
"Nov" => 11,
"Dec" => 12,
other => return Err(Error::Partial(format!("INTERNALDATE month {other:?}"))),
};
Ok(m)
}
fn parse_zone(s: &str) -> Result<(char, u32, u32), Error> {
let s = s.trim();
if s.len() != 5 {
return Err(Error::Partial(format!("INTERNALDATE zone {s:?}")));
}
let sign = s.as_bytes()[0] as char;
if sign != '+' && sign != '-' {
return Err(Error::Partial(format!("INTERNALDATE zone sign {sign}")));
}
let hh: u32 = s[1..3]
.parse()
.map_err(|e| Error::Partial(format!("INTERNALDATE zone hour: {e}")))?;
let mm: u32 = s[3..5]
.parse()
.map_err(|e| Error::Partial(format!("INTERNALDATE zone min: {e}")))?;
Ok((sign, hh, mm))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn utc_zone_becomes_z() {
assert_eq!(
imap_internaldate_to_rfc3339("17-Jul-1996 02:44:25 +0000").unwrap(),
"1996-07-17T02:44:25Z"
);
}
#[test]
fn positive_offset_preserved() {
assert_eq!(
imap_internaldate_to_rfc3339("17-Jul-1996 02:44:25 +0200").unwrap(),
"1996-07-17T02:44:25+02:00"
);
}
#[test]
fn negative_offset_preserved() {
assert_eq!(
imap_internaldate_to_rfc3339("17-Jul-1996 02:44:25 -0700").unwrap(),
"1996-07-17T02:44:25-07:00"
);
}
#[test]
fn single_digit_day_padded() {
assert_eq!(
imap_internaldate_to_rfc3339("5-Jan-2024 09:05:01 +0000").unwrap(),
"2024-01-05T09:05:01Z"
);
}
#[test]
fn leading_space_single_digit_day() {
assert_eq!(
imap_internaldate_to_rfc3339(" 5-Jan-2024 09:05:01 +0000").unwrap(),
"2024-01-05T09:05:01Z"
);
}
#[test]
fn invalid_month_errors() {
assert!(imap_internaldate_to_rfc3339("1-XYZ-2024 00:00:00 +0000").is_err());
}
#[test]
fn malformed_input_errors() {
assert!(imap_internaldate_to_rfc3339("garbage").is_err());
assert!(imap_internaldate_to_rfc3339("17-Jul-1996").is_err());
}
}