Rethink the whole line discipline architecture. Instead of having

multiple switchable line disciplines, we now have a single unified
one which changes its behaviour based on option settings. Each
option setting can be suggested by the back end and/or the terminal
handler, and can be forcibly overridden by the configuration. Local
echo and local line editing are separate, independently switchable,
options.

[originally from svn r895]
This commit is contained in:
Simon Tatham 2001-01-24 14:08:20 +00:00
Родитель 89505459e3
Коммит 7a79df8fe6
12 изменённых файлов: 329 добавлений и 217 удалений

244
ldisc.c
Просмотреть файл

@ -1,21 +1,27 @@
/*
* 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;
@ -32,7 +38,7 @@ static int plen(unsigned char c) {
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);
@ -52,108 +58,124 @@ static void bsb(int n) {
#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);
}
/*
* 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);
}
}
}
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--;
}
}
if (len > 0)
back->send(buf, len);
}
Ldisc ldisc_term = { term_send };
Ldisc ldisc_simple = { simple_send };

32
plink.c
Просмотреть файл

@ -119,18 +119,11 @@ void verify_ssh_host_key(char *host, int port, char *keytype,
}
}
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;
@ -144,6 +137,23 @@ void from_backend(int is_stderr, char *data, int len) {
}
}
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];
@ -403,7 +413,6 @@ int main(int argc, char **argv) {
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 */
}
}
@ -475,10 +484,11 @@ int main(int argc, char **argv) {
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

28
putty.h
Просмотреть файл

@ -115,6 +115,21 @@ typedef enum {
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);
@ -122,6 +137,7 @@ typedef struct {
void (*special) (Telnet_Special code);
Socket (*socket) (void);
int (*sendok) (void);
int (*ldisc) (int);
int default_port;
} Backend;
@ -133,12 +149,6 @@ extern struct backend_list {
Backend *backend;
} backends[];
typedef struct {
void (*send) (char *buf, int len);
} Ldisc;
GLOBAL Ldisc *ldisc;
typedef struct {
/* Basic options */
char host[512];
@ -176,7 +186,8 @@ typedef struct {
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;
@ -333,6 +344,7 @@ void term_invalidate(void);
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);
@ -367,7 +379,7 @@ extern Backend ssh_backend;
* Exports from ldisc.c.
*/
extern Ldisc ldisc_term, ldisc_simple;
extern void ldisc_send(char *buf, int len);
/*
* Exports from sshrand.c.

12
raw.c
Просмотреть файл

@ -70,11 +70,6 @@ static char *raw_init (char *host, int port, char **realhost) {
sk_addr_free(addr);
/*
* We have no pre-session phase.
*/
begin_session();
return NULL;
}
@ -109,6 +104,12 @@ static Socket raw_socket(void) { return s; }
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,
@ -116,5 +117,6 @@ Backend raw_backend = {
raw_special,
raw_socket,
raw_sendok,
raw_ldisc,
1
};

Просмотреть файл

@ -102,8 +102,6 @@ static char *rlogin_init (char *host, int port, char **realhost) {
sk_write(s, &z, 1);
}
begin_session();
return NULL;
}
@ -142,6 +140,10 @@ static Socket rlogin_socket(void) { return s; }
static int rlogin_sendok(void) { return 1; }
static int rlogin_ldisc(int option) {
return 0;
}
Backend rlogin_backend = {
rlogin_init,
rlogin_send,
@ -149,5 +151,6 @@ Backend rlogin_backend = {
rlogin_special,
rlogin_socket,
rlogin_sendok,
rlogin_ldisc,
1
};

1
scp.c
Просмотреть файл

@ -74,7 +74,6 @@ static void send_str_msg(unsigned int msg_id, char *str);
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,

Просмотреть файл

@ -93,7 +93,8 @@ void save_settings (char *section, int do_host, Config *cfg) {
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);
@ -237,7 +238,8 @@ void load_settings (char *section, int do_host, Config *cfg) {
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);

20
ssh.c
Просмотреть файл

@ -272,6 +272,7 @@ int (*ssh_get_password)(const char *prompt, char *str, int maxlen) = NULL;
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 */
@ -1840,8 +1841,11 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
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) {
@ -1871,9 +1875,9 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
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) {
@ -2743,9 +2747,12 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int 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;
}
/*
@ -2793,8 +2800,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
/*
* Transfer data!
*/
ldisc_send(NULL, 0); /* cause ldisc to notice changes */
ssh_send_ok = 1;
begin_session();
while (1) {
static int try_send;
crReturnV;
@ -3005,6 +3012,8 @@ static char *ssh_init (char *host, int port, char **realhost) {
#endif
ssh_send_ok = 0;
ssh_editing = 0;
ssh_echoing = 0;
p = connect_to_host(host, port, realhost);
if (p != NULL)
@ -3100,6 +3109,12 @@ static Socket ssh_socket(void) { return s; }
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,
@ -3107,5 +3122,6 @@ Backend ssh_backend = {
ssh_special,
ssh_socket,
ssh_sendok,
ssh_ldisc,
22
};

Просмотреть файл

@ -132,6 +132,8 @@ static struct Opt *opts[] = {
&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;
@ -170,8 +172,11 @@ static void deactivate_option (struct Opt *o) {
* 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) {
@ -509,15 +514,6 @@ static char *telnet_init (char *host, int port, char **realhost) {
/*
* 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;
@ -531,11 +527,6 @@ static char *telnet_init (char *host, int port, char **realhost) {
*/
in_synch = FALSE;
/*
* We have no pre-session phase.
*/
begin_session();
return NULL;
}
@ -638,6 +629,12 @@ static Socket telnet_socket(void) { return s; }
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,
@ -645,5 +642,6 @@ Backend telnet_backend = {
telnet_special,
telnet_socket,
telnet_sendok,
telnet_ldisc,
23
};

Просмотреть файл

@ -78,6 +78,8 @@ static int use_bce; /* Use Background coloured erase */
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];
@ -183,6 +185,8 @@ static void power_on(void) {
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;
@ -707,6 +711,10 @@ static void toggle_mode (int mode, int query, int state) {
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;
@ -724,16 +732,8 @@ static void toggle_mode (int mode, int query, int 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;
@ -804,7 +804,7 @@ static int beep_overload = 0;
* An xterm returns "xterm" (5 characters)
*/
compatibility(OTHER);
ldisc->send ("PuTTY", 5);
ldisc_send ("PuTTY", 5);
break;
case '\007':
beep_count++;
@ -1056,7 +1056,7 @@ static int beep_overload = 0;
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);
@ -1199,16 +1199,16 @@ static int beep_overload = 0;
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 */
@ -1420,7 +1420,7 @@ static int beep_overload = 0;
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;
@ -1692,7 +1692,7 @@ static int beep_overload = 0;
termstate = VT52_Y1;
break;
case 'Z':
ldisc->send ("\033/Z", 3);
ldisc_send ("\033/Z", 3);
break;
case '=':
app_keypad_keys = TRUE;
@ -2162,7 +2162,7 @@ void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
/* 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;
@ -2203,7 +2203,7 @@ void term_paste() {
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) {
@ -2226,6 +2226,12 @@ void term_deselect (void) {
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.
*/

Просмотреть файл

@ -200,6 +200,17 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue,
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,
@ -238,14 +249,14 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue,
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,
@ -489,7 +500,12 @@ static void init_dlg_ctrls(HWND hwnd) {
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);
@ -681,8 +697,26 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) {
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",
@ -695,19 +729,18 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) {
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);
}
@ -1081,6 +1114,7 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
* 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");
@ -1144,6 +1178,8 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
}
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"))
@ -1398,10 +1434,25 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
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 ||

Просмотреть файл

@ -101,13 +101,10 @@ static Mouse_Button lastbtn;
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";
@ -318,11 +315,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
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;
@ -1220,11 +1212,10 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
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;
@ -1615,7 +1606,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
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);
@ -1628,7 +1619,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
buf[1] = wParam;
buf[0] = wParam >> 8;
ldisc->send (buf, 2);
ldisc_send (buf, 2);
}
case WM_CHAR:
case WM_SYSCHAR:
@ -1640,7 +1631,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
*/
{
char c = xlat_kbd2tty((unsigned char)wParam);
ldisc->send (&c, 1);
ldisc_send (&c, 1);
}
return 0;
}