melib/mbox: add MboxFormat::append() method

Add support for writing mbox files
lazy_fetch
Manos Pitsidianakis 2021-01-09 16:37:29 +02:00
parent dcccd303ac
commit 4050f6893f
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
3 changed files with 123 additions and 7 deletions

View File

@ -48,6 +48,8 @@ use std::str::FromStr;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex, RwLock};
pub mod write;
type Offset = usize;
type Length = usize;
@ -323,7 +325,7 @@ macro_rules! find_From__line {
}
impl MboxFormat {
fn parse<'i>(&self, input: &'i [u8]) -> IResult<&'i [u8], Envelope> {
pub fn parse<'i>(&self, input: &'i [u8]) -> IResult<&'i [u8], Envelope> {
let orig_input = input;
let mut input = input;
match self {
@ -649,12 +651,12 @@ pub fn mbox_parse(
Ok((&[], envelopes))
}
struct MessageIterator<'a> {
index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>,
input: &'a [u8],
file_offset: usize,
offset: usize,
format: Option<MboxFormat>,
pub struct MessageIterator<'a> {
pub index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>,
pub input: &'a [u8],
pub file_offset: usize,
pub offset: usize,
pub format: Option<MboxFormat>,
}
impl<'a> Iterator for MessageIterator<'a> {

View File

@ -0,0 +1,112 @@
/*
* meli - mailbox module.
*
* Copyright 2021 Manos Pitsidianakis
*
* This file is part of meli.
*
* meli is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* meli is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use super::*;
impl MboxFormat {
pub fn append(
&self,
writer: &mut dyn std::io::Write,
input: &[u8],
envelope_from: Option<&Address>,
delivery_date: Option<crate::UnixTimestamp>,
is_empty: bool,
crlf: bool,
) -> Result<()> {
let line_ending: &'static [u8] = if crlf { &b"\r\n"[..] } else { &b"\n"[..] };
if !is_empty {
writer.write_all(line_ending)?;
writer.write_all(line_ending)?;
}
writer.write_all(&b"From "[..])?;
if let Some(from) = envelope_from {
writer.write_all(from.address_spec_raw())?;
} else {
writer.write_all(&b"MAILER-DAEMON"[..])?;
}
writer.write_all(&b" "[..])?;
writer.write_all(
crate::datetime::timestamp_to_string(
delivery_date.unwrap_or_else(|| crate::datetime::now()),
Some(crate::datetime::ASCTIME_FMT),
true,
)
.trim()
.as_bytes(),
)?;
writer.write_all(line_ending)?;
let (mut headers, body) = parser::mail(input)?;
match self {
MboxFormat::MboxO | MboxFormat::MboxRd => Err(MeliError::new("Unimplemented.")),
MboxFormat::MboxCl => {
headers.retain(|(header_name, _)| {
!header_name.eq_ignore_ascii_case(b"Content-Length")
});
let len = (body.len()
+ body
.windows(b"\nFrom ".len())
.filter(|w| w == b"\nFrom ")
.count()
+ if body.starts_with(b"From ") { 1 } else { 0 })
.to_string();
for (h, v) in headers
.into_iter()
.chain(Some((&b"Content-Length"[..], len.as_bytes())))
{
writer.write_all(h)?;
writer.write_all(&b": "[..])?;
writer.write_all(v)?;
writer.write_all(line_ending)?;
}
writer.write_all(line_ending)?;
if body.starts_with(b"From ") {
writer.write_all(&[b'>'])?;
}
for i in 0..body.len() {
writer.write_all(&[body[i]])?;
if body[i..].starts_with(b"\nFrom ") {
writer.write_all(&[b'>'])?;
}
}
Ok(())
}
MboxFormat::MboxCl2 => {
headers.retain(|(header_name, _)| {
!header_name.eq_ignore_ascii_case(b"Content-Length")
});
let len = body.len().to_string();
for (h, v) in headers
.into_iter()
.chain(Some((&b"Content-Length"[..], len.as_bytes())))
{
writer.write_all(h)?;
writer.write_all(&b": "[..])?;
writer.write_all(v)?;
writer.write_all(line_ending)?;
}
writer.write_all(line_ending)?;
writer.write_all(body)?;
Ok(())
}
}
}
}

View File

@ -48,6 +48,8 @@ pub const RFC3339_FMT: &str = "%Y-%m-%d\0";
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"
pub const ASCTIME_FMT: &str = "%a %b %d %H:%M:%S %Y\n\0";
extern "C" {
fn strptime(