1use std::io;
4
5use crate::Callbacks;
6
7mod error;
8pub use error::ReadError;
9
10pub mod file_io;
11
12mod identities;
13pub use identities::read_identities;
14
15mod recipients;
16pub use recipients::read_recipients;
17
18pub struct StdinGuard {
20 stdin_used: bool,
21}
22
23impl StdinGuard {
24 pub fn new(input_is_stdin: bool) -> Self {
29 Self {
30 stdin_used: input_is_stdin,
31 }
32 }
33
34 fn open(&mut self, filename: String) -> Result<file_io::InputReader, ReadError> {
35 let input = file_io::InputReader::new(Some(filename))?;
36 if matches!(input, file_io::InputReader::Stdin(_)) {
37 if self.stdin_used {
38 return Err(ReadError::MultipleStdin);
39 }
40 self.stdin_used = true;
41 }
42 Ok(input)
43 }
44}
45
46#[derive(Clone, Copy)]
48pub struct UiCallbacks;
49
50impl Callbacks for UiCallbacks {
51 fn display_message(&self, message: &str) {
52 eprintln!("{}", message);
53 }
54
55 fn confirm(&self, message: &str, yes_string: &str, no_string: Option<&str>) -> Option<bool> {
56 #[cfg(feature = "console")]
57 {
58 let term = console::Term::stderr();
59 let cancel_str = no_string.unwrap_or("no");
60 let initial = format!("{}: ({}/{}) ", message, yes_string, cancel_str);
61 loop {
62 term.write_str(&initial).ok()?;
63 let response = term.read_line().ok()?.to_lowercase();
64 if ["y", "yes"].contains(&response.as_str())
65 || response == yes_string.to_lowercase()
66 {
67 break Some(true);
68 } else if ["n", "no"].contains(&response.as_str())
69 || Some(response.as_str()) == no_string.map(|s| s.to_lowercase()).as_deref()
70 {
71 break Some(false);
72 }
73 }
74 }
75 #[cfg(not(feature = "console"))]
76 {
77 let _ = (message, yes_string, no_string);
78 None
79 }
80 }
81
82 fn request_public_string(&self, description: &str) -> Option<String> {
83 #[cfg(feature = "console")]
84 {
85 let term = console::Term::stderr();
86 term.write_str(description).ok()?;
87 term.read_line().ok().filter(|s| !s.is_empty())
88 }
89 #[cfg(not(feature = "console"))]
90 {
91 let _ = description;
92 None
93 }
94 }
95
96 fn request_passphrase(&self, _description: &str) -> Option<anubis_core::secrecy::SecretString> {
97 None
99 }
100}