Edit documentation
parent
f2899b63d2
commit
ac8e334ae9
|
@ -39,4 +39,6 @@ extern crate bitflags;
|
|||
pub use mailbox::*;
|
||||
pub use conf::*;
|
||||
|
||||
pub use mailbox::backends::{RefreshEventConsumer, Backends};
|
||||
pub use mailbox::backends::{RefreshEventConsumer, RefreshEvent, Backends};
|
||||
pub use mailbox::email::{Envelope, Flag};
|
||||
pub use error::{Result, MeliError};
|
||||
|
|
|
@ -38,6 +38,7 @@ extern crate crossbeam;
|
|||
use std::path::PathBuf;
|
||||
use memmap::{Mmap, Protection};
|
||||
|
||||
/// `BackendOp` implementor for Maildir
|
||||
#[derive(Debug, Default)]
|
||||
pub struct MaildirOp {
|
||||
path: String,
|
||||
|
@ -113,6 +114,7 @@ impl BackendOp for MaildirOp {
|
|||
}
|
||||
|
||||
|
||||
/// Maildir backend https://cr.yp.to/proto/maildir.html
|
||||
#[derive(Debug)]
|
||||
pub struct MaildirType {
|
||||
path: String,
|
||||
|
@ -215,7 +217,7 @@ impl MaildirType {
|
|||
let m = match Email::parse(&buffer) {
|
||||
Ok((v, rest)) => match rest.len() {
|
||||
0 => v,
|
||||
_ =>
|
||||
_ =>
|
||||
{ eprintln!("{:?}", String::from_utf8(rest.to_vec()).unwrap());
|
||||
panic!("didn't parse"); },
|
||||
},
|
||||
|
|
|
@ -95,7 +95,8 @@ pub trait MailBackend: ::std::fmt::Debug {
|
|||
/// # Example
|
||||
/// ```
|
||||
/// use melib::mailbox::backends::{BackendOp, BackendOpGenerator};
|
||||
/// use melib::error::Result;
|
||||
/// use melib::Result;
|
||||
/// use melib::{Envelope, Flag};
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// struct FooOp {}
|
||||
|
@ -113,7 +114,7 @@ pub trait MailBackend: ::std::fmt::Debug {
|
|||
/// fn fetch_body(&mut self) -> Result<&[u8]> {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// fn fetch_flags((&self) -> Flag {
|
||||
/// fn fetch_flags(&self) -> Flag {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
|
|
|
@ -36,19 +36,24 @@ use std::ascii::AsciiExt;
|
|||
use chrono;
|
||||
use chrono::TimeZone;
|
||||
|
||||
/* Helper struct to return slices from a struct on demand */
|
||||
/// Helper struct to return slices from a struct field on demand.
|
||||
#[derive(Clone, Debug)]
|
||||
struct StrBuilder {
|
||||
offset: usize,
|
||||
length: usize,
|
||||
}
|
||||
|
||||
/// Structs implementing this trait must contain a `StrBuilder` field.
|
||||
pub trait StrBuild {
|
||||
fn new(&str, &str) -> Self;
|
||||
/// Create a new `Self` out of a string and a slice
|
||||
fn new(string: &str, slice: &str) -> Self;
|
||||
/// Get the slice part of the string
|
||||
fn get_raw(&self) -> &str;
|
||||
/// Get the entire string as a slice
|
||||
fn get_val(&self) -> &str;
|
||||
}
|
||||
|
||||
/// `MessageID` is accessed through the `StrBuild` trait.
|
||||
#[derive(Clone)]
|
||||
pub struct MessageID(String, StrBuilder);
|
||||
|
||||
|
@ -119,7 +124,13 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
/* A very primitive mail object */
|
||||
/// `Envelope` represents all the data of an email we need to know.
|
||||
///
|
||||
/// Attachments (the email's body) is parsed on demand with `get_body`.
|
||||
///
|
||||
/// Access to the underlying email object in the account's backend (for example the file or the
|
||||
/// entry in an IMAP server) is given through `operation_token`. For more information see
|
||||
/// `BackendOp`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Envelope {
|
||||
date: String,
|
||||
|
@ -142,7 +153,110 @@ pub struct Envelope {
|
|||
|
||||
|
||||
impl Envelope {
|
||||
pub fn get_date(&self) -> i64 {
|
||||
pub fn new(token: Box<BackendOpGenerator>) -> Self {
|
||||
Envelope {
|
||||
date: "".to_string(),
|
||||
from: None,
|
||||
to: None,
|
||||
body: None,
|
||||
subject: None,
|
||||
message_id: None,
|
||||
in_reply_to: None,
|
||||
references: None,
|
||||
|
||||
datetime: None,
|
||||
timestamp: 0,
|
||||
|
||||
thread: 0,
|
||||
|
||||
operation_token: Arc::new(token),
|
||||
flags: Flag::default(),
|
||||
}
|
||||
}
|
||||
pub fn from(operation_token: Box<BackendOpGenerator>) -> Option<Envelope> {
|
||||
let operation = operation_token.generate();
|
||||
let mut e = Envelope::new(operation_token);
|
||||
e.flags = operation.fetch_flags();
|
||||
Some(e)
|
||||
}
|
||||
|
||||
pub fn populate_headers(&mut self) -> () {
|
||||
let mut operation = self.operation_token.generate();
|
||||
let headers = match parser::headers(operation.fetch_headers().unwrap()).to_full_result() {
|
||||
Ok(v) => v,
|
||||
_ => {
|
||||
let operation = self.operation_token.generate();
|
||||
eprintln!("error in parsing mail\n{}", operation.description());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut in_reply_to = None;
|
||||
let mut datetime = None;
|
||||
|
||||
for (name, value) in headers {
|
||||
if value.len() == 1 && value.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if name.eq_ignore_ascii_case("to") {
|
||||
let parse_result = parser::subject(value.as_bytes());
|
||||
let value = if parse_result.is_done() {
|
||||
parse_result.to_full_result().unwrap()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
self.set_to(value);
|
||||
} else if name.eq_ignore_ascii_case("from") {
|
||||
let parse_result = parser::subject(value.as_bytes());
|
||||
let value = if parse_result.is_done() {
|
||||
parse_result.to_full_result().unwrap()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
self.set_from(value);
|
||||
} else if name.eq_ignore_ascii_case("subject") {
|
||||
let parse_result = parser::subject(value.trim().as_bytes());
|
||||
let value = if parse_result.is_done() {
|
||||
parse_result.to_full_result().unwrap()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
self.set_subject(value);
|
||||
} else if name.eq_ignore_ascii_case("message-id") {
|
||||
self.set_message_id(value);
|
||||
} else if name.eq_ignore_ascii_case("references") {
|
||||
{
|
||||
let parse_result = parser::references(value.as_bytes());
|
||||
if parse_result.is_done() {
|
||||
for v in parse_result.to_full_result().unwrap() {
|
||||
self.push_references(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.set_references(value.to_string());
|
||||
} else if name.eq_ignore_ascii_case("in-reply-to") {
|
||||
self.set_in_reply_to(value);
|
||||
in_reply_to = Some(value);
|
||||
} else if name.eq_ignore_ascii_case("date") {
|
||||
self.set_date(value.to_string());
|
||||
datetime = Some(value.to_string());
|
||||
}
|
||||
}
|
||||
/*
|
||||
* https://tools.ietf.org/html/rfc5322#section-3.6.4
|
||||
*
|
||||
* if self.message_id.is_none() { ...
|
||||
*/
|
||||
if let Some(ref mut x) = in_reply_to {
|
||||
self.push_references(x);
|
||||
}
|
||||
if let Some(ref mut d) = datetime {
|
||||
if let Some(d) = parser::date(d) {
|
||||
self.set_datetime(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn get_date(&self) -> i64 {
|
||||
self.timestamp
|
||||
}
|
||||
pub fn get_datetime(&self) -> chrono::DateTime<chrono::FixedOffset> {
|
||||
|
@ -323,11 +437,9 @@ impl Envelope {
|
|||
pub fn set_thread(&mut self, new_val: usize) -> () {
|
||||
self.thread = new_val;
|
||||
}
|
||||
pub fn set_datetime(&mut self, new_val: Option<chrono::DateTime<chrono::FixedOffset>>) -> () {
|
||||
self.datetime = new_val;
|
||||
if let Some(v) = self.datetime {
|
||||
self.timestamp = v.timestamp();
|
||||
}
|
||||
pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) -> () {
|
||||
self.datetime = Some(new_val);
|
||||
self.timestamp = new_val.timestamp();
|
||||
}
|
||||
pub fn get_flags(&self) -> Flag {
|
||||
self.flags
|
||||
|
@ -335,107 +447,6 @@ impl Envelope {
|
|||
pub fn is_seen(&self) -> bool {
|
||||
!(self.flags & Flag::SEEN).is_empty()
|
||||
}
|
||||
pub fn new(token: Box<BackendOpGenerator>) -> Self {
|
||||
Envelope {
|
||||
date: "".to_string(),
|
||||
from: None,
|
||||
to: None,
|
||||
body: None,
|
||||
subject: None,
|
||||
message_id: None,
|
||||
in_reply_to: None,
|
||||
references: None,
|
||||
|
||||
datetime: None,
|
||||
timestamp: 0,
|
||||
|
||||
thread: 0,
|
||||
|
||||
operation_token: Arc::new(token),
|
||||
flags: Flag::default(),
|
||||
}
|
||||
}
|
||||
pub fn from(operation_token: Box<BackendOpGenerator>) -> Option<Envelope> {
|
||||
let operation = operation_token.generate();
|
||||
let mut e = Envelope::new(operation_token);
|
||||
e.flags = operation.fetch_flags();
|
||||
Some(e)
|
||||
}
|
||||
|
||||
pub fn populate_headers(&mut self) -> () {
|
||||
let mut operation = self.operation_token.generate();
|
||||
let headers = match parser::headers(operation.fetch_headers().unwrap()).to_full_result() {
|
||||
Ok(v) => v,
|
||||
_ => {
|
||||
let operation = self.operation_token.generate();
|
||||
eprintln!("error in parsing mail\n{}", operation.description());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut in_reply_to = None;
|
||||
let mut datetime = None;
|
||||
|
||||
for (name, value) in headers {
|
||||
if value.len() == 1 && value.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if name.eq_ignore_ascii_case("to") {
|
||||
let parse_result = parser::subject(value.as_bytes());
|
||||
let value = if parse_result.is_done() {
|
||||
parse_result.to_full_result().unwrap()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
self.set_to(value);
|
||||
} else if name.eq_ignore_ascii_case("from") {
|
||||
let parse_result = parser::subject(value.as_bytes());
|
||||
let value = if parse_result.is_done() {
|
||||
parse_result.to_full_result().unwrap()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
self.set_from(value);
|
||||
} else if name.eq_ignore_ascii_case("subject") {
|
||||
let parse_result = parser::subject(value.trim().as_bytes());
|
||||
let value = if parse_result.is_done() {
|
||||
parse_result.to_full_result().unwrap()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
self.set_subject(value);
|
||||
} else if name.eq_ignore_ascii_case("message-id") {
|
||||
self.set_message_id(value);
|
||||
} else if name.eq_ignore_ascii_case("references") {
|
||||
{
|
||||
let parse_result = parser::references(value.as_bytes());
|
||||
if parse_result.is_done() {
|
||||
for v in parse_result.to_full_result().unwrap() {
|
||||
self.push_references(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.set_references(value.to_string());
|
||||
} else if name.eq_ignore_ascii_case("in-reply-to") {
|
||||
self.set_in_reply_to(value);
|
||||
in_reply_to = Some(value);
|
||||
} else if name.eq_ignore_ascii_case("date") {
|
||||
self.set_date(value.to_string());
|
||||
datetime = Some(value.to_string());
|
||||
}
|
||||
}
|
||||
/*
|
||||
* https://tools.ietf.org/html/rfc5322#section-3.6.4
|
||||
*
|
||||
* if self.message_id.is_none() { ...
|
||||
*/
|
||||
if let Some(ref mut x) = in_reply_to {
|
||||
self.push_references(x);
|
||||
}
|
||||
if let Some(ref mut d) = datetime {
|
||||
self.set_datetime(parser::date(d));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Envelope {}
|
||||
|
|
|
@ -27,13 +27,13 @@ use mailbox::backends::MailBackend;
|
|||
use error::Result;
|
||||
pub mod accounts;
|
||||
pub use mailbox::accounts::Account;
|
||||
mod thread;
|
||||
use mailbox::thread::{build_threads, Container};
|
||||
pub mod thread;
|
||||
pub use mailbox::thread::{build_threads, Container};
|
||||
|
||||
use std::option::Option;
|
||||
|
||||
|
||||
/// `Mailbox` represents a folder of mail. Currently only `Maildir` is supported.
|
||||
/// `Mailbox` represents a folder of mail.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Mailbox {
|
||||
pub path: String,
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use mailbox::email::Envelope;
|
||||
use mailbox::*;
|
||||
use error::MeliError;
|
||||
use super::*;
|
||||
|
||||
use super::pager::Pager;
|
||||
use std::error::Error;
|
||||
|
|
|
@ -24,18 +24,27 @@ pub mod pager;
|
|||
|
||||
extern crate ncurses;
|
||||
extern crate melib;
|
||||
use melib::mailbox::backends::RefreshEvent;
|
||||
use melib::*;
|
||||
|
||||
/* Color pairs; foreground && background. */
|
||||
/// Default color.
|
||||
pub static COLOR_PAIR_DEFAULT: i16 = 1;
|
||||
/// Highlighted cursor line in index view.
|
||||
pub static COLOR_PAIR_CURSOR: i16 = 2;
|
||||
/// Header colour in pager view.
|
||||
pub static COLOR_PAIR_HEADERS: i16 = 3;
|
||||
/// Indentation symbol color in index view.
|
||||
pub static COLOR_PAIR_THREAD_INDENT: i16 = 4;
|
||||
/// Line color for odd entries in index view.
|
||||
pub static COLOR_PAIR_THREAD_ODD: i16 = 5;
|
||||
/// Line color for even entries in index view.
|
||||
pub static COLOR_PAIR_THREAD_EVEN: i16 = 6;
|
||||
/// Line color for unread odd entries in index view.
|
||||
pub static COLOR_PAIR_UNREAD_ODD: i16 = 7;
|
||||
/// Line color for unread even entries in index view.
|
||||
pub static COLOR_PAIR_UNREAD_EVEN: i16 = 8;
|
||||
|
||||
/// Dummy object to provide `ncurses` initialization and destruction.
|
||||
pub struct TUI;
|
||||
|
||||
impl TUI {
|
||||
|
@ -71,8 +80,12 @@ impl Drop for TUI {
|
|||
}
|
||||
}
|
||||
|
||||
/// `ThreadEvent` encapsulates all of the possible values we need to transfer between our threads
|
||||
/// to the main process.
|
||||
pub enum ThreadEvent {
|
||||
/// User input.
|
||||
Input(ncurses::WchResult),
|
||||
/// A watched folder has been refreshed.
|
||||
RefreshMailbox{ name: String },
|
||||
//Decode { _ }, // For gpg2 signature check
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use mailbox;
|
||||
use super::*;
|
||||
|
||||
extern crate ncurses;
|
||||
|
||||
|
@ -35,7 +35,7 @@ pub struct Pager {
|
|||
}
|
||||
|
||||
impl Pager {
|
||||
pub fn new(parent: ncurses::WINDOW, entry: &mut mailbox::Envelope) -> Pager {
|
||||
pub fn new(parent: ncurses::WINDOW, entry: &mut Envelope) -> Pager {
|
||||
let mut screen_height = 0;
|
||||
let mut screen_width = 0;
|
||||
ncurses::getmaxyx(parent, &mut screen_height, &mut screen_width);
|
||||
|
@ -130,7 +130,7 @@ impl Pager {
|
|||
w - 1,
|
||||
);
|
||||
}
|
||||
fn print_entry_headers(win: ncurses::WINDOW, mail: &mut mailbox::Envelope) -> i32 {
|
||||
fn print_entry_headers(win: ncurses::WINDOW, mail: &mut Envelope) -> i32 {
|
||||
let mut i = 0;
|
||||
ncurses::wattron(win, ncurses::COLOR_PAIR(super::COLOR_PAIR_HEADERS));
|
||||
ncurses::waddstr(win, "Date: ");
|
||||
|
@ -171,7 +171,7 @@ impl Pager {
|
|||
}
|
||||
fn print_entry_content(
|
||||
win: ncurses::WINDOW,
|
||||
mail: &mut mailbox::Envelope,
|
||||
mail: &mut Envelope,
|
||||
height: i32,
|
||||
) -> (ncurses::WINDOW, i32, i32) {
|
||||
let mut h = 0;
|
||||
|
@ -208,7 +208,7 @@ impl Pager {
|
|||
}
|
||||
fn print_entry(
|
||||
win: ncurses::WINDOW,
|
||||
mail: &mut mailbox::Envelope,
|
||||
mail: &mut Envelope,
|
||||
) -> (ncurses::WINDOW, i32, i32) {
|
||||
let header_height = Pager::print_entry_headers(win, mail);
|
||||
Pager::print_entry_content(win, mail, header_height + 2)
|
||||
|
|
Loading…
Reference in New Issue