Edit documentation

embed
Manos Pitsidianakis 2017-10-01 17:31:20 +03:00
parent f2899b63d2
commit ac8e334ae9
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
8 changed files with 153 additions and 126 deletions

View File

@ -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};

View File

@ -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"); },
},

View File

@ -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!()
/// }
/// }

View File

@ -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 {}

View File

@ -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,

View File

@ -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;

View File

@ -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
}

View File

@ -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)