Skip to content

Commit

Permalink
Merge pull request #17 from infincia/add-non-password-responses
Browse files Browse the repository at this point in the history
Add support for reading non-password responses, e.g. account names/questions
  • Loading branch information
conradkleinespel authored Mar 27, 2017
2 parents f11fd4b + 673fadb commit 7399b41
Showing 1 changed file with 52 additions and 5 deletions.
57 changes: 52 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,25 @@ mod unix {

/// Reads a password from STDIN.
pub fn read_password() -> IoResult<String> {
read_input(true)
}

/// Reads a password from STDIN.
pub fn read_response() -> IoResult<String> {
read_input(false)
}

fn read_input(hide: bool) -> IoResult<String> {
// Make two copies of the terminal settings. The first one will be modified
// and the second one will act as a backup for when we want to set the
// terminal back to its original state.
let mut term = try!(termios::Termios::from_fd(STDIN_FILENO));
let term_orig = term;

// Hide the password. This is what makes this function useful.
term.c_lflag &= !termios::ECHO;
if hide {
// Hide the password. This is what makes this function useful.
term.c_lflag &= !termios::ECHO;
}

// But don't hide the NL character when the user hits ENTER.
term.c_lflag |= termios::ECHONL;
Expand Down Expand Up @@ -142,6 +153,16 @@ mod windows {

/// Reads a password from STDIN.
pub fn read_password() -> IoResult<String> {
read_input(true)
}

/// Reads a password from STDIN.
pub fn read_response() -> IoResult<String> {
read_input(false)
}

fn read_input(hide: bool) -> IoResult<String> {

// Get the stdin handle
let handle = unsafe { kernel32::GetStdHandle(winapi::STD_INPUT_HANDLE) };
if handle == winapi::INVALID_HANDLE_VALUE {
Expand All @@ -152,10 +173,13 @@ mod windows {
if unsafe { kernel32::GetConsoleMode(handle, &mut mode as winapi::LPDWORD) } == 0 {
return Err(Error::last_os_error())
}
let new_mode_flags = match hide {
true => winapi::ENABLE_LINE_INPUT | winapi::ENABLE_PROCESSED_INPUT,
false => winapi::ENABLE_LINE_INPUT | winapi::ENABLE_PROCESSED_INPUT| ENABLE_ECHO_INPUT,
};

// We want to be able to read line by line, and we still want backspace to work
if unsafe { kernel32::SetConsoleMode(
handle, winapi::ENABLE_LINE_INPUT | winapi::ENABLE_PROCESSED_INPUT,
) } == 0 {
if unsafe { kernel32::SetConsoleMode(handle, new_mode_flags) } == 0 {
return Err(Error::last_os_error())
}
// If your password is over 0x1000 characters you have paranoia problems
Expand Down Expand Up @@ -185,11 +209,34 @@ mod windows {
}
}

#[cfg(not(windows))]
pub use unix::read_response;
#[cfg(windows)]
pub use windows::read_response;

#[cfg(not(windows))]
pub use unix::read_password;
#[cfg(windows)]
pub use windows::read_password;

/// Prompts for a response on STDOUT and reads it from STDIN.
pub fn prompt_response_stdout(prompt: &str) -> std::io::Result<String> {
let mut stdout = std::io::stdout();

try!(write!(stdout, "{}", prompt));
try!(stdout.flush());
read_response()
}

/// Prompts for a password on STDERR and reads it from STDIN.
pub fn prompt_response_stderr(prompt: &str) -> std::io::Result<String> {
let mut stderr = std::io::stderr();

try!(write!(stderr, "{}", prompt));
try!(stderr.flush());
read_response()
}

/// Prompts for a password on STDOUT and reads it from STDIN.
pub fn prompt_password_stdout(prompt: &str) -> std::io::Result<String> {
let mut stdout = std::io::stdout();
Expand Down

0 comments on commit 7399b41

Please sign in to comment.