Fix proper viewing for multipart alternatives, html view and quoted printable soft breaks
parent
93b36a9941
commit
14d65838b7
|
@ -83,15 +83,39 @@ impl Display for ContentType {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ContentType {
|
||||
pub fn is_text(&self) -> bool {
|
||||
if let ContentType::Text { .. } = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ContentSubType {
|
||||
Plain,
|
||||
Html,
|
||||
Other { tag: Vec<u8> },
|
||||
}
|
||||
|
||||
impl ContentSubType {
|
||||
pub fn is_html(&self) -> bool {
|
||||
if let ContentSubType::Html = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ContentSubType {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
match *self {
|
||||
ContentSubType::Plain => write!(f, "plain"),
|
||||
ContentSubType::Html => write!(f, "html"),
|
||||
ContentSubType::Other { tag: ref t } => write!(f, "{}", String::from_utf8_lossy(t)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,14 +18,14 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
use data_encoding::BASE64_MIME;
|
||||
use mailbox::email::parser;
|
||||
|
||||
pub use mailbox::email::attachment_types::*;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub enum AttachmentType {
|
||||
Data {
|
||||
tag: Vec<u8>,
|
||||
|
@ -39,6 +39,16 @@ pub enum AttachmentType {
|
|||
},
|
||||
}
|
||||
|
||||
impl fmt::Debug for AttachmentType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AttachmentType::Data { .. } => write!(f, "AttachmentType::Data {{ .. }}"),
|
||||
AttachmentType::Text { .. } => write!(f, "AttachmentType::Text {{ .. }}"),
|
||||
AttachmentType::Multipart { of_type, subattachments } => write!(f, "AttachmentType::Multipart {{ of_type: {:?},\nsubattachments: {:?} }}", of_type, subattachments),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Data
|
||||
|
@ -54,17 +64,27 @@ pub struct AttachmentBuilder {
|
|||
raw: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct Attachment {
|
||||
content_type: (ContentType, ContentSubType),
|
||||
content_transfer_encoding: ContentTransferEncoding,
|
||||
|
||||
raw: Vec<u8>,
|
||||
|
||||
attachment_type: AttachmentType,
|
||||
}
|
||||
impl Display for AttachmentType {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
|
||||
impl fmt::Debug for Attachment {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Attachment {{\n content_type: {:?},\n content_transfer_encoding: {:?},\n raw: Vec of {} bytes\n attachment_type: {:?}\n }}",
|
||||
self.content_type,
|
||||
self.content_transfer_encoding,
|
||||
self.raw.len(),
|
||||
self.attachment_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AttachmentType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AttachmentType::Data { tag: ref t } => write!(f, "{}", String::from_utf8_lossy(t)),
|
||||
AttachmentType::Text { content: ref c } => write!(f, "{}", String::from_utf8_lossy(c)),
|
||||
|
@ -108,7 +128,9 @@ impl AttachmentBuilder {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if !cst.eq_ignore_ascii_case(b"plain") {
|
||||
if cst.eq_ignore_ascii_case(b"html") {
|
||||
self.content_type.1 = ContentSubType::Html;
|
||||
} else if !cst.eq_ignore_ascii_case(b"plain") {
|
||||
self.content_type.1 = ContentSubType::Other {
|
||||
tag: cst.to_ascii_lowercase(),
|
||||
};
|
||||
|
@ -144,25 +166,27 @@ impl AttachmentBuilder {
|
|||
self
|
||||
}
|
||||
fn decode(&self) -> Vec<u8> {
|
||||
// TODO merge this and standalone decode() function
|
||||
let charset = match self.content_type.0 {
|
||||
ContentType::Text{ charset: c } => c,
|
||||
_ => Default::default(),
|
||||
};
|
||||
let decoded_result = parser::decode_charset(&self.raw, charset);
|
||||
let b: &[u8] = decoded_result.as_ref().map(|v| v.as_bytes()).unwrap_or_else(|_| &self.raw);
|
||||
|
||||
match self.content_transfer_encoding {
|
||||
ContentTransferEncoding::Base64 => match BASE64_MIME.decode(b) {
|
||||
let bytes = match self.content_transfer_encoding {
|
||||
ContentTransferEncoding::Base64 => match BASE64_MIME.decode(&self.raw) {
|
||||
Ok(v) => v,
|
||||
_ => b.to_vec(),
|
||||
_ => self.raw.to_vec(),
|
||||
},
|
||||
ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_text(b)
|
||||
ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_bytes(&self.raw)
|
||||
.to_full_result()
|
||||
.unwrap(),
|
||||
ContentTransferEncoding::_7Bit
|
||||
| ContentTransferEncoding::_8Bit
|
||||
| ContentTransferEncoding::Other { .. } => b.to_vec(),
|
||||
}
|
||||
| ContentTransferEncoding::Other { .. } => self.raw.to_vec(),
|
||||
};
|
||||
|
||||
let decoded_result = parser::decode_charset(&bytes, charset);
|
||||
decoded_result.as_ref().map(|v| v.as_bytes()).unwrap_or_else(|_| &self.raw).to_vec()
|
||||
}
|
||||
pub fn build(self) -> Attachment {
|
||||
let attachment_type = match self.content_type.0 {
|
||||
|
@ -172,9 +196,9 @@ impl AttachmentBuilder {
|
|||
ContentType::Multipart { boundary: ref b } => {
|
||||
let multipart_type = match self.content_type.1 {
|
||||
ContentSubType::Other { ref tag } => match &tag[..] {
|
||||
b"mixed" => MultipartType::Mixed,
|
||||
b"alternative" => MultipartType::Alternative,
|
||||
b"digest" => MultipartType::Digest,
|
||||
b"mixed" | b"Mixed" | b"MIXED" => MultipartType::Mixed,
|
||||
b"alternative" | b"Alternative" | b"ALTERNATIVE" => MultipartType::Alternative,
|
||||
b"digest" | b"Digest" | b"DIGEST" => MultipartType::Digest,
|
||||
_ => MultipartType::Unsupported { tag: tag.clone() },
|
||||
},
|
||||
_ => panic!(),
|
||||
|
@ -238,8 +262,8 @@ impl AttachmentBuilder {
|
|||
}
|
||||
|
||||
|
||||
impl Display for Attachment {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
impl fmt::Display for Attachment {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.attachment_type {
|
||||
AttachmentType::Data { .. } => {
|
||||
write!(f, "Data attachment of type {}", self.mime_type())
|
||||
|
@ -265,13 +289,13 @@ impl Attachment {
|
|||
pub fn bytes(&self) -> &[u8] {
|
||||
&self.raw
|
||||
}
|
||||
fn get_text_recursive(&self, text: &mut String) {
|
||||
fn get_text_recursive(&self, text: &mut Vec<u8>) {
|
||||
match self.attachment_type {
|
||||
AttachmentType::Data { .. } => {
|
||||
//text.push_str(&format!("Data attachment of type {}", self.mime_type()));
|
||||
}
|
||||
AttachmentType::Text { content: ref t } => {
|
||||
text.push_str(&String::from_utf8_lossy(t));
|
||||
AttachmentType::Text { .. } => {
|
||||
text.extend(decode(self, None));
|
||||
}
|
||||
AttachmentType::Multipart {
|
||||
of_type: ref multipart_type,
|
||||
|
@ -286,15 +310,15 @@ impl Attachment {
|
|||
} else {
|
||||
for a in sub_att_vec {
|
||||
a.get_text_recursive(text);
|
||||
text.push_str("\n\n");
|
||||
text.extend_from_slice(b"\n\n");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn text(&self) -> String {
|
||||
let mut text = String::with_capacity(self.raw.len());
|
||||
let mut text = Vec::with_capacity(self.raw.len());
|
||||
self.get_text_recursive(&mut text);
|
||||
text
|
||||
String::from_utf8_lossy(&text).into()
|
||||
}
|
||||
pub fn description(&self) -> Vec<String> {
|
||||
self.attachments().iter().map(|a| a.text()).collect()
|
||||
|
@ -341,24 +365,66 @@ pub fn interpret_format_flowed(_t: &str) -> String {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn decode(a: &Attachment) -> Vec<u8> {
|
||||
fn decode_rec_helper(a: &Attachment, filter: &Option<Box<Fn(&Attachment) -> Vec<u8>>>) -> Vec<u8> {
|
||||
if let Some(filter) = filter {
|
||||
return filter(a);
|
||||
}
|
||||
match a.attachment_type {
|
||||
AttachmentType::Data { .. } => { Vec::new()},
|
||||
AttachmentType::Text { .. } => decode_helper(a, filter),
|
||||
AttachmentType::Multipart {
|
||||
of_type: ref multipart_type,
|
||||
subattachments: ref sub_att_vec,
|
||||
} => if *multipart_type == MultipartType::Alternative {
|
||||
for a in sub_att_vec {
|
||||
if a.content_type.1 == ContentSubType::Plain {
|
||||
return decode_helper(a, filter);
|
||||
}
|
||||
}
|
||||
decode_helper(a, filter)
|
||||
} else {
|
||||
let mut vec = Vec::new();
|
||||
for a in sub_att_vec {
|
||||
vec.extend(decode_rec_helper(a, filter));
|
||||
vec.extend_from_slice(b"\n\n");
|
||||
}
|
||||
vec
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn decode_rec(a: &Attachment, filter: Option<Box<Fn(&Attachment) -> Vec<u8>>>) -> Vec<u8> {
|
||||
decode_rec_helper(a, &filter)
|
||||
}
|
||||
fn decode_helper(a: &Attachment, filter: &Option<Box<Fn(&Attachment) -> Vec<u8>>>) -> Vec<u8> {
|
||||
if let Some(filter) = filter {
|
||||
return filter(a);
|
||||
}
|
||||
|
||||
let charset = match a.content_type.0 {
|
||||
ContentType::Text{ charset: c } => c,
|
||||
_ => Default::default(),
|
||||
};
|
||||
let decoded_result = parser::decode_charset(a.bytes(), charset);
|
||||
let b: &[u8] = decoded_result.as_ref().map(|v| v.as_bytes()).unwrap_or_else(|_| a.bytes());
|
||||
|
||||
match a.content_transfer_encoding {
|
||||
ContentTransferEncoding::Base64 => match BASE64_MIME.decode(b) {
|
||||
|
||||
let bytes = match a.content_transfer_encoding {
|
||||
ContentTransferEncoding::Base64 => match BASE64_MIME.decode(a.bytes()) {
|
||||
Ok(v) => v,
|
||||
_ => b.to_vec(),
|
||||
_ => a.bytes().to_vec(),
|
||||
},
|
||||
ContentTransferEncoding::QuotedPrintable => parser::quoted_printed_bytes(b)
|
||||
ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_bytes(a.bytes())
|
||||
.to_full_result()
|
||||
.unwrap(),
|
||||
ContentTransferEncoding::_7Bit
|
||||
| ContentTransferEncoding::_8Bit
|
||||
| ContentTransferEncoding::Other { .. } => b.to_vec(),
|
||||
| ContentTransferEncoding::Other { .. } => a.bytes().to_vec(),
|
||||
};
|
||||
|
||||
if a.content_type().0.is_text() {
|
||||
let decoded_result = parser::decode_charset(&bytes, charset);
|
||||
decoded_result.as_ref().map(|v| v.as_bytes()).unwrap_or_else(|_| a.bytes()).to_vec()
|
||||
} else {
|
||||
bytes.to_vec()
|
||||
}
|
||||
}
|
||||
pub fn decode(a: &Attachment, filter: Option<Box<Fn(&Attachment) -> Vec<u8>>>) -> Vec<u8> {
|
||||
decode_helper(a, &filter)
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ fn encoded_word(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
|
|||
Ok(v) => v,
|
||||
Err(_) => encoded.to_vec(),
|
||||
},
|
||||
b'q' | b'Q' => match quoted_printed_bytes(encoded) {
|
||||
b'q' | b'Q' => match quoted_printable_bytes_header(encoded) {
|
||||
IResult::Done(b"", s) => s,
|
||||
_ => return IResult::Error(error_code!(ErrorKind::Custom(43))),
|
||||
},
|
||||
|
@ -296,16 +296,38 @@ pub fn decode_charset(s: &[u8], charset: Charset) -> Result<String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn quoted_printable_soft_break(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
if input.len() < 2 {
|
||||
IResult::Incomplete(Needed::Size(1))
|
||||
} else if input[0] == b'=' && input[1] == b'\n' {
|
||||
IResult::Done(&input[2..], &input[0..2]) // `=\n` is an escaped space character.
|
||||
} else {
|
||||
IResult::Error(error_code!(ErrorKind::Custom(43)))
|
||||
}
|
||||
}
|
||||
|
||||
named!(qp_underscore_header<u8>, do_parse!(tag!("_") >> ({ b' ' })));
|
||||
|
||||
/// For atoms in Header values.
|
||||
// With MIME, headers in quoted printable format can contain underscores that represent spaces.
|
||||
// In non-header context, an underscore is just a plain underscore.
|
||||
named!(
|
||||
pub quoted_printed_bytes<Vec<u8>>,
|
||||
pub quoted_printable_bytes_header<Vec<u8>>,
|
||||
many0!(alt_complete!(
|
||||
quoted_printable_byte | qp_underscore_header | le_u8
|
||||
))
|
||||
);
|
||||
|
||||
/// For atoms in Header values.
|
||||
named!(
|
||||
pub quoted_printable_bytes<Vec<u8>>,
|
||||
many0!(alt_complete!(
|
||||
preceded!(quoted_printable_soft_break, quoted_printable_byte) |
|
||||
preceded!(quoted_printable_soft_break, le_u8)
|
||||
| quoted_printable_byte | le_u8
|
||||
))
|
||||
);
|
||||
|
||||
|
||||
named!(
|
||||
encoded_word_list<Vec<u8>>,
|
||||
ws!(do_parse!(
|
||||
|
@ -527,11 +549,7 @@ fn test_address() {
|
|||
println!("{:?}", rfc2822address_list(s).unwrap());
|
||||
}
|
||||
|
||||
named!(pub rfc2822address_list<Vec<Address>>, ws!(
|
||||
separated_list!(is_a!(","), address)
|
||||
|
||||
|
||||
));
|
||||
named!(pub rfc2822address_list<Vec<Address>>, ws!( separated_list!(is_a!(","), address)));
|
||||
|
||||
named!(pub address_list<String>, ws!(do_parse!(
|
||||
list: alt_complete!( encoded_word_list | ascii_token) >>
|
||||
|
@ -766,15 +784,15 @@ named!(pub content_type< (&[u8], &[u8], Vec<(&[u8], &[u8])>) >,
|
|||
} )
|
||||
));
|
||||
|
||||
named!(pub quoted_printable_text<Vec<u8>>,
|
||||
do_parse!(
|
||||
bytes: many0!(alt_complete!(
|
||||
preceded!(tag!("=\n"), quoted_printable_byte) |
|
||||
preceded!(tag!("=\n"), le_u8) |
|
||||
quoted_printable_byte |
|
||||
le_u8)) >>
|
||||
( {
|
||||
bytes
|
||||
} )
|
||||
)
|
||||
);
|
||||
//named!(pub quoted_printable_text<Vec<u8>>,
|
||||
// do_parse!(
|
||||
// bytes: many0!(alt_complete!(
|
||||
// preceded!(tag!("=\n"), quoted_printable_byte) |
|
||||
// preceded!(tag!("=\n"), le_u8) |
|
||||
// quoted_printable_byte |
|
||||
// le_u8)) >>
|
||||
// ( {
|
||||
// bytes
|
||||
// } )
|
||||
// )
|
||||
//);
|
||||
|
|
|
@ -70,6 +70,78 @@ impl MailView {
|
|||
cmd_buf: String::with_capacity(4),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the string to be displayed in the Viewer
|
||||
fn attachment_to_text(&self, envelope: &Envelope) -> String {
|
||||
let finder = LinkFinder::new();
|
||||
let body = envelope.body();
|
||||
let body_text = if body.content_type().0.is_text() && body.content_type().1.is_html() {
|
||||
String::from_utf8_lossy(&decode(&body, Some(Box::new(|a: &Attachment| {
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
let raw = decode(a, None);
|
||||
let mut html_filter = Command::new("w3m")
|
||||
.args(&["-I", "utf-8", "-T", "text/html"])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to start html filter process");
|
||||
|
||||
html_filter.stdin.as_mut().unwrap().write_all(&raw).expect("Failed to write to w3m stdin");
|
||||
html_filter.wait_with_output().unwrap().stdout
|
||||
})))).into_owned()
|
||||
} else {
|
||||
String::from_utf8_lossy(&decode_rec(&body, None)).into()
|
||||
};
|
||||
match self.mode {
|
||||
ViewMode::Normal => {
|
||||
let mut t = body_text.to_string();
|
||||
if body.count_attachments() > 1 {
|
||||
t = body.attachments().iter().enumerate().fold(
|
||||
t,
|
||||
|mut s, (idx, a)| {
|
||||
s.push_str(&format!("[{}] {}\n\n", idx, a));
|
||||
s
|
||||
},
|
||||
);
|
||||
}
|
||||
t
|
||||
}
|
||||
ViewMode::Raw => String::from_utf8_lossy(&envelope.bytes()).into_owned(),
|
||||
ViewMode::Url => {
|
||||
let mut t = body_text.to_string();
|
||||
for (lidx, l) in finder.links(&body.text()).enumerate() {
|
||||
let offset = if lidx < 10 {
|
||||
lidx * 3
|
||||
} else if lidx < 100 {
|
||||
26 + (lidx - 9) * 4
|
||||
} else if lidx < 1000 {
|
||||
385 + (lidx - 99) * 5
|
||||
} else {
|
||||
panic!("BUG: Message body with more than 100 urls");
|
||||
};
|
||||
t.insert_str(l.start() + offset, &format!("[{}]", lidx));
|
||||
}
|
||||
if body.count_attachments() > 1 {
|
||||
t = 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 = body.attachments();
|
||||
let mut ret = "Viewing attachment. Press `r` to return \n".to_string();
|
||||
ret.push_str(&attachments[aidx].text());
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for MailView {
|
||||
|
@ -177,61 +249,15 @@ impl Component for MailView {
|
|||
.as_ref()
|
||||
.unwrap();
|
||||
let envelope: &Envelope = &mailbox.collection[envelope_idx];
|
||||
let text = self.attachment_to_text(envelope);
|
||||
|
||||
let finder = LinkFinder::new();
|
||||
let mut text = match self.mode {
|
||||
ViewMode::Normal => {
|
||||
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
|
||||
}
|
||||
ViewMode::Raw => String::from_utf8_lossy(&envelope.bytes()).into_owned(),
|
||||
ViewMode::Url => {
|
||||
let mut t = envelope.body().text().to_string();
|
||||
for (lidx, l) in finder.links(&envelope.body().text()).enumerate() {
|
||||
let offset = if lidx < 10 {
|
||||
lidx * 3
|
||||
} else if lidx < 100 {
|
||||
26 + (lidx - 9) * 4
|
||||
} else if lidx < 1000 {
|
||||
385 + (lidx - 99) * 5
|
||||
} else {
|
||||
panic!("BUG: Message body with more than 100 urls");
|
||||
};
|
||||
t.insert_str(l.start() + offset, &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
|
||||
}
|
||||
ViewMode::Attachment(aidx) => {
|
||||
let attachments = envelope.body().attachments();
|
||||
let mut ret = "Viewing attachment. Press `r` to return \n".to_string();
|
||||
ret.push_str(&attachments[aidx].text());
|
||||
ret
|
||||
}
|
||||
};
|
||||
let mut buf = CellBuffer::from(&text);
|
||||
if self.mode == ViewMode::Url {
|
||||
// URL indexes must be colored (ugh..)
|
||||
let lines: Vec<&str> = text.split('\n').map(|l| l.trim_right()).collect();
|
||||
let mut shift = 0;
|
||||
let mut lidx_total = 0;
|
||||
let finder = LinkFinder::new();
|
||||
for r in &lines {
|
||||
for l in finder.links(&r) {
|
||||
let offset = if lidx_total < 10 {
|
||||
|
@ -331,7 +357,7 @@ impl Component for MailView {
|
|||
let attachment_type = u.mime_type();
|
||||
let binary = query_default_app(&attachment_type);
|
||||
if let Ok(binary) = binary {
|
||||
let mut p = create_temp_file(&decode(u), None);
|
||||
let mut p = create_temp_file(&decode(u, None), None);
|
||||
Command::new(&binary)
|
||||
.arg(p.path())
|
||||
.stdin(Stdio::piped())
|
||||
|
|
|
@ -45,18 +45,6 @@ pub enum SortField {
|
|||
impl FromStr for SortField {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
eprintln!("sortfield from_str {}", s);
|
||||
match s.trim() {
|
||||
"subject" | "s" | "sub" | "sbj" | "subj" => {
|
||||
eprintln!("parsed: subject");
|
||||
}
|
||||
"date" | "d" => {
|
||||
eprintln!("parsed date");
|
||||
}
|
||||
_ => {
|
||||
eprintln!("error in parse");
|
||||
}
|
||||
}
|
||||
match s.trim() {
|
||||
"subject" | "s" | "sub" | "sbj" | "subj" => Ok(SortField::Subject),
|
||||
"date" | "d" => Ok(SortField::Date),
|
||||
|
@ -68,7 +56,6 @@ impl FromStr for SortField {
|
|||
impl FromStr for SortOrder {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
eprintln!("sortoder from_str {}", s);
|
||||
match s.trim() {
|
||||
"asc" => Ok(SortOrder::Asc),
|
||||
"desc" => Ok(SortOrder::Desc),
|
||||
|
|
|
@ -183,10 +183,6 @@ impl State<std::io::Stdout> {
|
|||
account.watch(RefreshEventConsumer::new(Box::new(move |r| {
|
||||
sender.send(ThreadEvent::from(r));
|
||||
})));
|
||||
}
|
||||
for (k, v) in &s.context.mailbox_hashes {
|
||||
eprintln!("{:x} -> {:?}", k, v);
|
||||
|
||||
}
|
||||
s
|
||||
}
|
||||
|
@ -348,9 +344,7 @@ impl<W: Write> State<W> {
|
|||
}
|
||||
/// Convert user commands to actions/method calls.
|
||||
fn parse_command(&mut self, cmd: &str) {
|
||||
eprintln!("cmd is {}", cmd);
|
||||
let result = parse_command(&cmd.as_bytes()).to_full_result();
|
||||
eprintln!("rseult is {:?}", result);
|
||||
|
||||
if let Ok(v) = result {
|
||||
self.rcv_event(UIEvent {
|
||||
|
|
|
@ -40,8 +40,8 @@ impl File {
|
|||
pub fn file(&mut self) -> std::fs::File {
|
||||
std::fs::File::create(&self.path).unwrap()
|
||||
}
|
||||
pub fn path(&mut self) -> &mut PathBuf {
|
||||
&mut self.path
|
||||
pub fn path(&self) -> &PathBuf {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue