melib: turn unicode algos and backends into features

embed
Manos Pitsidianakis 2019-09-21 21:23:06 +03:00
parent f066f35410
commit 6e75160b70
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
6 changed files with 191 additions and 69 deletions

View File

@ -12,16 +12,24 @@ crossbeam = "0.7.2"
data-encoding = "2.1.1" data-encoding = "2.1.1"
encoding = "0.2.33" encoding = "0.2.33"
fnv = "1.0.3" fnv = "1.0.3"
memmap = "0.5.2" memmap = { version = "0.5.2", optional = true }
nom = "3.2.0" nom = "3.2.0"
notify = "4.0.1" notify = { version = "4.0.1", optional = true }
notify-rust = "^3" notify-rust = { version = "^3", optional = true }
termion = "1.5.1" termion = "1.5.1"
xdg = "2.1.0" xdg = "2.1.0"
native-tls = "0.2" native-tls = { version ="0.2", optional=true }
serde = "1.0.71" serde = "1.0.71"
serde_derive = "1.0.71" serde_derive = "1.0.71"
bincode = "1.0.1" bincode = "1.0.1"
uuid = { version = "0.6", features = ["serde", "v4"] } uuid = { version = "0.6", features = ["serde", "v4"] }
text_processing = { path = "../text_processing", version = "*" } text_processing = { path = "../text_processing", version = "*", optional= true }
libc = {version = "0.2.59", features = ["extra_traits",]} libc = {version = "0.2.59", features = ["extra_traits",]}
[features]
default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend"]
unicode_algorithms = ["text_processing"]
imap_backend = ["native-tls"]
maildir_backend = ["notify", "notify-rust", "memmap"]
mbox_backend = ["notify", "notify-rust", "memmap"]

View File

@ -18,16 +18,22 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>. * along with meli. If not, see <http://www.gnu.org/licenses/>.
*/ */
#[cfg(feature = "imap_backend")]
pub mod imap; pub mod imap;
#[cfg(feature = "maildir_backend")]
pub mod maildir; pub mod maildir;
#[cfg(feature = "mbox_backend")]
pub mod mbox; pub mod mbox;
#[cfg(feature = "imap_backend")]
pub use self::imap::ImapType; pub use self::imap::ImapType;
use crate::async_workers::*; use crate::async_workers::*;
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::error::{MeliError, Result}; use crate::error::{MeliError, Result};
//use mailbox::backends::imap::ImapType;
#[cfg(feature = "maildir_backend")]
use self::maildir::MaildirType; use self::maildir::MaildirType;
#[cfg(feature = "mbox_backend")]
use self::mbox::MboxType; use self::mbox::MboxType;
use super::email::{Envelope, EnvelopeHash, Flag}; use super::email::{Envelope, EnvelopeHash, Flag};
use std::fmt; use std::fmt;
@ -57,18 +63,27 @@ impl Backends {
let mut b = Backends { let mut b = Backends {
map: FnvHashMap::with_capacity_and_hasher(1, Default::default()), map: FnvHashMap::with_capacity_and_hasher(1, Default::default()),
}; };
b.register( #[cfg(feature = "maildir_backend")]
"maildir".to_string(), {
Box::new(|| Box::new(|f, i| Box::new(MaildirType::new(f, i)))), b.register(
); "maildir".to_string(),
b.register( Box::new(|| Box::new(|f, i| Box::new(MaildirType::new(f, i)))),
"mbox".to_string(), );
Box::new(|| Box::new(|f, i| Box::new(MboxType::new(f, i)))), }
); #[cfg(feature = "mbox_backend")]
b.register( {
"imap".to_string(), b.register(
Box::new(|| Box::new(|f, i| Box::new(ImapType::new(f, i)))), "mbox".to_string(),
); Box::new(|| Box::new(|f, i| Box::new(MboxType::new(f, i)))),
);
}
#[cfg(feature = "imap_backend")]
{
b.register(
"imap".to_string(),
Box::new(|| Box::new(|f, i| Box::new(ImapType::new(f, i)))),
);
}
b b
} }

View File

@ -1,22 +1,51 @@
use super::*; use super::*;
#[cfg(feature = "unicode_algorithms")]
use text_processing::grapheme_clusters::Graphemes; use text_processing::grapheme_clusters::Graphemes;
pub fn encode_header(value: &str) -> String { pub fn encode_header(value: &str) -> String {
let mut ret = String::with_capacity(value.len()); let mut ret = String::with_capacity(value.len());
let graphemes = value.graphemes_indices();
let mut is_current_window_ascii = true; let mut is_current_window_ascii = true;
let mut current_window_start = 0; let mut current_window_start = 0;
for (idx, g) in graphemes { #[cfg(feature = "unicode_algorithms")]
match (g.is_ascii(), is_current_window_ascii) { {
(true, true) => { let graphemes = value.graphemes_indices();
ret.push_str(g); for (idx, g) in graphemes {
} match (g.is_ascii(), is_current_window_ascii) {
(true, false) => { (true, true) => {
/* If !g.is_whitespace() ret.push_str(g);
* }
* Whitespaces inside encoded tokens must be greedily taken, (true, false) => {
* instead of splitting each non-ascii word into separate encoded tokens. */ /* If !g.is_whitespace()
if !g.split_whitespace().collect::<Vec<&str>>().is_empty() { *
* Whitespaces inside encoded tokens must be greedily taken,
* instead of splitting each non-ascii word into separate encoded tokens. */
if !g.split_whitespace().collect::<Vec<&str>>().is_empty() {
ret.push_str(&format!(
"=?UTF-8?B?{}?=",
BASE64_MIME
.encode(value[current_window_start..idx].as_bytes())
.trim()
));
if idx != value.len() - 1 {
ret.push(' ');
}
is_current_window_ascii = true;
current_window_start = idx;
ret.push_str(g);
}
}
(false, true) => {
current_window_start = idx;
is_current_window_ascii = false;
}
/* RFC2047 recommends:
* 'While there is no limit to the length of a multiple-line header field, each line of
* a header field that contains one or more 'encoded-word's is limited to 76
* characters.'
* This is a rough compliance.
*/
(false, false) if (((4 * (idx - current_window_start) / 3) + 3) & !3) > 33 => {
ret.push_str(&format!( ret.push_str(&format!(
"=?UTF-8?B?{}?=", "=?UTF-8?B?{}?=",
BASE64_MIME BASE64_MIME
@ -26,34 +55,67 @@ pub fn encode_header(value: &str) -> String {
if idx != value.len() - 1 { if idx != value.len() - 1 {
ret.push(' '); ret.push(' ');
} }
is_current_window_ascii = true;
current_window_start = idx; current_window_start = idx;
ret.push_str(g);
} }
(false, false) => {}
} }
(false, true) => { }
current_window_start = idx; }
is_current_window_ascii = false; #[cfg(not(feature = "unicode_algorithms"))]
} {
/* RFC2047 recommends: /* TODO: test this. If it works as fine as the one above, there's no need to keep the above
* 'While there is no limit to the length of a multiple-line header field, each line of * implementation.*/
* a header field that contains one or more 'encoded-word's is limited to 76 let mut idx = 0;
* characters.' for g in value.chars() {
* This is a rough compliance. match (g.is_ascii(), is_current_window_ascii) {
*/ (true, true) => {
(false, false) if (((4 * (idx - current_window_start) / 3) + 3) & !3) > 33 => { ret.push(g);
ret.push_str(&format!(
"=?UTF-8?B?{}?=",
BASE64_MIME
.encode(value[current_window_start..idx].as_bytes())
.trim()
));
if idx != value.len() - 1 {
ret.push(' ');
} }
current_window_start = idx; (true, false) => {
/* If !g.is_whitespace()
*
* Whitespaces inside encoded tokens must be greedily taken,
* instead of splitting each non-ascii word into separate encoded tokens. */
if !g.is_whitespace() {
ret.push_str(&format!(
"=?UTF-8?B?{}?=",
BASE64_MIME
.encode(value[current_window_start..idx].as_bytes())
.trim()
));
if idx != value.len() - 1 {
ret.push(' ');
}
is_current_window_ascii = true;
current_window_start = idx;
ret.push(g);
}
}
(false, true) => {
current_window_start = idx;
is_current_window_ascii = false;
}
/* RFC2047 recommends:
* 'While there is no limit to the length of a multiple-line header field, each line of
* a header field that contains one or more 'encoded-word's is limited to 76
* characters.'
* This is a rough compliance.
*/
(false, false) if (((4 * (idx - current_window_start) / 3) + 3) & !3) > 33 => {
ret.push_str(&format!(
"=?UTF-8?B?{}?=",
BASE64_MIME
.encode(value[current_window_start..idx].as_bytes())
.trim()
));
if idx != value.len() - 1 {
ret.push(' ');
}
current_window_start = idx;
}
(false, false) => {}
} }
(false, false) => {} idx += std::mem::size_of::<char>();
} }
} }
/* If the last part of the header value is encoded, it won't be pushed inside the previous for /* If the last part of the header value is encoded, it won't be pushed inside the previous for

View File

@ -118,6 +118,7 @@ impl<T> From<std::sync::PoisonError<T>> for MeliError {
} }
} }
#[cfg(feature = "imap_backend")]
impl From<native_tls::HandshakeError<std::net::TcpStream>> for MeliError { impl From<native_tls::HandshakeError<std::net::TcpStream>> for MeliError {
#[inline] #[inline]
fn from(kind: native_tls::HandshakeError<std::net::TcpStream>) -> MeliError { fn from(kind: native_tls::HandshakeError<std::net::TcpStream>) -> MeliError {
@ -125,6 +126,7 @@ impl From<native_tls::HandshakeError<std::net::TcpStream>> for MeliError {
} }
} }
#[cfg(feature = "imap_backend")]
impl From<native_tls::Error> for MeliError { impl From<native_tls::Error> for MeliError {
#[inline] #[inline]
fn from(kind: native_tls::Error) -> MeliError { fn from(kind: native_tls::Error) -> MeliError {

View File

@ -84,6 +84,7 @@ pub mod dbg {
} }
} }
#[cfg(feature = "unicode_algorithms")]
extern crate text_processing; extern crate text_processing;
#[macro_use] #[macro_use]
@ -113,7 +114,6 @@ extern crate nom;
extern crate chrono; extern crate chrono;
extern crate data_encoding; extern crate data_encoding;
extern crate encoding; extern crate encoding;
extern crate memmap;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;

View File

@ -35,6 +35,8 @@
use crate::email::parser::BytesExt; use crate::email::parser::BytesExt;
use crate::email::*; use crate::email::*;
use crate::structs::StackVec; use crate::structs::StackVec;
#[cfg(feature = "unicode_algorithms")]
use text_processing::grapheme_clusters::*; use text_processing::grapheme_clusters::*;
use uuid::Uuid; use uuid::Uuid;
@ -504,10 +506,19 @@ impl ThreadNode {
buf.get(&probe).map(|n| n.message.as_ref()).unwrap_or(None), buf.get(&probe).map(|n| n.message.as_ref()).unwrap_or(None),
buf.get(&child).map(|n| n.message.as_ref()).unwrap_or(None), buf.get(&child).map(|n| n.message.as_ref()).unwrap_or(None),
) { ) {
(Some(p), Some(c)) => envelopes[p] (Some(p), Some(c)) => {
.subject() #[cfg(feature = "unicode_algorithms")]
.split_graphemes() {
.cmp(&envelopes[c].subject().split_graphemes()), envelopes[p]
.subject()
.split_graphemes()
.cmp(&envelopes[c].subject().split_graphemes())
}
#[cfg(not(feature = "unicode_algorithms"))]
{
envelopes[p].subject().cmp(&envelopes[c].subject())
}
}
(Some(_), None) => Ordering::Greater, (Some(_), None) => Ordering::Greater,
(None, Some(_)) => Ordering::Less, (None, Some(_)) => Ordering::Less,
(None, None) => Ordering::Equal, (None, None) => Ordering::Equal,
@ -523,10 +534,19 @@ impl ThreadNode {
buf.get(&probe).map(|n| n.message.as_ref()).unwrap_or(None), buf.get(&probe).map(|n| n.message.as_ref()).unwrap_or(None),
buf.get(&child).map(|n| n.message.as_ref()).unwrap_or(None), buf.get(&child).map(|n| n.message.as_ref()).unwrap_or(None),
) { ) {
(Some(p), Some(c)) => envelopes[c] (Some(p), Some(c)) => {
.subject() #[cfg(feature = "unicode_algorithms")]
.split_graphemes() {
.cmp(&envelopes[p].subject().split_graphemes()), envelopes[c]
.subject()
.split_graphemes()
.cmp(&envelopes[p].subject().split_graphemes())
}
#[cfg(not(feature = "unicode_algorithms"))]
{
envelopes[c].subject().cmp(&envelopes[p].subject())
}
}
(Some(_), None) => Ordering::Less, (Some(_), None) => Ordering::Less,
(None, Some(_)) => Ordering::Greater, (None, Some(_)) => Ordering::Greater,
(None, None) => Ordering::Equal, (None, None) => Ordering::Equal,
@ -1078,9 +1098,16 @@ impl Threads {
} }
let ma = &envelopes[&a.unwrap()]; let ma = &envelopes[&a.unwrap()];
let mb = &envelopes[&b.unwrap()]; let mb = &envelopes[&b.unwrap()];
ma.subject() #[cfg(feature = "unicode_algorithms")]
.split_graphemes() {
.cmp(&mb.subject().split_graphemes()) ma.subject()
.split_graphemes()
.cmp(&mb.subject().split_graphemes())
}
#[cfg(not(feature = "unicode_algorithms"))]
{
ma.subject().cmp(&mb.subject())
}
} }
(SortField::Subject, SortOrder::Asc) => { (SortField::Subject, SortOrder::Asc) => {
let a = &self.thread_nodes[&a].message(); let a = &self.thread_nodes[&a].message();
@ -1100,10 +1127,18 @@ impl Threads {
} }
let ma = &envelopes[&a.unwrap()]; let ma = &envelopes[&a.unwrap()];
let mb = &envelopes[&b.unwrap()]; let mb = &envelopes[&b.unwrap()];
mb.subject() #[cfg(feature = "unicode_algorithms")]
.as_ref() {
.split_graphemes() mb.subject()
.cmp(&ma.subject().split_graphemes()) .as_ref()
.split_graphemes()
.cmp(&ma.subject().split_graphemes())
}
#[cfg(not(feature = "unicode_algorithms"))]
{
mb.subject().as_ref().cmp(&ma.subject())
}
} }
}); });
} }