+/*
+ * ldisc.c: PuTTY line discipline. Sits between the input coming
+ * from keypresses in the window, and the output channel leading to
+ * the back end. Implements echo and/or local line editing,
+ * depending on what's currently configured.
+ */
+
#include <windows.h>
#include <stdio.h>
#include <ctype.h>
#include "putty.h"
-/*
- * ldisc.c: PuTTY line disciplines
- */
+#define ECHOING (cfg.localecho == LD_YES || \
+ (cfg.localecho == LD_BACKEND && \
+ (back->ldisc(LD_ECHO) || term_ldisc(LD_ECHO))))
+#define EDITING (cfg.localedit == LD_YES || \
+ (cfg.localedit == LD_BACKEND && \
+ (back->ldisc(LD_EDIT) || term_ldisc(LD_EDIT))))
static void c_write (char *buf, int len) {
from_backend(0, buf, len);
}
-static void c_write1 (char c) {
- c_write(&c, 1);
-}
-
static char *term_buf = NULL;
static int term_buflen = 0, term_bufsiz = 0, term_quotenext = 0;
static void pwrite(unsigned char c) {
if ((c >= 32 && c <= 126) ||
(c >= 160)) {
- c_write1(c);
+ c_write(&c, 1);
} else if (c < 128) {
char cc[2];
cc[1] = (c == 127 ? '?' : c + 0x40);
#define CTRL(x) (x^'@')
-static void term_send(char *buf, int len) {
- while (len--) {
- char c;
- c = *buf++;
- switch (term_quotenext ? ' ' : c) {
- /*
- * ^h/^?: delete one char and output one BSB
- * ^w: delete, and output BSBs, to return to last space/nonspace
- * boundary
- * ^u: delete, and output BSBs, to return to BOL
- * ^c: Do a ^u then send a telnet IP
- * ^z: Do a ^u then send a telnet SUSP
- * ^\: Do a ^u then send a telnet ABORT
- * ^r: echo "^R\n" and redraw line
- * ^v: quote next char
- * ^d: if at BOL, end of file and close connection, else send line
- * and reset to BOL
- * ^m: send line-plus-\r\n and reset to BOL
- */
- case CTRL('H'): case CTRL('?'): /* backspace/delete */
- if (term_buflen > 0) {
- bsb(plen(term_buf[term_buflen-1]));
- term_buflen--;
- }
- break;
- case CTRL('W'): /* delete word */
- while (term_buflen > 0) {
- bsb(plen(term_buf[term_buflen-1]));
- term_buflen--;
- if (term_buflen > 0 &&
- isspace(term_buf[term_buflen-1]) &&
- !isspace(term_buf[term_buflen]))
- break;
- }
- break;
- case CTRL('U'): /* delete line */
- case CTRL('C'): /* Send IP */
- case CTRL('\\'): /* Quit */
- case CTRL('Z'): /* Suspend */
- while (term_buflen > 0) {
- bsb(plen(term_buf[term_buflen-1]));
- term_buflen--;
- }
- back->special (TS_EL);
- if( c == CTRL('C') ) back->special (TS_IP);
- if( c == CTRL('Z') ) back->special (TS_SUSP);
- if( c == CTRL('\\') ) back->special (TS_ABORT);
- break;
- case CTRL('R'): /* redraw line */
- c_write("^R\r\n", 4);
- {
- int i;
- for (i = 0; i < term_buflen; i++)
- pwrite(term_buf[i]);
- }
- break;
- case CTRL('V'): /* quote next char */
- term_quotenext = TRUE;
- break;
- case CTRL('D'): /* logout or send */
- if (term_buflen == 0) {
- back->special (TS_EOF);
- } else {
- back->send(term_buf, term_buflen);
- term_buflen = 0;
- }
- break;
- case CTRL('M'): /* send with newline */
- if (term_buflen > 0)
- back->send(term_buf, term_buflen);
- if (cfg.protocol == PROT_RAW)
- back->send("\r\n", 2);
- else
- back->send("\r", 1);
- c_write("\r\n", 2);
- term_buflen = 0;
- break;
- default: /* get to this label from ^V handler */
- if (term_buflen >= term_bufsiz) {
- term_bufsiz = term_buflen + 256;
- term_buf = saferealloc(term_buf, term_bufsiz);
- }
- term_buf[term_buflen++] = c;
- pwrite(c);
- term_quotenext = FALSE;
- break;
- }
+void ldisc_send(char *buf, int len) {
+ /*
+ * Called with len=0 when the options change. We must inform
+ * the front end in case it needs to know.
+ */
+ if (len == 0) {
+ void ldisc_update(int echo, int edit);
+ ldisc_update(ECHOING, EDITING);
}
-}
-
-static void simple_send(char *buf, int len) {
- if( term_buflen != 0 )
- {
- back->send(term_buf, term_buflen);
- while (term_buflen > 0) {
- bsb(plen(term_buf[term_buflen-1]));
- term_buflen--;
- }
+ /*
+ * Either perform local editing, or just send characters.
+ */
+ if (EDITING) {
+ while (len--) {
+ char c;
+ c = *buf++;
+ switch (term_quotenext ? ' ' : c) {
+ /*
+ * ^h/^?: delete one char and output one BSB
+ * ^w: delete, and output BSBs, to return to last
+ * space/nonspace boundary
+ * ^u: delete, and output BSBs, to return to BOL
+ * ^c: Do a ^u then send a telnet IP
+ * ^z: Do a ^u then send a telnet SUSP
+ * ^\: Do a ^u then send a telnet ABORT
+ * ^r: echo "^R\n" and redraw line
+ * ^v: quote next char
+ * ^d: if at BOL, end of file and close connection,
+ * else send line and reset to BOL
+ * ^m: send line-plus-\r\n and reset to BOL
+ */
+ case CTRL('H'): case CTRL('?'): /* backspace/delete */
+ if (term_buflen > 0) {
+ if (ECHOING)
+ bsb(plen(term_buf[term_buflen-1]));
+ term_buflen--;
+ }
+ break;
+ case CTRL('W'): /* delete word */
+ while (term_buflen > 0) {
+ if (ECHOING)
+ bsb(plen(term_buf[term_buflen-1]));
+ term_buflen--;
+ if (term_buflen > 0 &&
+ isspace(term_buf[term_buflen-1]) &&
+ !isspace(term_buf[term_buflen]))
+ break;
+ }
+ break;
+ case CTRL('U'): /* delete line */
+ case CTRL('C'): /* Send IP */
+ case CTRL('\\'): /* Quit */
+ case CTRL('Z'): /* Suspend */
+ while (term_buflen > 0) {
+ if (ECHOING)
+ bsb(plen(term_buf[term_buflen-1]));
+ term_buflen--;
+ }
+ back->special (TS_EL);
+ if( c == CTRL('C') ) back->special (TS_IP);
+ if( c == CTRL('Z') ) back->special (TS_SUSP);
+ if( c == CTRL('\\') ) back->special (TS_ABORT);
+ break;
+ case CTRL('R'): /* redraw line */
+ if (ECHOING) {
+ int i;
+ c_write("^R\r\n", 4);
+ for (i = 0; i < term_buflen; i++)
+ pwrite(term_buf[i]);
+ }
+ break;
+ case CTRL('V'): /* quote next char */
+ term_quotenext = TRUE;
+ break;
+ case CTRL('D'): /* logout or send */
+ if (term_buflen == 0) {
+ back->special (TS_EOF);
+ } else {
+ back->send(term_buf, term_buflen);
+ term_buflen = 0;
+ }
+ break;
+ case CTRL('M'): /* send with newline */
+ if (term_buflen > 0)
+ back->send(term_buf, term_buflen);
+ if (cfg.protocol == PROT_RAW)
+ back->send("\r\n", 2);
+ else
+ back->send("\r", 1);
+ if (ECHOING)
+ c_write("\r\n", 2);
+ term_buflen = 0;
+ break;
+ default: /* get to this label from ^V handler */
+ if (term_buflen >= term_bufsiz) {
+ term_bufsiz = term_buflen + 256;
+ term_buf = saferealloc(term_buf, term_bufsiz);
+ }
+ term_buf[term_buflen++] = c;
+ if (ECHOING)
+ pwrite(c);
+ term_quotenext = FALSE;
+ break;
+ }
+ }
+ } else {
+ if( term_buflen != 0 )
+ {
+ back->send(term_buf, term_buflen);
+ while (term_buflen > 0) {
+ bsb(plen(term_buf[term_buflen-1]));
+ term_buflen--;
+ }
+ }
+ if (len > 0) {
+ if (ECHOING)
+ c_write(buf, len);
+ back->send(buf, len);
+ }
}
- if (len > 0)
- back->send(buf, len);
}
-
-Ldisc ldisc_term = { term_send };
-Ldisc ldisc_simple = { simple_send };
}
}
-HANDLE outhandle, errhandle;
+HANDLE inhandle, outhandle, errhandle;
DWORD orig_console_mode;
WSAEVENT netevent;
-void begin_session(void) {
- if (!cfg.ldisc_term)
- SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT);
- else
- SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), orig_console_mode);
-}
-
void from_backend(int is_stderr, char *data, int len) {
int pos;
DWORD ret;
}
}
+int term_ldisc(int mode) { return FALSE; }
+void ldisc_update(int echo, int edit) {
+ /* Update stdin read mode to reflect changes in line discipline. */
+ DWORD mode;
+
+ mode = ENABLE_PROCESSED_INPUT;
+ if (echo)
+ mode = mode | ENABLE_ECHO_INPUT;
+ else
+ mode = mode &~ ENABLE_ECHO_INPUT;
+ if (edit)
+ mode = mode | ENABLE_LINE_INPUT;
+ else
+ mode = mode &~ ENABLE_LINE_INPUT;
+ SetConsoleMode(inhandle, mode);
+}
+
struct input_data {
DWORD len;
char buffer[4096];
len2 = strlen(cp); len -= len2; cp += len2;
}
cfg.nopty = TRUE; /* command => no terminal */
- cfg.ldisc_term = TRUE; /* use stdin like a line buffer */
break; /* done with cmdline */
}
}
stdinevent = CreateEvent(NULL, FALSE, FALSE, NULL);
- GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &orig_console_mode);
- SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT);
+ inhandle = GetStdHandle(STD_INPUT_HANDLE);
outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
errhandle = GetStdHandle(STD_ERROR_HANDLE);
+ GetConsoleMode(inhandle, &orig_console_mode);
+ SetConsoleMode(inhandle, ENABLE_PROCESSED_INPUT);
/*
* Turn off ECHO and LINE input modes. We don't care if this
VT_XWINDOWS, VT_OEMANSI, VT_OEMONLY, VT_POORMAN
} VT_Mode;
+enum {
+ /*
+ * Line discipline option states: off, on, up to the backend.
+ */
+ LD_YES, LD_NO, LD_BACKEND
+};
+
+enum {
+ /*
+ * Line discipline options which the backend might try to control.
+ */
+ LD_EDIT, /* local line editing */
+ LD_ECHO /* local echo */
+};
+
typedef struct {
char *(*init) (char *host, int port, char **realhost);
void (*send) (char *buf, int len);
void (*special) (Telnet_Special code);
Socket (*socket) (void);
int (*sendok) (void);
+ int (*ldisc) (int);
int default_port;
} Backend;
Backend *backend;
} backends[];
-typedef struct {
- void (*send) (char *buf, int len);
-} Ldisc;
-
-GLOBAL Ldisc *ldisc;
-
typedef struct {
/* Basic options */
char host[512];
int alt_f4; /* is it special? */
int alt_space; /* is it special? */
int alt_only; /* is it special? */
- int ldisc_term;
+ int localecho;
+ int localedit;
int alwaysontop;
int scroll_on_key;
int scroll_on_disp;
void term_blink(int set_cursor);
void term_paste(void);
void term_nopaste(void);
+int telnet_ldisc(int option);
void from_backend(int is_stderr, char *data, int len);
void logfopen (void);
void logfclose (void);
* Exports from ldisc.c.
*/
-extern Ldisc ldisc_term, ldisc_simple;
+extern void ldisc_send(char *buf, int len);
/*
* Exports from sshrand.c.
sk_addr_free(addr);
- /*
- * We have no pre-session phase.
- */
- begin_session();
-
return NULL;
}
static int raw_sendok(void) { return 1; }
+static int raw_ldisc(int option) {
+ if (option == LD_EDIT || option == LD_ECHO)
+ return 1;
+ return 0;
+}
+
Backend raw_backend = {
raw_init,
raw_send,
raw_special,
raw_socket,
raw_sendok,
+ raw_ldisc,
1
};
sk_write(s, &z, 1);
}
- begin_session();
-
return NULL;
}
static int rlogin_sendok(void) { return 1; }
+static int rlogin_ldisc(int option) {
+ return 0;
+}
+
Backend rlogin_backend = {
rlogin_init,
rlogin_send,
rlogin_special,
rlogin_socket,
rlogin_sendok,
+ rlogin_ldisc,
1
};
static void gui_update_stats(char *name, unsigned long size,
int percentage, unsigned long elapsed);
-void begin_session(void) { }
void logevent(char *string) { }
void verify_ssh_host_key(char *host, int port, char *keytype,
write_setting_i (sesskey, "AltSpace", cfg->alt_space);
write_setting_i (sesskey, "AltOnly", cfg->alt_only);
write_setting_i (sesskey, "ComposeKey", cfg->compose_key);
- write_setting_i (sesskey, "LdiscTerm", cfg->ldisc_term);
+ write_setting_i (sesskey, "LocalEcho", cfg->localecho);
+ write_setting_i (sesskey, "LocalEdit", cfg->localedit);
write_setting_i (sesskey, "AlwaysOnTop", cfg->alwaysontop);
write_setting_i (sesskey, "HideMousePtr", cfg->hide_mouseptr);
write_setting_i (sesskey, "CurType", cfg->cursor_type);
gppi (sesskey, "AltSpace", 0, &cfg->alt_space);
gppi (sesskey, "AltOnly", 0, &cfg->alt_only);
gppi (sesskey, "ComposeKey", 0, &cfg->compose_key);
- gppi (sesskey, "LdiscTerm", 0, &cfg->ldisc_term);
+ gppi (sesskey, "LocalEcho", LD_BACKEND, &cfg->localecho);
+ gppi (sesskey, "LocalEdit", LD_BACKEND, &cfg->localedit);
gppi (sesskey, "AlwaysOnTop", 0, &cfg->alwaysontop);
gppi (sesskey, "HideMousePtr", 0, &cfg->hide_mouseptr);
gppi (sesskey, "CurType", 0, &cfg->cursor_type);
static char *savedhost;
static int savedport;
static int ssh_send_ok;
+static int ssh_echoing, ssh_editing;
static tree234 *ssh_channels; /* indexed by local id */
static struct ssh_channel *mainchan; /* primary session channel */
crReturnV;
} else if (pktin.type == SSH1_SMSG_FAILURE) {
c_write("Server refused to allocate pty\r\n", 32);
+ ssh_editing = ssh_echoing = 1;
}
logevent("Allocated pty");
+ } else {
+ ssh_editing = ssh_echoing = 1;
}
if (cfg.compression) {
if (eof_needed)
ssh_special(TS_EOF);
+ ldisc_send(NULL, 0); /* cause ldisc to notice changes */
ssh_send_ok = 1;
ssh_channels = newtree234(ssh_channelcmp);
- begin_session();
while (1) {
crReturnV;
if (ispkt) {
crReturnV;
}
c_write("Server refused to allocate pty\r\n", 32);
+ ssh_editing = ssh_echoing = 1;
} else {
logevent("Allocated pty");
}
+ } else {
+ ssh_editing = ssh_echoing = 1;
}
/*
/*
* Transfer data!
*/
+ ldisc_send(NULL, 0); /* cause ldisc to notice changes */
ssh_send_ok = 1;
- begin_session();
while (1) {
static int try_send;
crReturnV;
#endif
ssh_send_ok = 0;
+ ssh_editing = 0;
+ ssh_echoing = 0;
p = connect_to_host(host, port, realhost);
if (p != NULL)
static int ssh_sendok(void) { return ssh_send_ok; }
+static int ssh_ldisc(int option) {
+ if (option == LD_ECHO) return ssh_echoing;
+ if (option == LD_EDIT) return ssh_editing;
+ return FALSE;
+}
+
Backend ssh_backend = {
ssh_init,
ssh_send,
ssh_special,
ssh_socket,
ssh_sendok,
+ ssh_ldisc,
22
};
&o_we_sga, &o_they_sga, NULL
};
+static int echoing = TRUE, editing = TRUE;
+
static int in_synch;
static int sb_opt, sb_len;
static char *sb_buf = NULL;
* Generate side effects of enabling or disabling an option.
*/
static void option_side_effects(struct Opt *o, int enabled) {
- if (o->option == TELOPT_ECHO && cfg.ldisc_term)
- ldisc = enabled ? &ldisc_simple : &ldisc_term;
+ if (o->option == TELOPT_ECHO && o->send == DO)
+ echoing = !enabled;
+ else if (o->option = TELOPT_SGA && o->send == DO)
+ editing = !enabled;
+ ldisc_send(NULL, 0); /* cause ldisc to notice the change */
}
static void activate_option (struct Opt *o) {
/*
* Initialise option states.
*/
- if( cfg.ldisc_term )
- {
- struct Opt **o;
-
- for (o = opts; *o; o++)
- if ((*o)->state == REQUESTED)
- (*o)->state = INACTIVE;
- }
- else
{
struct Opt **o;
*/
in_synch = FALSE;
- /*
- * We have no pre-session phase.
- */
- begin_session();
-
return NULL;
}
static int telnet_sendok(void) { return 1; }
+static int telnet_ldisc(int option) {
+ if (option == LD_ECHO) return echoing;
+ if (option == LD_EDIT) return editing;
+ return FALSE;
+}
+
Backend telnet_backend = {
telnet_init,
telnet_send,
telnet_special,
telnet_socket,
telnet_sendok,
+ telnet_ldisc,
23
};
static int blinker; /* When blinking is the cursor on ? */
static int tblinker; /* When the blinking text is on */
static int blink_is_real; /* Actually blink blinking text */
+static int term_echoing; /* Does terminal want local echo? */
+static int term_editing; /* Does terminal want local edit? */
static unsigned long cset_attr[2];
rvideo = 0;
cursor_on = 1;
save_attr = curr_attr = ATTR_DEFAULT;
+ term_editing = term_echoing = FALSE;
+ ldisc_send(NULL, 0); /* cause ldisc to notice changes */
app_cursor_keys = cfg.app_cursor;
app_keypad_keys = cfg.app_keypad;
use_bce = cfg.bce;
case 8: /* auto key repeat */
repeat_off = !state;
break;
+ case 10: /* set local edit mode */
+ term_editing = state;
+ ldisc_send(NULL, 0); /* cause ldisc to notice changes */
+ break;
case 25: /* enable/disable cursor */
compatibility2(OTHER,VT220);
cursor_on = state;
insert = state;
break;
case 12: /* set echo mode */
- /*
- * This may be very good in smcup and rmcup (or smkx & rmkx) if you
- * have a long RTT and the telnet client/daemon doesn't understand
- * linemode.
- *
- * DONT send TS_RECHO/TS_LECHO; the telnet daemon tries to fix the
- * tty and _really_ confuses some programs.
- */
- compatibility2(OTHER,VT220);
- ldisc = (state? &ldisc_simple : &ldisc_term);
+ term_echoing = !state;
+ ldisc_send(NULL, 0); /* cause ldisc to notice changes */
break;
case 20: /* Return sends ... */
cr_lf_return = state;
* An xterm returns "xterm" (5 characters)
*/
compatibility(OTHER);
- ldisc->send ("PuTTY", 5);
+ ldisc_send ("PuTTY", 5);
break;
case '\007':
beep_count++;
break;
case 'Z': /* terminal type query */
compatibility(VT100);
- ldisc->send (id_string, strlen(id_string));
+ ldisc_send (id_string, strlen(id_string));
break;
case 'c': /* restore power-on settings */
compatibility(VT100);
case 'c': /* terminal type query */
compatibility(VT100);
/* This is the response for a VT102 */
- ldisc->send (id_string, strlen(id_string));
+ ldisc_send (id_string, strlen(id_string));
break;
case 'n': /* cursor position query */
if (esc_args[0] == 6) {
char buf[32];
sprintf (buf, "\033[%d;%dR", curs_y + 1, curs_x + 1);
- ldisc->send (buf, strlen(buf));
+ ldisc_send (buf, strlen(buf));
}
else if (esc_args[0] == 5) {
- ldisc->send ("\033[0n", 4);
+ ldisc_send ("\033[0n", 4);
}
break;
case 'h': /* toggle modes to high */
if (i == 0 || i == 1) {
strcpy (buf, "\033[2;1;1;112;112;1;0x");
buf[2] += i;
- ldisc->send (buf, 20);
+ ldisc_send (buf, 20);
}
}
break;
termstate = VT52_Y1;
break;
case 'Z':
- ldisc->send ("\033/Z", 3);
+ ldisc_send ("\033/Z", 3);
break;
case '=':
app_keypad_keys = TRUE;
/* Assume a small paste will be OK in one go. */
if (paste_len<256) {
- ldisc->send (paste_buffer, paste_len);
+ ldisc_send (paste_buffer, paste_len);
if (paste_buffer) sfree(paste_buffer);
paste_buffer = 0;
paste_pos = paste_hold = paste_len = 0;
if (paste_buffer[paste_pos + n++] == '\r')
break;
}
- ldisc->send (paste_buffer+paste_pos, n);
+ ldisc_send (paste_buffer+paste_pos, n);
paste_pos += n;
if (paste_pos < paste_len) {
term_update();
}
+int term_ldisc(int option) {
+ if (option == LD_ECHO) return term_echoing;
+ if (option == LD_EDIT) return term_editing;
+ return FALSE;
+}
+
/*
* from_backend(), to get data from the backend for the terminal.
*/
IDC_CLOSEEXIT,
sessionpanelend,
+ loggingpanelstart,
+ IDC_BOX_LOGGING1,
+ IDC_LSTATSTATIC,
+ IDC_LSTATOFF,
+ IDC_LSTATASCII,
+ IDC_LSTATRAW,
+ IDC_LGFSTATIC,
+ IDC_LGFEDIT,
+ IDC_LGFBUTTON,
+ loggingpanelend,
+
keyboardpanelstart,
IDC_TITLE_KEYBOARD,
IDC_BOX_KEYBOARD1,
IDC_BEEP,
IDC_BCE,
IDC_BLINKTEXT,
- IDC_LDISCTERM,
- IDC_LSTATSTATIC,
- IDC_LSTATOFF,
- IDC_LSTATASCII,
- IDC_LSTATRAW,
- IDC_LGFSTATIC,
- IDC_LGFEDIT,
- IDC_LGFBUTTON,
+ IDC_ECHOSTATIC,
+ IDC_ECHOBACKEND,
+ IDC_ECHOYES,
+ IDC_ECHONO,
+ IDC_EDITSTATIC,
+ IDC_EDITBACKEND,
+ IDC_EDITYES,
+ IDC_EDITNO,
terminalpanelend,
windowpanelstart,
CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
CheckDlgButton (hwnd, IDC_ALTONLY, cfg.alt_only);
CheckDlgButton (hwnd, IDC_COMPOSEKEY, cfg.compose_key);
- CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
+ CheckRadioButton (hwnd, IDC_ECHOBACKEND, IDC_ECHONO,
+ cfg.localecho == LD_BACKEND ? IDC_ECHOBACKEND:
+ cfg.localecho == LD_YES ? IDC_ECHOYES : IDC_ECHONO);
+ CheckRadioButton (hwnd, IDC_EDITBACKEND, IDC_EDITNO,
+ cfg.localedit == LD_BACKEND ? IDC_EDITBACKEND:
+ cfg.localedit == LD_YES ? IDC_EDITYES : IDC_EDITNO);
CheckDlgButton (hwnd, IDC_ALWAYSONTOP, cfg.alwaysontop);
CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
CheckDlgButton (hwnd, IDC_SCROLLDISP, cfg.scroll_on_disp);
endbox(&cp);
}
+ if (panel == loggingpanelstart) {
+ /* The Logging panel. Accelerators used: [acgo] lpt */
+ struct ctlpos cp;
+ ctlposinit(&cp, hwnd, 80, 3, 13);
+ bartitle(&cp, "Options controlling session logging",
+ IDC_TITLE_TERMINAL);
+ beginbox(&cp, NULL, IDC_BOX_LOGGING1);
+ radiobig(&cp,
+ "Session logging:", IDC_LSTATSTATIC,
+ "Logging &turned off completely", IDC_LSTATOFF,
+ "Log &printable output only", IDC_LSTATASCII,
+ "&Log all session output", IDC_LSTATRAW, NULL);
+ editbutton(&cp, "Log &file name:",
+ IDC_LGFSTATIC, IDC_LGFEDIT, "Bro&wse...",
+ IDC_LGFBUTTON);
+ endbox(&cp);
+ }
+
if (panel == terminalpanelstart) {
- /* The Terminal panel. Accelerators used: [acgo] &dflbenuw */
+ /* The Terminal panel. Accelerators used: [acgo] &dflbentuw */
struct ctlpos cp;
ctlposinit(&cp, hwnd, 80, 3, 13);
bartitle(&cp, "Options controlling the terminal emulation",
checkbox(&cp, "&Beep enabled", IDC_BEEP);
checkbox(&cp, "Use background colour to &erase screen", IDC_BCE);
checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
- checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
endbox(&cp);
- beginbox(&cp, "Control session logging",
+ beginbox(&cp, "Line discipline options",
IDC_BOX_TERMINAL2);
- radiobig(&cp,
- "Session logging:", IDC_LSTATSTATIC,
- "Logging turned &off completely", IDC_LSTATOFF,
- "Log printable output only", IDC_LSTATASCII,
- "Log all session output", IDC_LSTATRAW, NULL);
- editbutton(&cp, "Log &file name:",
- IDC_LGFSTATIC, IDC_LGFEDIT, "Bro&wse...",
- IDC_LGFBUTTON);
+ radioline(&cp, "Local echo:", IDC_ECHOSTATIC, 3,
+ "A&uto", IDC_ECHOBACKEND,
+ "Force on", IDC_ECHOYES,
+ "Force off", IDC_ECHONO, NULL);
+ radioline(&cp, "Local line editing:", IDC_EDITSTATIC, 3,
+ "Au&to", IDC_EDITBACKEND,
+ "Force on", IDC_EDITYES,
+ "Force off", IDC_EDITNO, NULL);
endbox(&cp);
}
* Set up the tree view contents.
*/
hsession = treeview_insert(&tvfaff, 0, "Session");
+ treeview_insert(&tvfaff, 1, "Logging");
treeview_insert(&tvfaff, 0, "Terminal");
treeview_insert(&tvfaff, 1, "Keyboard");
treeview_insert(&tvfaff, 0, "Window");
}
if (!strcmp(buffer, "Session"))
create_controls(hwnd, dlgtype, sessionpanelstart);
+ if (!strcmp(buffer, "Logging"))
+ create_controls(hwnd, dlgtype, loggingpanelstart);
if (!strcmp(buffer, "Keyboard"))
create_controls(hwnd, dlgtype, keyboardpanelstart);
if (!strcmp(buffer, "Terminal"))
HIWORD(wParam) == BN_DOUBLECLICKED)
cfg.alt_only = IsDlgButtonChecked (hwnd, IDC_ALTONLY);
break;
- case IDC_LDISCTERM:
+ case IDC_ECHOBACKEND:
+ case IDC_ECHOYES:
+ case IDC_ECHONO:
if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
+ HIWORD(wParam) == BN_DOUBLECLICKED) {
+ if (LOWORD(wParam)==IDC_ECHOBACKEND) cfg.localecho=LD_BACKEND;
+ if (LOWORD(wParam)==IDC_ECHOYES) cfg.localecho=LD_YES;
+ if (LOWORD(wParam)==IDC_ECHONO) cfg.localecho=LD_NO;
+ }
+ break;
+ case IDC_EDITBACKEND:
+ case IDC_EDITYES:
+ case IDC_EDITNO:
+ if (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED) {
+ if (LOWORD(wParam)==IDC_EDITBACKEND) cfg.localedit=LD_BACKEND;
+ if (LOWORD(wParam)==IDC_EDITYES) cfg.localedit=LD_YES;
+ if (LOWORD(wParam)==IDC_EDITNO) cfg.localedit=LD_NO;
+ }
break;
case IDC_ALWAYSONTOP:
if (HIWORD(wParam) == BN_CLICKED ||
static char *window_name, *icon_name;
-static Ldisc *real_ldisc;
-
static int compose_state = 0;
-void begin_session(void) {
- ldisc = real_ldisc;
-}
+/* Dummy routine, only required in plink. */
+void ldisc_update(int echo, int edit) {}
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
static char appname[] = "PuTTY";
return 1;
}
- real_ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple);
- /* To start with, we use the simple line discipline, so we can
- * type passwords etc without fear of them being echoed... */
- ldisc = &ldisc_simple;
-
if (!prev) {
wndclass.style = 0;
wndclass.lpfnWndProc = WndProc;
init_fonts(0);
sfree(logpal);
/*
- * Telnet will change local echo -> remote if the
- * remote asks.
+ * Flush the line discipline's edit buffer in the
+ * case where local editing has just been disabled.
*/
- if (cfg.protocol != PROT_TELNET)
- ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple);
+ ldisc_send(NULL, 0);
if (pal)
DeleteObject(pal);
logpal = NULL;
len = TranslateKey (message, wParam, lParam, buf);
if (len == -1)
return DefWindowProc (hwnd, message, wParam, lParam);
- ldisc->send (buf, len);
+ ldisc_send (buf, len);
if (len > 0)
show_mouseptr(0);
buf[1] = wParam;
buf[0] = wParam >> 8;
- ldisc->send (buf, 2);
+ ldisc_send (buf, 2);
}
case WM_CHAR:
case WM_SYSCHAR:
*/
{
char c = xlat_kbd2tty((unsigned char)wParam);
- ldisc->send (&c, 1);
+ ldisc_send (&c, 1);
}
return 0;
}