summaryrefslogtreecommitdiffstats
path: root/sq/src/commands/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'sq/src/commands/mod.rs')
-rw-r--r--sq/src/commands/mod.rs56
1 files changed, 50 insertions, 6 deletions
diff --git a/sq/src/commands/mod.rs b/sq/src/commands/mod.rs
index 45c1201c..0150441b 100644
--- a/sq/src/commands/mod.rs
+++ b/sq/src/commands/mod.rs
@@ -7,6 +7,9 @@ use std::time::SystemTime;
use rpassword;
use sequoia_openpgp as openpgp;
+use crate::openpgp::{
+ armor,
+};
use crate::openpgp::types::{
CompressionAlgorithm,
};
@@ -28,6 +31,8 @@ use crate::openpgp::policy::Policy;
use crate::{
Config,
+ parse_armor_kind,
+ create_or_stdout_pgp,
};
pub mod decrypt;
@@ -438,17 +443,54 @@ pub fn split(input: &mut (dyn io::Read + Sync + Send), prefix: &str)
}
/// Joins the given files.
-pub fn join(inputs: Option<clap::Values>, output: &mut dyn io::Write)
+pub fn join(config: Config, m: &clap::ArgMatches)
-> Result<()> {
+ // Either we know what kind of armor we want to produce, or we
+ // need to detect it using the first packet we see.
+ let kind = parse_armor_kind(m.value_of("kind"));
+ let output = m.value_of("output");
+ let mut sink =
+ if m.is_present("binary") {
+ // No need for any auto-detection.
+ Some(create_or_stdout_pgp(output, config.force,
+ true, // Binary.
+ armor::Kind::File)?)
+ } else if let Some(kind) = kind {
+ Some(create_or_stdout_pgp(output, config.force,
+ false, // Armored.
+ kind)?)
+ } else {
+ None // Defer.
+ };
+
/// Writes a bit-accurate copy of all top-level packets in PPR to
/// OUTPUT.
- fn copy(mut ppr: PacketParserResult, output: &mut dyn io::Write)
+ fn copy(mut ppr: PacketParserResult,
+ output: Option<&str>, force: bool,
+ sink: &mut Option<Message>)
-> Result<()> {
while let PacketParserResult::Some(pp) = ppr {
+ if sink.is_none() {
+ // Autodetect using the first packet.
+ let kind = match pp.packet {
+ Packet::Signature(_) => armor::Kind::Signature,
+ Packet::SecretKey(_) => armor::Kind::SecretKey,
+ Packet::PublicKey(_) => armor::Kind::PublicKey,
+ Packet::PKESK(_) | Packet::SKESK(_) =>
+ armor::Kind::Message,
+ _ => armor::Kind::File,
+ };
+
+ *sink = Some(create_or_stdout_pgp(output, force,
+ false, // Armored.
+ kind)?);
+ }
+
// We (ab)use the mapping feature to create byte-accurate
// copies.
for field in pp.map().expect("must be mapped").iter() {
- output.write_all(field.as_bytes())?;
+ sink.as_mut().expect("initialized at this point")
+ .write_all(field.as_bytes())?;
}
ppr = pp.next()?.1;
@@ -456,18 +498,20 @@ pub fn join(inputs: Option<clap::Values>, output: &mut dyn io::Write)
Ok(())
}
- if let Some(inputs) = inputs {
+ if let Some(inputs) = m.values_of("input") {
for name in inputs {
let ppr =
openpgp::parse::PacketParserBuilder::from_file(name)?
.map(true).build()?;
- copy(ppr, output)?;
+ copy(ppr, output, config.force, &mut sink)?;
}
} else {
let ppr =
openpgp::parse::PacketParserBuilder::from_reader(io::stdin())?
.map(true).build()?;
- copy(ppr, output)?;
+ copy(ppr, output, config.force, &mut sink)?;
}
+
+ sink.unwrap().finalize()?;
Ok(())
}