/* $Id: ssh_ui.c,v 1.6 2001/02/11 03:35:15 tls Exp $ */ /* * Copyright (c) 2001 Jason R. Thorpe. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * This module implements the FreSSH user interface. */ #include #include #include #include #include #include #include #include "ssh_ui.h" struct ui_state { int ui_fd_in; /* input TTY file descriptor */ int ui_fd_out; /* output TTY file descriptor */ int ui_needclose; /* need to close the FDs */ struct termios ui_term; /* save terminal state */ }; /* * ui_open: * * Open the user interface. */ static int ui_open(struct ui_state *ui) { int fd; fd = open("/dev/tty", O_RDWR); if (fd == -1) { /* Use stdin and stderr. */ ui->ui_fd_in = fileno(stdin); ui->ui_fd_out = fileno(stderr); ui->ui_needclose = 0; } else { ui->ui_fd_in = ui->ui_fd_out = fd; ui->ui_needclose = 1; } /* * Flush stdout and stderr so our messages * won't get garbled. */ fflush(stdout); fflush(stderr); return (0); } /* * ui_close: * * Close the user interface. */ static void ui_close(struct ui_state *ui) { if (ui->ui_needclose) { (void) close(ui->ui_fd_in); if (ui->ui_fd_in != ui->ui_fd_out) (void) close(ui->ui_fd_out); } } /* * ui_echo_disable: * * Disable character echo on the user interface. */ static int ui_echo_disable(struct ui_state *ui) { struct termios term; if (tcgetattr(ui->ui_fd_in, &ui->ui_term) != 0) return (-1); term = ui->ui_term; /* structure copy */ term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); if (tcsetattr(ui->ui_fd_in, TCSANOW, &term) != 0) return (-1); return (0); } /* * ui_echo_restore: * * Restore character echo on the user interface. */ static int ui_echo_restore(struct ui_state *ui) { if (tcsetattr(ui->ui_fd_in, TCSANOW, &ui->ui_term) != 0) return (-1); return (0); } /* * ui_output: * * Send output to the user interface. */ static size_t ui_output(struct ui_state *ui, const char *buf, size_t bufsize) { return (write(ui->ui_fd_out, buf, bufsize)); } /* * ui_input: * * Get input from the user interface. */ static size_t ui_input(struct ui_state *ui, char *buf, size_t bufsize, int echo) { size_t rv; char ch; if (echo == 0) ui_echo_disable(ui); for (rv = 0;;) { if (read(ui->ui_fd_in, &ch, 1) != 1) break; if (ch == '\n') break; if (rv < bufsize) buf[rv++] = ch; } buf[rv] = '\0'; if (echo == 0) { ui_echo_restore(ui); (void) ui_output(ui, "\n", 1); } return (rv); } /* * ssh_ui_prompt: * * Present a prompt to the user and get a response. Only * echo the response if requested. */ int ssh_ui_prompt(char **pp, const char *prompt, int echo) { char buf[128]; struct ui_state ui; size_t len; int rv = 0; if (ui_open(&ui) < 0) return (-1); if (prompt != NULL) { /* Write the prompt. */ (void) ui_output(&ui, prompt, strlen(prompt)); } /* Get the response. */ len = ui_input(&ui, buf, sizeof(buf), echo); if (len <= 0) { /* NL or interrupt. */ buf[0] = '\0'; } if (rv == 0) { *pp = strdup(buf); if (*pp == NULL) rv = -1; } memset(buf, 0, sizeof(buf)); ui_close(&ui); return (rv); } /* * ssh_ui_message: * * Write a message to the user interface. */ void ssh_ui_message(const char *message) { struct ui_state ui; if (ui_open(&ui) < 0) return; (void) ui_output(&ui, message, strlen(message)); (void) ui_output(&ui, "\n", 1); ui_close(&ui); }