summaryrefslogtreecommitdiffstats
path: root/tool
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2018-06-06 16:29:01 +0200
committerJustus Winter <justus@sequoia-pgp.org>2018-06-06 16:35:10 +0200
commitdac624a298d33877858d969d90690bdd3c69da92 (patch)
treeeec4c1edbda73db5c9bb00d67339d34c8ede66db /tool
parent0c44ac9e0bb8d1b96267a012363762486e9a1d0b (diff)
tool: Implement 'split' subcommand to split OpenPGP messages.
Diffstat (limited to 'tool')
-rw-r--r--tool/src/cli.rs12
-rw-r--r--tool/src/commands.rs47
-rw-r--r--tool/src/sq-usage.rs19
-rw-r--r--tool/src/sq.rs8
4 files changed, 85 insertions, 1 deletions
diff --git a/tool/src/cli.rs b/tool/src/cli.rs
index f965e4e7..eb1f4004 100644
--- a/tool/src/cli.rs
+++ b/tool/src/cli.rs
@@ -97,6 +97,18 @@ pub fn build() -> App<'static, 'static> {
.long("hex")
.short("x")
.help("Print a hexdump")))
+ .subcommand(SubCommand::with_name("split")
+ .about("Splits a message into OpenPGP packets")
+ .arg(Arg::with_name("input").value_name("FILE")
+ .long("input")
+ .short("i")
+ .help("Sets the input file to use"))
+ .arg(Arg::with_name("prefix").value_name("FILE")
+ .long("prefix")
+ .short("p")
+ .help("Sets the prefix to use for output files \
+ (defaults to the input filename with a dash, \
+ or 'output')")))
.subcommand(SubCommand::with_name("keyserver")
.about("Interacts with keyservers")
.arg(Arg::with_name("server").value_name("URI")
diff --git a/tool/src/commands.rs b/tool/src/commands.rs
index 2ad9ebda..e992904d 100644
--- a/tool/src/commands.rs
+++ b/tool/src/commands.rs
@@ -1,5 +1,7 @@
use failure::{self, ResultExt};
-use std::io;
+use std::cmp::Ordering;
+use std::fs::File;
+use std::io::{self, Write};
use rpassword;
extern crate openpgp;
@@ -193,6 +195,49 @@ pub fn dump(input: &mut io::Read, output: &mut io::Write, map: bool)
Ok(())
}
+pub fn split(input: &mut io::Read, prefix: &str)
+ -> Result<(), failure::Error> {
+ // We (ab)use the mapping feature to create byte-accurate dumps of
+ // nested packets.
+ let mut ppo =
+ openpgp::parse::PacketParserBuilder::from_reader(input)?
+ .map(true).finalize()?;
+
+ // This encodes our position in the tree.
+ let mut pos = vec![0];
+
+ while let Some(pp) = ppo {
+ if let Some(ref map) = pp.map {
+ let filename = format!(
+ "{}{}--{:?}", prefix,
+ pos.iter().map(|n| format!("{}", n))
+ .collect::<Vec<String>>().join("-"),
+ pp.packet.tag());
+ let mut sink = File::create(filename)
+ .context("Failed to create output file")?;
+
+ // Write all the bytes.
+ for (_, buf) in map.iter() {
+ sink.write_all(buf)?;
+ }
+ }
+
+ let (_, old_depth, ppo_, new_depth) = pp.recurse()?;
+ ppo = ppo_;
+
+ // Update pos.
+ match old_depth.cmp(&new_depth) {
+ Ordering::Less =>
+ pos.push(0),
+ Ordering::Equal =>
+ *pos.last_mut().unwrap() += 1,
+ Ordering::Greater => {
+ pos.pop();
+ },
+ }
+ }
+ Ok(())
+}
struct HexDumper {
offset: usize,
diff --git a/tool/src/sq-usage.rs b/tool/src/sq-usage.rs
index a48b6ddb..f6e4220d 100644
--- a/tool/src/sq-usage.rs
+++ b/tool/src/sq-usage.rs
@@ -26,6 +26,7 @@
//! help Prints this message or the help of the given subcommand(s)
//! keyserver Interacts with keyservers
//! list Lists key stores and known keys
+//! split Splits a message into OpenPGP packets
//! store Interacts with key stores
//! ```
//!
@@ -255,6 +256,24 @@
//! <PREFIX> List only stores with the given domain prefix
//! ```
//!
+//! ## Subcommand split
+//!
+//! ```text
+//! Splits a message into OpenPGP packets
+//!
+//! USAGE:
+//! sq split [OPTIONS]
+//!
+//! FLAGS:
+//! -h, --help Prints help information
+//! -V, --version Prints version information
+//!
+//! OPTIONS:
+//! -i, --input <FILE> Sets the input file to use
+//! -p, --prefix <FILE> Sets the prefix to use for output files (defaults to the input filename with a dash, or
+//! 'output')
+//! ```
+//!
//! ## Subcommand store
//!
//! ```text
diff --git a/tool/src/sq.rs b/tool/src/sq.rs
index ea484e70..cf528cc5 100644
--- a/tool/src/sq.rs
+++ b/tool/src/sq.rs
@@ -105,6 +105,14 @@ fn real_main() -> Result<(), failure::Error> {
let mut input = openpgp::Reader::from_reader(input)?;
commands::dump(&mut input, &mut output, m.is_present("hex"))?;
},
+ ("split", Some(m)) => {
+ let input = open_or_stdin(m.value_of("input"))?;
+ let prefix = m.value_of("prefix").map(|p| p.to_owned()).
+ unwrap_or(
+ m.value_of("input").unwrap_or("output").to_owned() + "-");
+ let mut input = openpgp::Reader::from_reader(input)?;
+ commands::split(&mut input, &prefix)?;
+ },
("keyserver", Some(m)) => {
let mut ks = if let Some(uri) = m.value_of("server") {
KeyServer::new(&ctx, &uri)