Add export-mbox command
parent
4050f6893f
commit
a4ae4da8b1
|
@ -418,6 +418,8 @@ Copy or move to other mailbox.
|
||||||
Copy or move to another account's mailbox.
|
Copy or move to another account's mailbox.
|
||||||
.It Cm delete
|
.It Cm delete
|
||||||
Delete selected threads.
|
Delete selected threads.
|
||||||
|
.It Cm export-mbox Ar FILEPATH
|
||||||
|
Export selected threads to mboxcl2 file.
|
||||||
.It Cm create-mailbox Ar ACCOUNT Ar MAILBOX_PATH
|
.It Cm create-mailbox Ar ACCOUNT Ar MAILBOX_PATH
|
||||||
create mailbox with given path.
|
create mailbox with given path.
|
||||||
Be careful with backends and separator sensitivity (eg IMAP)
|
Be careful with backends and separator sensitivity (eg IMAP)
|
||||||
|
|
|
@ -419,6 +419,19 @@ define_commands!([
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
{ tags: ["export-mbox "],
|
||||||
|
desc: "export-mbox PATH",
|
||||||
|
tokens: &[One(Literal("export-mbox")), One(Filepath)],
|
||||||
|
parser:(
|
||||||
|
fn export_mbox(input: &[u8]) -> IResult<&[u8], Action> {
|
||||||
|
let (input, _) = tag("export-mbox")(input.trim())?;
|
||||||
|
let (input, _) = is_a(" ")(input)?;
|
||||||
|
let (input, path) = quoted_argument(input.trim())?;
|
||||||
|
let (input, _) = eof(input)?;
|
||||||
|
Ok((input, Listing(ExportMbox(Some(melib::backends::mbox::MboxFormat::MboxCl2), path.to_string().into()))))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
{ tags: ["list-archive", "list-post", "list-unsubscribe", "list-"],
|
{ tags: ["list-archive", "list-post", "list-unsubscribe", "list-"],
|
||||||
desc: "list-[unsubscribe/post/archive]",
|
desc: "list-[unsubscribe/post/archive]",
|
||||||
tokens: &[One(Alternatives(&[to_stream!(One(Literal("list-archive"))), to_stream!(One(Literal("list-post"))), to_stream!(One(Literal("list-unsubscribe")))]))],
|
tokens: &[One(Alternatives(&[to_stream!(One(Literal("list-archive"))), to_stream!(One(Literal("list-post"))), to_stream!(One(Literal("list-unsubscribe")))]))],
|
||||||
|
@ -852,6 +865,7 @@ fn listing_action(input: &[u8]) -> IResult<&[u8], Action> {
|
||||||
select,
|
select,
|
||||||
toggle_thread_snooze,
|
toggle_thread_snooze,
|
||||||
open_in_new_tab,
|
open_in_new_tab,
|
||||||
|
export_mbox,
|
||||||
_tag,
|
_tag,
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ pub enum ListingAction {
|
||||||
MoveTo(MailboxPath),
|
MoveTo(MailboxPath),
|
||||||
MoveToOtherAccount(AccountName, MailboxPath),
|
MoveToOtherAccount(AccountName, MailboxPath),
|
||||||
Import(PathBuf, MailboxPath),
|
Import(PathBuf, MailboxPath),
|
||||||
|
ExportMbox(Option<melib::backends::mbox::MboxFormat>, PathBuf),
|
||||||
Delete,
|
Delete,
|
||||||
OpenInNewTab,
|
OpenInNewTab,
|
||||||
Tag(TagAction),
|
Tag(TagAction),
|
||||||
|
|
|
@ -342,6 +342,87 @@ pub trait MailListingTrait: ListingTrait {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ListingAction::ExportMbox(format, ref path) => {
|
||||||
|
use futures::future::try_join_all;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
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.clone().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 {
|
||||||
|
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());
|
||||||
|
if let Some((env, ref bytes)) = iter.next() {
|
||||||
|
format.append(
|
||||||
|
&mut file,
|
||||||
|
bytes.as_slice(),
|
||||||
|
env.from().get(0),
|
||||||
|
Some(env.date()),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
for (env, bytes) in iter {
|
||||||
|
format.append(
|
||||||
|
&mut file,
|
||||||
|
bytes.as_slice(),
|
||||||
|
env.from().get(0),
|
||||||
|
Some(env.date()),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
file.flush()?;
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
let r: Result<()> = cl.await;
|
||||||
|
let _ = sender.send(r);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
let handle = account.job_executor.spawn_blocking(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),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}))),
|
||||||
|
logging_level: melib::LoggingLevel::INFO,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
ListingAction::MoveToOtherAccount(ref _account_name, ref _mailbox_path) => {
|
ListingAction::MoveToOtherAccount(ref _account_name, ref _mailbox_path) => {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
|
@ -967,6 +1048,7 @@ impl Component for Listing {
|
||||||
| Action::Listing(a @ ListingAction::MoveTo(_))
|
| Action::Listing(a @ ListingAction::MoveTo(_))
|
||||||
| Action::Listing(a @ ListingAction::CopyToOtherAccount(_, _))
|
| Action::Listing(a @ ListingAction::CopyToOtherAccount(_, _))
|
||||||
| Action::Listing(a @ ListingAction::MoveToOtherAccount(_, _))
|
| Action::Listing(a @ ListingAction::MoveToOtherAccount(_, _))
|
||||||
|
| Action::Listing(a @ ListingAction::ExportMbox(_, _))
|
||||||
| Action::Listing(a @ ListingAction::Tag(_)) => {
|
| Action::Listing(a @ ListingAction::Tag(_)) => {
|
||||||
let focused = self.component.get_focused_items(context);
|
let focused = self.component.get_focused_items(context);
|
||||||
self.component.perform_action(context, focused, a);
|
self.component.perform_action(context, focused, a);
|
||||||
|
|
Loading…
Reference in New Issue