#define WCHAR wchar_t
#define BYTE unsigned char
+/*
+ * Unix-specific global flag
+ *
+ * FLAG_STDERR_TTY indicates that standard error might be a terminal and
+ * might get its configuration munged, so anything trying to output plain
+ * text (i.e. with newlines in it) will need to put it back into cooked
+ * mode first. Applications setting this flag should also call
+ * stderr_tty_init() before messing with any terminal modes, and can call
+ * premsg() before outputting text to stderr and postmsg() afterwards.
+ */
+#define FLAG_STDERR_TTY 0x1000
+
/* Things pty.c needs from pterm.c */
char *get_x_display(void *frontend);
int font_dimension(void *frontend, int which);/* 0 for width, 1 for height */
/* Things uxstore.c provides to pterm.c */
void provide_xrm_string(char *string);
+/* Things provided by uxcons.c */
+struct termios;
+void stderr_tty_init(void);
+void premsg(struct termios *);
+void postmsg(struct termios *);
+
/* The interface used by uxsel.c */
void uxsel_init(void);
typedef int (*uxsel_callback_fn)(int fd, int event);
static void *console_logctx = NULL;
+static struct termios orig_termios_stderr;
+static int stderr_is_a_tty;
+
+void stderr_tty_init()
+{
+ /* Ensure that if stderr is a tty, we can get it back to a sane state. */
+ if ((flags & FLAG_STDERR_TTY) && isatty(STDERR_FILENO)) {
+ stderr_is_a_tty = TRUE;
+ tcgetattr(STDERR_FILENO, &orig_termios_stderr);
+ }
+}
+
+void premsg(struct termios *cf)
+{
+ if (stderr_is_a_tty) {
+ tcgetattr(STDERR_FILENO, cf);
+ tcsetattr(STDERR_FILENO, TCSADRAIN, &orig_termios_stderr);
+ }
+}
+void postmsg(struct termios *cf)
+{
+ if (stderr_is_a_tty)
+ tcsetattr(STDERR_FILENO, TCSADRAIN, cf);
+}
+
/*
* Clean up and exit.
*/
static const char abandoned[] = "Connection abandoned.\n";
char line[32];
+ struct termios cf;
/*
* Verify the key.
if (ret == 0) /* success - key matched OK */
return 1;
+ premsg(&cf);
if (ret == 2) { /* key was different */
if (console_batch_mode) {
fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
if (line[0] == 'y' || line[0] == 'Y')
store_host_key(host, port, keytype, keystr);
+ postmsg(&cf);
return 1;
} else {
fprintf(stderr, abandoned);
+ postmsg(&cf);
return 0;
}
}
static const char abandoned[] = "Connection abandoned.\n";
char line[32];
+ struct termios cf;
+ premsg(&cf);
if (console_batch_mode) {
fprintf(stderr, msg_batch, algtype, algname);
return 0;
}
if (line[0] == 'y' || line[0] == 'Y') {
+ postmsg(&cf);
return 1;
} else {
fprintf(stderr, abandoned);
+ postmsg(&cf);
return 0;
}
}
"Logging will not be enabled.\n";
char line[32];
+ struct termios cf;
+ premsg(&cf);
if (console_batch_mode) {
fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename.path);
fflush(stderr);
tcsetattr(0, TCSANOW, &oldmode);
}
+ postmsg(&cf);
if (line[0] == 'y' || line[0] == 'Y')
return 2;
else if (line[0] == 'n' || line[0] == 'N')
"Once the key is loaded into PuTTYgen, you can perform\n"
"this conversion simply by saving it again.\n";
+ struct termios cf;
+ premsg(&cf);
fputs(message, stderr);
+ postmsg(&cf);
}
void console_provide_logctx(void *logctx)
void logevent(void *frontend, const char *string)
{
+ struct termios cf;
+ premsg(&cf);
if (console_logctx)
log_eventlog(console_logctx, string);
+ postmsg(&cf);
}
static void console_data_untrusted(const char *data, int len)
void *logctx;
+static struct termios orig_termios;
+
void fatalbox(char *p, ...)
{
+ struct termios cf;
va_list ap;
+ premsg(&cf);
fprintf(stderr, "FATAL ERROR: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
+ postmsg(&cf);
if (logctx) {
log_free(logctx);
logctx = NULL;
}
void modalfatalbox(char *p, ...)
{
+ struct termios cf;
va_list ap;
+ premsg(&cf);
fprintf(stderr, "FATAL ERROR: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
+ postmsg(&cf);
if (logctx) {
log_free(logctx);
logctx = NULL;
}
void connection_fatal(void *frontend, char *p, ...)
{
+ struct termios cf;
va_list ap;
+ premsg(&cf);
fprintf(stderr, "FATAL ERROR: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
+ postmsg(&cf);
if (logctx) {
log_free(logctx);
logctx = NULL;
}
void cmdline_error(char *p, ...)
{
+ struct termios cf;
va_list ap;
+ premsg(&cf);
fprintf(stderr, "plink: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
+ postmsg(&cf);
exit(1);
}
static int local_tty = FALSE; /* do we have a local tty? */
-static struct termios orig_termios;
static Backend *back;
static void *backhandle;
default_protocol = PROT_SSH;
default_port = 22;
- flags = FLAG_STDERR;
+ flags = FLAG_STDERR | FLAG_STDERR_TTY;
+
+ stderr_tty_init();
/*
* Process the command line.
*/