melib: turn unicode algos and backends into features
parent
f066f35410
commit
6e75160b70
|
@ -12,16 +12,24 @@ crossbeam = "0.7.2"
|
|||
data-encoding = "2.1.1"
|
||||
encoding = "0.2.33"
|
||||
fnv = "1.0.3"
|
||||
memmap = "0.5.2"
|
||||
memmap = { version = "0.5.2", optional = true }
|
||||
nom = "3.2.0"
|
||||
notify = "4.0.1"
|
||||
notify-rust = "^3"
|
||||
notify = { version = "4.0.1", optional = true }
|
||||
notify-rust = { version = "^3", optional = true }
|
||||
termion = "1.5.1"
|
||||
xdg = "2.1.0"
|
||||
native-tls = "0.2"
|
||||
native-tls = { version ="0.2", optional=true }
|
||||
serde = "1.0.71"
|
||||
serde_derive = "1.0.71"
|
||||
bincode = "1.0.1"
|
||||
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",]}
|
||||
|
||||
[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"]
|
||||
|
|
|
@ -18,16 +18,22 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#[cfg(feature = "imap_backend")]
|
||||
pub mod imap;
|
||||
#[cfg(feature = "maildir_backend")]
|
||||
pub mod maildir;
|
||||
#[cfg(feature = "mbox_backend")]
|
||||
pub mod mbox;
|
||||
|
||||
#[cfg(feature = "imap_backend")]
|
||||
pub use self::imap::ImapType;
|
||||
use crate::async_workers::*;
|
||||
use crate::conf::AccountSettings;
|
||||
use crate::error::{MeliError, Result};
|
||||
//use mailbox::backends::imap::ImapType;
|
||||
|
||||
#[cfg(feature = "maildir_backend")]
|
||||
use self::maildir::MaildirType;
|
||||
#[cfg(feature = "mbox_backend")]
|
||||
use self::mbox::MboxType;
|
||||
use super::email::{Envelope, EnvelopeHash, Flag};
|
||||
use std::fmt;
|
||||
|
@ -57,18 +63,27 @@ impl Backends {
|
|||
let mut b = Backends {
|
||||
map: FnvHashMap::with_capacity_and_hasher(1, Default::default()),
|
||||
};
|
||||
b.register(
|
||||
"maildir".to_string(),
|
||||
Box::new(|| Box::new(|f, i| Box::new(MaildirType::new(f, i)))),
|
||||
);
|
||||
b.register(
|
||||
"mbox".to_string(),
|
||||
Box::new(|| Box::new(|f, i| Box::new(MboxType::new(f, i)))),
|
||||
);
|
||||
b.register(
|
||||
"imap".to_string(),
|
||||
Box::new(|| Box::new(|f, i| Box::new(ImapType::new(f, i)))),
|
||||
);
|
||||
#[cfg(feature = "maildir_backend")]
|
||||
{
|
||||
b.register(
|
||||
"maildir".to_string(),
|
||||
Box::new(|| Box::new(|f, i| Box::new(MaildirType::new(f, i)))),
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "mbox_backend")]
|
||||
{
|
||||
b.register(
|
||||
"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
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,51 @@
|
|||
use super::*;
|
||||
|
||||
#[cfg(feature = "unicode_algorithms")]
|
||||
use text_processing::grapheme_clusters::Graphemes;
|
||||
|
||||
pub fn encode_header(value: &str) -> String {
|
||||
let mut ret = String::with_capacity(value.len());
|
||||
let graphemes = value.graphemes_indices();
|
||||
let mut is_current_window_ascii = true;
|
||||
let mut current_window_start = 0;
|
||||
for (idx, g) in graphemes {
|
||||
match (g.is_ascii(), is_current_window_ascii) {
|
||||
(true, true) => {
|
||||
ret.push_str(g);
|
||||
}
|
||||
(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.split_whitespace().collect::<Vec<&str>>().is_empty() {
|
||||
#[cfg(feature = "unicode_algorithms")]
|
||||
{
|
||||
let graphemes = value.graphemes_indices();
|
||||
for (idx, g) in graphemes {
|
||||
match (g.is_ascii(), is_current_window_ascii) {
|
||||
(true, true) => {
|
||||
ret.push_str(g);
|
||||
}
|
||||
(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.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!(
|
||||
"=?UTF-8?B?{}?=",
|
||||
BASE64_MIME
|
||||
|
@ -26,34 +55,67 @@ pub fn encode_header(value: &str) -> String {
|
|||
if idx != value.len() - 1 {
|
||||
ret.push(' ');
|
||||
}
|
||||
is_current_window_ascii = true;
|
||||
current_window_start = idx;
|
||||
ret.push_str(g);
|
||||
}
|
||||
(false, false) => {}
|
||||
}
|
||||
(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(' ');
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "unicode_algorithms"))]
|
||||
{
|
||||
/* TODO: test this. If it works as fine as the one above, there's no need to keep the above
|
||||
* implementation.*/
|
||||
let mut idx = 0;
|
||||
for g in value.chars() {
|
||||
match (g.is_ascii(), is_current_window_ascii) {
|
||||
(true, true) => {
|
||||
ret.push(g);
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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 {
|
||||
#[inline]
|
||||
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 {
|
||||
#[inline]
|
||||
fn from(kind: native_tls::Error) -> MeliError {
|
||||
|
|
|
@ -84,6 +84,7 @@ pub mod dbg {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unicode_algorithms")]
|
||||
extern crate text_processing;
|
||||
|
||||
#[macro_use]
|
||||
|
@ -113,7 +114,6 @@ extern crate nom;
|
|||
extern crate chrono;
|
||||
extern crate data_encoding;
|
||||
extern crate encoding;
|
||||
extern crate memmap;
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
use crate::email::parser::BytesExt;
|
||||
use crate::email::*;
|
||||
use crate::structs::StackVec;
|
||||
|
||||
#[cfg(feature = "unicode_algorithms")]
|
||||
use text_processing::grapheme_clusters::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -504,10 +506,19 @@ impl ThreadNode {
|
|||
buf.get(&probe).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]
|
||||
.subject()
|
||||
.split_graphemes()
|
||||
.cmp(&envelopes[c].subject().split_graphemes()),
|
||||
(Some(p), Some(c)) => {
|
||||
#[cfg(feature = "unicode_algorithms")]
|
||||
{
|
||||
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,
|
||||
(None, Some(_)) => Ordering::Less,
|
||||
(None, None) => Ordering::Equal,
|
||||
|
@ -523,10 +534,19 @@ impl ThreadNode {
|
|||
buf.get(&probe).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]
|
||||
.subject()
|
||||
.split_graphemes()
|
||||
.cmp(&envelopes[p].subject().split_graphemes()),
|
||||
(Some(p), Some(c)) => {
|
||||
#[cfg(feature = "unicode_algorithms")]
|
||||
{
|
||||
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,
|
||||
(None, Some(_)) => Ordering::Greater,
|
||||
(None, None) => Ordering::Equal,
|
||||
|
@ -1078,9 +1098,16 @@ impl Threads {
|
|||
}
|
||||
let ma = &envelopes[&a.unwrap()];
|
||||
let mb = &envelopes[&b.unwrap()];
|
||||
ma.subject()
|
||||
.split_graphemes()
|
||||
.cmp(&mb.subject().split_graphemes())
|
||||
#[cfg(feature = "unicode_algorithms")]
|
||||
{
|
||||
ma.subject()
|
||||
.split_graphemes()
|
||||
.cmp(&mb.subject().split_graphemes())
|
||||
}
|
||||
#[cfg(not(feature = "unicode_algorithms"))]
|
||||
{
|
||||
ma.subject().cmp(&mb.subject())
|
||||
}
|
||||
}
|
||||
(SortField::Subject, SortOrder::Asc) => {
|
||||
let a = &self.thread_nodes[&a].message();
|
||||
|
@ -1100,10 +1127,18 @@ impl Threads {
|
|||
}
|
||||
let ma = &envelopes[&a.unwrap()];
|
||||
let mb = &envelopes[&b.unwrap()];
|
||||
mb.subject()
|
||||
.as_ref()
|
||||
.split_graphemes()
|
||||
.cmp(&ma.subject().split_graphemes())
|
||||
#[cfg(feature = "unicode_algorithms")]
|
||||
{
|
||||
mb.subject()
|
||||
.as_ref()
|
||||
.split_graphemes()
|
||||
.cmp(&ma.subject().split_graphemes())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unicode_algorithms"))]
|
||||
{
|
||||
mb.subject().as_ref().cmp(&ma.subject())
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue