diff options
Diffstat (limited to 'sq/src/commands/mod.rs')
-rw-r--r-- | sq/src/commands/mod.rs | 56 |
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(()) } |