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
Tests / Test on ${{ matrix.build }} (linux-amd64, ubuntu-latest, stable, x86_64-unknown-linux-gnu) (push) Failing after 6m8s
Details
parent
1d0405ed5b
commit
8e698cabcf
|
@ -29,7 +29,7 @@ use quote::{format_ident, quote};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
// Write ConfigStructOverride to overrides.rs
|
// Write ConfigStructOverride to overrides.rs
|
||||||
pub fn override_derive(filenames: &[(&str, &str)]) {
|
pub(crate) fn override_derive(filenames: &[(&str, &str)]) {
|
||||||
let mut output_file =
|
let mut output_file =
|
||||||
File::create("src/conf/overrides.rs").expect("Unable to open output file");
|
File::create("src/conf/overrides.rs").expect("Unable to open output file");
|
||||||
let mut output_string = r##"// @generated
|
let mut output_string = r##"// @generated
|
||||||
|
|
|
@ -40,7 +40,7 @@ use super::*;
|
||||||
use crate::{conf::accounts::JobRequest, jobs::JoinHandle, terminal::embed::EmbedTerminal};
|
use crate::{conf::accounts::JobRequest, jobs::JoinHandle, terminal::embed::EmbedTerminal};
|
||||||
|
|
||||||
#[cfg(feature = "gpgme")]
|
#[cfg(feature = "gpgme")]
|
||||||
mod gpg;
|
pub mod gpg;
|
||||||
|
|
||||||
pub mod edit_attachments;
|
pub mod edit_attachments;
|
||||||
use edit_attachments::*;
|
use edit_attachments::*;
|
||||||
|
|
|
@ -444,8 +444,327 @@ pub trait MailListingTrait: ListingTrait {
|
||||||
envs_to_set: SmallVec<[EnvelopeHash; 8]>,
|
envs_to_set: SmallVec<[EnvelopeHash; 8]>,
|
||||||
a: &ListingAction,
|
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_hash = self.coordinates().0;
|
||||||
let account = &mut context.accounts[&account_hash];
|
|
||||||
let mailbox_hash = self.coordinates().1;
|
let mailbox_hash = self.coordinates().1;
|
||||||
/*{
|
/*{
|
||||||
let threads_lck = account.collection.get_threads(mailbox_hash);
|
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()) {
|
inner(context, envs_to_set, account_hash, mailbox_hash, a);
|
||||||
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!(),
|
|
||||||
}
|
|
||||||
self.set_dirty(true);
|
self.set_dirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ mod thread;
|
||||||
pub use thread::*;
|
pub use thread::*;
|
||||||
mod types;
|
mod types;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
mod state;
|
pub mod state;
|
||||||
use state::*;
|
use state::*;
|
||||||
|
|
||||||
pub mod envelope;
|
pub mod envelope;
|
||||||
|
|
|
@ -1010,7 +1010,7 @@ mod pp {
|
||||||
|
|
||||||
/// Expands `include` macros in configuration file and other configuration
|
/// Expands `include` macros in configuration file and other configuration
|
||||||
/// files (eg. themes) in the filesystem.
|
/// 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() {
|
let p_buf: PathBuf = if path.as_ref().is_relative() {
|
||||||
path.as_ref().expand().canonicalize()?
|
path.as_ref().expand().canonicalize()?
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -466,6 +466,8 @@ impl Account {
|
||||||
let backend = map.get(&settings.account().format)(
|
let backend = map.get(&settings.account().format)(
|
||||||
settings.account(),
|
settings.account(),
|
||||||
Box::new(move |path: &str| {
|
Box::new(move |path: &str| {
|
||||||
|
// disjoint-capture-in-closures
|
||||||
|
let _ = &s;
|
||||||
s.account.subscribed_mailboxes.is_empty()
|
s.account.subscribed_mailboxes.is_empty()
|
||||||
|| (s.mailbox_confs.contains_key(path)
|
|| (s.mailbox_confs.contains_key(path)
|
||||||
&& s.mailbox_confs[path].mailbox_conf().subscribe.is_true())
|
&& s.mailbox_confs[path].mailbox_conf().subscribe.is_true())
|
||||||
|
|
|
@ -171,7 +171,7 @@ macro_rules! named_unit_variant {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mod strings {
|
pub mod strings {
|
||||||
named_unit_variant!(server_submission);
|
named_unit_variant!(server_submission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,11 @@ use crate::types::{ThreadEvent, UIEvent};
|
||||||
|
|
||||||
type AsyncTask = async_task::Runnable;
|
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.
|
// Pop a task from the local queue, if not empty.
|
||||||
local.pop().or_else(|| {
|
local.pop().or_else(|| {
|
||||||
// Otherwise, we need to look for a task elsewhere.
|
// Otherwise, we need to look for a task elsewhere.
|
||||||
|
|
|
@ -26,13 +26,13 @@ use serde::{de, de::Visitor, Deserialize, Deserializer};
|
||||||
mod color;
|
mod color;
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod position;
|
pub mod position;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod cells;
|
pub mod cells;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod keys;
|
pub mod keys;
|
||||||
pub mod embed;
|
pub mod embed;
|
||||||
mod text_editing;
|
pub mod text_editing;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub use self::{cells::*, keys::*, position::*, text_editing::*};
|
pub use self::{cells::*, keys::*, position::*, text_editing::*};
|
||||||
|
|
|
@ -746,7 +746,6 @@ impl Serialize for Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use aliases::*;
|
|
||||||
pub mod aliases {
|
pub mod aliases {
|
||||||
use super::Color;
|
use super::Color;
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,10 @@ mod watch;
|
||||||
pub use watch::*;
|
pub use watch::*;
|
||||||
mod search;
|
mod search;
|
||||||
pub use search::*;
|
pub use search::*;
|
||||||
mod cache;
|
pub mod cache;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod managesieve;
|
pub mod managesieve;
|
||||||
mod untagged;
|
pub mod untagged;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet},
|
collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet},
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
mod sync;
|
pub mod sync;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -104,7 +104,7 @@ pub trait ImapCacheReset: Send + core::fmt::Debug {
|
||||||
pub use sqlite3_m::*;
|
pub use sqlite3_m::*;
|
||||||
|
|
||||||
#[cfg(feature = "sqlite3")]
|
#[cfg(feature = "sqlite3")]
|
||||||
mod sqlite3_m {
|
pub mod sqlite3_m {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::utils::sqlite3::{
|
use crate::utils::sqlite3::{
|
||||||
self,
|
self,
|
||||||
|
@ -739,7 +739,7 @@ pub(super) async fn fetch_cached_envs(state: &mut FetchState) -> Result<Option<V
|
||||||
pub use default_m::*;
|
pub use default_m::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "sqlite3"))]
|
#[cfg(not(feature = "sqlite3"))]
|
||||||
mod default_m {
|
pub mod default_m {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DefaultCache;
|
pub struct DefaultCache;
|
||||||
|
|
|
@ -25,11 +25,6 @@ use std::{
|
||||||
time::SystemTime,
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
use nom::{
|
|
||||||
branch::alt, bytes::complete::tag, combinator::map, multi::separated_list1,
|
|
||||||
sequence::separated_pair,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore};
|
use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore};
|
||||||
use crate::{
|
use crate::{
|
||||||
conf::AccountSettings,
|
conf::AccountSettings,
|
||||||
|
@ -43,17 +38,6 @@ pub struct ManageSieveConnection {
|
||||||
pub inner: ImapConnection,
|
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)]
|
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
||||||
pub enum ManageSieveResponse<'a> {
|
pub enum ManageSieveResponse<'a> {
|
||||||
Ok {
|
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 {
|
impl ManageSieveConnection {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
account_hash: crate::backends::AccountHash,
|
account_hash: crate::backends::AccountHash,
|
||||||
|
@ -479,3 +238,247 @@ impl ManageSieveConnection {
|
||||||
Ok(())
|
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,
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -202,20 +202,20 @@ fn get_rw_lock_blocking(f: &File, path: &Path) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct MboxMailbox {
|
pub struct MboxMailbox {
|
||||||
hash: MailboxHash,
|
pub hash: MailboxHash,
|
||||||
name: String,
|
pub name: String,
|
||||||
path: PathBuf,
|
pub path: PathBuf,
|
||||||
fs_path: PathBuf,
|
pub fs_path: PathBuf,
|
||||||
content: Vec<u8>,
|
pub content: Vec<u8>,
|
||||||
children: Vec<MailboxHash>,
|
pub children: Vec<MailboxHash>,
|
||||||
parent: Option<MailboxHash>,
|
pub parent: Option<MailboxHash>,
|
||||||
usage: Arc<RwLock<SpecialUsageMailbox>>,
|
pub usage: Arc<RwLock<SpecialUsageMailbox>>,
|
||||||
is_subscribed: bool,
|
pub is_subscribed: bool,
|
||||||
permissions: MailboxPermissions,
|
pub permissions: MailboxPermissions,
|
||||||
pub total: Arc<Mutex<usize>>,
|
pub total: Arc<Mutex<usize>>,
|
||||||
pub unseen: 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 {
|
impl BackendMailbox for MboxMailbox {
|
||||||
|
@ -285,11 +285,11 @@ impl BackendMailbox for MboxMailbox {
|
||||||
/// `BackendOp` implementor for Mbox
|
/// `BackendOp` implementor for Mbox
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct MboxOp {
|
pub struct MboxOp {
|
||||||
_hash: EnvelopeHash,
|
pub _hash: EnvelopeHash,
|
||||||
path: PathBuf,
|
pub path: PathBuf,
|
||||||
offset: Offset,
|
pub offset: Offset,
|
||||||
length: Length,
|
pub length: Length,
|
||||||
slice: std::cell::RefCell<Option<Vec<u8>>>,
|
pub slice: std::cell::RefCell<Option<Vec<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MboxOp {
|
impl MboxOp {
|
||||||
|
|
|
@ -30,6 +30,7 @@ use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{get_conf_val, get_path_hash};
|
use crate::{get_conf_val, get_path_hash};
|
||||||
mod store;
|
mod store;
|
||||||
|
pub use store::*;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod protocol_parser;
|
mod protocol_parser;
|
||||||
pub use protocol_parser::*;
|
pub use protocol_parser::*;
|
||||||
|
|
|
@ -55,7 +55,7 @@ CREATE TABLE IF NOT EXISTS article (
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Store {
|
pub struct Store {
|
||||||
connection: Connection,
|
pub connection: Connection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store {
|
impl Store {
|
||||||
|
|
|
@ -718,7 +718,7 @@ impl MailBackend for NotmuchDb {
|
||||||
use notify::{watcher, RecursiveMode, Watcher};
|
use notify::{watcher, RecursiveMode, Watcher};
|
||||||
|
|
||||||
let account_hash = self.account_hash;
|
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 lib = self.lib.clone();
|
||||||
let path = self.path.clone();
|
let path = self.path.clone();
|
||||||
let revision_uuid = self.revision_uuid.clone();
|
let revision_uuid = self.revision_uuid.clone();
|
||||||
|
@ -748,7 +748,7 @@ impl MailBackend for NotmuchDb {
|
||||||
mailboxes.clone(),
|
mailboxes.clone(),
|
||||||
index.clone(),
|
index.clone(),
|
||||||
mailbox_index.clone(),
|
mailbox_index.clone(),
|
||||||
collection.tag_index.clone(),
|
tag_index.clone(),
|
||||||
account_hash,
|
account_hash,
|
||||||
event_consumer.clone(),
|
event_consumer.clone(),
|
||||||
new_revision_uuid,
|
new_revision_uuid,
|
||||||
|
@ -826,7 +826,7 @@ impl MailBackend for NotmuchDb {
|
||||||
self.lib.clone(),
|
self.lib.clone(),
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
let collection = self.collection.clone();
|
let tag_index = self.collection.clone().tag_index;
|
||||||
let index = self.index.clone();
|
let index = self.index.clone();
|
||||||
|
|
||||||
Ok(Box::pin(async move {
|
Ok(Box::pin(async move {
|
||||||
|
@ -914,11 +914,7 @@ impl MailBackend for NotmuchDb {
|
||||||
for (f, v) in flags.iter() {
|
for (f, v) in flags.iter() {
|
||||||
if let (Err(tag), true) = (f, v) {
|
if let (Err(tag), true) = (f, v) {
|
||||||
let hash = TagHash::from_bytes(tag.as_bytes());
|
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ macro_rules! named_unit_variant {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mod strings {
|
pub mod strings {
|
||||||
named_unit_variant!(ask);
|
named_unit_variant!(ask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ impl<'de> Deserialize<'de> for ToggleFlag {
|
||||||
{
|
{
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum InnerToggleFlag {
|
enum InnerToggleFlag {
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
#[serde(with = "strings::ask")]
|
#[serde(with = "strings::ask")]
|
||||||
Ask,
|
Ask,
|
||||||
|
|
|
@ -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]`
|
///`msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]`
|
||||||
pub fn msg_id(input: &[u8]) -> IResult<&[u8], MessageID> {
|
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 (input, _) = opt(cfws)(input)?;
|
||||||
let orig_input = input;
|
let orig_input = input;
|
||||||
let (input, _) = tag("<")(input)?;
|
let (input, _) = tag("<")(input)?;
|
||||||
|
|
|
@ -30,6 +30,9 @@ struct TagData {
|
||||||
io_state: Arc<Mutex<IoState>>,
|
io_state: Arc<Mutex<IoState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// .
|
||||||
pub unsafe extern "C" fn gpgme_register_io_cb(
|
pub unsafe extern "C" fn gpgme_register_io_cb(
|
||||||
data: *mut ::std::os::raw::c_void,
|
data: *mut ::std::os::raw::c_void,
|
||||||
fd: ::std::os::raw::c_int,
|
fd: ::std::os::raw::c_int,
|
||||||
|
@ -66,6 +69,9 @@ pub unsafe extern "C" fn gpgme_register_io_cb(
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// .
|
||||||
pub unsafe extern "C" fn gpgme_remove_io_cb(tag: *mut ::std::os::raw::c_void) {
|
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 tag_data: Arc<TagData> = Arc::from_raw(tag as *const _);
|
||||||
let mut io_state_lck = tag_data.io_state.lock().unwrap();
|
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);
|
let _ = Arc::into_raw(tag_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// .
|
||||||
pub unsafe extern "C" fn gpgme_event_io_cb(
|
pub unsafe extern "C" fn gpgme_event_io_cb(
|
||||||
data: *mut ::std::os::raw::c_void,
|
data: *mut ::std::os::raw::c_void,
|
||||||
type_: gpgme_event_io_t,
|
type_: gpgme_event_io_t,
|
||||||
|
|
|
@ -72,9 +72,9 @@ macro_rules! c_string_literal {
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
mod bindings;
|
pub mod bindings;
|
||||||
use bindings::*;
|
use bindings::*;
|
||||||
mod io;
|
pub mod io;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum GpgmeFlag {
|
pub enum GpgmeFlag {
|
||||||
|
@ -804,7 +804,8 @@ impl Context {
|
||||||
.chain_err_summary(|| {
|
.chain_err_summary(|| {
|
||||||
"libgpgme error: could not perform seek on signature data object"
|
"libgpgme error: could not perform seek on signature data object"
|
||||||
})?;
|
})?;
|
||||||
_ = text;
|
// disjoint-capture-in-closures
|
||||||
|
let _ = &text;
|
||||||
sig.into_bytes()
|
sig.into_bytes()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1127,7 +1128,8 @@ impl Context {
|
||||||
cipher
|
cipher
|
||||||
.seek(std::io::SeekFrom::Start(0))
|
.seek(std::io::SeekFrom::Start(0))
|
||||||
.chain_err_summary(|| "libgpgme error: could not perform seek on plain text")?;
|
.chain_err_summary(|| "libgpgme error: could not perform seek on plain text")?;
|
||||||
_ = plain;
|
// disjoint-capture-in-closures
|
||||||
|
let _ = &plain;
|
||||||
cipher.into_bytes()
|
cipher.into_bytes()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
pub mod grapheme_clusters;
|
pub mod grapheme_clusters;
|
||||||
pub mod line_break;
|
pub mod line_break;
|
||||||
pub mod search;
|
pub mod search;
|
||||||
mod tables;
|
pub mod tables;
|
||||||
mod types;
|
pub mod types;
|
||||||
pub use types::Reflow;
|
pub use types::Reflow;
|
||||||
pub mod wcwidth;
|
pub mod wcwidth;
|
||||||
pub use grapheme_clusters::*;
|
pub use grapheme_clusters::*;
|
||||||
|
|
|
@ -741,7 +741,7 @@ const TIMEZONE_ABBR: &[(&[u8], (i8, i8))] = &[
|
||||||
(b"YEKT", (05, 0)),
|
(b"YEKT", (05, 0)),
|
||||||
];
|
];
|
||||||
|
|
||||||
mod lib {
|
pub mod lib {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use libc::tm;
|
use libc::tm;
|
||||||
|
|
Loading…
Reference in New Issue