|
|
@ -31,6 +31,7 @@ use indexmap::IndexSet; |
|
|
|
use nix::sys::wait::WaitStatus;
|
|
|
|
use std::convert::TryInto;
|
|
|
|
use std::future::Future;
|
|
|
|
use std::process::{Command, Stdio};
|
|
|
|
use std::str::FromStr;
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
|
|
|
@ -1262,7 +1263,6 @@ impl Component for Composer { |
|
|
|
self.mode = ViewMode::Embed;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
use std::process::{Command, Stdio};
|
|
|
|
/* Kill input thread so that spawned command can be sole receiver of stdin */
|
|
|
|
{
|
|
|
|
context.input_kill();
|
|
|
@ -1334,17 +1334,22 @@ impl Component for Composer { |
|
|
|
return false;
|
|
|
|
}
|
|
|
|
let f = create_temp_file(&[], None, None, true);
|
|
|
|
match std::process::Command::new("sh")
|
|
|
|
match Command::new("sh")
|
|
|
|
.args(&["-c", command])
|
|
|
|
.stdin(std::process::Stdio::null())
|
|
|
|
.stdout(std::process::Stdio::from(f.file()))
|
|
|
|
.stdin(Stdio::null())
|
|
|
|
.stdout(Stdio::from(f.file()))
|
|
|
|
.spawn()
|
|
|
|
.and_then(|child| Ok(child.wait_with_output()?.stderr))
|
|
|
|
{
|
|
|
|
Ok(child) => {
|
|
|
|
let _ = child
|
|
|
|
.wait_with_output()
|
|
|
|
.expect("failed to launch command")
|
|
|
|
.stdout;
|
|
|
|
Ok(stderr) => {
|
|
|
|
if !stderr.is_empty() {
|
|
|
|
context.replies.push_back(UIEvent::StatusEvent(
|
|
|
|
StatusEvent::DisplayMessage(format!(
|
|
|
|
"Command stderr output: `{}`.",
|
|
|
|
String::from_utf8_lossy(&stderr)
|
|
|
|
)),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
let attachment =
|
|
|
|
match melib::email::compose::attachment_from_file(f.path()) {
|
|
|
|
Ok(a) => a,
|
|
|
@ -1361,6 +1366,7 @@ impl Component for Composer { |
|
|
|
}
|
|
|
|
};
|
|
|
|
self.draft.attachments_mut().push(attachment);
|
|
|
|
self.has_changes = true;
|
|
|
|
self.dirty = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
@ -1388,6 +1394,78 @@ impl Component for Composer { |
|
|
|
}
|
|
|
|
};
|
|
|
|
self.draft.attachments_mut().push(attachment);
|
|
|
|
self.has_changes = true;
|
|
|
|
self.dirty = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Action::Compose(ComposeAction::AddAttachmentFilePicker(ref command)) => {
|
|
|
|
let command = if let Some(ref cmd) = command
|
|
|
|
.as_ref()
|
|
|
|
.or_else(|| context.settings.terminal.file_picker_command.as_ref())
|
|
|
|
{
|
|
|
|
cmd.as_str()
|
|
|
|
} else {
|
|
|
|
context.replies.push_back(UIEvent::Notification(
|
|
|
|
None,
|
|
|
|
"You haven't defined any command to launch.".into(),
|
|
|
|
Some(NotificationType::Error(melib::error::ErrorKind::None)),
|
|
|
|
));
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
/* Kill input thread so that spawned command can be sole receiver of stdin */
|
|
|
|
{
|
|
|
|
context.input_kill();
|
|
|
|
}
|
|
|
|
|
|
|
|
log(
|
|
|
|
format!("Executing: sh -c \"{}\"", command.replace("\"", "\\\"")),
|
|
|
|
DEBUG,
|
|
|
|
);
|
|
|
|
match Command::new("sh")
|
|
|
|
.args(&["-c", command])
|
|
|
|
.stdin(Stdio::inherit())
|
|
|
|
.stdout(Stdio::inherit())
|
|
|
|
.stderr(Stdio::piped())
|
|
|
|
.spawn()
|
|
|
|
.and_then(|child| Ok(child.wait_with_output()?.stderr))
|
|
|
|
{
|
|
|
|
Ok(stderr) => {
|
|
|
|
debug!(&String::from_utf8_lossy(&stderr));
|
|
|
|
for path in stderr.split(|c| [b'\0', b'\t', b'\n'].contains(c)) {
|
|
|
|
match melib::email::compose::attachment_from_file(
|
|
|
|
&String::from_utf8_lossy(&path).as_ref(),
|
|
|
|
) {
|
|
|
|
Ok(a) => {
|
|
|
|
self.draft.attachments_mut().push(a);
|
|
|
|
self.has_changes = true;
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
context.replies.push_back(UIEvent::Notification(
|
|
|
|
Some(format!(
|
|
|
|
"could not add attachment: {}",
|
|
|
|
String::from_utf8_lossy(&path)
|
|
|
|
)),
|
|
|
|
err.to_string(),
|
|
|
|
Some(NotificationType::Error(
|
|
|
|
melib::error::ErrorKind::None,
|
|
|
|
)),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
let command = command.to_string();
|
|
|
|
context.replies.push_back(UIEvent::Notification(
|
|
|
|
Some(format!("Failed to execute {}: {}", command, err)),
|
|
|
|
err.to_string(),
|
|
|
|
Some(NotificationType::Error(melib::error::ErrorKind::External)),
|
|
|
|
));
|
|
|
|
context.restore_input();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
context.replies.push_back(UIEvent::Fork(ForkType::Finished));
|
|
|
|
self.dirty = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|