From dd55b04186c295319602d95d2486225570ed3591 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Mon, 7 Jan 2019 20:55:37 +0000 Subject: Implement QR code decoding using zbarimg --- src/main.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index b3fb3f3..9c2a8c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,13 @@ use std::fs; use std::io; use std::path; use std::process; +use std::string; #[derive(Debug)] enum Error { IoError(io::Error), Error(String), + Utf8Error(string::FromUtf8Error), } impl fmt::Display for Error { @@ -19,6 +21,7 @@ impl fmt::Display for Error { match *self { Error::IoError(ref err) => write!(f, "IO error: {}", err), Error::Error(ref string) => write!(f, "Error: {}", string), + Error::Utf8Error(ref err) => write!(f, "UTF-8 error: {}", err), } } } @@ -35,6 +38,23 @@ impl From for Error { } } +impl From<(&str, process::ExitStatus)> for Error { + fn from(data: (&str, process::ExitStatus)) -> Error { + let (command, status) = data; + let msg = match status.code() { + Some(code) => format!("{} failed with error code {}", command, code), + None => format!("{} was terminated by a signal", command), + }; + Error::Error(msg) + } +} + +impl From for Error { + fn from(error: string::FromUtf8Error) -> Error { + Error::Utf8Error(error) + } +} + #[derive(Debug)] struct Options { slot: u8, @@ -82,13 +102,32 @@ fn import_qr_code() -> Result { temp.release(); Ok(path) } else { - match status.code() { - Some(code) => Err(Error::Error(format!( - "import failed with error code {}", - code - ))), - None => Err(Error::from("import was terminated by a signal")), + Err(Error::from(("import", status))) + } +} + +fn decode_qr_code(path: &path::Path) -> Result { + let output = process::Command::new("zbarimg") + .arg("--quiet") + .arg("--raw") + .arg(path) + .output()?; + if output.status.success() { + let output = String::from_utf8(output.stdout)?; + let urls = output + .split("\n") + .filter(|url| url.starts_with("otpauth://")) + .collect::>(); + if urls.is_empty() { + Err(Error::from("Could not find an otpauth QR code")) + } else { + if urls.len() > 1 { + println!("Found more than otpauth QR code, using the first one."); + } + Ok(urls[0].to_string()) } + } else { + Err(Error::from(("zbarimg", output.status))) } } @@ -97,6 +136,7 @@ fn run(options: Options) -> Result<(), Error> { Some(ref file) => path::PathBuf::from(file), None => import_qr_code()?, }; + println!("{}", decode_qr_code(&path)?); if options.file.is_none() { fs::remove_file(&path)?; } -- cgit v1.2.1