Clippy fixes
parent
3a02b6fb80
commit
b1a7188771
12
build.rs
12
build.rs
|
@ -37,14 +37,9 @@ fn main() {
|
|||
]);
|
||||
#[cfg(feature = "cli-docs")]
|
||||
{
|
||||
use flate2::Compression;
|
||||
use flate2::GzBuilder;
|
||||
use flate2::{Compression, GzBuilder};
|
||||
const MANDOC_OPTS: &[&str] = &["-T", "utf8", "-I", "os=Generated by mandoc(1)"];
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::{env, fs::File, io::prelude::*, path::Path, process::Command};
|
||||
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let mut out_dir_path = Path::new(&out_dir).to_path_buf();
|
||||
|
@ -57,7 +52,8 @@ fn main() {
|
|||
.output()
|
||||
.or_else(|_| Command::new("man").arg("-l").arg(filepath).output())
|
||||
.expect(
|
||||
"could not execute `mandoc` or `man`. If the binaries are not available in the PATH, disable `cli-docs` feature to be able to continue compilation.",
|
||||
"could not execute `mandoc` or `man`. If the binaries are not available in \
|
||||
the PATH, disable `cli-docs` feature to be able to continue compilation.",
|
||||
);
|
||||
|
||||
let file = File::create(&out_dir_path).unwrap_or_else(|err| {
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::prelude::*,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
|
@ -29,7 +31,8 @@ use quote::{format_ident, quote};
|
|||
pub fn override_derive(filenames: &[(&str, &str)]) {
|
||||
let mut output_file =
|
||||
File::create("src/conf/overrides.rs").expect("Unable to open output file");
|
||||
let mut output_string = r##"/*
|
||||
let mut output_string = r##"// @generated
|
||||
/*
|
||||
* meli - conf/overrides.rs
|
||||
*
|
||||
* Copyright 2020 Manos Pitsidianakis
|
||||
|
@ -60,7 +63,7 @@ use super::*;
|
|||
|
||||
'file_loop: for (filename, ident) in filenames {
|
||||
println!("cargo:rerun-if-changed={}", filename);
|
||||
let mut file = File::open(&filename)
|
||||
let mut file = File::open(filename)
|
||||
.unwrap_or_else(|err| panic!("Unable to open file `{}` {}", filename, err));
|
||||
|
||||
let mut src = String::new();
|
||||
|
|
|
@ -29,11 +29,12 @@ fn main() -> Result<(), std::io::Error> {
|
|||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed={}", MOD_PATH);
|
||||
/* Line break tables */
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{prelude::*, BufReader},
|
||||
path::Path,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
const LINE_BREAK_TABLE_URL: &str =
|
||||
"http://www.unicode.org/Public/UCD/latest/ucd/LineBreak.txt";
|
||||
/* Grapheme width tables */
|
||||
|
@ -52,7 +53,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||
std::process::exit(0);
|
||||
}
|
||||
let mut child = Command::new("curl")
|
||||
.args(&["-o", "-", LINE_BREAK_TABLE_URL])
|
||||
.args(["-o", "-", LINE_BREAK_TABLE_URL])
|
||||
.stdout(Stdio::piped())
|
||||
.stdin(Stdio::null())
|
||||
.stderr(Stdio::inherit())
|
||||
|
@ -69,7 +70,8 @@ fn main() -> Result<(), std::io::Error> {
|
|||
let tokens: &str = line.split_whitespace().next().unwrap();
|
||||
|
||||
let semicolon_idx: usize = tokens.chars().position(|c| c == ';').unwrap();
|
||||
/* LineBreak.txt list is ascii encoded so we can assume each char takes one byte: */
|
||||
/* LineBreak.txt list is ascii encoded so we can assume each char takes one
|
||||
* byte: */
|
||||
let chars_str: &str = &tokens[..semicolon_idx];
|
||||
|
||||
let mut codepoint_iter = chars_str.split("..");
|
||||
|
@ -87,21 +89,21 @@ fn main() -> Result<(), std::io::Error> {
|
|||
child.wait()?;
|
||||
|
||||
let child = Command::new("curl")
|
||||
.args(&["-o", "-", UNICODE_DATA_URL])
|
||||
.args(["-o", "-", UNICODE_DATA_URL])
|
||||
.stdout(Stdio::piped())
|
||||
.output()?;
|
||||
|
||||
let unicode_data = String::from_utf8_lossy(&child.stdout);
|
||||
|
||||
let child = Command::new("curl")
|
||||
.args(&["-o", "-", EAW_URL])
|
||||
.args(["-o", "-", EAW_URL])
|
||||
.stdout(Stdio::piped())
|
||||
.output()?;
|
||||
|
||||
let eaw_data = String::from_utf8_lossy(&child.stdout);
|
||||
|
||||
let child = Command::new("curl")
|
||||
.args(&["-o", "-", EMOJI_DATA_URL])
|
||||
.args(["-o", "-", EMOJI_DATA_URL])
|
||||
.stdout(Stdio::piped())
|
||||
.output()?;
|
||||
|
||||
|
@ -198,13 +200,13 @@ fn main() -> Result<(), std::io::Error> {
|
|||
}
|
||||
// Apply the following special cases:
|
||||
// - The unassigned code points in the following blocks default to "W":
|
||||
// CJK Unified Ideographs Extension A: U+3400..U+4DBF
|
||||
// CJK Unified Ideographs: U+4E00..U+9FFF
|
||||
// CJK Compatibility Ideographs: U+F900..U+FAFF
|
||||
// - All undesignated code points in Planes 2 and 3, whether inside or
|
||||
// outside of allocated blocks, default to "W":
|
||||
// Plane 2: U+20000..U+2FFFD
|
||||
// Plane 3: U+30000..U+3FFFD
|
||||
// - CJK Unified Ideographs Extension A: U+3400..U+4DBF
|
||||
// - CJK Unified Ideographs: U+4E00..U+9FFF
|
||||
// - CJK Compatibility Ideographs: U+F900..U+FAFF
|
||||
// - All undesignated code points in Planes 2 and 3, whether inside or outside
|
||||
// of allocated blocks, default to "W":
|
||||
// - Plane 2: U+20000..U+2FFFD
|
||||
// - Plane 3: U+30000..U+3FFFD
|
||||
const WIDE_RANGES: [(usize, usize); 5] = [
|
||||
(0x3400, 0x4DBF),
|
||||
(0x4E00, 0x9FFF),
|
||||
|
@ -245,12 +247,12 @@ fn main() -> Result<(), std::io::Error> {
|
|||
}
|
||||
|
||||
use std::str::FromStr;
|
||||
let mut v = comment.trim().split_whitespace().next().unwrap();
|
||||
let mut v = comment.split_whitespace().next().unwrap();
|
||||
if v.starts_with('E') {
|
||||
v = &v[1..];
|
||||
}
|
||||
if v.as_bytes()
|
||||
.get(0)
|
||||
.first()
|
||||
.map(|c| !c.is_ascii_digit())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
|
@ -325,7 +327,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut file = File::create(&mod_path)?;
|
||||
let mut file = File::create(mod_path)?;
|
||||
file.write_all(
|
||||
br#"/*
|
||||
* meli - text_processing crate.
|
||||
|
|
|
@ -24,12 +24,14 @@ pub mod vcard;
|
|||
|
||||
pub mod mutt;
|
||||
|
||||
use crate::datetime::{self, UnixTimestamp};
|
||||
use crate::parsec::Parser;
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, ops::Deref};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use std::ops::Deref;
|
||||
use crate::{
|
||||
datetime::{self, UnixTimestamp},
|
||||
parsec::Parser,
|
||||
};
|
||||
|
||||
#[derive(Hash, Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(from = "String")]
|
||||
|
@ -85,7 +87,8 @@ pub struct Card {
|
|||
last_edited: UnixTimestamp,
|
||||
extra_properties: HashMap<String, String>,
|
||||
|
||||
/// If true, we can't make any changes because we do not manage this resource.
|
||||
/// If true, we can't make any changes because we do not manage this
|
||||
/// resource.
|
||||
external_resource: bool,
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
*/
|
||||
|
||||
//! # Mutt contact formats
|
||||
//!
|
||||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use super::*;
|
||||
use crate::parsec::{is_not, map_res, match_literal_anycase, prefix, Parser};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
//alias <nickname> [ <long name> ] <address>
|
||||
// From mutt doc:
|
||||
|
|
|
@ -27,11 +27,13 @@
|
|||
//! - Version 4 [RFC 6350: vCard Format Specification](https://datatracker.ietf.org/doc/rfc6350/)
|
||||
//! - Parameter escaping [RFC 6868 Parameter Value Encoding in iCalendar and vCard](https://datatracker.ietf.org/doc/rfc6868/)
|
||||
|
||||
use std::{collections::HashMap, convert::TryInto};
|
||||
|
||||
use super::*;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::parsec::{match_literal_anycase, one_or_more, peek, prefix, take_until, Parser};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
parsec::{match_literal_anycase, one_or_more, peek, prefix, take_until, Parser},
|
||||
};
|
||||
|
||||
/* Supported vcard versions */
|
||||
pub trait VCardVersion: core::fmt::Debug {}
|
||||
|
@ -86,7 +88,11 @@ impl CardDeserializer {
|
|||
input = if (!input.starts_with(HEADER_CRLF) || !input.ends_with(FOOTER_CRLF))
|
||||
&& (!input.starts_with(HEADER_LF) || !input.ends_with(FOOTER_LF))
|
||||
{
|
||||
return Err(Error::new(format!("Error while parsing vcard: input does not start or end with correct header and footer. input is:\n{:?}", input)));
|
||||
return Err(Error::new(format!(
|
||||
"Error while parsing vcard: input does not start or end with correct header and \
|
||||
footer. input is:\n{:?}",
|
||||
input
|
||||
)));
|
||||
} else if input.starts_with(HEADER_CRLF) {
|
||||
&input[HEADER_CRLF.len()..input.len() - FOOTER_CRLF.len()]
|
||||
} else {
|
||||
|
|
|
@ -36,35 +36,41 @@ pub mod jmap;
|
|||
pub mod maildir;
|
||||
#[cfg(feature = "mbox_backend")]
|
||||
pub mod mbox;
|
||||
use std::{
|
||||
any::Any,
|
||||
borrow::Cow,
|
||||
collections::{BTreeSet, HashMap},
|
||||
fmt,
|
||||
fmt::Debug,
|
||||
future::Future,
|
||||
ops::Deref,
|
||||
pin::Pin,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use futures::stream::Stream;
|
||||
|
||||
#[cfg(feature = "imap_backend")]
|
||||
pub use self::imap::ImapType;
|
||||
#[cfg(feature = "imap_backend")]
|
||||
pub use self::nntp::NntpType;
|
||||
use crate::conf::AccountSettings;
|
||||
use crate::error::{Error, ErrorKind, Result};
|
||||
|
||||
#[cfg(feature = "maildir_backend")]
|
||||
use self::maildir::MaildirType;
|
||||
#[cfg(feature = "mbox_backend")]
|
||||
use self::mbox::MboxType;
|
||||
#[cfg(feature = "imap_backend")]
|
||||
pub use self::nntp::NntpType;
|
||||
use super::email::{Envelope, EnvelopeHash, Flag};
|
||||
use futures::stream::Stream;
|
||||
use std::any::Any;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
use std::future::Future;
|
||||
use std::ops::Deref;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use crate::{
|
||||
conf::AccountSettings,
|
||||
error::{Error, ErrorKind, Result},
|
||||
};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! get_path_hash {
|
||||
($path:expr) => {{
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::{
|
||||
collections::hash_map::DefaultHasher,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
let mut hasher = DefaultHasher::new();
|
||||
$path.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
|
@ -97,10 +103,13 @@ impl Default for Backends {
|
|||
}
|
||||
|
||||
#[cfg(feature = "notmuch_backend")]
|
||||
pub const NOTMUCH_ERROR_MSG: &str =
|
||||
"libnotmuch5 was not found in your system. Make sure it is installed and in the library paths. For a custom file path, use `library_file_path` setting in your notmuch account.\n";
|
||||
pub const NOTMUCH_ERROR_MSG: &str = "libnotmuch5 was not found in your system. Make sure it is \
|
||||
installed and in the library paths. For a custom file path, \
|
||||
use `library_file_path` setting in your notmuch account.\n";
|
||||
#[cfg(not(feature = "notmuch_backend"))]
|
||||
pub const NOTMUCH_ERROR_MSG: &str = "this version of meli is not compiled with notmuch support. Use an appropriate version and make sure libnotmuch5 is installed and in the library paths.\n";
|
||||
pub const NOTMUCH_ERROR_MSG: &str = "this version of meli is not compiled with notmuch support. \
|
||||
Use an appropriate version and make sure libnotmuch5 is \
|
||||
installed and in the library paths.\n";
|
||||
|
||||
#[cfg(not(feature = "notmuch_backend"))]
|
||||
pub const NOTMUCH_ERROR_DETAILS: &str = "";
|
||||
|
@ -432,13 +441,14 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
|
|||
}
|
||||
}
|
||||
|
||||
/// A `BackendOp` manages common operations for the various mail backends. They only live for the
|
||||
/// duration of the operation. They are generated by the `operation` method of `Mailbackend` trait.
|
||||
/// A `BackendOp` manages common operations for the various mail backends. They
|
||||
/// only live for the duration of the operation. They are generated by the
|
||||
/// `operation` method of `Mailbackend` trait.
|
||||
///
|
||||
/// # Motivation
|
||||
///
|
||||
/// We need a way to do various operations on individual mails regardless of what backend they come
|
||||
/// from (eg local or imap).
|
||||
/// We need a way to do various operations on individual mails regardless of
|
||||
/// what backend they come from (eg local or imap).
|
||||
///
|
||||
/// # Creation
|
||||
/// ```ignore
|
||||
|
@ -474,8 +484,8 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
|
|||
|
||||
/// Wrapper for BackendOps that are to be set read-only.
|
||||
///
|
||||
/// Warning: Backend implementations may still cause side-effects (for example IMAP can set the
|
||||
/// Seen flag when fetching an envelope)
|
||||
/// Warning: Backend implementations may still cause side-effects (for example
|
||||
/// IMAP can set the Seen flag when fetching an envelope)
|
||||
#[derive(Debug)]
|
||||
pub struct ReadOnlyOp {
|
||||
op: Box<dyn BackendOp>,
|
||||
|
|
|
@ -36,26 +36,29 @@ use cache::{ImapCacheReset, ModSequence};
|
|||
pub mod managesieve;
|
||||
mod untagged;
|
||||
|
||||
use crate::backends::{
|
||||
RefreshEventKind::{self, *},
|
||||
*,
|
||||
use std::{
|
||||
collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet},
|
||||
convert::TryFrom,
|
||||
hash::Hasher,
|
||||
pin::Pin,
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex},
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use crate::collection::Collection;
|
||||
use crate::conf::AccountSettings;
|
||||
use crate::connections::timeout;
|
||||
use crate::email::{parser::BytesExt, *};
|
||||
use crate::error::{Error, Result, ResultIntoError};
|
||||
use futures::lock::Mutex as FutureMutex;
|
||||
use futures::stream::Stream;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::convert::TryFrom;
|
||||
use std::hash::Hasher;
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, SystemTime};
|
||||
use futures::{lock::Mutex as FutureMutex, stream::Stream};
|
||||
|
||||
use crate::{
|
||||
backends::{
|
||||
RefreshEventKind::{self, *},
|
||||
*,
|
||||
},
|
||||
collection::Collection,
|
||||
conf::AccountSettings,
|
||||
connections::timeout,
|
||||
email::{parser::BytesExt, *},
|
||||
error::{Error, Result, ResultIntoError},
|
||||
};
|
||||
|
||||
pub type ImapNum = usize;
|
||||
pub type UID = ImapNum;
|
||||
|
@ -340,7 +343,8 @@ impl MailBackend for ImapType {
|
|||
cache_handle,
|
||||
};
|
||||
|
||||
/* do this in a closure to prevent recursion limit error in async_stream macro */
|
||||
/* do this in a closure to prevent recursion limit error in async_stream
|
||||
* macro */
|
||||
let prepare_cl = |f: &ImapMailbox| {
|
||||
f.set_warm(true);
|
||||
if let Ok(mut exists) = f.exists.lock() {
|
||||
|
@ -526,15 +530,15 @@ impl MailBackend for ImapType {
|
|||
}
|
||||
|
||||
fn operation(&self, hash: EnvelopeHash) -> Result<Box<dyn BackendOp>> {
|
||||
let (uid, mailbox_hash) = if let Some(v) =
|
||||
self.uid_store.hash_index.lock().unwrap().get(&hash)
|
||||
{
|
||||
*v
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
"Message not found in local cache, it might have been deleted before you requested it."
|
||||
let (uid, mailbox_hash) =
|
||||
if let Some(v) = self.uid_store.hash_index.lock().unwrap().get(&hash) {
|
||||
*v
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
"Message not found in local cache, it might have been deleted before you \
|
||||
requested it.",
|
||||
));
|
||||
};
|
||||
};
|
||||
Ok(Box::new(ImapOp::new(
|
||||
uid,
|
||||
mailbox_hash,
|
||||
|
@ -749,8 +753,20 @@ impl MailBackend for ImapType {
|
|||
cmd.push_str("\\Draft ");
|
||||
}
|
||||
Ok(_) => {
|
||||
crate::log(format!("Application error: more than one flag bit set in set_flags: {:?}", flags), crate::ERROR);
|
||||
return Err(Error::new(format!("Application error: more than one flag bit set in set_flags: {:?}", flags)).set_kind(crate::ErrorKind::Bug));
|
||||
crate::log(
|
||||
format!(
|
||||
"Application error: more than one flag bit set in \
|
||||
set_flags: {:?}",
|
||||
flags
|
||||
),
|
||||
crate::ERROR,
|
||||
);
|
||||
return Err(Error::new(format!(
|
||||
"Application error: more than one flag bit set in set_flags: \
|
||||
{:?}",
|
||||
flags
|
||||
))
|
||||
.set_kind(crate::ErrorKind::Bug));
|
||||
}
|
||||
Err(tag) => {
|
||||
let hash = TagHash::from_bytes(tag.as_bytes());
|
||||
|
@ -812,13 +828,17 @@ impl MailBackend for ImapType {
|
|||
Ok(_) => {
|
||||
crate::log(
|
||||
format!(
|
||||
"Application error: more than one flag bit set in set_flags: {:?}", flags
|
||||
),
|
||||
"Application error: more than one flag bit set in \
|
||||
set_flags: {:?}",
|
||||
flags
|
||||
),
|
||||
crate::ERROR,
|
||||
);
|
||||
return Err(Error::new(format!(
|
||||
"Application error: more than one flag bit set in set_flags: {:?}", flags
|
||||
)));
|
||||
"Application error: more than one flag bit set in set_flags: \
|
||||
{:?}",
|
||||
flags
|
||||
)));
|
||||
}
|
||||
Err(tag) => {
|
||||
cmd.push_str(tag);
|
||||
|
@ -892,16 +912,17 @@ impl MailBackend for ImapType {
|
|||
Ok(Box::pin(async move {
|
||||
/* Must transform path to something the IMAP server will accept
|
||||
*
|
||||
* Each root mailbox has a hierarchy delimeter reported by the LIST entry. All paths
|
||||
* must use this delimeter to indicate children of this mailbox.
|
||||
* Each root mailbox has a hierarchy delimeter reported by the LIST entry.
|
||||
* All paths must use this delimeter to indicate children of this
|
||||
* mailbox.
|
||||
*
|
||||
* A new root mailbox should have the default delimeter, which can be found out by issuing
|
||||
* an empty LIST command as described in RFC3501:
|
||||
* A new root mailbox should have the default delimeter, which can be found
|
||||
* out by issuing an empty LIST command as described in RFC3501:
|
||||
* C: A101 LIST "" ""
|
||||
* S: * LIST (\Noselect) "/" ""
|
||||
*
|
||||
* The default delimiter for us is '/' just like UNIX paths. I apologise if this
|
||||
* decision is unpleasant for you.
|
||||
* The default delimiter for us is '/' just like UNIX paths. I apologise if
|
||||
* this decision is unpleasant for you.
|
||||
*/
|
||||
|
||||
{
|
||||
|
@ -924,8 +945,8 @@ impl MailBackend for ImapType {
|
|||
}
|
||||
}
|
||||
|
||||
/* FIXME Do not try to CREATE a sub-mailbox in a mailbox that has the \Noinferiors
|
||||
* flag set. */
|
||||
/* FIXME Do not try to CREATE a sub-mailbox in a mailbox
|
||||
* that has the \Noinferiors flag set. */
|
||||
}
|
||||
|
||||
let mut response = Vec::with_capacity(8 * 1024);
|
||||
|
@ -950,7 +971,17 @@ impl MailBackend for ImapType {
|
|||
ret?;
|
||||
let new_hash = MailboxHash::from_bytes(path.as_str().as_bytes());
|
||||
uid_store.mailboxes.lock().await.clear();
|
||||
Ok((new_hash, new_mailbox_fut?.await.map_err(|err| Error::new(format!("Mailbox create was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", String::from_utf8_lossy(&response), err)))?))
|
||||
Ok((
|
||||
new_hash,
|
||||
new_mailbox_fut?.await.map_err(|err| {
|
||||
Error::new(format!(
|
||||
"Mailbox create was succesful (returned `{}`) but listing mailboxes \
|
||||
afterwards returned `{}`",
|
||||
String::from_utf8_lossy(&response),
|
||||
err
|
||||
))
|
||||
})?,
|
||||
))
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -970,7 +1001,12 @@ impl MailBackend for ImapType {
|
|||
imap_path = mailboxes[&mailbox_hash].imap_path().to_string();
|
||||
let permissions = mailboxes[&mailbox_hash].permissions();
|
||||
if !permissions.delete_mailbox {
|
||||
return Err(Error::new(format!("You do not have permission to delete `{}`. Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions)));
|
||||
return Err(Error::new(format!(
|
||||
"You do not have permission to delete `{}`. Set permissions for this \
|
||||
mailbox are {}",
|
||||
mailboxes[&mailbox_hash].name(),
|
||||
permissions
|
||||
)));
|
||||
}
|
||||
}
|
||||
let mut response = Vec::with_capacity(8 * 1024);
|
||||
|
@ -998,7 +1034,15 @@ impl MailBackend for ImapType {
|
|||
let ret: Result<()> = ImapResponse::try_from(response.as_slice())?.into();
|
||||
ret?;
|
||||
uid_store.mailboxes.lock().await.clear();
|
||||
new_mailbox_fut?.await.map_err(|err| format!("Mailbox delete was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", String::from_utf8_lossy(&response), err).into())
|
||||
new_mailbox_fut?.await.map_err(|err| {
|
||||
format!(
|
||||
"Mailbox delete was succesful (returned `{}`) but listing mailboxes \
|
||||
afterwards returned `{}`",
|
||||
String::from_utf8_lossy(&response),
|
||||
err
|
||||
)
|
||||
.into()
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -1064,7 +1108,12 @@ impl MailBackend for ImapType {
|
|||
let mailboxes = uid_store.mailboxes.lock().await;
|
||||
let permissions = mailboxes[&mailbox_hash].permissions();
|
||||
if !permissions.delete_mailbox {
|
||||
return Err(Error::new(format!("You do not have permission to rename mailbox `{}` (rename is equivalent to delete + create). Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions)));
|
||||
return Err(Error::new(format!(
|
||||
"You do not have permission to rename mailbox `{}` (rename is equivalent \
|
||||
to delete + create). Set permissions for this mailbox are {}",
|
||||
mailboxes[&mailbox_hash].name(),
|
||||
permissions
|
||||
)));
|
||||
}
|
||||
if mailboxes[&mailbox_hash].separator != b'/' {
|
||||
new_path = new_path.replace(
|
||||
|
@ -1089,7 +1138,14 @@ impl MailBackend for ImapType {
|
|||
let ret: Result<()> = ImapResponse::try_from(response.as_slice())?.into();
|
||||
ret?;
|
||||
uid_store.mailboxes.lock().await.clear();
|
||||
new_mailbox_fut?.await.map_err(|err| format!("Mailbox rename was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", String::from_utf8_lossy(&response), err))?;
|
||||
new_mailbox_fut?.await.map_err(|err| {
|
||||
format!(
|
||||
"Mailbox rename was succesful (returned `{}`) but listing mailboxes \
|
||||
afterwards returned `{}`",
|
||||
String::from_utf8_lossy(&response),
|
||||
err
|
||||
)
|
||||
})?;
|
||||
Ok(BackendMailbox::clone(
|
||||
&uid_store.mailboxes.lock().await[&new_hash],
|
||||
))
|
||||
|
@ -1107,7 +1163,12 @@ impl MailBackend for ImapType {
|
|||
let mailboxes = uid_store.mailboxes.lock().await;
|
||||
let permissions = mailboxes[&mailbox_hash].permissions();
|
||||
if !permissions.change_permissions {
|
||||
return Err(Error::new(format!("You do not have permission to change permissions for mailbox `{}`. Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions)));
|
||||
return Err(Error::new(format!(
|
||||
"You do not have permission to change permissions for mailbox `{}`. Set \
|
||||
permissions for this mailbox are {}",
|
||||
mailboxes[&mailbox_hash].name(),
|
||||
permissions
|
||||
)));
|
||||
}
|
||||
|
||||
Err(Error::new("Unimplemented."))
|
||||
|
@ -1262,7 +1323,8 @@ impl ImapType {
|
|||
|
||||
if use_oauth2 && !s.extra.contains_key("server_password_command") {
|
||||
return Err(Error::new(format!(
|
||||
"({}) `use_oauth2` use requires `server_password_command` set with a command that returns an OAUTH2 token. Consult documentation for guidance.",
|
||||
"({}) `use_oauth2` use requires `server_password_command` set with a command that \
|
||||
returns an OAUTH2 token. Consult documentation for guidance.",
|
||||
s.name,
|
||||
)));
|
||||
}
|
||||
|
@ -1524,14 +1586,16 @@ impl ImapType {
|
|||
if !s.extra.contains_key("server_password_command") {
|
||||
if use_oauth2 {
|
||||
return Err(Error::new(format!(
|
||||
"({}) `use_oauth2` use requires `server_password_command` set with a command that returns an OAUTH2 token. Consult documentation for guidance.",
|
||||
"({}) `use_oauth2` use requires `server_password_command` set with a command \
|
||||
that returns an OAUTH2 token. Consult documentation for guidance.",
|
||||
s.name,
|
||||
)));
|
||||
}
|
||||
get_conf_val!(s["server_password"])?;
|
||||
} else if s.extra.contains_key("server_password") {
|
||||
return Err(Error::new(format!(
|
||||
"Configuration error ({}): both server_password and server_password_command are set, cannot choose",
|
||||
"Configuration error ({}): both server_password and server_password_command are \
|
||||
set, cannot choose",
|
||||
s.name.as_str(),
|
||||
)));
|
||||
}
|
||||
|
@ -1541,7 +1605,8 @@ impl ImapType {
|
|||
let use_starttls = get_conf_val!(s["use_starttls"], false)?;
|
||||
if !use_tls && use_starttls {
|
||||
return Err(Error::new(format!(
|
||||
"Configuration error ({}): incompatible use_tls and use_starttls values: use_tls = false, use_starttls = true",
|
||||
"Configuration error ({}): incompatible use_tls and use_starttls values: use_tls \
|
||||
= false, use_starttls = true",
|
||||
s.name.as_str(),
|
||||
)));
|
||||
}
|
||||
|
@ -1565,7 +1630,8 @@ impl ImapType {
|
|||
#[cfg(not(feature = "deflate_compression"))]
|
||||
if s.extra.contains_key("use_deflate") {
|
||||
return Err(Error::new(format!(
|
||||
"Configuration error ({}): setting `use_deflate` is set but this version of meli isn't compiled with DEFLATE support.",
|
||||
"Configuration error ({}): setting `use_deflate` is set but this version of meli \
|
||||
isn't compiled with DEFLATE support.",
|
||||
s.name.as_str(),
|
||||
)));
|
||||
}
|
||||
|
@ -1578,8 +1644,10 @@ impl ImapType {
|
|||
let diff = extra_keys.difference(&keys).collect::<Vec<&&str>>();
|
||||
if !diff.is_empty() {
|
||||
return Err(Error::new(format!(
|
||||
"Configuration error ({}): the following flags are set but are not recognized: {:?}.",
|
||||
s.name.as_str(), diff
|
||||
"Configuration error ({}): the following flags are set but are not recognized: \
|
||||
{:?}.",
|
||||
s.name.as_str(),
|
||||
diff
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
|
@ -1658,7 +1726,14 @@ async fn fetch_hlpr(state: &mut FetchState) -> Result<Vec<Envelope>> {
|
|||
/* Try resetting the database */
|
||||
if let Some(ref mut cache_handle) = state.cache_handle {
|
||||
if let Err(err) = cache_handle.reset() {
|
||||
crate::log(format!("IMAP cache error: could not reset cache for {}. Reason: {}", state.uid_store.account_name, err), crate::ERROR);
|
||||
crate::log(
|
||||
format!(
|
||||
"IMAP cache error: could not reset cache for {}. Reason: \
|
||||
{}",
|
||||
state.uid_store.account_name, err
|
||||
),
|
||||
crate::ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
state.stage = FetchStage::InitialFresh;
|
||||
|
@ -1743,11 +1818,14 @@ async fn fetch_hlpr(state: &mut FetchState) -> Result<Vec<Envelope>> {
|
|||
if max_uid_left > 0 {
|
||||
debug!("{} max_uid_left= {}", mailbox_hash, max_uid_left);
|
||||
let command = if max_uid_left == 1 {
|
||||
"UID FETCH 1 (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE)".to_string()
|
||||
"UID FETCH 1 (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] \
|
||||
BODYSTRUCTURE)"
|
||||
.to_string()
|
||||
} else {
|
||||
format!(
|
||||
"UID FETCH {}:{} (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE)",
|
||||
std::cmp::max(max_uid_left.saturating_sub(chunk_size), 1),
|
||||
"UID FETCH {}:{} (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS \
|
||||
(REFERENCES)] BODYSTRUCTURE)",
|
||||
std::cmp::max(max_uid_left.saturating_sub(chunk_size), 1),
|
||||
max_uid_left
|
||||
)
|
||||
};
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
|
||||
use super::*;
|
||||
mod sync;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::{
|
||||
backends::MailboxHash,
|
||||
email::{Envelope, EnvelopeHash},
|
||||
error::*,
|
||||
};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[derive(Debug, PartialEq, Hash, Eq, Ord, PartialOrd, Copy, Clone)]
|
||||
pub struct ModSequence(pub std::num::NonZeroU64);
|
||||
|
@ -105,10 +106,11 @@ pub use sqlite3_m::*;
|
|||
#[cfg(feature = "sqlite3")]
|
||||
mod sqlite3_m {
|
||||
use super::*;
|
||||
use crate::sqlite3::rusqlite::types::{
|
||||
FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput,
|
||||
use crate::sqlite3::{
|
||||
self,
|
||||
rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput},
|
||||
DatabaseDescription,
|
||||
};
|
||||
use crate::sqlite3::{self, DatabaseDescription};
|
||||
|
||||
type Sqlite3UID = i32;
|
||||
|
||||
|
@ -287,23 +289,45 @@ mod sqlite3_m {
|
|||
})?;
|
||||
|
||||
if let Some(Ok(highestmodseq)) = select_response.highestmodseq {
|
||||
self.connection.execute(
|
||||
"INSERT OR IGNORE INTO mailbox (uidvalidity, flags, highestmodseq, mailbox_hash) VALUES (?1, ?2, ?3, ?4)",
|
||||
sqlite3::params![select_response.uidvalidity as Sqlite3UID, select_response.flags.1.iter().map(|s| s.as_str()).collect::<Vec<&str>>().join("\0").as_bytes(), highestmodseq, mailbox_hash],
|
||||
)
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not insert uidvalidity {} in header_cache of account {}",
|
||||
select_response.uidvalidity, self.uid_store.account_name
|
||||
)
|
||||
})?;
|
||||
self.connection
|
||||
.execute(
|
||||
"INSERT OR IGNORE INTO mailbox (uidvalidity, flags, highestmodseq, \
|
||||
mailbox_hash) VALUES (?1, ?2, ?3, ?4)",
|
||||
sqlite3::params![
|
||||
select_response.uidvalidity as Sqlite3UID,
|
||||
select_response
|
||||
.flags
|
||||
.1
|
||||
.iter()
|
||||
.map(|s| s.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.join("\0")
|
||||
.as_bytes(),
|
||||
highestmodseq,
|
||||
mailbox_hash
|
||||
],
|
||||
)
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not insert uidvalidity {} in header_cache of account {}",
|
||||
select_response.uidvalidity, self.uid_store.account_name
|
||||
)
|
||||
})?;
|
||||
} else {
|
||||
self.connection
|
||||
.execute(
|
||||
"INSERT OR IGNORE INTO mailbox (uidvalidity, flags, mailbox_hash) VALUES (?1, ?2, ?3)",
|
||||
"INSERT OR IGNORE INTO mailbox (uidvalidity, flags, mailbox_hash) VALUES \
|
||||
(?1, ?2, ?3)",
|
||||
sqlite3::params![
|
||||
select_response.uidvalidity as Sqlite3UID,
|
||||
select_response.flags.1.iter().map(|s| s.as_str()).collect::<Vec<&str>>().join("\0").as_bytes(),
|
||||
select_response
|
||||
.flags
|
||||
.1
|
||||
.iter()
|
||||
.map(|s| s.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.join("\0")
|
||||
.as_bytes(),
|
||||
mailbox_hash
|
||||
],
|
||||
)
|
||||
|
@ -463,9 +487,24 @@ mod sqlite3_m {
|
|||
{
|
||||
max_uid = std::cmp::max(max_uid, *uid);
|
||||
tx.execute(
|
||||
"INSERT OR REPLACE INTO envelopes (hash, uid, mailbox_hash, modsequence, envelope) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
sqlite3::params![envelope.hash(), *uid as Sqlite3UID, mailbox_hash, modseq, &envelope],
|
||||
).chain_err_summary(|| format!("Could not insert envelope {} {} in header_cache of account {}", envelope.message_id(), envelope.hash(), uid_store.account_name))?;
|
||||
"INSERT OR REPLACE INTO envelopes (hash, uid, mailbox_hash, modsequence, \
|
||||
envelope) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
sqlite3::params![
|
||||
envelope.hash(),
|
||||
*uid as Sqlite3UID,
|
||||
mailbox_hash,
|
||||
modseq,
|
||||
&envelope
|
||||
],
|
||||
)
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not insert envelope {} {} in header_cache of account {}",
|
||||
envelope.message_id(),
|
||||
envelope.hash(),
|
||||
uid_store.account_name
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
tx.commit()?;
|
||||
|
@ -523,15 +562,17 @@ mod sqlite3_m {
|
|||
env.tags_mut()
|
||||
.extend(tags.iter().map(|t| TagHash::from_bytes(t.as_bytes())));
|
||||
tx.execute(
|
||||
"UPDATE envelopes SET envelope = ?1 WHERE mailbox_hash = ?2 AND uid = ?3;",
|
||||
sqlite3::params![&env, mailbox_hash, *uid as Sqlite3UID],
|
||||
)
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not update envelope {} uid {} from mailbox {} account {}",
|
||||
env_hash, *uid, mailbox_hash, uid_store.account_name
|
||||
)
|
||||
})?;
|
||||
"UPDATE envelopes SET envelope = ?1 WHERE mailbox_hash = ?2 AND \
|
||||
uid = ?3;",
|
||||
sqlite3::params![&env, mailbox_hash, *uid as Sqlite3UID],
|
||||
)
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not update envelope {} uid {} from mailbox {} account \
|
||||
{}",
|
||||
env_hash, *uid, mailbox_hash, uid_store.account_name
|
||||
)
|
||||
})?;
|
||||
uid_store
|
||||
.envelopes
|
||||
.lock()
|
||||
|
@ -563,8 +604,9 @@ mod sqlite3_m {
|
|||
let mut ret: Vec<(UID, Envelope, Option<ModSequence>)> = match identifier {
|
||||
Ok(uid) => {
|
||||
let mut stmt = self.connection.prepare(
|
||||
"SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1 AND uid = ?2;",
|
||||
)?;
|
||||
"SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1 \
|
||||
AND uid = ?2;",
|
||||
)?;
|
||||
|
||||
let x = stmt
|
||||
.query_map(sqlite3::params![mailbox_hash, uid as Sqlite3UID], |row| {
|
||||
|
@ -579,8 +621,9 @@ mod sqlite3_m {
|
|||
}
|
||||
Err(env_hash) => {
|
||||
let mut stmt = self.connection.prepare(
|
||||
"SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1 AND hash = ?2;",
|
||||
)?;
|
||||
"SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1 \
|
||||
AND hash = ?2;",
|
||||
)?;
|
||||
|
||||
let x = stmt
|
||||
.query_map(sqlite3::params![mailbox_hash, env_hash], |row| {
|
||||
|
|
|
@ -130,7 +130,8 @@ impl ImapConnection {
|
|||
// 2. tag1 UID FETCH <lastseenuid+1>:* <descriptors>
|
||||
self.send_command(
|
||||
format!(
|
||||
"UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE)",
|
||||
"UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] \
|
||||
BODYSTRUCTURE)",
|
||||
max_uid + 1
|
||||
)
|
||||
.as_bytes(),
|
||||
|
@ -375,9 +376,9 @@ impl ImapConnection {
|
|||
// client MUST
|
||||
// * empty the local cache of that mailbox;
|
||||
// * "forget" the cached HIGHESTMODSEQ value for the mailbox;
|
||||
// * remove any pending "actions" that refer to UIDs in that
|
||||
// mailbox (note that this doesn't affect actions performed on
|
||||
// client-generated fake UIDs; see Section 5); and
|
||||
// * remove any pending "actions" that refer to UIDs in that mailbox (note
|
||||
// that this doesn't affect actions performed on client-generated fake UIDs;
|
||||
// see Section 5); and
|
||||
// * skip steps 1b and 2-II;
|
||||
cache_handle.clear(mailbox_hash, &select_response)?;
|
||||
return Ok(None);
|
||||
|
@ -398,9 +399,9 @@ impl ImapConnection {
|
|||
let new_highestmodseq = select_response.highestmodseq.unwrap().unwrap();
|
||||
let mut refresh_events = vec![];
|
||||
// 1b) Check the mailbox HIGHESTMODSEQ.
|
||||
// If the cached value is the same as the one returned by the server, skip fetching
|
||||
// message flags on step 2-II, i.e., the client only has to find out which messages got
|
||||
// expunged.
|
||||
// If the cached value is the same as the one returned by the server, skip
|
||||
// fetching message flags on step 2-II, i.e., the client only has to
|
||||
// find out which messages got expunged.
|
||||
if cached_highestmodseq != new_highestmodseq {
|
||||
/* Cache is synced, only figure out which messages got expunged */
|
||||
|
||||
|
@ -415,7 +416,8 @@ impl ImapConnection {
|
|||
// 2. tag1 UID FETCH <lastseenuid+1>:* <descriptors>
|
||||
self.send_command(
|
||||
format!(
|
||||
"UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE) (CHANGEDSINCE {})",
|
||||
"UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] \
|
||||
BODYSTRUCTURE) (CHANGEDSINCE {})",
|
||||
cached_max_uid + 1,
|
||||
cached_highestmodseq,
|
||||
)
|
||||
|
@ -571,8 +573,8 @@ impl ImapConnection {
|
|||
.insert(mailbox_hash, Ok(new_highestmodseq));
|
||||
}
|
||||
let mut valid_envs = BTreeSet::default();
|
||||
// This should be UID SEARCH 1:<maxuid> but it's difficult to compare to cached UIDs at the
|
||||
// point of calling this function
|
||||
// This should be UID SEARCH 1:<maxuid> but it's difficult to compare to cached
|
||||
// UIDs at the point of calling this function
|
||||
self.send_command(b"UID SEARCH ALL").await?;
|
||||
self.read_response(&mut response, RequiredResponses::SEARCH)
|
||||
.await?;
|
||||
|
@ -614,7 +616,8 @@ impl ImapConnection {
|
|||
Ok(Some(payload.into_iter().map(|(_, env)| env).collect()))
|
||||
}
|
||||
|
||||
//rfc7162_Quick Flag Changes Resynchronization (CONDSTORE)_and Quick Mailbox Resynchronization (QRESYNC)
|
||||
//rfc7162_Quick Flag Changes Resynchronization (CONDSTORE)_and Quick Mailbox
|
||||
// Resynchronization (QRESYNC)
|
||||
pub async fn resync_condstoreqresync(
|
||||
&mut self,
|
||||
_cache_handle: Box<dyn ImapCache>,
|
||||
|
@ -634,8 +637,8 @@ impl ImapConnection {
|
|||
)
|
||||
};
|
||||
|
||||
/* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE only
|
||||
* returns READ-ONLY for both cases) */
|
||||
/* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE
|
||||
* only returns READ-ONLY for both cases) */
|
||||
let mut select_response = self
|
||||
.select_mailbox(mailbox_hash, &mut response, true)
|
||||
.await?
|
||||
|
|
|
@ -20,33 +20,38 @@
|
|||
*/
|
||||
|
||||
use super::protocol_parser::{ImapLineSplit, ImapResponse, RequiredResponses, SelectResponse};
|
||||
use crate::backends::{MailboxHash, RefreshEvent};
|
||||
use crate::connections::{lookup_ipv4, timeout, Connection};
|
||||
use crate::email::parser::BytesExt;
|
||||
use crate::error::*;
|
||||
use crate::{
|
||||
backends::{MailboxHash, RefreshEvent},
|
||||
connections::{lookup_ipv4, timeout, Connection},
|
||||
email::parser::BytesExt,
|
||||
error::*,
|
||||
};
|
||||
extern crate native_tls;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
convert::TryFrom,
|
||||
future::Future,
|
||||
iter::FromIterator,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant, SystemTime},
|
||||
};
|
||||
|
||||
use futures::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use native_tls::TlsConnector;
|
||||
pub use smol::Async as AsyncWrapper;
|
||||
use std::collections::HashSet;
|
||||
use std::convert::TryFrom;
|
||||
use std::future::Future;
|
||||
use std::iter::FromIterator;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant, SystemTime};
|
||||
|
||||
const IMAP_PROTOCOL_TIMEOUT: Duration = Duration::from_secs(60 * 28);
|
||||
|
||||
use super::protocol_parser;
|
||||
use super::{Capabilities, ImapServerConf, UIDStore};
|
||||
use super::{protocol_parser, Capabilities, ImapServerConf, UIDStore};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum SyncPolicy {
|
||||
None,
|
||||
///rfc4549 `Synch Ops for Disconnected IMAP4 Clients` <https://tools.ietf.org/html/rfc4549>
|
||||
Basic,
|
||||
///rfc7162 `IMAP Extensions: Quick Flag Changes Resynchronization (CONDSTORE) and Quick Mailbox Resynchronization (QRESYNC)`
|
||||
///rfc7162 `IMAP Extensions: Quick Flag Changes Resynchronization
|
||||
/// (CONDSTORE) and Quick Mailbox Resynchronization (QRESYNC)`
|
||||
Condstore,
|
||||
CondstoreQresync,
|
||||
}
|
||||
|
@ -144,13 +149,14 @@ impl ImapStream {
|
|||
if let Some(timeout) = server_conf.timeout {
|
||||
TcpStream::connect_timeout(&addr, timeout)?
|
||||
} else {
|
||||
TcpStream::connect(&addr)?
|
||||
TcpStream::connect(addr)?
|
||||
},
|
||||
))?;
|
||||
if server_conf.use_starttls {
|
||||
let err_fn = || {
|
||||
if server_conf.server_port == 993 {
|
||||
"STARTTLS failed. Server port is set to 993, which normally uses TLS. Maybe try disabling use_starttls."
|
||||
"STARTTLS failed. Server port is set to 993, which normally uses TLS. \
|
||||
Maybe try disabling use_starttls."
|
||||
} else {
|
||||
"STARTTLS failed. Is the connection already encrypted?"
|
||||
}
|
||||
|
@ -246,7 +252,7 @@ impl ImapStream {
|
|||
if let Some(timeout) = server_conf.timeout {
|
||||
TcpStream::connect_timeout(&addr, timeout)?
|
||||
} else {
|
||||
TcpStream::connect(&addr)?
|
||||
TcpStream::connect(addr)?
|
||||
},
|
||||
))?
|
||||
};
|
||||
|
@ -350,10 +356,14 @@ impl ImapStream {
|
|||
.any(|cap| cap.eq_ignore_ascii_case(b"AUTH=XOAUTH2"))
|
||||
{
|
||||
return Err(Error::new(format!(
|
||||
"Could not connect to {}: OAUTH2 is enabled but server did not return AUTH=XOAUTH2 capability. Returned capabilities were: {}",
|
||||
&server_conf.server_hostname,
|
||||
capabilities.iter().map(|capability|
|
||||
String::from_utf8_lossy(capability).to_string()).collect::<Vec<String>>().join(" ")
|
||||
"Could not connect to {}: OAUTH2 is enabled but server did not return \
|
||||
AUTH=XOAUTH2 capability. Returned capabilities were: {}",
|
||||
&server_conf.server_hostname,
|
||||
capabilities
|
||||
.iter()
|
||||
.map(|capability| String::from_utf8_lossy(capability).to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
)));
|
||||
}
|
||||
ret.send_command(
|
||||
|
@ -414,8 +424,8 @@ impl ImapStream {
|
|||
}
|
||||
|
||||
if capabilities.is_none() {
|
||||
/* sending CAPABILITY after LOGIN automatically is an RFC recommendation, so check
|
||||
* for lazy servers */
|
||||
/* sending CAPABILITY after LOGIN automatically is an RFC recommendation, so
|
||||
* check for lazy servers */
|
||||
drop(capabilities);
|
||||
ret.send_command(b"CAPABILITY").await?;
|
||||
ret.read_response(&mut res).await.unwrap();
|
||||
|
@ -648,7 +658,14 @@ impl ImapConnection {
|
|||
| ImapResponse::Bad(code)
|
||||
| ImapResponse::Preauth(code)
|
||||
| ImapResponse::Bye(code) => {
|
||||
crate::log(format!("Could not use COMPRESS=DEFLATE in account `{}`: server replied with `{}`", self.uid_store.account_name, code), crate::LoggingLevel::WARN);
|
||||
crate::log(
|
||||
format!(
|
||||
"Could not use COMPRESS=DEFLATE in account `{}`: server \
|
||||
replied with `{}`",
|
||||
self.uid_store.account_name, code
|
||||
),
|
||||
crate::LoggingLevel::WARN,
|
||||
);
|
||||
}
|
||||
ImapResponse::Ok(_) => {
|
||||
let ImapStream {
|
||||
|
@ -750,7 +767,7 @@ impl ImapConnection {
|
|||
&required_responses
|
||||
);*/
|
||||
for l in response.split_rn() {
|
||||
/*debug!("check line: {}", &l);*/
|
||||
/* debug!("check line: {}", &l); */
|
||||
if required_responses.check(l) || !self.process_untagged(l).await? {
|
||||
ret.extend_from_slice(l);
|
||||
}
|
||||
|
|
|
@ -19,13 +19,16 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use super::protocol_parser::SelectResponse;
|
||||
use crate::backends::{
|
||||
BackendMailbox, LazyCountSet, Mailbox, MailboxHash, MailboxPermissions, SpecialUsageMailbox,
|
||||
};
|
||||
use crate::error::*;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
use super::protocol_parser::SelectResponse;
|
||||
use crate::{
|
||||
backends::{
|
||||
BackendMailbox, LazyCountSet, Mailbox, MailboxHash, MailboxPermissions, SpecialUsageMailbox,
|
||||
},
|
||||
error::*,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ImapMailbox {
|
||||
pub hash: MailboxHash,
|
||||
|
@ -51,7 +54,8 @@ impl ImapMailbox {
|
|||
&self.imap_path
|
||||
}
|
||||
|
||||
/// Establish that mailbox contents have been fetched at least once during this execution
|
||||
/// Establish that mailbox contents have been fetched at least once during
|
||||
/// this execution
|
||||
#[inline(always)]
|
||||
pub fn set_warm(&self, new_value: bool) {
|
||||
*self.warm.lock().unwrap() = new_value;
|
||||
|
|
|
@ -19,19 +19,25 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore};
|
||||
use crate::conf::AccountSettings;
|
||||
use crate::email::parser::IResult;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::get_conf_val;
|
||||
use crate::imap::RequiredResponses;
|
||||
use std::{
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use nom::{
|
||||
branch::alt, bytes::complete::tag, combinator::map, multi::separated_list1,
|
||||
sequence::separated_pair,
|
||||
};
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::SystemTime;
|
||||
|
||||
use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore};
|
||||
use crate::{
|
||||
conf::AccountSettings,
|
||||
email::parser::IResult,
|
||||
error::{Error, Result},
|
||||
get_conf_val,
|
||||
imap::RequiredResponses,
|
||||
};
|
||||
|
||||
pub struct ManageSieveConnection {
|
||||
pub inner: ImapConnection,
|
||||
|
@ -61,12 +67,17 @@ pub enum ManageSieveResponse<'a> {
|
|||
}
|
||||
|
||||
mod parser {
|
||||
use nom::{
|
||||
bytes::complete::tag,
|
||||
character::complete::crlf,
|
||||
combinator::{iterator, map, opt},
|
||||
};
|
||||
pub use nom::{
|
||||
bytes::complete::{is_not, tag_no_case},
|
||||
sequence::{delimited, pair, preceded, terminated},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use nom::bytes::complete::tag;
|
||||