.c.obj:
cl $(COMPAT) $(FWHACK) $(CFLAGS) /c $*.c
-PUTTYOBJS = window.obj windlg.obj terminal.obj telnet.obj raw.obj xlat.obj
+POBJS1 = window.obj windlg.obj terminal.obj telnet.obj raw.obj
+POBJS2 = xlat.obj ldisc.obj
OBJS1 = misc.obj noise.obj
OBJS2 = ssh.obj sshcrc.obj sshdes.obj sshmd5.obj sshrsa.obj sshrand.obj
OBJS3 = sshsha.obj sshblowf.obj version.obj sizetip.obj
all: putty.exe pscp.exe
-putty.exe: $(PUTTYOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
+putty.exe: $(POBJS1) $(POBJS2) $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
link /debug -out:putty.exe @link.rsp
-puttyd.exe: $(PUTTYOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
+puttyd.exe: $(POBJS1) $(POBJS2) $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
link /debug -out:puttyd.exe @link.rsp
link.rsp: makefile
echo /nologo /subsystem:windows > link.rsp
- echo $(PUTTYOBJS) >> link.rsp
+ echo $(POBJS1) >> link.rsp
+ echo $(POBJS2) >> link.rsp
echo $(OBJS1) >> link.rsp
echo $(OBJS2) >> link.rsp
echo $(OBJS3) >> link.rsp
telnet.obj: telnet.c putty.h
raw.obj: raw.c putty.h
xlat.obj: xlat.c putty.h
+ldisc.obj: ldisc.c putty.h
misc.obj: misc.c putty.h
noise.obj: noise.c putty.h ssh.h
ssh.obj: ssh.c ssh.h putty.h
--- /dev/null
+#include <windows.h>
+#include <stdio.h>
+
+#include "putty.h"
+
+/*
+ * ldisc.c: PuTTY line disciplines
+ */
+
+static void c_write (char *buf, int len) {
+ while (len--) {
+ int new_head = (inbuf_head + 1) & INBUF_MASK;
+ int c = (unsigned char) *buf;
+ if (new_head != inbuf_reap) {
+ inbuf[inbuf_head] = *buf++;
+ inbuf_head = new_head;
+ }
+ }
+}
+
+static char *term_buf = NULL;
+static int term_buflen = 0, term_bufsiz = 0, term_quotenext = 0;
+
+static int plen(unsigned char c) {
+ if ((c >= 32 && c <= 126) ||
+ (c >= 160))
+ return 1;
+ else if (c < 128)
+ return 2; /* ^x for some x */
+ else
+ return 4; /* <XY> for hex XY */
+}
+
+static void pwrite(unsigned char c) {
+ if ((c >= 32 && c <= 126) ||
+ (c >= 160)) {
+ char cc = (char)c;
+ c_write(&cc, 1);
+ } else if (c < 128) {
+ char cc[2];
+ cc[1] = (c == 127 ? '?' : c + 0x40);
+ cc[0] = '^';
+ c_write(cc, 2);
+ } else {
+ char cc[5];
+ sprintf(cc, "<%02X>", c);
+ c_write(cc, 4);
+ }
+}
+
+static void bsb(int n) {
+ while (n--)
+ c_write("\010 \010", 3);
+}
+
+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
+ * ^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/^j: send line-plus-\r\n and reset to BOL
+ */
+ case 8: case 127: /* backspace/delete */
+ if (term_buflen > 0) {
+ bsb(plen(term_buf[term_buflen-1]));
+ term_buflen--;
+ }
+ break;
+ case 23: /* ^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 21: /* ^U delete line */
+ while (term_buflen > 0) {
+ bsb(plen(term_buf[term_buflen-1]));
+ term_buflen--;
+ }
+ break;
+ case 18: /* ^R redraw line */
+ c_write("^R\r\n", 4);
+ {
+ int i;
+ for (i = 0; i < term_buflen; i++)
+ pwrite(term_buf[i]);
+ }
+ break;
+ case 22: /* ^V quote next char */
+ term_quotenext = TRUE;
+ break;
+ case 4: /* ^D logout or send */
+ if (term_buflen == 0) {
+ /* FIXME: eof */;
+ } else {
+ back->send(term_buf, term_buflen);
+ term_buflen = 0;
+ }
+ break;
+ case 13: case 10: /* ^M/^J send with newline */
+ back->send(term_buf, term_buflen);
+ back->send("\r\n", 2);
+ 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;
+ }
+ }
+}
+
+static void simple_send(char *buf, int len) {
+ back->send(buf, len);
+}
+
+Ldisc ldisc_term = { term_send };
+Ldisc ldisc_simple = { simple_send };
GLOBAL Backend *back;
+typedef struct {
+ void (*send) (char *buf, int len);
+} Ldisc;
+
+GLOBAL Ldisc *ldisc;
+
typedef struct {
/* Basic options */
char host[512];
int nethack_keypad;
int alt_f4; /* is it special? */
int alt_space; /* is it special? */
+ int ldisc_term;
/* Terminal options */
int savelines;
int dec_om;
extern Backend ssh_backend;
+/*
+ * Exports from ldisc.c.
+ */
+
+extern Ldisc ldisc_term, ldisc_simple;
+
/*
* Exports from sshrand.c.
*/
do_toplevel:
switch (c) {
case '\005': /* terminal type query */
- back->send ("\033[?1;2c", 7);
+ ldisc->send ("\033[?1;2c", 7);
break;
case '\007':
beep();
must_update = TRUE;
break;
case 'Z': /* terminal type query */
- back->send ("\033[?6c", 5);
+ ldisc->send ("\033[?6c", 5);
break;
case 'c': /* restore power-on settings */
power_on();
must_update = TRUE;
break;
case 'c': /* terminal type query */
- back->send ("\033[?6c", 5);
+ ldisc->send ("\033[?6c", 5);
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);
- back->send (buf, strlen(buf));
+ ldisc->send (buf, strlen(buf));
}
break;
case 'h': /* toggle a mode to high */
if (i == 0 || i == 1) {
strcpy (buf, "\033[2;1;1;112;112;1;0x");
buf[2] += i;
- back->send (buf, 20);
+ ldisc->send (buf, 20);
}
}
break;
for(i=0;i<p-q;i++)
{
c=xlat_kbd2tty(q[i]);
- back->send(&c,1);
+ ldisc->send(&c,1);
}
}
if (p <= data+len-sizeof(sel_nl) &&
!memcmp(p, sel_nl, sizeof(sel_nl))) {
- back->send ("\r", 1);
+ ldisc->send ("\r", 1);
p += sizeof(sel_nl);
}
q = p;
#define IDC1_CURAPPLIC 1016
#define IDC1_ALTF4 1017
#define IDC1_ALTSPACE 1018
+#define IDC1_LDISCTERM 1019
#define IDC2_WRAPMODE 1001
#define IDC2_DECOM 1002
IDC1_ALTF4, 3, 113, 162, 10
AUTOCHECKBOX "ALT-Space is special (S&ystem menu)",
IDC1_ALTSPACE, 3, 123, 162, 10
+ AUTOCHECKBOX "&Use local terminal line discipline",
+ IDC1_LDISCTERM, 3, 133, 162, 10
END
IDD_PANEL2 DIALOG DISCARDABLE 6, 30, 168, 163
wppi (sesskey, "NetHackKeypad", cfg.nethack_keypad);
wppi (sesskey, "AltF4", cfg.alt_f4);
wppi (sesskey, "AltSpace", cfg.alt_space);
+ wppi (sesskey, "LdiscTerm", cfg.ldisc_term);
wppi (sesskey, "ScrollbackLines", cfg.savelines);
wppi (sesskey, "DECOriginMode", cfg.dec_om);
wppi (sesskey, "AutoWrapMode", cfg.wrap_mode);
gppi (sesskey, "NetHackKeypad", 0, &cfg.nethack_keypad);
gppi (sesskey, "AltF4", 1, &cfg.alt_f4);
gppi (sesskey, "AltSpace", 0, &cfg.alt_space);
+ gppi (sesskey, "LdiscTerm", 0, &cfg.ldisc_term);
gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
CheckDlgButton (hwnd, IDC1_ALTF4, cfg.alt_f4);
CheckDlgButton (hwnd, IDC1_ALTSPACE, cfg.alt_space);
+ CheckDlgButton (hwnd, IDC1_LDISCTERM, cfg.ldisc_term);
break;
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED)
cfg.alt_space = IsDlgButtonChecked (hwnd, IDC1_ALTSPACE);
break;
+ case IDC1_LDISCTERM:
+ if (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED)
+ cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC1_LDISCTERM);
+ break;
}
}
return GeneralPanelProc (hwnd, msg, wParam, lParam);
}
back = (cfg.protocol == PROT_SSH ? &ssh_backend :
- cfg.protocol == PROT_TELNET ? &telnet_backend : &raw_backend );
+ cfg.protocol == PROT_TELNET ? &telnet_backend :
+ &raw_backend);
+
+ ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple);
if (!prev) {
wndclass.style = 0;
len = TranslateKey (wParam, lParam, buf);
if (len == -1)
return DefWindowProc (hwnd, message, wParam, lParam);
- back->send (buf, len);
+ ldisc->send (buf, len);
}
return 0;
case WM_KEYUP:
*/
{
char c = xlat_kbd2tty((unsigned char)wParam);
- back->send (&c, 1);
+ ldisc->send (&c, 1);
}
return 0;
}