зеркало из https://github.com/github/putty.git
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:
Родитель
89505459e3
Коммит
7a79df8fe6
244
ldisc.c
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
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
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
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
|
||||
};
|
||||
|
|
7
rlogin.c
7
rlogin.c
|
@ -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
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
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
|
||||
};
|
||||
|
|
30
telnet.c
30
telnet.c
|
@ -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
|
||||
};
|
||||
|
|
44
terminal.c
44
terminal.c
|
@ -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.
|
||||
*/
|
||||
|
|
97
windlg.c
97
windlg.c
|
@ -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 ||
|
||||
|
|
25
window.c
25
window.c
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче