store headers in same order in drafts

memfd
Manos Pitsidianakis 5 years ago
parent d5c0f113d8
commit 7ff22229a9
No known key found for this signature in database
GPG Key ID: 73627C2F690DF710

@ -4,6 +4,9 @@ use data_encoding::BASE64_MIME;
use std::str; use std::str;
mod random; mod random;
mod mime;
use self::mime::*;
use super::parser; use super::parser;
@ -15,6 +18,7 @@ pub struct Draft {
// FIXME: Preserve header order // FIXME: Preserve header order
// FIXME: Validate headers, allow custom ones // FIXME: Validate headers, allow custom ones
headers: FnvHashMap<String, String>, headers: FnvHashMap<String, String>,
header_order: Vec<String>,
body: String, body: String,
attachments: Vec<Attachment>, attachments: Vec<Attachment>,
@ -23,18 +27,28 @@ pub struct Draft {
impl Default for Draft { impl Default for Draft {
fn default() -> Self { fn default() -> Self {
let mut headers = FnvHashMap::with_capacity_and_hasher(8, Default::default()); let mut headers = FnvHashMap::with_capacity_and_hasher(8, Default::default());
let mut header_order = Vec::with_capacity(8);
headers.insert("From".into(), "".into()); headers.insert("From".into(), "".into());
headers.insert("To".into(), "".into()); headers.insert("To".into(), "".into());
headers.insert("Cc".into(), "".into()); headers.insert("Cc".into(), "".into());
headers.insert("Bcc".into(), "".into()); headers.insert("Bcc".into(), "".into());
header_order.push("From".into());
header_order.push("To".into());
header_order.push("Cc".into());
header_order.push("Bcc".into());
let now: DateTime<Local> = Local::now(); let now: DateTime<Local> = Local::now();
headers.insert("Date".into(), now.to_rfc2822()); headers.insert("Date".into(), now.to_rfc2822());
headers.insert("Subject".into(), "".into()); headers.insert("Subject".into(), "".into());
headers.insert("Message-ID".into(), random::gen_message_id()); headers.insert("Message-ID".into(), random::gen_message_id());
headers.insert("User-Agent".into(), "meli".into()); headers.insert("User-Agent".into(), "meli".into());
header_order.push("Date".into());
header_order.push("Subject".into());
header_order.push("Message-ID".into());
header_order.push("User-Agent".into());
Draft { Draft {
headers, headers,
header_order,
body: String::new(), body: String::new(),
attachments: Vec::new(), attachments: Vec::new(),
@ -46,7 +60,7 @@ impl str::FromStr for Draft {
type Err = MeliError; type Err = MeliError;
fn from_str(s: &str) -> Result<Self> { fn from_str(s: &str) -> Result<Self> {
if s.is_empty() { if s.is_empty() {
return Err(MeliError::new("sadfsa")); return Err(MeliError::new("Empty input in Draft::from_str"));
} }
let (headers, _) = parser::mail(s.as_bytes()).to_full_result()?; let (headers, _) = parser::mail(s.as_bytes()).to_full_result()?;
@ -56,10 +70,13 @@ impl str::FromStr for Draft {
if ignore_header(k) { if ignore_header(k) {
continue; continue;
} }
ret.headers.insert( if ret.headers.insert(
String::from_utf8(k.to_vec())?, String::from_utf8(k.to_vec())?,
String::from_utf8(v.to_vec())?, String::from_utf8(v.to_vec())?,
); ).is_none() {
ret.header_order.push(String::from_utf8(k.to_vec())?);
}
} }
let body = Envelope::new(0).body_bytes(s.as_bytes()); let body = Envelope::new(0).body_bytes(s.as_bytes());
@ -92,8 +109,10 @@ impl Draft {
envelope.message_id_display() envelope.message_id_display()
), ),
); );
ret.header_order.push("References".into());
ret.headers_mut() ret.headers_mut()
.insert("In-Reply-To".into(), envelope.message_id_display().into()); .insert("In-Reply-To".into(), envelope.message_id_display().into());
ret.header_order.push("In-Reply-To".into());
ret.headers_mut() ret.headers_mut()
.insert("To".into(), envelope.field_from_to_string()); .insert("To".into(), envelope.field_from_to_string());
ret.headers_mut() ret.headers_mut()
@ -135,16 +154,21 @@ impl Draft {
pub fn to_string(&self) -> Result<String> { pub fn to_string(&self) -> Result<String> {
let mut ret = String::new(); let mut ret = String::new();
let headers = &["Date", "From", "To", "Cc", "Bcc", "Subject", "Message-ID"]; for k in &self.header_order {
for k in headers { let v = &self.headers[k];
ret.extend(format!("{}: {}\n", k, &self.headers[*k]).chars()); ret.extend(format!("{}: {}\n", k, v).chars());
} }
for (k, v) in &self.headers { ret.push('\n');
if headers.contains(&k.as_str()) { ret.push_str(&self.body);
continue;
} Ok(ret)
}
pub fn finalise(self) -> Result<String> {
let mut ret = String::new();
for k in &self.header_order {
let v = &self.headers[k];
ret.extend(format!("{}: {}\n", k, v).chars()); ret.extend(format!("{}: {}\n", k, v).chars());
} }
@ -167,6 +191,7 @@ impl Draft {
} }
Ok(ret) Ok(ret)
} }
} }

@ -129,9 +129,22 @@ named!(name<&[u8]>, is_not!(":\n"));
/* Parse a single header as a tuple -> (&str, Vec<&str>) */ /* Parse a single header as a tuple -> (&str, Vec<&str>) */
named!( named!(
header<(&[u8], &[u8])>, header_has_val<(&[u8], &[u8])>,
separated_pair!(complete!(name), ws!(tag!(b":")), complete!(header_value)) separated_pair!(complete!(name), ws!(tag!(b":")), complete!(header_value))
); );
named!(
header_no_val<(&[u8], &[u8])>,
do_parse!(
name: complete!(name) >>
tag!(b":") >>
opt!(is_a!(" \t")) >>
tag!(b"\n") >>
( { (name, b"") } )));
named!(
header<(&[u8], &[u8])>,
alt_complete!(header_no_val | header_has_val));
/* Parse all headers -> Vec<(&str, Vec<&str>)> */ /* Parse all headers -> Vec<(&str, Vec<&str>)> */
named!(pub headers<std::vec::Vec<(&[u8], &[u8])>>, named!(pub headers<std::vec::Vec<(&[u8], &[u8])>>,
many1!(complete!(header))); many1!(complete!(header)));

@ -399,7 +399,15 @@ impl Component for Composer {
}); });
return true; return true;
} }
('n', _) => {} ('n', _) => {},
('y', ViewMode::Discard(u)) => {
eprintln!("{:?}", self.draft.to_string());
context.replies.push_back(UIEvent {
id: 0,
event_type: UIEventType::Action(Tab(Kill(*u))),
});
return true;
},
_ => { _ => {
return false; return false;
} }

Loading…
Cancel
Save