mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-30 19:12:48 -05:00
Merge out from trunk, to keep this branch viable. We are now up to
date as of r7913.
[originally from svn r7914]
[r7913 == d7eda6d99c
]
This commit is contained in:
@ -49,6 +49,7 @@ struct uctrl {
|
||||
GtkAdjustment *adj; /* for the scrollbar in a list box */
|
||||
guint entrysig;
|
||||
guint textsig;
|
||||
int nclicks;
|
||||
};
|
||||
|
||||
struct dlgparam {
|
||||
@ -98,8 +99,10 @@ static gboolean listitem_single_key(GtkWidget *item, GdkEventKey *event,
|
||||
gpointer data);
|
||||
static gboolean listitem_multi_key(GtkWidget *item, GdkEventKey *event,
|
||||
gpointer data);
|
||||
static gboolean listitem_button(GtkWidget *item, GdkEventButton *event,
|
||||
gpointer data);
|
||||
static gboolean listitem_button_press(GtkWidget *item, GdkEventButton *event,
|
||||
gpointer data);
|
||||
static gboolean listitem_button_release(GtkWidget *item, GdkEventButton *event,
|
||||
gpointer data);
|
||||
static void menuitem_activate(GtkMenuItem *item, gpointer data);
|
||||
static void coloursel_ok(GtkButton *button, gpointer data);
|
||||
static void coloursel_cancel(GtkButton *button, gpointer data);
|
||||
@ -467,7 +470,9 @@ void dlg_listbox_addwithid(union control *ctrl, void *dlg,
|
||||
gtk_signal_connect(GTK_OBJECT(listitem), "focus_in_event",
|
||||
GTK_SIGNAL_FUNC(widget_focus), dp);
|
||||
gtk_signal_connect(GTK_OBJECT(listitem), "button_press_event",
|
||||
GTK_SIGNAL_FUNC(listitem_button), dp);
|
||||
GTK_SIGNAL_FUNC(listitem_button_press), dp);
|
||||
gtk_signal_connect(GTK_OBJECT(listitem), "button_release_event",
|
||||
GTK_SIGNAL_FUNC(listitem_button_release), dp);
|
||||
gtk_object_set_data(GTK_OBJECT(listitem), "user-data",
|
||||
GINT_TO_POINTER(id));
|
||||
} else {
|
||||
@ -1121,13 +1126,26 @@ static gboolean listitem_multi_key(GtkWidget *item, GdkEventKey *event,
|
||||
return listitem_key(item, event, data, TRUE);
|
||||
}
|
||||
|
||||
static gboolean listitem_button(GtkWidget *item, GdkEventButton *event,
|
||||
gpointer data)
|
||||
static gboolean listitem_button_press(GtkWidget *item, GdkEventButton *event,
|
||||
gpointer data)
|
||||
{
|
||||
struct dlgparam *dp = (struct dlgparam *)data;
|
||||
if (event->type == GDK_2BUTTON_PRESS ||
|
||||
event->type == GDK_3BUTTON_PRESS) {
|
||||
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(item));
|
||||
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(item));
|
||||
switch (event->type) {
|
||||
default:
|
||||
case GDK_BUTTON_PRESS: uc->nclicks = 1; break;
|
||||
case GDK_2BUTTON_PRESS: uc->nclicks = 2; break;
|
||||
case GDK_3BUTTON_PRESS: uc->nclicks = 3; break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean listitem_button_release(GtkWidget *item, GdkEventButton *event,
|
||||
gpointer data)
|
||||
{
|
||||
struct dlgparam *dp = (struct dlgparam *)data;
|
||||
struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(item));
|
||||
if (uc->nclicks>1) {
|
||||
uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
|
||||
return TRUE;
|
||||
}
|
||||
@ -1412,6 +1430,7 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs,
|
||||
uc->entry = uc->list = uc->menu = NULL;
|
||||
uc->button = uc->optmenu = uc->text = NULL;
|
||||
uc->label = NULL;
|
||||
uc->nclicks = 0;
|
||||
|
||||
switch (ctrl->generic.type) {
|
||||
case CTRL_BUTTON:
|
||||
@ -2749,7 +2768,7 @@ static void licence_clicked(GtkButton *button, gpointer data)
|
||||
char *title;
|
||||
|
||||
char *licence =
|
||||
"Copyright 1997-2007 Simon Tatham.\n\n"
|
||||
"Copyright 1997-2008 Simon Tatham.\n\n"
|
||||
|
||||
"Portions copyright Robert de Bath, Joris van Rantwijk, Delian "
|
||||
"Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas "
|
||||
@ -2830,7 +2849,7 @@ void about_box(void *window)
|
||||
w, FALSE, FALSE, 5);
|
||||
gtk_widget_show(w);
|
||||
|
||||
w = gtk_label_new("Copyright 1997-2007 Simon Tatham. All rights reserved");
|
||||
w = gtk_label_new("Copyright 1997-2008 Simon Tatham. All rights reserved");
|
||||
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(aboutbox)->vbox),
|
||||
w, FALSE, FALSE, 5);
|
||||
gtk_widget_show(w);
|
||||
|
@ -663,13 +663,12 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
||||
end = 2;
|
||||
}
|
||||
|
||||
/* Control-Break is the same as Control-C */
|
||||
/* Control-Break sends a Break special to the backend */
|
||||
if (event->keyval == GDK_Break &&
|
||||
(event->state & GDK_CONTROL_MASK)) {
|
||||
output[1] = '\003';
|
||||
use_ucsoutput = FALSE;
|
||||
end = 2;
|
||||
special = TRUE;
|
||||
if (inst->back)
|
||||
inst->back->special(inst->backhandle, TS_BRK);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* We handle Return ourselves, because it needs to be flagged as
|
||||
@ -724,6 +723,13 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
||||
end = 1 + sprintf(output+1, "\033[Z");
|
||||
use_ucsoutput = FALSE;
|
||||
}
|
||||
/* And normal Tab is Tab, if the keymap hasn't already told us.
|
||||
* (Curiously, at least one version of the MacOS 10.5 X server
|
||||
* doesn't translate Tab for us. */
|
||||
if (event->keyval == GDK_Tab && end <= 1) {
|
||||
output[1] = '\t';
|
||||
end = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* NetHack keypad mode.
|
||||
@ -1431,7 +1437,7 @@ void palette_reset(void *frontend)
|
||||
int r = i / 36, g = (i / 6) % 6, b = i % 6;
|
||||
inst->cols[i+16].red = r ? r * 0x2828 + 0x3737 : 0;
|
||||
inst->cols[i+16].green = g ? g * 0x2828 + 0x3737 : 0;
|
||||
inst->cols[i+16].blue = b ? b + 0x2828 + 0x3737 : 0;
|
||||
inst->cols[i+16].blue = b ? b * 0x2828 + 0x3737 : 0;
|
||||
} else {
|
||||
int shade = i - 216;
|
||||
shade = shade * 0x0a0a + 0x0808;
|
||||
@ -1864,7 +1870,7 @@ void sys_cursor(void *frontend, int x, int y)
|
||||
*/
|
||||
void do_beep(void *frontend, int mode)
|
||||
{
|
||||
if (mode != BELL_VISUAL)
|
||||
if (mode == BELL_DEFAULT)
|
||||
gdk_beep();
|
||||
}
|
||||
|
||||
@ -2408,7 +2414,7 @@ static void help(FILE *fp) {
|
||||
}
|
||||
}
|
||||
|
||||
int do_cmdline(int argc, char **argv, int do_everything,
|
||||
int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
|
||||
struct gui_data *inst, Config *cfg)
|
||||
{
|
||||
int err = 0;
|
||||
@ -2614,7 +2620,8 @@ int do_cmdline(int argc, char **argv, int do_everything,
|
||||
exit(1);
|
||||
|
||||
} else if(p[0] != '-' && (!do_everything ||
|
||||
process_nonoption_arg(p, cfg))) {
|
||||
process_nonoption_arg(p, cfg,
|
||||
allow_launch))) {
|
||||
/* do nothing */
|
||||
|
||||
} else {
|
||||
@ -3321,6 +3328,7 @@ void set_window_icon(GtkWidget *window, const char *const *const *icon,
|
||||
int n_icon)
|
||||
{
|
||||
GdkPixmap *iconpm;
|
||||
GdkBitmap *iconmask;
|
||||
#if GTK_CHECK_VERSION(2,0,0)
|
||||
GList *iconlist;
|
||||
int n;
|
||||
@ -3330,9 +3338,9 @@ void set_window_icon(GtkWidget *window, const char *const *const *icon,
|
||||
return;
|
||||
|
||||
gtk_widget_realize(window);
|
||||
iconpm = gdk_pixmap_create_from_xpm_d(window->window, NULL,
|
||||
iconpm = gdk_pixmap_create_from_xpm_d(window->window, &iconmask,
|
||||
NULL, (gchar **)icon[0]);
|
||||
gdk_window_set_icon(window->window, NULL, iconpm, NULL);
|
||||
gdk_window_set_icon(window->window, NULL, iconpm, iconmask);
|
||||
|
||||
#if GTK_CHECK_VERSION(2,0,0)
|
||||
iconlist = NULL;
|
||||
@ -3492,15 +3500,23 @@ int pt_main(int argc, char **argv)
|
||||
/* Splatter this argument so it doesn't clutter a ps listing */
|
||||
memset(argv[1], 0, strlen(argv[1]));
|
||||
} else {
|
||||
if (do_cmdline(argc, argv, 0, inst, &inst->cfg))
|
||||
/* By default, we bring up the config dialog, rather than launching
|
||||
* a session. This gets set to TRUE if something happens to change
|
||||
* that (e.g., a hostname is specified on the command-line). */
|
||||
int allow_launch = FALSE;
|
||||
if (do_cmdline(argc, argv, 0, &allow_launch, inst, &inst->cfg))
|
||||
exit(1); /* pre-defaults pass to get -class */
|
||||
do_defaults(NULL, &inst->cfg);
|
||||
if (do_cmdline(argc, argv, 1, inst, &inst->cfg))
|
||||
if (do_cmdline(argc, argv, 1, &allow_launch, inst, &inst->cfg))
|
||||
exit(1); /* post-defaults, do everything */
|
||||
|
||||
cmdline_run_saved(&inst->cfg);
|
||||
|
||||
if (!cfg_launchable(&inst->cfg) && !cfgbox(&inst->cfg))
|
||||
if (loaded_session)
|
||||
allow_launch = TRUE;
|
||||
|
||||
if ((!allow_launch || !cfg_launchable(&inst->cfg)) &&
|
||||
!cfgbox(&inst->cfg))
|
||||
exit(0); /* config box hit Cancel */
|
||||
}
|
||||
|
||||
|
20
unix/unix.h
20
unix/unix.h
@ -60,6 +60,18 @@ extern long tickcount_offset;
|
||||
#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 */
|
||||
@ -80,7 +92,7 @@ int reallyclose(void *frontend);
|
||||
|
||||
/* Things pterm.c needs from {ptermm,uxputty}.c */
|
||||
char *make_default_wintitle(char *hostname);
|
||||
int process_nonoption_arg(char *arg, Config *cfg);
|
||||
int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch);
|
||||
|
||||
/* pterm.c needs this special function in xkeysym.c */
|
||||
int keysym_to_unicode(int keysym);
|
||||
@ -91,6 +103,12 @@ char *x_get_default(const char *key);
|
||||
/* 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);
|
||||
|
@ -18,6 +18,31 @@ int console_batch_mode = FALSE;
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -101,6 +126,7 @@ int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
|
||||
static const char abandoned[] = "Connection abandoned.\n";
|
||||
|
||||
char line[32];
|
||||
struct termios cf;
|
||||
|
||||
/*
|
||||
* Verify the key.
|
||||
@ -110,6 +136,7 @@ int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
|
||||
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);
|
||||
@ -141,9 +168,11 @@ int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -166,7 +195,9 @@ int askalg(void *frontend, const char *algtype, const char *algname,
|
||||
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;
|
||||
@ -187,9 +218,11 @@ int askalg(void *frontend, const char *algtype, const char *algname,
|
||||
}
|
||||
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
postmsg(&cf);
|
||||
return 1;
|
||||
} else {
|
||||
fprintf(stderr, abandoned);
|
||||
postmsg(&cf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -215,7 +248,9 @@ int askappend(void *frontend, Filename filename,
|
||||
"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);
|
||||
@ -235,6 +270,7 @@ int askappend(void *frontend, Filename filename,
|
||||
tcsetattr(0, TCSANOW, &oldmode);
|
||||
}
|
||||
|
||||
postmsg(&cf);
|
||||
if (line[0] == 'y' || line[0] == 'Y')
|
||||
return 2;
|
||||
else if (line[0] == 'n' || line[0] == 'N')
|
||||
@ -266,7 +302,10 @@ void old_keyfile_warning(void)
|
||||
"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)
|
||||
@ -276,8 +315,11 @@ 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)
|
||||
|
24
unix/uxnet.c
24
unix/uxnet.c
@ -97,6 +97,10 @@ static int cmpfortree(void *av, void *bv)
|
||||
return -1;
|
||||
if (as > bs)
|
||||
return +1;
|
||||
if (a < b)
|
||||
return -1;
|
||||
if (a > b)
|
||||
return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -453,6 +457,14 @@ static int try_connect(Actual_Socket sock)
|
||||
short localport;
|
||||
int fl, salen;
|
||||
|
||||
/*
|
||||
* Remove the socket from the tree before we overwrite its
|
||||
* internal socket id, because that forms part of the tree's
|
||||
* sorting criterion. We'll add it back before exiting this
|
||||
* function, whether we changed anything or not.
|
||||
*/
|
||||
del234(sktree, sock);
|
||||
|
||||
if (sock->s >= 0)
|
||||
close(sock->s);
|
||||
|
||||
@ -605,9 +617,14 @@ static int try_connect(Actual_Socket sock)
|
||||
}
|
||||
|
||||
uxsel_tell(sock);
|
||||
add234(sktree, sock);
|
||||
|
||||
ret:
|
||||
|
||||
/*
|
||||
* No matter what happened, put the socket back in the tree.
|
||||
*/
|
||||
add234(sktree, sock);
|
||||
|
||||
if (err)
|
||||
plug_log(sock->plug, 1, sock->addr, sock->port, strerror(err), err);
|
||||
return err;
|
||||
@ -1060,6 +1077,7 @@ static int net_select_result(int fd, int event)
|
||||
#endif
|
||||
socklen_t addrlen = sizeof(ss);
|
||||
int t; /* socket of connection */
|
||||
int fl;
|
||||
|
||||
memset(&ss, 0, addrlen);
|
||||
t = accept(s->s, (struct sockaddr *)&ss, &addrlen);
|
||||
@ -1067,6 +1085,10 @@ static int net_select_result(int fd, int event)
|
||||
break;
|
||||
}
|
||||
|
||||
fl = fcntl(t, F_GETFL);
|
||||
if (fl != -1)
|
||||
fcntl(t, F_SETFL, fl | O_NONBLOCK);
|
||||
|
||||
if (s->localhost_only &&
|
||||
!sockaddr_is_loopback((struct sockaddr *)&ss)) {
|
||||
close(t); /* someone let nonlocal through?! */
|
||||
|
141
unix/uxplink.c
141
unix/uxplink.c
@ -27,14 +27,19 @@
|
||||
|
||||
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;
|
||||
@ -43,12 +48,15 @@ void fatalbox(char *p, ...)
|
||||
}
|
||||
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;
|
||||
@ -57,12 +65,15 @@ void modalfatalbox(char *p, ...)
|
||||
}
|
||||
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;
|
||||
@ -71,17 +82,19 @@ void connection_fatal(void *frontend, char *p, ...)
|
||||
}
|
||||
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 = 0; /* do we have a local tty? */
|
||||
static struct termios orig_termios;
|
||||
static int local_tty = FALSE; /* do we have a local tty? */
|
||||
|
||||
static Backend *back;
|
||||
static void *backhandle;
|
||||
@ -106,7 +119,7 @@ int platform_default_i(const char *name, int def)
|
||||
if (!strcmp(name, "TermWidth") ||
|
||||
!strcmp(name, "TermHeight")) {
|
||||
struct winsize size;
|
||||
if (ioctl(0, TIOCGWINSZ, (void *)&size) >= 0)
|
||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, (void *)&size) >= 0)
|
||||
return (!strcmp(name, "TermWidth") ? size.ws_col : size.ws_row);
|
||||
}
|
||||
return def;
|
||||
@ -180,7 +193,7 @@ void ldisc_update(void *frontend, int echo, int edit)
|
||||
*/
|
||||
mode.c_iflag = (mode.c_iflag | INPCK | PARMRK) & ~IGNPAR;
|
||||
|
||||
tcsetattr(0, TCSANOW, &mode);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &mode);
|
||||
}
|
||||
|
||||
/* Helper function to extract a special character from a termios. */
|
||||
@ -366,48 +379,49 @@ char *get_ttymode(void *frontend, const char *mode)
|
||||
void cleanup_termios(void)
|
||||
{
|
||||
if (local_tty)
|
||||
tcsetattr(0, TCSANOW, &orig_termios);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
|
||||
}
|
||||
|
||||
bufchain stdout_data, stderr_data;
|
||||
|
||||
void try_output(int is_stderr)
|
||||
int try_output(int is_stderr)
|
||||
{
|
||||
bufchain *chain = (is_stderr ? &stderr_data : &stdout_data);
|
||||
int fd = (is_stderr ? 2 : 1);
|
||||
int fd = (is_stderr ? STDERR_FILENO : STDOUT_FILENO);
|
||||
void *senddata;
|
||||
int sendlen, ret;
|
||||
int sendlen, ret, fl;
|
||||
|
||||
if (bufchain_size(chain) == 0)
|
||||
return;
|
||||
return bufchain_size(&stdout_data) + bufchain_size(&stderr_data);
|
||||
|
||||
bufchain_prefix(chain, &senddata, &sendlen);
|
||||
ret = write(fd, senddata, sendlen);
|
||||
if (ret > 0)
|
||||
bufchain_consume(chain, ret);
|
||||
else if (ret < 0) {
|
||||
fl = fcntl(fd, F_GETFL);
|
||||
if (fl != -1 && !(fl & O_NONBLOCK))
|
||||
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
|
||||
do {
|
||||
bufchain_prefix(chain, &senddata, &sendlen);
|
||||
ret = write(fd, senddata, sendlen);
|
||||
if (ret > 0)
|
||||
bufchain_consume(chain, ret);
|
||||
} while (ret == sendlen && bufchain_size(chain) != 0);
|
||||
if (fl != -1 && !(fl & O_NONBLOCK))
|
||||
fcntl(fd, F_SETFL, fl);
|
||||
if (ret < 0 && errno != EAGAIN) {
|
||||
perror(is_stderr ? "stderr: write" : "stdout: write");
|
||||
exit(1);
|
||||
}
|
||||
return bufchain_size(&stdout_data) + bufchain_size(&stderr_data);
|
||||
}
|
||||
|
||||
int from_backend(void *frontend_handle, int is_stderr,
|
||||
const char *data, int len)
|
||||
{
|
||||
int osize, esize;
|
||||
|
||||
if (is_stderr) {
|
||||
bufchain_add(&stderr_data, data, len);
|
||||
try_output(1);
|
||||
return try_output(TRUE);
|
||||
} else {
|
||||
bufchain_add(&stdout_data, data, len);
|
||||
try_output(0);
|
||||
return try_output(FALSE);
|
||||
}
|
||||
|
||||
osize = bufchain_size(&stdout_data);
|
||||
esize = bufchain_size(&stderr_data);
|
||||
|
||||
return osize + esize;
|
||||
}
|
||||
|
||||
int from_backend_untrusted(void *frontend_handle, const char *data, int len)
|
||||
@ -582,7 +596,9 @@ int main(int argc, char **argv)
|
||||
default_protocol = PROT_SSH;
|
||||
default_port = 22;
|
||||
|
||||
flags = FLAG_STDERR;
|
||||
flags = FLAG_STDERR | FLAG_STDERR_TTY;
|
||||
|
||||
stderr_tty_init();
|
||||
/*
|
||||
* Process the command line.
|
||||
*/
|
||||
@ -596,15 +612,11 @@ int main(int argc, char **argv)
|
||||
* Override the default protocol if PLINK_PROTOCOL is set.
|
||||
*/
|
||||
char *p = getenv("PLINK_PROTOCOL");
|
||||
int i;
|
||||
if (p) {
|
||||
for (i = 0; backends[i].backend != NULL; i++) {
|
||||
if (!strcmp(backends[i].name, p)) {
|
||||
default_protocol = cfg.protocol = backends[i].protocol;
|
||||
default_port = cfg.port =
|
||||
backends[i].backend->default_port;
|
||||
break;
|
||||
}
|
||||
const Backend *b = backend_from_name(p);
|
||||
if (b) {
|
||||
default_protocol = cfg.protocol = b->protocol;
|
||||
default_port = cfg.port = b->default_port;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -681,19 +693,14 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
r = strchr(p, ',');
|
||||
if (r) {
|
||||
int i, j;
|
||||
for (i = 0; backends[i].backend != NULL; i++) {
|
||||
j = strlen(backends[i].name);
|
||||
if (j == r - p &&
|
||||
!memcmp(backends[i].name, p, j)) {
|
||||
default_protocol = cfg.protocol =
|
||||
backends[i].protocol;
|
||||
portnumber =
|
||||
backends[i].backend->default_port;
|
||||
p = r + 1;
|
||||
break;
|
||||
}
|
||||
const Backend *b;
|
||||
*r = '\0';
|
||||
b = backend_from_name(p);
|
||||
if (b) {
|
||||
default_protocol = cfg.protocol = b->protocol;
|
||||
portnumber = b->default_port;
|
||||
}
|
||||
p = r + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -836,19 +843,11 @@ int main(int argc, char **argv)
|
||||
* Select protocol. This is farmed out into a table in a
|
||||
* separate file to enable an ssh-free variant.
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
back = NULL;
|
||||
for (i = 0; backends[i].backend != NULL; i++)
|
||||
if (backends[i].protocol == cfg.protocol) {
|
||||
back = backends[i].backend;
|
||||
break;
|
||||
}
|
||||
if (back == NULL) {
|
||||
fprintf(stderr,
|
||||
"Internal fault: Unsupported protocol found\n");
|
||||
return 1;
|
||||
}
|
||||
back = backend_from_proto(cfg.protocol);
|
||||
if (back == NULL) {
|
||||
fprintf(stderr,
|
||||
"Internal fault: Unsupported protocol found\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -869,6 +868,14 @@ int main(int argc, char **argv)
|
||||
sk_init();
|
||||
uxsel_init();
|
||||
|
||||
/*
|
||||
* Unix Plink doesn't provide any way to add forwardings after the
|
||||
* connection is set up, so if there are none now, we can safely set
|
||||
* the "simple" flag.
|
||||
*/
|
||||
if (cfg.protocol == PROT_SSH && !cfg.x11_forward && !cfg.agentfwd &&
|
||||
cfg.portfwd[0] == '\0' && cfg.portfwd[1] == '\0')
|
||||
cfg.ssh_simple = TRUE;
|
||||
/*
|
||||
* Start up the connection.
|
||||
*/
|
||||
@ -897,7 +904,7 @@ int main(int argc, char **argv)
|
||||
* fails, because we know we aren't necessarily running in a
|
||||
* console.
|
||||
*/
|
||||
local_tty = (tcgetattr(0, &orig_termios) == 0);
|
||||
local_tty = (tcgetattr(STDIN_FILENO, &orig_termios) == 0);
|
||||
atexit(cleanup_termios);
|
||||
ldisc_update(NULL, 1, 1);
|
||||
sending = FALSE;
|
||||
@ -921,17 +928,17 @@ int main(int argc, char **argv)
|
||||
back->sendok(backhandle) &&
|
||||
back->sendbuffer(backhandle) < MAX_STDIN_BACKLOG) {
|
||||
/* If we're OK to send, then try to read from stdin. */
|
||||
FD_SET_MAX(0, maxfd, rset);
|
||||
FD_SET_MAX(STDIN_FILENO, maxfd, rset);
|
||||
}
|
||||
|
||||
if (bufchain_size(&stdout_data) > 0) {
|
||||
/* If we have data for stdout, try to write to stdout. */
|
||||
FD_SET_MAX(1, maxfd, wset);
|
||||
FD_SET_MAX(STDOUT_FILENO, maxfd, wset);
|
||||
}
|
||||
|
||||
if (bufchain_size(&stderr_data) > 0) {
|
||||
/* If we have data for stderr, try to write to stderr. */
|
||||
FD_SET_MAX(2, maxfd, wset);
|
||||
FD_SET_MAX(STDERR_FILENO, maxfd, wset);
|
||||
}
|
||||
|
||||
/* Count the currently active fds. */
|
||||
@ -1028,12 +1035,12 @@ int main(int argc, char **argv)
|
||||
back->size(backhandle, size.ws_col, size.ws_row);
|
||||
}
|
||||
|
||||
if (FD_ISSET(0, &rset)) {
|
||||
if (FD_ISSET(STDIN_FILENO, &rset)) {
|
||||
char buf[4096];
|
||||
int ret;
|
||||
|
||||
if (connopen && back->connected(backhandle)) {
|
||||
ret = read(0, buf, sizeof(buf));
|
||||
ret = read(STDIN_FILENO, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
perror("stdin: read");
|
||||
exit(1);
|
||||
@ -1049,12 +1056,12 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(1, &wset)) {
|
||||
try_output(0);
|
||||
if (FD_ISSET(STDOUT_FILENO, &wset)) {
|
||||
back->unthrottle(backhandle, try_output(FALSE));
|
||||
}
|
||||
|
||||
if (FD_ISSET(2, &wset)) {
|
||||
try_output(1);
|
||||
if (FD_ISSET(STDERR_FILENO, &wset)) {
|
||||
back->unthrottle(backhandle, try_output(TRUE));
|
||||
}
|
||||
|
||||
if ((!connopen || !back->connected(backhandle)) &&
|
||||
|
@ -33,7 +33,7 @@ void cleanup_exit(int code)
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int process_nonoption_arg(char *arg, Config *cfg)
|
||||
int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch)
|
||||
{
|
||||
return 0; /* pterm doesn't have any. */
|
||||
}
|
||||
|
14
unix/uxpty.c
14
unix/uxpty.c
@ -360,8 +360,10 @@ static void pty_open_master(Pty pty)
|
||||
/*
|
||||
* Set the pty master into non-blocking mode.
|
||||
*/
|
||||
int i = 1;
|
||||
ioctl(pty->master_fd, FIONBIO, &i);
|
||||
int fl;
|
||||
fl = fcntl(pty->master_fd, F_GETFL);
|
||||
if (fl != -1 && !(fl & O_NONBLOCK))
|
||||
fcntl(pty->master_fd, F_SETFL, fl | O_NONBLOCK);
|
||||
}
|
||||
|
||||
if (!ptys_by_fd)
|
||||
@ -775,10 +777,10 @@ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg,
|
||||
close(slavefd);
|
||||
setsid();
|
||||
#ifdef TIOCSCTTY
|
||||
ioctl(slavefd, TIOCSCTTY, 1);
|
||||
ioctl(0, TIOCSCTTY, 1);
|
||||
#endif
|
||||
pgrp = getpid();
|
||||
tcsetpgrp(slavefd, pgrp);
|
||||
tcsetpgrp(0, pgrp);
|
||||
setpgid(pgrp, pgrp);
|
||||
close(open(pty->name, O_WRONLY, 0));
|
||||
setpgid(pgrp, pgrp);
|
||||
@ -1085,5 +1087,7 @@ Backend pty_backend = {
|
||||
pty_provide_logctx,
|
||||
pty_unthrottle,
|
||||
pty_cfg_info,
|
||||
1
|
||||
"pty",
|
||||
-1,
|
||||
0
|
||||
};
|
||||
|
@ -33,13 +33,7 @@ void cleanup_exit(int code)
|
||||
|
||||
Backend *select_backend(Config *cfg)
|
||||
{
|
||||
int i;
|
||||
Backend *back = NULL;
|
||||
for (i = 0; backends[i].backend != NULL; i++)
|
||||
if (backends[i].protocol == cfg->protocol) {
|
||||
back = backends[i].backend;
|
||||
break;
|
||||
}
|
||||
Backend *back = backend_from_proto(cfg->protocol);
|
||||
assert(back != NULL);
|
||||
return back;
|
||||
}
|
||||
@ -53,7 +47,7 @@ static int got_host = 0;
|
||||
|
||||
const int use_event_log = 1, new_session = 1, saved_sessions = 1;
|
||||
|
||||
int process_nonoption_arg(char *arg, Config *cfg)
|
||||
int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch)
|
||||
{
|
||||
char *p, *q = arg;
|
||||
|
||||
@ -104,6 +98,8 @@ int process_nonoption_arg(char *arg, Config *cfg)
|
||||
cfg->host[sizeof(cfg->host) - 1] = '\0';
|
||||
got_host = 1;
|
||||
}
|
||||
if (got_host)
|
||||
*allow_launch = TRUE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -135,13 +131,10 @@ int main(int argc, char **argv)
|
||||
default_protocol = be_default_protocol;
|
||||
/* Find the appropriate default port. */
|
||||
{
|
||||
int i;
|
||||
Backend *b = backend_from_proto(default_protocol);
|
||||
default_port = 0; /* illegal */
|
||||
for (i = 0; backends[i].backend != NULL; i++)
|
||||
if (backends[i].protocol == default_protocol) {
|
||||
default_port = backends[i].backend->default_port;
|
||||
break;
|
||||
}
|
||||
if (b)
|
||||
default_port = b->default_port;
|
||||
}
|
||||
return pt_main(argc, argv);
|
||||
}
|
||||
|
@ -536,5 +536,7 @@ Backend serial_backend = {
|
||||
serial_provide_logctx,
|
||||
serial_unthrottle,
|
||||
serial_cfg_info,
|
||||
1
|
||||
"serial",
|
||||
PROT_SERIAL,
|
||||
0
|
||||
};
|
||||
|
Reference in New Issue
Block a user