diff --git a/melib/src/mailbox/email/mod.rs b/melib/src/mailbox/email/mod.rs
index 2c812d401..bcc0d8e76 100644
--- a/melib/src/mailbox/email/mod.rs
+++ b/melib/src/mailbox/email/mod.rs
@@ -27,7 +27,6 @@ pub use self::attachments::*;
use std::string::String;
use std::sync::Arc;
-//use std;
use std::cmp::Ordering;
use std::fmt;
use std::option::Option;
@@ -35,6 +34,69 @@ use std::option::Option;
use chrono;
use chrono::TimeZone;
+
+
+#[derive(Clone, Debug, )]
+pub struct GroupAddress {
+ raw: String,
+ display_name: StrBuilder,
+ mailbox_list: Vec
,
+}
+
+#[derive(Clone, Debug, )]
+pub struct MailboxAddress {
+ raw: String,
+ display_name: StrBuilder,
+ address_spec: StrBuilder,
+}
+
+#[derive(Clone, Debug, )]
+pub enum Address {
+ Mailbox(MailboxAddress),
+ Group(GroupAddress),
+}
+
+impl Eq for Address {}
+impl PartialEq for Address {
+ fn eq(&self, other: &Address) -> bool {
+ match (self, other) {
+ (Address::Mailbox(_), Address::Group(_)) |
+ (Address::Group(_), Address::Mailbox(_)) => {
+ false
+ },
+ (Address::Mailbox(s), Address::Mailbox(o)) => {
+ s.address_spec.display(&s.raw) == o.address_spec.display(&o.raw)
+ },
+ (Address::Group(s), Address::Group(o)) => {
+ s.display_name.display(&s.raw) == o.display_name.display(&o.raw) &&
+ s.mailbox_list.iter().zip(o.mailbox_list.iter()).fold(true, |b, (s, o)| b && (s == o))
+ },
+ }
+ }
+}
+
+impl fmt::Display for Address {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Address::Mailbox(m) if m.display_name.length > 0 => {
+ write!(f, "{} <{}>", m.display_name.display(&m.raw), m.address_spec.display(&m.raw))
+ },
+ Address::Group(g) => {
+ let attachment_strings: Vec = g.mailbox_list.iter().map(|a| format!("{}", a)).collect();
+ write!(f, "{}: {}", g.display_name.display(&g.raw), attachment_strings.join(", "))
+ },
+ Address::Mailbox(m) => {
+ write!(f, "{}", m.address_spec.display(&m.raw))
+ },
+ }
+
+ }
+
+
+}
+
+
+
/// Helper struct to return slices from a struct field on demand.
#[derive(Clone, Debug)]
struct StrBuilder {
@@ -52,6 +114,14 @@ pub trait StrBuild {
fn val(&self) -> &str;
}
+impl StrBuilder {
+ fn display<'a>(&self, s: &'a str) -> &'a str {
+ let offset = self.offset;
+ let length = self.length;
+ &s[offset..offset+length]
+ }
+}
+
/// `MessageID` is accessed through the `StrBuild` trait.
#[derive(Clone)]
pub struct MessageID(String, StrBuilder);
@@ -63,14 +133,14 @@ impl StrBuild for MessageID {
string.to_string(),
StrBuilder {
offset: offset,
- length: slice.len() + 1,
+ length: slice.len()+ 1,
},
)
}
fn raw(&self) -> &str {
let offset = self.1.offset;
let length = self.1.length;
- &self.0[offset..length]
+ &self.0[offset..offset+length-1]
}
fn val(&self) -> &str {
&self.0
@@ -133,8 +203,8 @@ bitflags! {
#[derive(Debug, Clone)]
pub struct Envelope {
date: String,
- from: Option,
- to: Option,
+ from: Vec,
+ to: Vec,
body: Option,
subject: Option,
message_id: Option,
@@ -155,8 +225,8 @@ impl Envelope {
pub fn new(token: Box) -> Self {
Envelope {
date: "".to_string(),
- from: None,
- to: None,
+ from: Vec::new(),
+ to: Vec::new(),
body: None,
subject: None,
message_id: None,
@@ -198,23 +268,23 @@ impl Envelope {
continue;
}
if name.eq_ignore_ascii_case("to") {
- let parse_result = parser::address_list(value.as_bytes());
+ let parse_result = parser::rfc2822address_list(value.as_bytes());
let value = if parse_result.is_done() {
parse_result.to_full_result().unwrap()
} else {
- "".to_string()
+ Vec::new()
};
self.set_to(value);
} else if name.eq_ignore_ascii_case("from") {
- let parse_result = parser::address_list(value.as_bytes());
+ let parse_result = parser::rfc2822address_list(value.as_bytes());
let value = if parse_result.is_done() {
parse_result.to_full_result().unwrap()
} else {
- "".to_string()
+ Vec::new()
};
self.set_from(value);
} else if name.eq_ignore_ascii_case("subject") {
- let parse_result = parser::subject(value.trim().as_bytes());
+ let parse_result = parser::phrase(value.trim().as_bytes());
let value = if parse_result.is_done() {
parse_result.to_full_result().unwrap()
} else {
@@ -269,17 +339,20 @@ impl Envelope {
pub fn date_as_str(&self) -> &str {
&self.date
}
- pub fn from(&self) -> &str {
- match self.from {
- Some(ref s) => s,
- None => "",
- }
+ pub fn from(&self) -> &Vec {
+ &self.from
}
- pub fn to(&self) -> &str {
- match self.to {
- Some(ref s) => s,
- None => "",
- }
+
+ pub fn from_to_string(&self) -> String {
+ let _strings: Vec = self.from.iter().map(|a| format!("{}", a)).collect();
+ _strings.join(", ")
+ }
+ pub fn to(&self) -> &Vec {
+ &self.to
+ }
+ pub fn to_to_string(&self) -> String {
+ let _strings: Vec = self.to.iter().map(|a| format!("{}", a)).collect();
+ _strings.join(", ")
}
pub fn body(&self) -> Attachment {
let mut operation = self.operation_token.generate();
@@ -338,11 +411,11 @@ impl Envelope {
fn set_date(&mut self, new_val: String) -> () {
self.date = new_val;
}
- fn set_from(&mut self, new_val: String) -> () {
- self.from = Some(new_val);
+ fn set_from(&mut self, new_val: Vec) -> () {
+ self.from = new_val;
}
- fn set_to(&mut self, new_val: String) -> () {
- self.to = Some(new_val);
+ fn set_to(&mut self, new_val: Vec) -> () {
+ self.to = new_val;
}
fn set_in_reply_to(&mut self, new_val: &str) -> () {
let slice = match parser::message_id(new_val.as_bytes()).to_full_result() {
diff --git a/melib/src/mailbox/email/parser.rs b/melib/src/mailbox/email/parser.rs
index 330fcc202..b8fa3951e 100644
--- a/melib/src/mailbox/email/parser.rs
+++ b/melib/src/mailbox/email/parser.rs
@@ -26,6 +26,16 @@ use nom::{is_hex_digit, le_u8};
use nom::{ErrorKind, IResult, Needed};
use nom::{Compare, CompareResult};
use encoding::{DecoderTrap, Encoding};
+use super::*;
+
+macro_rules! is_whitespace {
+ ($var:ident) => (
+ $var == b' ' && $var == b'\t' && $var == b'\n' && $var == b'\r'
+ );
+ ($var:expr) => (
+ $var == b' ' && $var == b'\t' && $var == b'\n' && $var == b'\r'
+ );
+}
fn quoted_printable_byte(input: &[u8]) -> IResult<&[u8], u8> {
if input.is_empty() || input.len() < 3 {
@@ -259,6 +269,205 @@ named!(ascii_token, do_parse!(
String::from_utf8_lossy(word).into_owned()
} )));
+fn display_addr(input: &[u8]) -> IResult<&[u8], Address> {
+ if input.is_empty() || input.len() < 3 {
+ IResult::Incomplete(Needed::Size(1))
+ } else if !is_whitespace!(input[0]) {
+ let mut display_name = StrBuilder {
+ offset: 0,
+ length: 0,
+ };
+ let mut flag = false;
+ for (i, b) in input[0..].iter().enumerate() {
+ if *b == b'<' {
+
+ display_name.length = if i != 0 { i-1 } else { 0 };
+ flag = true;
+ break;
+ }
+ }
+ if !flag {
+ return IResult::Error(error_code!(ErrorKind::Custom(43)));
+ }
+ let mut end = input.len();
+ let mut flag = false;
+ for (i, b) in input[display_name.length+2..].iter().enumerate() {
+ if *b == b'@' {
+ flag = true;
+ }
+ if *b == b'>' {
+ end = i;
+ break;
+ }
+ }
+ if flag {
+ let mut address_spec = StrBuilder {
+ offset: display_name.length + 2,
+ length: end,
+ };
+ match phrase(&input[0..end+display_name.length+3]) {
+ IResult::Error(e) => IResult::Error(e),
+ IResult::Incomplete(i) => IResult::Incomplete(i),
+ IResult::Done(rest, raw) => {
+ display_name.length = raw.find('<').unwrap();
+ address_spec.offset = display_name.length + 1;
+ address_spec.length = raw.len() - display_name.length - 2;
+ IResult::Done(rest, Address::Mailbox(MailboxAddress {
+ raw: raw,
+ display_name: display_name,
+ address_spec: address_spec,
+ }))
+ },
+ }
+ } else {
+ IResult::Error(error_code!(ErrorKind::Custom(43)))
+ }
+ } else {
+ IResult::Error(error_code!(ErrorKind::Custom(43)))
+ }
+
+}
+
+
+
+fn addr_spec(input: &[u8]) -> IResult<&[u8], Address> {
+ if input.is_empty() || input.len() < 3 {
+ IResult::Incomplete(Needed::Size(1))
+ } else if !is_whitespace!(input[0]) {
+ let mut end = input[1..].len();
+ let mut flag = false;
+ for (i, b) in input[1..].iter().enumerate() {
+ if *b == b'@' {
+ flag = true;
+ }
+ if is_whitespace!(*b) {
+ end = i;
+ break;
+ }
+ }
+ if flag {
+ IResult::Done(&input[end..], Address::Mailbox(MailboxAddress {
+ raw: String::from_utf8_lossy(&input[0..end+1]).to_string(),
+ display_name: StrBuilder {
+ offset: 0,
+ length: 0,
+ },
+ address_spec: StrBuilder {
+ offset: 0,
+ length: input[0..end+1].len(),
+ },
+ }))
+ } else {
+ IResult::Error(error_code!(ErrorKind::Custom(43)))
+ }
+ } else {
+ IResult::Error(error_code!(ErrorKind::Custom(42)))
+ }
+}
+
+
+named!(mailbox, ws!(alt_complete!(
+ display_addr |
+ addr_spec
+ )));
+named!(mailbox_list>, many0!(mailbox));
+
+
+#[test]
+fn test_mailbox() {
+ {
+ let s = b"epilys@postretch";
+ let r = mailbox(s).unwrap().1;
+ match r {
+ Address::Mailbox(ref m) => {
+ println!("----\n`{}`, `{}`\n----", m.display_name.display(&m.raw), m.address_spec.display(&m.raw));
+ },
+ _ => {},
+ }
+ }
+ let s = b"Manos ";
+ eprintln!("{:?}", display_addr(s).unwrap());
+ let r = display_addr(s).unwrap().1;
+ match r {
+ Address::Mailbox(ref m) => {
+ println!("----\n`{}`, `{}`\n----", m.display_name.display(&m.raw), m.address_spec.display(&m.raw));
+ },
+ _ => {},
+ }
+
+}
+
+
+//named!(group_t, ws!( do_parse!(
+// display_name: take_until1!(":") >>
+// mailbox_list: many0!(mailbox) >>
+// end: is_a!(";") >>
+// ({
+//
+// })
+// )));
+//
+
+fn group(input: &[u8]) -> IResult<&[u8], Address> {
+ let mut flag = false;
+ let mut dlength = 0;
+ for (i, b) in input.iter().enumerate() {
+ if *b == b':' {
+ flag = true;
+ dlength = i;
+ break;
+ }
+ }
+ if !flag {
+ return IResult::Error(error_code!(ErrorKind::Custom(43)));
+ }
+
+ match mailbox_list(&input[dlength..]) {
+ IResult::Error(e) => {
+ return IResult::Error(e);
+ }
+ IResult::Done(rest, vec) => {
+ let size: usize = (rest.as_ptr() as usize) - ((&input[0..] as &[u8]).as_ptr() as usize);
+ return IResult::Done(rest, Address::Group(GroupAddress {
+ raw: String::from_utf8(input[0..size].to_vec()).unwrap(),
+ display_name: StrBuilder {
+ offset: 0,
+ length: dlength,
+ },
+ mailbox_list: vec,
+ }));
+ },
+ IResult::Incomplete(i) => {
+ return IResult::Incomplete(i);
+ },
+ }
+}
+
+
+
+
+
+named!(address, ws!(
+ alt_complete!(mailbox | group)));
+
+#[test]
+fn test_address() {
+ let s = b"Manos Pitsidianakis ,
+ qemu-devel , qemu-block ,
+ Alberto Garcia , Stefan Hajnoczi ";
+ println!("{:?}", rfc2822address_list(s).unwrap());
+
+}
+
+
+
+named!(pub rfc2822address_list>, ws!(
+ separated_list!(is_a!(","), address)
+
+
+ ));
+
+
named!(pub address_list, ws!(do_parse!(
list: alt_complete!( encoded_word_list | ascii_token) >>
( {
@@ -278,7 +487,8 @@ named!(pub address_list, ws!(do_parse!(
} )
)));
-named!(pub subject, ws!(do_parse!(
+
+named!(pub phrase, ws!(do_parse!(
list: many0!(alt_complete!( encoded_word_list | ascii_token)) >>
( {
let string_len = list.iter().fold(0, |mut acc, x| { acc+=x.len(); acc }) + list.len() - 1;
@@ -298,52 +508,52 @@ named!(pub subject, ws!(do_parse!(
)));
#[test]
-fn test_subject() {
- let subject_s = "list.free.de mailing list memberships reminder".as_bytes();
+fn test_phrase() {
+ let phrase_s = "list.free.de mailing list memberships reminder".as_bytes();
assert_eq!(
(
&b""[..],
"list.free.de mailing list memberships reminder".to_string()
),
- subject(subject_s).unwrap()
+ phrase(phrase_s).unwrap()
);
- let subject_s = "=?UTF-8?B?zp3Orc6/IM+Az4HOv8+Dz4nPgM65zrrPjCDOvM6uzr3Phc68zrEgzrHPhs6v?= =?UTF-8?B?z4fOuM63?=".as_bytes();
+ let phrase_s = "=?UTF-8?B?zp3Orc6/IM+Az4HOv8+Dz4nPgM65zrrPjCDOvM6uzr3Phc68zrEgzrHPhs6v?= =?UTF-8?B?z4fOuM63?=".as_bytes();
assert_eq!(
(
&b""[..],
"Νέο προσωπικό μήνυμα αφίχθη".to_string()
),
- subject(subject_s).unwrap()
+ phrase(phrase_s).unwrap()
);
- let subject_s = "=?utf-8?B?bW9vZGxlOiDOsc69zrHPg866z4zPgM63z4POtyDOv868zqzOtM6xz4Igz4M=?= =?utf-8?B?z4XOts63z4TOrs+DzrXPic69?=".as_bytes();
+ let phrase_s = "=?utf-8?B?bW9vZGxlOiDOsc69zrHPg866z4zPgM63z4POtyDOv868zqzOtM6xz4Igz4M=?= =?utf-8?B?z4XOts63z4TOrs+DzrXPic69?=".as_bytes();
assert_eq!(
(
&b""[..],
"moodle: ανασκόπηση ομάδας συζητήσεων".to_string()
),
- subject(subject_s).unwrap()
+ phrase(phrase_s).unwrap()
);
- let subject_s =
+ let phrase_s =
"=?UTF-8?B?zp3Orc6/IM+Az4HOv8+Dz4nPgM65zrrPjCDOvM6uzr3Phc68zrEgzrHPhs6v?=".as_bytes();
assert_eq!(
"Νέο προσωπικό μήνυμα αφί".to_string(),
- from_utf8(&encoded_word(subject_s).to_full_result().unwrap()).unwrap()
+ from_utf8(&encoded_word(phrase_s).to_full_result().unwrap()).unwrap()
);
- let subject_s = "=?UTF-8?Q?=CE=A0=CF=81=CF=8C=CF=83=CE=B8=CE=B5?=".as_bytes();
+ let phrase_s = "=?UTF-8?Q?=CE=A0=CF=81=CF=8C=CF=83=CE=B8=CE=B5?=".as_bytes();
assert_eq!(
"Πρόσθε".to_string(),
- from_utf8(&encoded_word(subject_s).to_full_result().unwrap()).unwrap()
+ from_utf8(&encoded_word(phrase_s).to_full_result().unwrap()).unwrap()
);
- let subject_s = "=?iso-8859-7?B?UmU6INDx/OLr5+zhIOzlIPTn7SDh9fHp4e3eIOLh8eTp4Q==?=".as_bytes();
+ let phrase_s = "=?iso-8859-7?B?UmU6INDx/OLr5+zhIOzlIPTn7SDh9fHp4e3eIOLh8eTp4Q==?=".as_bytes();
assert_eq!(
"Re: Πρόβλημα με την αυριανή βαρδια".to_string(),
- from_utf8(&encoded_word(subject_s).to_full_result().unwrap()).unwrap()
+ from_utf8(&encoded_word(phrase_s).to_full_result().unwrap()).unwrap()
);
- let subject_s = "=?UTF-8?Q?=CE=A0=CF=81=CF=8C=CF=83=CE=B8=CE=B5?=
+ let phrase_s = "=?UTF-8?Q?=CE=A0=CF=81=CF=8C=CF=83=CE=B8=CE=B5?=
=?UTF-8?Q?=CF=84=CE=B7_=CE=B5=CE=BE=CE=B5=CF=84?=
=?UTF-8?Q?=CE=B1=CF=83=CF=84=CE=B9=CE=BA=CE=AE?="
.as_bytes();
@@ -352,7 +562,7 @@ fn test_subject() {
&b""[..],
"Πρόσθετη εξεταστική".to_string()
),
- subject(subject_s).unwrap()
+ phrase(phrase_s).unwrap()
);
}
fn eat_comments(input: &str) -> String {
@@ -388,7 +598,7 @@ fn test_eat_comments() {
*
* We should use a custom parser here*/
pub fn date(input: &str) -> Option> {
- let parsed_result = subject(eat_comments(input).as_bytes())
+ let parsed_result = phrase(eat_comments(input).as_bytes())
.to_full_result()
.unwrap()
.replace("-", "+");
diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs
index d7e7794ee..649737ace 100644
--- a/ui/src/components/mail/view.rs
+++ b/ui/src/components/mail/view.rs
@@ -1,10 +1,9 @@
use super::*;
-use linkify::{LinkFinder, Link};
+use linkify::{Link, LinkFinder};
use std::process::{Command, Stdio};
use mime_apps::query_default_app;
-
#[derive(PartialEq, Debug)]
enum ViewMode {
Normal,
@@ -35,8 +34,11 @@ pub struct MailView {
}
impl MailView {
- pub fn new(coordinates: (usize, usize, usize), pager: Option, subview: Option>) -> Self {
-
+ pub fn new(
+ coordinates: (usize, usize, usize),
+ pager: Option,
+ subview: Option>,
+ ) -> Self {
MailView {
coordinates: coordinates,
pager: pager,
@@ -49,15 +51,20 @@ impl MailView {
}
}
-
impl Component for MailView {
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
let upper_left = upper_left!(area);
let bottom_right = bottom_right!(area);
let (envelope_idx, y): (usize, usize) = {
- let threaded = context.accounts[self.coordinates.0].runtime_settings.threaded;
- let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1].as_ref().unwrap().as_ref().unwrap();
+ let threaded = context.accounts[self.coordinates.0]
+ .runtime_settings
+ .threaded;
+ let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1]
+ .as_ref()
+ .unwrap()
+ .as_ref()
+ .unwrap();
let envelope_idx: usize = if threaded {
mailbox.threaded_mail(self.coordinates.2)
} else {
@@ -66,98 +73,125 @@ impl Component for MailView {
let envelope: &Envelope = &mailbox.collection[envelope_idx];
- let (x,y) = write_string_to_grid(&format!("Date: {}", envelope.date_as_str()),
- grid,
- Color::Byte(33),
- Color::Default,
- area,
- true);
+ let (x, y) = write_string_to_grid(
+ &format!("Date: {}", envelope.date_as_str()),
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ area,
+ true,
+ );
for x in x..=get_x(bottom_right) {
grid[(x, y)].set_ch(' ');
grid[(x, y)].set_bg(Color::Default);
grid[(x, y)].set_fg(Color::Default);
}
- let (x,y) = write_string_to_grid(&format!("From: {}", envelope.from()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, y+1), bottom_right),
- true);
+ let (x, y) = write_string_to_grid(
+ &format!("From: {}", envelope.from_to_string()),
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, y + 1), bottom_right),
+ true,
+ );
for x in x..=get_x(bottom_right) {
grid[(x, y)].set_ch(' ');
grid[(x, y)].set_bg(Color::Default);
grid[(x, y)].set_fg(Color::Default);
}
- let (x,y) = write_string_to_grid(&format!("To: {}", envelope.to()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, y+1), bottom_right),
- true);
+ let (x, y) = write_string_to_grid(
+ &format!("To: {}", envelope.to_to_string()),
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, y + 1), bottom_right),
+ true,
+ );
for x in x..=get_x(bottom_right) {
grid[(x, y)].set_ch(' ');
grid[(x, y)].set_bg(Color::Default);
grid[(x, y)].set_fg(Color::Default);
}
- let (x,y) = write_string_to_grid(&format!("Subject: {}", envelope.subject()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, y+1), bottom_right),
- true);
+ let (x, y) = write_string_to_grid(
+ &format!("Subject: {}", envelope.subject()),
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, y + 1), bottom_right),
+ true,
+ );
for x in x..=get_x(bottom_right) {
grid[(x, y)].set_ch(' ');
grid[(x, y)].set_bg(Color::Default);
grid[(x, y)].set_fg(Color::Default);
}
- let (x, y) = write_string_to_grid(&format!("Message-ID: {}", envelope.message_id_raw()),
- grid,
- Color::Byte(33),
- Color::Default,
- (set_y(upper_left, y+1), bottom_right),
- true);
+ let (x, y) = write_string_to_grid(
+ &format!("Message-ID: {}", envelope.message_id_raw()),
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, y + 1), bottom_right),
+ true,
+ );
for x in x..=get_x(bottom_right) {
grid[(x, y)].set_ch(' ');
grid[(x, y)].set_bg(Color::Default);
grid[(x, y)].set_fg(Color::Default);
}
- clear_area(grid,
- (set_y(upper_left, y+1), set_y(bottom_right, y+2)));
- context.dirty_areas.push_back((upper_left, set_y(bottom_right, y+1)));
+ clear_area(grid, (set_y(upper_left, y + 1), set_y(bottom_right, y + 2)));
+ context
+ .dirty_areas
+ .push_back((upper_left, set_y(bottom_right, y + 1)));
(envelope_idx, y + 1)
};
if self.dirty {
let buf = {
- let mailbox_idx = self.coordinates; // coordinates are mailbox idxs
- let mailbox = &mut context.accounts[mailbox_idx.0][mailbox_idx.1].as_ref().unwrap().as_ref().unwrap();
- let envelope : &Envelope = &mailbox.collection[envelope_idx];
+ let mailbox_idx = self.coordinates; // coordinates are mailbox idxs
+ let mailbox = &mut context.accounts[mailbox_idx.0][mailbox_idx.1]
+ .as_ref()
+ .unwrap()
+ .as_ref()
+ .unwrap();
+ let envelope: &Envelope = &mailbox.collection[envelope_idx];
let finder = LinkFinder::new();
let mut text = match self.mode {
ViewMode::Url => {
let mut t = envelope.body().text().to_string();
for (lidx, l) in finder.links(&envelope.body().text()).enumerate() {
- t.insert_str(l.start()+(lidx*3), &format!("[{}]", lidx));
+ t.insert_str(l.start() + (lidx * 3), &format!("[{}]", lidx));
}
if envelope.body().count_attachments() > 1 {
- t = envelope.body().attachments().iter().enumerate().fold(t, |mut s, (idx, a)| { s.push_str(&format!("[{}] {}\n\n", idx, a)); s });
+ t = envelope.body().attachments().iter().enumerate().fold(
+ t,
+ |mut s, (idx, a)| {
+ s.push_str(&format!("[{}] {}\n\n", idx, a));
+ s
+ },
+ );
}
t
- },
+ }
ViewMode::Attachment(aidx) => {
let attachments = envelope.body().attachments();
let mut ret = format!("Viewing attachment. Press `r` to return \n");
ret.push_str(&attachments[aidx].text());
ret
- },
+ }
_ => {
let mut t = envelope.body().text().to_string();
if envelope.body().count_attachments() > 1 {
- t = envelope.body().attachments().iter().enumerate().fold(t, |mut s, (idx, a)| { s.push_str(&format!("[{}] {}\n\n", idx, a)); s });
+ t = envelope.body().attachments().iter().enumerate().fold(
+ t,
+ |mut s, (idx, a)| {
+ s.push_str(&format!("[{}] {}\n\n", idx, a));
+ s
+ },
+ );
}
t
- },
+ }
};
let mut buf = CellBuffer::from(&text);
match self.mode {
@@ -172,10 +206,10 @@ impl Component for MailView {
buf[(l.start() + shift - 3, 0)].set_fg(Color::Byte(226));
}
// Each Cell represents one char so next line will be:
- shift += r.chars().count()+1;
+ shift += r.chars().count() + 1;
}
- },
- _ => {},
+ }
+ _ => {}
}
buf
};
@@ -188,29 +222,41 @@ impl Component for MailView {
self.pager = Some(Pager::from_buf(buf, cursor_pos));
self.dirty = false;
}
- self.pager.as_mut().map(|p| p.draw(grid, (set_y(upper_left, y + 1),bottom_right), context));
+ self.pager
+ .as_mut()
+ .map(|p| p.draw(grid, (set_y(upper_left, y + 1), bottom_right), context));
}
-
fn process_event(&mut self, event: &UIEvent, context: &mut Context) {
match event.event_type {
UIEventType::Input(Key::Esc) => {
self.cmd_buf.clear();
- },
- UIEventType::Input(Key::Char(c)) if c >= '0' && c <= '9' => { //TODO:this should be an Action
+ }
+ UIEventType::Input(Key::Char(c)) if c >= '0' && c <= '9' => {
+ //TODO:this should be an Action
self.cmd_buf.push(c);
- },
- UIEventType::Input(Key::Char('r')) if self.mode.is_attachment() => { //TODO:one quit shortcut?
+ }
+ UIEventType::Input(Key::Char('r')) if self.mode.is_attachment() => {
+ //TODO:one quit shortcut?
self.mode = ViewMode::Normal;
self.dirty = true;
- },
- UIEventType::Input(Key::Char('a')) if self.cmd_buf.len() > 0 && self.mode == ViewMode::Normal => { //TODO:this should be an Action
+ }
+ UIEventType::Input(Key::Char('a'))
+ if self.cmd_buf.len() > 0 && self.mode == ViewMode::Normal =>
+ {
+ //TODO:this should be an Action
let lidx = self.cmd_buf.parse::().unwrap();
self.cmd_buf.clear();
{
- let threaded = context.accounts[self.coordinates.0].runtime_settings.threaded;
- let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1].as_ref().unwrap().as_ref().unwrap();
+ let threaded = context.accounts[self.coordinates.0]
+ .runtime_settings
+ .threaded;
+ let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1]
+ .as_ref()
+ .unwrap()
+ .as_ref()
+ .unwrap();
let envelope_idx: usize = if threaded {
mailbox.threaded_mail(self.coordinates.2)
} else {
@@ -223,11 +269,16 @@ impl Component for MailView {
ContentType::Text => {
self.mode = ViewMode::Attachment(lidx);
self.dirty = true;
- },
+ }
ContentType::Multipart { .. } => {
- context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::StatusNotification(format!("Multipart attachments are not supported yet.")) });
+ context.replies.push_back(UIEvent {
+ id: 0,
+ event_type: UIEventType::StatusNotification(format!(
+ "Multipart attachments are not supported yet."
+ )),
+ });
return;
- },
+ }
ContentType::Unsupported { .. } => {
let attachment_type = u.mime_type();
let binary = query_default_app(&attachment_type);
@@ -240,28 +291,45 @@ impl Component for MailView {
.spawn()
.expect(&format!("Failed to start {}", binary.display()));
} else {
- context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::StatusNotification(format!("Couldn't find a default application for type {}", attachment_type)) });
+ context.replies.push_back(UIEvent {
+ id: 0,
+ event_type: UIEventType::StatusNotification(format!(
+ "Couldn't find a default application for type {}",
+ attachment_type
+ )),
+ });
return;
}
-
- },
+ }
}
-
} else {
- context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::StatusNotification(format!("Attachment `{}` not found.", lidx)) });
+ context.replies.push_back(UIEvent {
+ id: 0,
+ event_type: UIEventType::StatusNotification(format!(
+ "Attachment `{}` not found.",
+ lidx
+ )),
+ });
return;
}
};
-
-
- },
- UIEventType::Input(Key::Char('g')) if self.cmd_buf.len() > 0 && self.mode == ViewMode::Url => { //TODO:this should be an Action
+ }
+ UIEventType::Input(Key::Char('g'))
+ if self.cmd_buf.len() > 0 && self.mode == ViewMode::Url =>
+ {
+ //TODO:this should be an Action
let lidx = self.cmd_buf.parse::().unwrap();
self.cmd_buf.clear();
let url = {
- let threaded = context.accounts[self.coordinates.0].runtime_settings.threaded;
- let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1].as_ref().unwrap().as_ref().unwrap();
+ let threaded = context.accounts[self.coordinates.0]
+ .runtime_settings
+ .threaded;
+ let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1]
+ .as_ref()
+ .unwrap()
+ .as_ref()
+ .unwrap();
let envelope_idx: usize = if threaded {
mailbox.threaded_mail(self.coordinates.2)
} else {
@@ -275,33 +343,37 @@ impl Component for MailView {
if let Some(u) = links.get(lidx) {
u.as_str().to_string()
} else {
- context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::StatusNotification(format!("Link `{}` not found.", lidx)) });
+ context.replies.push_back(UIEvent {
+ id: 0,
+ event_type: UIEventType::StatusNotification(format!(
+ "Link `{}` not found.",
+ lidx
+ )),
+ });
return;
}
};
-
Command::new("xdg-open")
.arg(url)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Failed to start xdg_open");
-
- },
- UIEventType::Input(Key::Char('u')) => { //TODO:this should be an Action
+ }
+ UIEventType::Input(Key::Char('u')) => {
+ //TODO:this should be an Action
match self.mode {
- ViewMode::Normal => { self.mode = ViewMode::Url },
- ViewMode::Url => { self.mode = ViewMode::Normal },
- _ => {},
+ ViewMode::Normal => self.mode = ViewMode::Url,
+ ViewMode::Url => self.mode = ViewMode::Normal,
+ _ => {}
}
self.dirty = true;
- },
- _ => {},
+ }
+ _ => {}
}
if let Some(ref mut sub) = self.subview {
sub.process_event(event, context);
-
} else {
if let Some(ref mut p) = self.pager {
p.process_event(event, context);
@@ -309,7 +381,8 @@ impl Component for MailView {
}
}
fn is_dirty(&self) -> bool {
- self.dirty || self.pager.as_ref().map(|p| p.is_dirty()).unwrap_or(false) ||
- self.subview.as_ref().map(|p| p.is_dirty()).unwrap_or(false)
+ self.dirty
+ || self.pager.as_ref().map(|p| p.is_dirty()).unwrap_or(false)
+ || self.subview.as_ref().map(|p| p.is_dirty()).unwrap_or(false)
}
}