forked from meli/meli
1
Fork 0

Clippy fixes

feature/export-vcards
Manos Pitsidianakis 2023-04-30 19:39:41 +03:00
parent 3a02b6fb80
commit b1a7188771
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
136 changed files with 4642 additions and 3388 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
pub use nom::bytes::complete::{is_not, tag_no_case};
use nom::character::complete::crlf;
use nom::combinator::{iterator, map, opt};
pub use nom::sequence::{delimited, pair, preceded, terminated};