Fix unreachable-pub and disjoint-capture lint errors
Tests / Test on ${{ matrix.build }} (linux-amd64, ubuntu-latest, stable, x86_64-unknown-linux-gnu) (push) Failing after 6m8s Details

pull/260/head
Manos Pitsidianakis 2023-07-20 00:19:42 +03:00
parent 1d0405ed5b
commit 8e698cabcf
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
23 changed files with 647 additions and 609 deletions

View File

@ -29,7 +29,7 @@ use quote::{format_ident, quote};
use regex::Regex;
// Write ConfigStructOverride to overrides.rs
pub fn override_derive(filenames: &[(&str, &str)]) {
pub(crate) 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##"// @generated

View File

@ -40,7 +40,7 @@ use super::*;
use crate::{conf::accounts::JobRequest, jobs::JoinHandle, terminal::embed::EmbedTerminal};
#[cfg(feature = "gpgme")]
mod gpg;
pub mod gpg;
pub mod edit_attachments;
use edit_attachments::*;

View File

@ -444,8 +444,327 @@ pub trait MailListingTrait: ListingTrait {
envs_to_set: SmallVec<[EnvelopeHash; 8]>,
a: &ListingAction,
) {
fn inner(
context: &mut Context,
envs_to_set: SmallVec<[EnvelopeHash; 8]>,
account_hash: AccountHash,
mailbox_hash: MailboxHash,
a: &ListingAction,
) {
let env_hashes = if let Ok(batch) = EnvelopeHashBatch::try_from(envs_to_set.as_slice())
{
batch
} else {
return;
};
let account = &mut context.accounts[&account_hash];
match a {
ListingAction::SetSeen => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Ok(Flag::SEEN), true)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("set_seen".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::SetFlags { env_hashes, handle },
);
}
}
}
ListingAction::SetUnseen => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Ok(Flag::SEEN), false)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("set_unseen".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::SetFlags { env_hashes, handle },
);
}
}
}
ListingAction::Tag(Remove(ref tag_str)) => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Err(tag_str.to_string()), false)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("remove_tag".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::SetFlags { env_hashes, handle },
);
}
}
}
ListingAction::Tag(Add(ref tag_str)) => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Err(tag_str.to_string()), true)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("add_tag".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::SetFlags { env_hashes, handle },
);
}
}
}
ListingAction::Delete => {
let job = account
.backend
.write()
.unwrap()
.delete_messages(env_hashes.clone(), mailbox_hash);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("delete".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::DeleteMessages { env_hashes, handle },
);
}
}
}
ListingAction::CopyTo(ref mailbox_path) => {
match account.mailbox_by_path(mailbox_path).and_then(
|destination_mailbox_hash| {
account.backend.write().unwrap().copy_messages(
env_hashes,
mailbox_hash,
destination_mailbox_hash,
/* move? */ false,
)
},
) {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("copy_to_mailbox".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "message copying".into(),
handle,
on_finish: None,
log_level: LogLevel::INFO,
},
);
}
}
}
ListingAction::CopyToOtherAccount(ref _account_name, ref _mailbox_path) => {
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"Copying to another account is currently unimplemented".into(),
)));
}
ListingAction::MoveTo(ref mailbox_path) => {
match account.mailbox_by_path(mailbox_path).and_then(
|destination_mailbox_hash| {
account.backend.write().unwrap().copy_messages(
env_hashes,
mailbox_hash,
destination_mailbox_hash,
/* move? */ true,
)
},
) {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("move_to_mailbox".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "message moving".into(),
handle,
on_finish: None,
log_level: LogLevel::INFO,
},
);
}
}
}
ListingAction::ExportMbox(format, ref path) => {
use std::{future::Future, io::Write, pin::Pin};
use futures::future::try_join_all;
let futures: Result<Vec<_>> = envs_to_set
.iter()
.map(|&env_hash| {
account.operation(env_hash).and_then(|mut op| op.as_bytes())
})
.collect::<Result<Vec<_>>>();
let path_ = path.to_path_buf();
let format = (*format).unwrap_or_default();
let collection = account.collection.clone();
let (sender, mut receiver) = crate::jobs::oneshot::channel();
let fut: Pin<Box<dyn Future<Output = Result<()>> + Send + 'static>> =
Box::pin(async move {
let cl = async move {
use melib::backends::mbox::MboxMetadata;
let bytes: Vec<Vec<u8>> = try_join_all(futures?).await?;
let envs: Vec<_> = envs_to_set
.iter()
.map(|&env_hash| collection.get_env(env_hash))
.collect();
let mut file =
std::io::BufWriter::new(std::fs::File::create(&path_)?);
let mut iter = envs.iter().zip(bytes.into_iter());
let tags_lck = collection.tag_index.read().unwrap();
if let Some((env, ref bytes)) = iter.next() {
let tags: Vec<&str> = env
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
format.append(
&mut file,
bytes.as_slice(),
env.from().get(0),
Some(env.date()),
(env.flags(), tags),
MboxMetadata::CClient,
true,
false,
)?;
}
for (env, bytes) in iter {
let tags: Vec<&str> = env
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
format.append(
&mut file,
bytes.as_slice(),
env.from().get(0),
Some(env.date()),
(env.flags(), tags),
MboxMetadata::CClient,
false,
false,
)?;
}
file.flush()?;
Ok(())
};
let r: Result<()> = cl.await;
let _ = sender.send(r);
Ok(())
});
let handle = account
.main_loop_handler
.job_executor
.spawn_blocking("export_to_mbox".into(), fut);
let path = path.to_path_buf();
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "exporting mbox".into(),
handle,
on_finish: Some(CallbackFn(Box::new(move |context: &mut Context| {
context.replies.push_back(match receiver.try_recv() {
Err(_) | Ok(None) => UIEvent::Notification(
Some("Could not export mbox".to_string()),
"Job was canceled.".to_string(),
Some(NotificationType::Info),
),
Ok(Some(Err(err))) => UIEvent::Notification(
Some("Could not export mbox".to_string()),
err.to_string(),
Some(NotificationType::Error(err.kind)),
),
Ok(Some(Ok(()))) => UIEvent::Notification(
Some("Succesfully exported mbox".to_string()),
format!("Wrote to file {}", path.display()),
Some(NotificationType::Info),
),
});
}))),
log_level: LogLevel::INFO,
},
);
}
ListingAction::MoveToOtherAccount(ref _account_name, ref _mailbox_path) => {
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"Moving to another account is currently unimplemented".into(),
)));
}
_ => unreachable!(),
}
}
let account_hash = self.coordinates().0;
let account = &mut context.accounts[&account_hash];
let mailbox_hash = self.coordinates().1;
/*{
let threads_lck = account.collection.get_threads(mailbox_hash);
@ -457,305 +776,7 @@ pub trait MailListingTrait: ListingTrait {
}
}
*/
let env_hashes = if let Ok(batch) = EnvelopeHashBatch::try_from(envs_to_set.as_slice()) {
batch
} else {
return;
};
match a {
ListingAction::SetSeen => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Ok(Flag::SEEN), true)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("set_seen".into(), fut);
account
.insert_job(handle.job_id, JobRequest::SetFlags { env_hashes, handle });
}
}
}
ListingAction::SetUnseen => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Ok(Flag::SEEN), false)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("set_unseen".into(), fut);
account
.insert_job(handle.job_id, JobRequest::SetFlags { env_hashes, handle });
}
}
}
ListingAction::Tag(Remove(ref tag_str)) => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Err(tag_str.to_string()), false)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("remove_tag".into(), fut);
account
.insert_job(handle.job_id, JobRequest::SetFlags { env_hashes, handle });
}
}
}
ListingAction::Tag(Add(ref tag_str)) => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Err(tag_str.to_string()), true)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("add_tag".into(), fut);
account
.insert_job(handle.job_id, JobRequest::SetFlags { env_hashes, handle });
}
}
}
ListingAction::Delete => {
let job = account
.backend
.write()
.unwrap()
.delete_messages(env_hashes.clone(), mailbox_hash);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("delete".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::DeleteMessages { env_hashes, handle },
);
}
}
}
ListingAction::CopyTo(ref mailbox_path) => {
match account
.mailbox_by_path(mailbox_path)
.and_then(|destination_mailbox_hash| {
account.backend.write().unwrap().copy_messages(
env_hashes,
mailbox_hash,
destination_mailbox_hash,
/* move? */ false,
)
}) {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("copy_to_mailbox".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "message copying".into(),
handle,
on_finish: None,
log_level: LogLevel::INFO,
},
);
}
}
}
ListingAction::CopyToOtherAccount(ref _account_name, ref _mailbox_path) => {
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"Copying to another account is currently unimplemented".into(),
)));
}
ListingAction::MoveTo(ref mailbox_path) => {
match account
.mailbox_by_path(mailbox_path)
.and_then(|destination_mailbox_hash| {
account.backend.write().unwrap().copy_messages(
env_hashes,
mailbox_hash,
destination_mailbox_hash,
/* move? */ true,
)
}) {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("move_to_mailbox".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "message moving".into(),
handle,
on_finish: None,
log_level: LogLevel::INFO,
},
);
}
}
}
ListingAction::ExportMbox(format, ref path) => {
use std::{future::Future, io::Write, pin::Pin};
use futures::future::try_join_all;
let futures: Result<Vec<_>> = envs_to_set
.iter()
.map(|&env_hash| account.operation(env_hash).and_then(|mut op| op.as_bytes()))
.collect::<Result<Vec<_>>>();
let path_ = path.to_path_buf();
let format = (*format).unwrap_or_default();
let collection = account.collection.clone();
let (sender, mut receiver) = crate::jobs::oneshot::channel();
let fut: Pin<Box<dyn Future<Output = Result<()>> + Send + 'static>> =
Box::pin(async move {
let cl = async move {
use melib::backends::mbox::MboxMetadata;
let bytes: Vec<Vec<u8>> = try_join_all(futures?).await?;
let envs: Vec<_> = envs_to_set
.iter()
.map(|&env_hash| collection.get_env(env_hash))
.collect();
let mut file = std::io::BufWriter::new(std::fs::File::create(&path_)?);
let mut iter = envs.iter().zip(bytes.into_iter());
let tags_lck = collection.tag_index.read().unwrap();
if let Some((env, ref bytes)) = iter.next() {
let tags: Vec<&str> = env
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
format.append(
&mut file,
bytes.as_slice(),
env.from().get(0),
Some(env.date()),
(env.flags(), tags),
MboxMetadata::CClient,
true,
false,
)?;
}
for (env, bytes) in iter {
let tags: Vec<&str> = env
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
format.append(
&mut file,
bytes.as_slice(),
env.from().get(0),
Some(env.date()),
(env.flags(), tags),
MboxMetadata::CClient,
false,
false,
)?;
}
file.flush()?;
Ok(())
};
let r: Result<()> = cl.await;
let _ = sender.send(r);
Ok(())
});
let handle = account
.main_loop_handler
.job_executor
.spawn_blocking("export_to_mbox".into(), fut);
let path = path.to_path_buf();
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "exporting mbox".into(),
handle,
on_finish: Some(CallbackFn(Box::new(move |context: &mut Context| {
context.replies.push_back(match receiver.try_recv() {
Err(_) | Ok(None) => UIEvent::Notification(
Some("Could not export mbox".to_string()),
"Job was canceled.".to_string(),
Some(NotificationType::Info),
),
Ok(Some(Err(err))) => UIEvent::Notification(
Some("Could not export mbox".to_string()),
err.to_string(),
Some(NotificationType::Error(err.kind)),
),
Ok(Some(Ok(()))) => UIEvent::Notification(
Some("Succesfully exported mbox".to_string()),
format!("Wrote to file {}", path.display()),
Some(NotificationType::Info),
),
});
}))),
log_level: LogLevel::INFO,
},
);
}
ListingAction::MoveToOtherAccount(ref _account_name, ref _mailbox_path) => {
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"Moving to another account is currently unimplemented".into(),
)));
}
_ => unreachable!(),
}
inner(context, envs_to_set, account_hash, mailbox_hash, a);
self.set_dirty(true);
}

View File

@ -45,7 +45,7 @@ mod thread;
pub use thread::*;
mod types;
pub use types::*;
mod state;
pub mod state;
use state::*;
pub mod envelope;

View File

@ -1010,7 +1010,7 @@ mod pp {
/// Expands `include` macros in configuration file and other configuration
/// files (eg. themes) in the filesystem.
pub fn pp<P: AsRef<Path>>(path: P) -> Result<String> {
pub(super) fn pp<P: AsRef<Path>>(path: P) -> Result<String> {
let p_buf: PathBuf = if path.as_ref().is_relative() {
path.as_ref().expand().canonicalize()?
} else {

View File

@ -466,6 +466,8 @@ impl Account {
let backend = map.get(&settings.account().format)(
settings.account(),
Box::new(move |path: &str| {
// disjoint-capture-in-closures
let _ = &s;
s.account.subscribed_mailboxes.is_empty()
|| (s.mailbox_confs.contains_key(path)
&& s.mailbox_confs[path].mailbox_conf().subscribe.is_true())

View File

@ -171,7 +171,7 @@ macro_rules! named_unit_variant {
};
}
mod strings {
pub mod strings {
named_unit_variant!(server_submission);
}

View File

@ -44,7 +44,11 @@ use crate::types::{ThreadEvent, UIEvent};
type AsyncTask = async_task::Runnable;
fn find_task<T>(local: &Worker<T>, global: &Injector<T>, stealers: &[Stealer<T>]) -> Option<T> {
fn find_task(
local: &Worker<MeliTask>,
global: &Injector<MeliTask>,
stealers: &[Stealer<MeliTask>],
) -> Option<MeliTask> {
// Pop a task from the local queue, if not empty.
local.pop().or_else(|| {
// Otherwise, we need to look for a task elsewhere.

View File

@ -26,13 +26,13 @@ use serde::{de, de::Visitor, Deserialize, Deserializer};
mod color;
pub use color::*;
#[macro_use]
mod position;
pub mod position;
#[macro_use]
mod cells;
pub mod cells;
#[macro_use]
mod keys;
pub mod keys;
pub mod embed;
mod text_editing;
pub mod text_editing;
use std::fmt;
pub use self::{cells::*, keys::*, position::*, text_editing::*};

View File

@ -746,7 +746,6 @@ impl Serialize for Color {
}
}
pub use aliases::*;
pub mod aliases {
use super::Color;

View File

@ -34,10 +34,10 @@ mod watch;
pub use watch::*;
mod search;
pub use search::*;
mod cache;
pub mod cache;
pub mod error;
pub mod managesieve;
mod untagged;
pub mod untagged;
use std::{
collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet},

View File

@ -20,7 +20,7 @@
*/
use super::*;
mod sync;
pub mod sync;
use std::convert::TryFrom;
use crate::{
@ -104,7 +104,7 @@ pub trait ImapCacheReset: Send + core::fmt::Debug {
pub use sqlite3_m::*;
#[cfg(feature = "sqlite3")]
mod sqlite3_m {
pub mod sqlite3_m {
use super::*;
use crate::utils::sqlite3::{
self,
@ -739,7 +739,7 @@ pub(super) async fn fetch_cached_envs(state: &mut FetchState) -> Result<Option<V
pub use default_m::*;
#[cfg(not(feature = "sqlite3"))]
mod default_m {
pub mod default_m {
use super::*;
#[derive(Debug)]
pub struct DefaultCache;

View File

@ -25,11 +25,6 @@ use std::{
time::SystemTime,
};
use nom::{
branch::alt, bytes::complete::tag, combinator::map, multi::separated_list1,
sequence::separated_pair,
};
use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore};
use crate::{
conf::AccountSettings,
@ -43,17 +38,6 @@ pub struct ManageSieveConnection {
pub inner: ImapConnection,
}
pub fn managesieve_capabilities(input: &[u8]) -> Result<Vec<(&[u8], &[u8])>> {
let (_, ret) = separated_list1(
tag(b"\r\n"),
alt((
separated_pair(quoted_raw, tag(b" "), quoted_raw),
map(quoted_raw, |q| (q, &b""[..])),
)),
)(input)?;
Ok(ret)
}
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum ManageSieveResponse<'a> {
Ok {
@ -66,231 +50,6 @@ 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::*;
pub fn sieve_name(input: &[u8]) -> IResult<&[u8], &[u8]> {
crate::backends::imap::protocol_parser::string_token(input)
}
// *(sieve-name [SP "ACTIVE"] CRLF)
// response-oknobye
pub fn listscripts(input: &[u8]) -> IResult<&[u8], Vec<(&[u8], bool)>> {
let mut it = iterator(
input,
alt((
terminated(
map(terminated(sieve_name, tag_no_case(b" ACTIVE")), |r| {
(r, true)
}),
crlf,
),
terminated(map(sieve_name, |r| (r, false)), crlf),
)),
);
let parsed = (&mut it).collect::<Vec<(&[u8], bool)>>();
let res: IResult<_, _> = it.finish();
let (rest, _) = res?;
Ok((rest, parsed))
}
// response-getscript = (sieve-script CRLF response-ok) /
// response-nobye
pub fn getscript(input: &[u8]) -> IResult<&[u8], &[u8]> {
sieve_name(input)
}
pub fn response_oknobye(input: &[u8]) -> IResult<&[u8], ManageSieveResponse> {
alt((
map(
terminated(
pair(
preceded(
tag_no_case(b"ok"),
opt(preceded(
tag(b" "),
delimited(tag(b"("), is_not(")"), tag(b")")),
)),
),
opt(preceded(tag(b" "), sieve_name)),
),
crlf,
),
|(code, message)| ManageSieveResponse::Ok { code, message },
),
map(
terminated(
pair(
preceded(
alt((tag_no_case(b"no"), tag_no_case(b"bye"))),
opt(preceded(
tag(b" "),
delimited(tag(b"("), is_not(")"), tag(b")")),
)),
),
opt(preceded(tag(b" "), sieve_name)),
),
crlf,
),
|(code, message)| ManageSieveResponse::NoBye { code, message },
),
))(input)
}
#[test]
fn test_managesieve_listscripts() {
let input_1 = b"\"summer_script\"\r\n\"vacation_script\"\r\n{13}\r\nclever\"script\r\n\"main_script\" ACTIVE\r\nOK";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_1),
Ok((
&b""[..],
vec![
(&b"summer_script"[..], false),
(&b"vacation_script"[..], false),
(&b"clever\"script"[..], false),
(&b"main_script"[..], true)
]
))
);
let input_2 = b"\"summer_script\"\r\n\"main_script\" active\r\nok";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_2),
Ok((
&b""[..],
vec![(&b"summer_script"[..], false), (&b"main_script"[..], true)]
))
);
let input_3 = b"ok";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_3),
Ok((&b""[..], vec![]))
);
}
#[test]
fn test_managesieve_general() {
assert_eq!(managesieve_capabilities(b"\"IMPLEMENTATION\" \"Dovecot Pigeonhole\"\r\n\"SIEVE\" \"fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext\"\r\n\"NOTIFY\" \"mailto\"\r\n\"SASL\" \"PLAIN\"\r\n\"STARTTLS\"\r\n\"VERSION\" \"1.0\"\r\n").unwrap(), vec![
(&b"IMPLEMENTATION"[..],&b"Dovecot Pigeonhole"[..]),
(&b"SIEVE"[..],&b"fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext"[..]),
(&b"NOTIFY"[..],&b"mailto"[..]),
(&b"SASL"[..],&b"PLAIN"[..]),
(&b"STARTTLS"[..], &b""[..]),
(&b"VERSION"[..],&b"1.0"[..])]
);
let response_ok = b"OK (WARNINGS) \"line 8: server redirect action limit is 2, this redirect might be ignored\"\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: Some(&b"WARNINGS"[..]),
message: Some(&b"line 8: server redirect action limit is 2, this redirect might be ignored"[..]),
}
))
);
let response_ok = b"OK (WARNINGS)\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: Some(&b"WARNINGS"[..]),
message: None,
}
))
);
let response_ok =
b"OK \"line 8: server redirect action limit is 2, this redirect might be ignored\"\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: None,
message: Some(&b"line 8: server redirect action limit is 2, this redirect might be ignored"[..]),
}
))
);
let response_ok = b"Ok\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: None,
message: None,
}
))
);
let response_nobye = b"No (NONEXISTENT) \"There is no script by that name\"\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: Some(&b"NONEXISTENT"[..]),
message: Some(&b"There is no script by that name"[..]),
}
))
);
let response_nobye = b"No (NONEXISTENT) {31}\r\nThere is no script by that name\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: Some(&b"NONEXISTENT"[..]),
message: Some(&b"There is no script by that name"[..]),
}
))
);
let response_nobye = b"No\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: None,
message: None,
}
))
);
}
}
// Return a byte sequence surrounded by "s and decoded if necessary
pub fn quoted_raw(input: &[u8]) -> IResult<&[u8], &[u8]> {
if input.is_empty() || input[0] != b'"' {
return Err(nom::Err::Error((input, "empty").into()));
}
let mut i = 1;
while i < input.len() {
if input[i] == b'\"' && input[i - 1] != b'\\' {
return Ok((&input[i + 1..], &input[1..i]));
}
i += 1;
}
Err(nom::Err::Error((input, "no quotes").into()))
}
impl ManageSieveConnection {
pub fn new(
account_hash: crate::backends::AccountHash,
@ -479,3 +238,247 @@ impl ManageSieveConnection {
Ok(())
}
}
pub mod parser {
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::crlf,
combinator::{iterator, map, opt},
multi::separated_list1,
sequence::separated_pair,
};
pub use nom::{
bytes::complete::{is_not, tag_no_case},
sequence::{delimited, pair, preceded, terminated},
};
use super::*;
/// Return a byte sequence surrounded by "s and decoded if necessary
pub fn quoted_raw(input: &[u8]) -> IResult<&[u8], &[u8]> {
if input.is_empty() || input[0] != b'"' {
return Err(nom::Err::Error((input, "empty").into()));
}
let mut i = 1;
while i < input.len() {
if input[i] == b'\"' && input[i - 1] != b'\\' {
return Ok((&input[i + 1..], &input[1..i]));
}
i += 1;
}
Err(nom::Err::Error((input, "no quotes").into()))
}
pub fn managesieve_capabilities(input: &[u8]) -> Result<Vec<(&[u8], &[u8])>> {
let (_, ret) = separated_list1(
tag(b"\r\n"),
alt((
separated_pair(quoted_raw, tag(b" "), quoted_raw),
map(quoted_raw, |q| (q, &b""[..])),
)),
)(input)?;
Ok(ret)
}
pub fn sieve_name(input: &[u8]) -> IResult<&[u8], &[u8]> {
crate::backends::imap::protocol_parser::string_token(input)
}
// *(sieve-name [SP "ACTIVE"] CRLF)
// response-oknobye
pub fn listscripts(input: &[u8]) -> IResult<&[u8], Vec<(&[u8], bool)>> {
let mut it = iterator(
input,
alt((
terminated(
map(terminated(sieve_name, tag_no_case(b" ACTIVE")), |r| {
(r, true)
}),
crlf,
),
terminated(map(sieve_name, |r| (r, false)), crlf),
)),
);
let parsed = (&mut it).collect::<Vec<(&[u8], bool)>>();
let res: IResult<_, _> = it.finish();
let (rest, _) = res?;
Ok((rest, parsed))
}
// response-getscript = (sieve-script CRLF response-ok) /
// response-nobye
pub fn getscript(input: &[u8]) -> IResult<&[u8], &[u8]> {
sieve_name(input)
}
pub fn response_oknobye(input: &[u8]) -> IResult<&[u8], ManageSieveResponse> {
alt((
map(
terminated(
pair(
preceded(
tag_no_case(b"ok"),
opt(preceded(
tag(b" "),
delimited(tag(b"("), is_not(")"), tag(b")")),
)),
),
opt(preceded(tag(b" "), sieve_name)),
),
crlf,
),
|(code, message)| ManageSieveResponse::Ok { code, message },
),
map(
terminated(
pair(
preceded(
alt((tag_no_case(b"no"), tag_no_case(b"bye"))),
opt(preceded(
tag(b" "),
delimited(tag(b"("), is_not(")"), tag(b")")),
)),
),
opt(preceded(tag(b" "), sieve_name)),
),
crlf,
),
|(code, message)| ManageSieveResponse::NoBye { code, message },
),
))(input)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_managesieve_listscripts() {
let input_1 = b"\"summer_script\"\r\n\"vacation_script\"\r\n{13}\r\nclever\"script\r\n\"main_script\" ACTIVE\r\nOK";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_1),
Ok((
&b""[..],
vec![
(&b"summer_script"[..], false),
(&b"vacation_script"[..], false),
(&b"clever\"script"[..], false),
(&b"main_script"[..], true)
]
))
);
let input_2 = b"\"summer_script\"\r\n\"main_script\" active\r\nok";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_2),
Ok((
&b""[..],
vec![(&b"summer_script"[..], false), (&b"main_script"[..], true)]
))
);
let input_3 = b"ok";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_3),
Ok((&b""[..], vec![]))
);
}
#[test]
fn test_managesieve_general() {
assert_eq!(managesieve_capabilities(b"\"IMPLEMENTATION\" \"Dovecot Pigeonhole\"\r\n\"SIEVE\" \"fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext\"\r\n\"NOTIFY\" \"mailto\"\r\n\"SASL\" \"PLAIN\"\r\n\"STARTTLS\"\r\n\"VERSION\" \"1.0\"\r\n").unwrap(), vec![
(&b"IMPLEMENTATION"[..],&b"Dovecot Pigeonhole"[..]),
(&b"SIEVE"[..],&b"fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext"[..]),
(&b"NOTIFY"[..],&b"mailto"[..]),
(&b"SASL"[..],&b"PLAIN"[..]),
(&b"STARTTLS"[..], &b""[..]),
(&b"VERSION"[..],&b"1.0"[..])]
);
let response_ok = b"OK (WARNINGS) \"line 8: server redirect action limit is 2, this redirect might be ignored\"\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: Some(&b"WARNINGS"[..]),
message: Some(&b"line 8: server redirect action limit is 2, this redirect might be ignored"[..]),
}
))
);
let response_ok = b"OK (WARNINGS)\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: Some(&b"WARNINGS"[..]),
message: None,
}
))
);
let response_ok =
b"OK \"line 8: server redirect action limit is 2, this redirect might be ignored\"\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: None,
message: Some(&b"line 8: server redirect action limit is 2, this redirect might be ignored"[..]),
}
))
);
let response_ok = b"Ok\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: None,
message: None,
}
))
);
let response_nobye = b"No (NONEXISTENT) \"There is no script by that name\"\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: Some(&b"NONEXISTENT"[..]),
message: Some(&b"There is no script by that name"[..]),
}
))
);
let response_nobye = b"No (NONEXISTENT) {31}\r\nThere is no script by that name\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: Some(&b"NONEXISTENT"[..]),
message: Some(&b"There is no script by that name"[..]),
}
))
);
let response_nobye = b"No\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: None,
message: None,
}
))
);
}
}
}

View File

@ -202,20 +202,20 @@ fn get_rw_lock_blocking(f: &File, path: &Path) -> Result<()> {
}
#[derive(Debug)]
struct MboxMailbox {
hash: MailboxHash,
name: String,
path: PathBuf,
fs_path: PathBuf,
content: Vec<u8>,
children: Vec<MailboxHash>,
parent: Option<MailboxHash>,
usage: Arc<RwLock<SpecialUsageMailbox>>,
is_subscribed: bool,
permissions: MailboxPermissions,
pub struct MboxMailbox {
pub hash: MailboxHash,
pub name: String,
pub path: PathBuf,
pub fs_path: PathBuf,
pub content: Vec<u8>,
pub children: Vec<MailboxHash>,
pub parent: Option<MailboxHash>,
pub usage: Arc<RwLock<SpecialUsageMailbox>>,
pub is_subscribed: bool,
pub permissions: MailboxPermissions,
pub total: Arc<Mutex<usize>>,
pub unseen: Arc<Mutex<usize>>,
index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>,
pub index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>,
}
impl BackendMailbox for MboxMailbox {
@ -285,11 +285,11 @@ impl BackendMailbox for MboxMailbox {
/// `BackendOp` implementor for Mbox
#[derive(Debug, Default)]
pub struct MboxOp {
_hash: EnvelopeHash,
path: PathBuf,
offset: Offset,
length: Length,
slice: std::cell::RefCell<Option<Vec<u8>>>,
pub _hash: EnvelopeHash,
pub path: PathBuf,
pub offset: Offset,
pub length: Length,
pub slice: std::cell::RefCell<Option<Vec<u8>>>,
}
impl MboxOp {

View File

@ -30,6 +30,7 @@ use smallvec::SmallVec;
use crate::{get_conf_val, get_path_hash};
mod store;
pub use store::*;
#[macro_use]
mod protocol_parser;
pub use protocol_parser::*;

View File

@ -55,7 +55,7 @@ CREATE TABLE IF NOT EXISTS article (
#[derive(Debug)]
pub struct Store {
connection: Connection,
pub connection: Connection,
}
impl Store {

View File

@ -718,7 +718,7 @@ impl MailBackend for NotmuchDb {
use notify::{watcher, RecursiveMode, Watcher};
let account_hash = self.account_hash;
let collection = self.collection.clone();
let tag_index = self.collection.tag_index.clone();
let lib = self.lib.clone();
let path = self.path.clone();
let revision_uuid = self.revision_uuid.clone();
@ -748,7 +748,7 @@ impl MailBackend for NotmuchDb {
mailboxes.clone(),
index.clone(),
mailbox_index.clone(),
collection.tag_index.clone(),
tag_index.clone(),
account_hash,
event_consumer.clone(),
new_revision_uuid,
@ -826,7 +826,7 @@ impl MailBackend for NotmuchDb {
self.lib.clone(),
true,
)?;
let collection = self.collection.clone();
let tag_index = self.collection.clone().tag_index;
let index = self.index.clone();
Ok(Box::pin(async move {
@ -914,11 +914,7 @@ impl MailBackend for NotmuchDb {
for (f, v) in flags.iter() {
if let (Err(tag), true) = (f, v) {
let hash = TagHash::from_bytes(tag.as_bytes());
collection
.tag_index
.write()
.unwrap()
.insert(hash, tag.to_string());
tag_index.write().unwrap().insert(hash, tag.to_string());
}
}

View File

@ -186,7 +186,7 @@ macro_rules! named_unit_variant {
};
}
mod strings {
pub mod strings {
named_unit_variant!(ask);
}
@ -253,7 +253,7 @@ impl<'de> Deserialize<'de> for ToggleFlag {
{
#[derive(Deserialize)]
#[serde(untagged)]
pub enum InnerToggleFlag {
enum InnerToggleFlag {
Bool(bool),
#[serde(with = "strings::ask")]
Ask,

View File

@ -2595,25 +2595,26 @@ pub mod address {
))
}
///`no-fold-literal = "[" *dtext "]"`
pub fn no_fold_literal(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
let orig_input = input;
let (input, _) = tag("[")(input)?;
let (input, ret) = many0(dtext)(input)?;
let (input, _) = tag("]")(input)?;
Ok((input, Cow::Borrowed(&orig_input[0..ret.len() + 1])))
}
///`id-left = dot-atom-text / obs-id-left`
pub fn id_left(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
dot_atom_text(input)
}
///`id-right = dot-atom-text / no-fold-literal / obs-id-right`
pub fn id_right(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
alt((dot_atom_text, no_fold_literal))(input)
}
///`msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]`
pub fn msg_id(input: &[u8]) -> IResult<&[u8], MessageID> {
///`no-fold-literal = "[" *dtext "]"`
pub fn no_fold_literal(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
let orig_input = input;
let (input, _) = tag("[")(input)?;
let (input, ret) = many0(dtext)(input)?;
let (input, _) = tag("]")(input)?;
Ok((input, Cow::Borrowed(&orig_input[0..ret.len() + 1])))
}
///`id-left = dot-atom-text / obs-id-left`
pub fn id_left(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
dot_atom_text(input)
}
///`id-right = dot-atom-text / no-fold-literal / obs-id-right`
pub fn id_right(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
alt((dot_atom_text, no_fold_literal))(input)
}
let (input, _) = opt(cfws)(input)?;
let orig_input = input;
let (input, _) = tag("<")(input)?;

View File

@ -30,6 +30,9 @@ struct TagData {
io_state: Arc<Mutex<IoState>>,
}
///
/// # Safety
/// .
pub unsafe extern "C" fn gpgme_register_io_cb(
data: *mut ::std::os::raw::c_void,
fd: ::std::os::raw::c_int,
@ -66,6 +69,9 @@ pub unsafe extern "C" fn gpgme_register_io_cb(
0
}
///
/// # Safety
/// .
pub unsafe extern "C" fn gpgme_remove_io_cb(tag: *mut ::std::os::raw::c_void) {
let tag_data: Arc<TagData> = Arc::from_raw(tag as *const _);
let mut io_state_lck = tag_data.io_state.lock().unwrap();
@ -75,6 +81,9 @@ pub unsafe extern "C" fn gpgme_remove_io_cb(tag: *mut ::std::os::raw::c_void) {
let _ = Arc::into_raw(tag_data);
}
///
/// # Safety
/// .
pub unsafe extern "C" fn gpgme_event_io_cb(
data: *mut ::std::os::raw::c_void,
type_: gpgme_event_io_t,

View File

@ -72,9 +72,9 @@ macro_rules! c_string_literal {
}
}};
}
mod bindings;
pub mod bindings;
use bindings::*;
mod io;
pub mod io;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GpgmeFlag {
@ -804,7 +804,8 @@ impl Context {
.chain_err_summary(|| {
"libgpgme error: could not perform seek on signature data object"
})?;
_ = text;
// disjoint-capture-in-closures
let _ = &text;
sig.into_bytes()
})
}
@ -1127,7 +1128,8 @@ impl Context {
cipher
.seek(std::io::SeekFrom::Start(0))
.chain_err_summary(|| "libgpgme error: could not perform seek on plain text")?;
_ = plain;
// disjoint-capture-in-closures
let _ = &plain;
cipher.into_bytes()
})
}

View File

@ -22,8 +22,8 @@
pub mod grapheme_clusters;
pub mod line_break;
pub mod search;
mod tables;
mod types;
pub mod tables;
pub mod types;
pub use types::Reflow;
pub mod wcwidth;
pub use grapheme_clusters::*;

View File

@ -741,7 +741,7 @@ const TIMEZONE_ABBR: &[(&[u8], (i8, i8))] = &[
(b"YEKT", (05, 0)),
];
mod lib {
pub mod lib {
use std::convert::TryFrom;
use libc::tm;