X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/fef97f438c8c83ac625799c88e8f2da53d5f51cc..22b26f2487d08d6d98f0ce3a75c10c7097264493:/windlg.c diff --git a/windlg.c b/windlg.c index 58b570fd..47888f4f 100644 --- a/windlg.c +++ b/windlg.c @@ -1,138 +1,70 @@ #include #include #include +#ifndef AUTO_WINSOCK +#ifdef WINSOCK_TWO +#include +#else #include +#endif +#endif #include #include -#include "putty.h" #include "ssh.h" +#include "putty.h" #include "win_res.h" +#include "storage.h" -#define NPANELS 7 -#define MAIN_NPANELS 7 -#define RECONF_NPANELS 4 +#define NPANELS 9 +#define MAIN_NPANELS 9 +#define RECONF_NPANELS 6 -static const char *const puttystr = PUTTY_REG_POS "\\Sessions"; +static char **events = NULL; +static int nevents = 0, negsize = 0; -static void get_sesslist(int allocate); - -static char **negots = NULL; -static int nnegots = 0, negsize = 0; static HWND logbox = NULL, abtbox = NULL; -static char hex[16] = "0123456789ABCDEF"; - -static void mungestr(char *in, char *out) { - int candot = 0; - - while (*in) { - if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' || - *in == '%' || *in < ' ' || *in > '~' || (*in == '.' && !candot)) { - *out++ = '%'; - *out++ = hex[((unsigned char)*in) >> 4]; - *out++ = hex[((unsigned char)*in) & 15]; - } else - *out++ = *in; - in++; - candot = 1; - } - *out = '\0'; - return; -} - -static void unmungestr(char *in, char *out) { - int candot = 0; - - while (*in) { - if (*in == '%' && in[1] && in[2]) { - int i, j; - - i = in[1] - '0'; i -= (i > 9 ? 7 : 0); - j = in[2] - '0'; j -= (j > 9 ? 7 : 0); - - *out++ = (i<<4) + j; - in += 3; - } else - *out++ = *in++; - } - *out = '\0'; - return; -} - -static void wpps(HKEY key, LPCTSTR name, LPCTSTR value) { - RegSetValueEx(key, name, 0, REG_SZ, value, 1+strlen(value)); -} - -static void wppi(HKEY key, LPCTSTR name, int value) { - RegSetValueEx(key, name, 0, REG_DWORD, - (CONST BYTE *)&value, sizeof(value)); -} - -static void gpps(HKEY key, LPCTSTR name, LPCTSTR def, - LPTSTR val, int len) { - DWORD type, size; - size = len; - - if (key == NULL || - RegQueryValueEx(key, name, 0, &type, val, &size) != ERROR_SUCCESS || - type != REG_SZ) { +static void gpps(void *handle, char *name, char *def, char *val, int len) { + if (!read_setting_s(handle, name, val, len)) { strncpy(val, def, len); val[len-1] = '\0'; } } -static void gppi(HKEY key, LPCTSTR name, int def, int *i) { - DWORD type, val, size; - size = sizeof(val); - - if (key == NULL || - RegQueryValueEx(key, name, 0, &type, - (BYTE *)&val, &size) != ERROR_SUCCESS || - size != sizeof(val) || type != REG_DWORD) - *i = def; - else - *i = val; +static void gppi(void *handle, char *name, int def, int *i) { + *i = read_setting_i(handle, name, def); } -typedef struct { - void *posn; - void *temp; - char dataspace[2048]; -} DTemplate; - static HINSTANCE hinst; -static char **sessions; -static int nsessions; +static int readytogo; static void save_settings (char *section, int do_host) { int i; - HKEY subkey1, sesskey; char *p; + void *sesskey; - p = malloc(3*strlen(section)+1); - mungestr(section, p); - - if (RegCreateKey(HKEY_CURRENT_USER, puttystr, &subkey1)!=ERROR_SUCCESS || - RegCreateKey(subkey1, p, &sesskey) != ERROR_SUCCESS) { - free(p); - sesskey = NULL; - } - - free(p); - RegCloseKey(subkey1); + sesskey = open_settings_w(section); + if (!sesskey) + return; - wppi (sesskey, "Present", 1); + write_setting_i (sesskey, "Present", 1); if (do_host) { - wpps (sesskey, "HostName", cfg.host); - wppi (sesskey, "PortNumber", cfg.port); - wpps (sesskey, "Protocol", - cfg.protocol == PROT_SSH ? "ssh" : "telnet"); + write_setting_s (sesskey, "HostName", cfg.host); + write_setting_i (sesskey, "PortNumber", cfg.port); + p = "raw"; + for (i = 0; backends[i].name != NULL; i++) + if (backends[i].protocol == cfg.protocol) { + p = backends[i].name; + break; + } + write_setting_s (sesskey, "Protocol", p); } - wppi (sesskey, "CloseOnExit", !!cfg.close_on_exit); - wpps (sesskey, "TerminalType", cfg.termtype); - wpps (sesskey, "TerminalSpeed", cfg.termspeed); + write_setting_i (sesskey, "CloseOnExit", !!cfg.close_on_exit); + write_setting_i (sesskey, "WarnOnClose", !!cfg.warn_on_close); + write_setting_s (sesskey, "TerminalType", cfg.termtype); + write_setting_s (sesskey, "TerminalSpeed", cfg.termspeed); { char buf[2*sizeof(cfg.environmt)], *p, *q; p = buf; @@ -150,37 +82,53 @@ static void save_settings (char *section, int do_host) { q++; } *p = '\0'; - wpps (sesskey, "Environment", buf); + write_setting_s (sesskey, "Environment", buf); } - wpps (sesskey, "UserName", cfg.username); - wppi (sesskey, "NoPTY", cfg.nopty); - wppi (sesskey, "RFCEnviron", cfg.rfc_environ); - wppi (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete); - wppi (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend); - wppi (sesskey, "LinuxFunctionKeys", cfg.linux_funkeys); - wppi (sesskey, "ApplicationCursorKeys", cfg.app_cursor); - wppi (sesskey, "ApplicationKeypad", cfg.app_keypad); - wppi (sesskey, "ScrollbackLines", cfg.savelines); - wppi (sesskey, "DECOriginMode", cfg.dec_om); - wppi (sesskey, "AutoWrapMode", cfg.wrap_mode); - wppi (sesskey, "LFImpliesCR", cfg.lfhascr); - wppi (sesskey, "WinNameAlways", cfg.win_name_always); - wppi (sesskey, "TermWidth", cfg.width); - wppi (sesskey, "TermHeight", cfg.height); - wpps (sesskey, "Font", cfg.font); - wppi (sesskey, "FontIsBold", cfg.fontisbold); - wppi (sesskey, "FontHeight", cfg.fontheight); - wppi (sesskey, "FontVTMode", cfg.vtmode); - wppi (sesskey, "TryPalette", cfg.try_palette); - wppi (sesskey, "BoldAsColour", cfg.bold_colour); + write_setting_s (sesskey, "UserName", cfg.username); + write_setting_i (sesskey, "NoPTY", cfg.nopty); + write_setting_i (sesskey, "AgentFwd", cfg.agentfwd); + write_setting_s (sesskey, "RemoteCmd", cfg.remote_cmd); + write_setting_s (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" : + cfg.cipher == CIPHER_DES ? "des" : "3des"); + write_setting_i (sesskey, "AuthTIS", cfg.try_tis_auth); + write_setting_i (sesskey, "SshProt", cfg.sshprot); + write_setting_s (sesskey, "PublicKeyFile", cfg.keyfile); + write_setting_s (sesskey, "RemoteCommand", cfg.remote_cmd); + write_setting_i (sesskey, "RFCEnviron", cfg.rfc_environ); + write_setting_i (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete); + write_setting_i (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend); + write_setting_i (sesskey, "LinuxFunctionKeys", cfg.funky_type); + write_setting_i (sesskey, "ApplicationCursorKeys", cfg.app_cursor); + write_setting_i (sesskey, "ApplicationKeypad", cfg.app_keypad); + write_setting_i (sesskey, "NetHackKeypad", cfg.nethack_keypad); + write_setting_i (sesskey, "AltF4", cfg.alt_f4); + write_setting_i (sesskey, "AltSpace", cfg.alt_space); + write_setting_i (sesskey, "LdiscTerm", cfg.ldisc_term); + write_setting_i (sesskey, "BlinkCur", cfg.blink_cur); + write_setting_i (sesskey, "Beep", cfg.beep); + write_setting_i (sesskey, "ScrollbackLines", cfg.savelines); + write_setting_i (sesskey, "DECOriginMode", cfg.dec_om); + write_setting_i (sesskey, "AutoWrapMode", cfg.wrap_mode); + write_setting_i (sesskey, "LFImpliesCR", cfg.lfhascr); + write_setting_i (sesskey, "WinNameAlways", cfg.win_name_always); + write_setting_s (sesskey, "WinTitle", cfg.wintitle); + write_setting_i (sesskey, "TermWidth", cfg.width); + write_setting_i (sesskey, "TermHeight", cfg.height); + write_setting_s (sesskey, "Font", cfg.font); + write_setting_i (sesskey, "FontIsBold", cfg.fontisbold); + write_setting_i (sesskey, "FontCharSet", cfg.fontcharset); + write_setting_i (sesskey, "FontHeight", cfg.fontheight); + write_setting_i (sesskey, "FontVTMode", cfg.vtmode); + write_setting_i (sesskey, "TryPalette", cfg.try_palette); + write_setting_i (sesskey, "BoldAsColour", cfg.bold_colour); for (i=0; i<22; i++) { char buf[20], buf2[30]; sprintf(buf, "Colour%d", i); sprintf(buf2, "%d,%d,%d", cfg.colours[i][0], cfg.colours[i][1], cfg.colours[i][2]); - wpps (sesskey, buf, buf2); + write_setting_s (sesskey, buf, buf2); } - wppi (sesskey, "MouseIsXterm", cfg.mouse_is_xterm); + write_setting_i (sesskey, "MouseIsXterm", cfg.mouse_is_xterm); for (i=0; i<256; i+=32) { char buf[20], buf2[256]; int j; @@ -190,58 +138,40 @@ static void save_settings (char *section, int do_host) { sprintf(buf2+strlen(buf2), "%s%d", (*buf2 ? "," : ""), cfg.wordness[j]); } - wpps (sesskey, buf, buf2); + write_setting_s (sesskey, buf, buf2); } - - RegCloseKey(sesskey); -} - -static void del_session (char *section) { - HKEY subkey1; - char *p; - - if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS) - return; - - p = malloc(3*strlen(section)+1); - mungestr(section, p); - RegDeleteKey(subkey1, p); - free(p); - - RegCloseKey(subkey1); + write_setting_i (sesskey, "KoiWinXlat", cfg.xlat_enablekoiwin); + write_setting_i (sesskey, "88592Xlat", cfg.xlat_88592w1250); + write_setting_i (sesskey, "CapsLockCyr", cfg.xlat_capslockcyr); + write_setting_i (sesskey, "ScrollBar", cfg.scrollbar); + write_setting_i (sesskey, "ScrollOnKey", cfg.scroll_on_key); + write_setting_i (sesskey, "LockSize", cfg.locksize); + write_setting_i (sesskey, "BCE", cfg.bce); + write_setting_i (sesskey, "BlinkText", cfg.blinktext); + + close_settings_w(sesskey); } static void load_settings (char *section, int do_host) { int i; - HKEY subkey1, sesskey; - char *p; + char prot[10]; + void *sesskey; - p = malloc(3*strlen(section)+1); - mungestr(section, p); - - if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS || - RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) { - free(p); - sesskey = NULL; - } + sesskey = open_settings_r(section); - free(p); - RegCloseKey(subkey1); + gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host)); + gppi (sesskey, "PortNumber", default_port, &cfg.port); + + gpps (sesskey, "Protocol", "default", prot, 10); + cfg.protocol = default_protocol; + for (i = 0; backends[i].name != NULL; i++) + if (!strcmp(prot, backends[i].name)) { + cfg.protocol = backends[i].protocol; + break; + } - if (do_host) { - char prot[10]; - gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host)); - gppi (sesskey, "PortNumber", 23, &cfg.port); - gpps (sesskey, "Protocol", "telnet", prot, 10); - if (!strcmp(prot, "ssh")) - cfg.protocol = PROT_SSH; - else - cfg.protocol = PROT_TELNET; - } else { - cfg.port = 23; - *cfg.host = '\0'; - } gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit); + gppi (sesskey, "WarnOnClose", 1, &cfg.warn_on_close); gpps (sesskey, "TerminalType", "xterm", cfg.termtype, sizeof(cfg.termtype)); gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed, @@ -250,7 +180,7 @@ static void load_settings (char *section, int do_host) { char buf[2*sizeof(cfg.environmt)], *p, *q; gpps (sesskey, "Environment", "", buf, sizeof(buf)); p = buf; - q = cfg.environmt; + q = cfg.environmt; while (*p) { while (*p && *p != ',') { int c = *p++; @@ -258,7 +188,7 @@ static void load_settings (char *section, int do_host) { c = '\t'; if (c == '\\') c = *p++; - *p++ = c; + *q++ = c; } if (*p == ',') p++; *q++ = '\0'; @@ -267,23 +197,48 @@ static void load_settings (char *section, int do_host) { } gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username)); gppi (sesskey, "NoPTY", 0, &cfg.nopty); + gppi (sesskey, "AgentFwd", 0, &cfg.agentfwd); + gpps (sesskey, "RemoteCmd", "", cfg.remote_cmd, sizeof(cfg.remote_cmd)); + { + char cipher[10]; + gpps (sesskey, "Cipher", "3des", cipher, 10); + if (!strcmp(cipher, "blowfish")) + cfg.cipher = CIPHER_BLOWFISH; + else if (!strcmp(cipher, "des")) + cfg.cipher = CIPHER_DES; + else + cfg.cipher = CIPHER_3DES; + } + gppi (sesskey, "SshProt", 1, &cfg.sshprot); + gppi (sesskey, "AuthTIS", 0, &cfg.try_tis_auth); + gpps (sesskey, "PublicKeyFile", "", cfg.keyfile, sizeof(cfg.keyfile)); + gpps (sesskey, "RemoteCommand", "", cfg.remote_cmd, + sizeof(cfg.remote_cmd)); gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ); gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete); gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend); - gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.linux_funkeys); + gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.funky_type); gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor); gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad); + 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, "BlinkCur", 0, &cfg.blink_cur); + gppi (sesskey, "Beep", 1, &cfg.beep); gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines); gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om); gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode); gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr); gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always); + gpps (sesskey, "WinTitle", "", cfg.wintitle, sizeof(cfg.wintitle)); gppi (sesskey, "TermWidth", 80, &cfg.width); gppi (sesskey, "TermHeight", 24, &cfg.height); gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font)); gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold); + gppi (sesskey, "FontCharSet", ANSI_CHARSET, &cfg.fontcharset); gppi (sesskey, "FontHeight", 10, &cfg.fontheight); - gppi (sesskey, "FontVTMode", VT_POORMAN, &cfg.vtmode); + gppi (sesskey, "FontVTMode", VT_OEMANSI, (int *)&cfg.vtmode); gppi (sesskey, "TryPalette", 0, &cfg.try_palette); gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour); for (i=0; i<22; i++) { @@ -295,10 +250,14 @@ static void load_settings (char *section, int do_host) { "85,255,255", "187,187,187", "255,255,255" }; char buf[20], buf2[30]; + int c0, c1, c2; sprintf(buf, "Colour%d", i); gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2)); - sscanf(buf2, "%d,%d,%d", &cfg.colours[i][0], - &cfg.colours[i][1], &cfg.colours[i][2]); + if(sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) { + cfg.colours[i][0] = c0; + cfg.colours[i][1] = c1; + cfg.colours[i][2] = c2; + } } gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm); for (i=0; i<256; i+=32) { @@ -324,7 +283,34 @@ static void load_settings (char *section, int do_host) { cfg.wordness[j] = atoi(q); } } - RegCloseKey(sesskey); + gppi (sesskey, "KoiWinXlat", 0, &cfg.xlat_enablekoiwin); + gppi (sesskey, "88592Xlat", 0, &cfg.xlat_88592w1250); + gppi (sesskey, "CapsLockCyr", 0, &cfg.xlat_capslockcyr); + gppi (sesskey, "ScrollBar", 1, &cfg.scrollbar); + gppi (sesskey, "ScrollOnKey", 0, &cfg.scroll_on_key); + gppi (sesskey, "LockSize", 0, &cfg.locksize); + gppi (sesskey, "BCE", 0, &cfg.bce); + gppi (sesskey, "BlinkText", 0, &cfg.blinktext); + + close_settings_r(sesskey); +} + +static void force_normal(HWND hwnd) +{ +static int recurse = 0; + + WINDOWPLACEMENT wp; + + if(recurse) return; + recurse = 1; + + wp.length = sizeof(wp); + if (GetWindowPlacement(hwnd, &wp)) + { + wp.showCmd = SW_SHOWNORMAL; + SetWindowPlacement(hwnd, &wp); + } + recurse = 0; } static void MyGetDlgItemInt (HWND hwnd, int id, int *result) { @@ -341,18 +327,56 @@ static int CALLBACK LogProc (HWND hwnd, UINT msg, switch (msg) { case WM_INITDIALOG: - for (i=0; ihwnd = hwnd; + cp->units = GetWindowLong(hwnd, GWL_USERDATA); + cp->font = GetWindowLong(hwnd, DWL_USER); + cp->ypos = GAPBETWEEN; + GetClientRect(hwnd, &r); + cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN; +} + +/* Used on kosher dialogs. */ +void ctlposinit2(struct ctlpos *cp, HWND hwnd) { + RECT r; + cp->hwnd = hwnd; + r.left = r.top = 0; + r.right = 4; + r.bottom = 8; + MapDialogRect(hwnd, &r); + cp->units = (r.bottom << 16) | r.right; + cp->font = SendMessage(hwnd, WM_GETFONT, 0, 0); + cp->ypos = GAPBETWEEN; + GetClientRect(hwnd, &r); + cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN; +} + +void doctl(struct ctlpos *cp, RECT r, char *wclass, int wstyle, int exstyle, + char *wtext, int wid) { + HWND ctl; + /* + * Note nonstandard use of RECT. This is deliberate: by + * transforming the width and height directly we arrange to + * have all supposedly same-sized controls really same-sized. + */ + + /* MapDialogRect, or its near equivalent. */ + r.left = (r.left * (cp->units & 0xFFFF)) / 4; + r.right = (r.right * (cp->units & 0xFFFF)) / 4; + r.top = (r.top * ((cp->units>>16) & 0xFFFF)) / 8; + r.bottom = (r.bottom * ((cp->units>>16) & 0xFFFF)) / 8; + + ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle, + r.left, r.top, r.right, r.bottom, + cp->hwnd, (HMENU)wid, hinst, NULL); + SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0)); +} + +/* + * Some edit boxes. Each one has a static above it. The percentages + * of the horizontal space are provided. + */ +void multiedit(struct ctlpos *cp, ...) { + RECT r; + va_list ap; + int percent, xpos; + + percent = xpos = 0; + va_start(ap, cp); + while (1) { + char *text; + int staticid, editid, pcwidth; + text = va_arg(ap, char *); + if (!text) + break; + staticid = va_arg(ap, int); + editid = va_arg(ap, int); + pcwidth = va_arg(ap, int); + + r.left = xpos + GAPBETWEEN; + percent += pcwidth; + xpos = (cp->width + GAPBETWEEN) * percent / 100; + r.right = xpos - r.left; + + r.top = cp->ypos; r.bottom = STATICHEIGHT; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, + text, staticid); + r.top = cp->ypos + 8 + GAPWITHIN; r.bottom = EDITHEIGHT; + doctl(cp, r, "EDIT", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE, + "", editid); + } + va_end(ap); + cp->ypos += 8+GAPWITHIN+12+GAPBETWEEN; +} + +/* + * A set of radio buttons on the same line, with a static above + * them. `nacross' dictates how many parts the line is divided into + * (you might want this not to equal the number of buttons if you + * needed to line up some 2s and some 3s to look good in the same + * panel). + */ +void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...) { + RECT r; + va_list ap; + int group; + int i; + + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = STATICHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id); + va_start(ap, nacross); + group = WS_GROUP; + i = 0; + while (1) { + char *btext; + int bid; + btext = va_arg(ap, char *); + if (!btext) + break; + bid = va_arg(ap, int); + r.left = GAPBETWEEN + i * (cp->width+GAPBETWEEN)/nacross; + r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left; + r.top = cp->ypos; r.bottom = RADIOHEIGHT; + doctl(cp, r, "BUTTON", + BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group, + 0, + btext, bid); + group = 0; + i++; + } + va_end(ap); + cp->ypos += r.bottom + GAPBETWEEN; +} + +/* + * A set of radio buttons on multiple lines, with a static above + * them. + */ +void radiobig(struct ctlpos *cp, char *text, int id, ...) { + RECT r; + va_list ap; + int group; + + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = STATICHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id); + va_start(ap, id); + group = WS_GROUP; + while (1) { + char *btext; + int bid; + btext = va_arg(ap, char *); + if (!btext) + break; + bid = va_arg(ap, int); + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = STATICHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "BUTTON", + BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group, + 0, + btext, bid); + group = 0; + } + va_end(ap); + cp->ypos += GAPBETWEEN - GAPWITHIN; +} + +/* + * A single standalone checkbox. + */ +void checkbox(struct ctlpos *cp, char *text, int id) { + RECT r; + + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = CHECKBOXHEIGHT; + cp->ypos += r.bottom + GAPBETWEEN; + doctl(cp, r, "BUTTON", + BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0, + text, id); +} + +/* + * A button on the right hand side, with a static to its left. + */ +void staticbtn(struct ctlpos *cp, char *stext, int sid, char *btext, int bid) { + const int height = (PUSHBTNHEIGHT > STATICHEIGHT ? + PUSHBTNHEIGHT : STATICHEIGHT); + RECT r; + int lwid, rwid, rpos; + + rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4; + lwid = rpos - 2*GAPBETWEEN; + rwid = cp->width + GAPBETWEEN - rpos; + + r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2; + r.right = lwid; r.bottom = STATICHEIGHT; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid); + + r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2; + r.right = rwid; r.bottom = PUSHBTNHEIGHT; + doctl(cp, r, "BUTTON", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, + 0, + btext, bid); + + cp->ypos += height + GAPBETWEEN; +} + +/* + * An edit control on the right hand side, with a static to its left. + */ +void staticedit(struct ctlpos *cp, char *stext, int sid, int eid) { + const int height = (EDITHEIGHT > STATICHEIGHT ? + EDITHEIGHT : STATICHEIGHT); + RECT r; + int lwid, rwid, rpos; + + rpos = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2; + lwid = rpos - 2*GAPBETWEEN; + rwid = cp->width + GAPBETWEEN - rpos; + + r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2; + r.right = lwid; r.bottom = STATICHEIGHT; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid); + + r.left = rpos; r.top = cp->ypos + (height-EDITHEIGHT)/2; + r.right = rwid; r.bottom = EDITHEIGHT; + doctl(cp, r, "EDIT", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE, + "", eid); + + cp->ypos += height + GAPBETWEEN; +} + +/* + * A tab-control substitute when a real tab control is unavailable. + */ +void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id) { + const int height = (COMBOHEIGHT > STATICHEIGHT ? + COMBOHEIGHT : STATICHEIGHT); + RECT r; + int bigwid, lwid, rwid, rpos; + static const int BIGGAP = 15; + static const int MEDGAP = 3; + + bigwid = cp->width + 2*GAPBETWEEN - 2*BIGGAP; + cp->ypos += MEDGAP; + rpos = BIGGAP + (bigwid + BIGGAP) / 2; + lwid = rpos - 2*BIGGAP; + rwid = bigwid + BIGGAP - rpos; + + r.left = BIGGAP; r.top = cp->ypos + (height-STATICHEIGHT)/2; + r.right = lwid; r.bottom = STATICHEIGHT; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid); + + r.left = rpos; r.top = cp->ypos + (height-COMBOHEIGHT)/2; + r.right = rwid; r.bottom = COMBOHEIGHT*10; + doctl(cp, r, "COMBOBOX", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | + CBS_DROPDOWNLIST | CBS_HASSTRINGS, + WS_EX_CLIENTEDGE, + "", lid); + + cp->ypos += height + MEDGAP + GAPBETWEEN; + + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = 2; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, + 0, "", s2id); +} + +/* + * A static line, followed by an edit control on the left hand side + * and a button on the right. + */ +void editbutton(struct ctlpos *cp, char *stext, int sid, + int eid, char *btext, int bid) { + const int height = (EDITHEIGHT > PUSHBTNHEIGHT ? + EDITHEIGHT : PUSHBTNHEIGHT); + RECT r; + int lwid, rwid, rpos; + + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = STATICHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid); + + rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4; + lwid = rpos - 2*GAPBETWEEN; + rwid = cp->width + GAPBETWEEN - rpos; + + r.left = GAPBETWEEN; r.top = cp->ypos + (height-EDITHEIGHT)/2; + r.right = lwid; r.bottom = EDITHEIGHT; + doctl(cp, r, "EDIT", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE, + "", eid); + + r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2; + r.right = rwid; r.bottom = PUSHBTNHEIGHT; + doctl(cp, r, "BUTTON", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, + 0, + btext, bid); + + cp->ypos += height + GAPBETWEEN; +} + +/* + * Special control which was hard to describe generically: the + * session-saver assembly. A static; below that an edit box; below + * that a list box. To the right of the list box, a column of + * buttons. + */ +void sesssaver(struct ctlpos *cp, char *text, + int staticid, int editid, int listid, ...) { + RECT r; + va_list ap; + int lwid, rwid, rpos; + int y; + const int LISTDEFHEIGHT = 66; + + rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4; + lwid = rpos - 2*GAPBETWEEN; + rwid = cp->width + GAPBETWEEN - rpos; + + /* The static control. */ + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = lwid; r.bottom = STATICHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid); + + /* The edit control. */ + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = lwid; r.bottom = EDITHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "EDIT", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE, + "", staticid); + + /* + * The buttons (we should hold off on the list box until we + * know how big the buttons are). + */ + va_start(ap, listid); + y = cp->ypos; + while (1) { + char *btext = va_arg(ap, char *); + int bid; + if (!btext) break; + bid = va_arg(ap, int); + r.left = rpos; r.top = y; + r.right = rwid; r.bottom = PUSHBTNHEIGHT; + y += r.bottom + GAPWITHIN; + doctl(cp, r, "BUTTON", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, + 0, + btext, bid); + } + + /* Compute list box height. LISTDEFHEIGHT, or height of buttons. */ + y -= cp->ypos; + y -= GAPWITHIN; + if (y < LISTDEFHEIGHT) y = LISTDEFHEIGHT; + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = lwid; r.bottom = y; + cp->ypos += y + GAPBETWEEN; + doctl(cp, r, "LISTBOX", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | + LBS_STANDARD | LBS_HASSTRINGS, + WS_EX_CLIENTEDGE, + "", listid); +} + +/* + * Another special control: the environment-variable setter. A + * static line first; then a pair of edit boxes with associated + * statics, and two buttons; then a list box. + */ +void envsetter(struct ctlpos *cp, char *stext, int sid, + char *e1stext, int e1sid, int e1id, + char *e2stext, int e2sid, int e2id, + int listid, char *b1text, int b1id, char *b2text, int b2id) { + RECT r; + const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ? + STATICHEIGHT : + EDITHEIGHT > PUSHBTNHEIGHT ? + EDITHEIGHT : PUSHBTNHEIGHT); + const static int percents[] = { 20, 35, 10, 25 }; + int i, j, xpos, percent; + const int LISTHEIGHT = 42; + + /* The static control. */ + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = STATICHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid); + + /* The statics+edits+buttons. */ + for (j = 0; j < 2; j++) { + percent = 10; + for (i = 0; i < 4; i++) { + xpos = (cp->width + GAPBETWEEN) * percent / 100; + r.left = xpos + GAPBETWEEN; + percent += percents[i]; + xpos = (cp->width + GAPBETWEEN) * percent / 100; + r.right = xpos - r.left; + r.top = cp->ypos; + r.bottom = (i==0 ? STATICHEIGHT : + i==1 ? EDITHEIGHT : + PUSHBTNHEIGHT); + r.top += (height-r.bottom)/2; + if (i==0) { + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, + j==0 ? e1stext : e2stext, j==0 ? e1sid : e2sid); + } else if (i==1) { + doctl(cp, r, "EDIT", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE, + "", j==0 ? e1id : e2id); + } else if (i==3) { + doctl(cp, r, "BUTTON", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, + 0, + j==0 ? b1text : b2text, j==0 ? b1id : b2id); + } + } + cp->ypos += height + GAPWITHIN; + } + + /* The list box. */ + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = LISTHEIGHT; + cp->ypos += r.bottom + GAPBETWEEN; + doctl(cp, r, "LISTBOX", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS | + LBS_USETABSTOPS, + WS_EX_CLIENTEDGE, + "", listid); +} + +/* + * Yet another special control: the character-class setter. A + * static, then a list, then a line containing a + * button-and-static-and-edit. + */ +void charclass(struct ctlpos *cp, char *stext, int sid, int listid, + char *btext, int bid, int eid, char *s2text, int s2id) { + RECT r; + const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ? + STATICHEIGHT : + EDITHEIGHT > PUSHBTNHEIGHT ? + EDITHEIGHT : PUSHBTNHEIGHT); + const static int percents[] = { 30, 40, 30 }; + int i, xpos, percent; + const int LISTHEIGHT = 66; + + /* The static control. */ + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = STATICHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid); + + /* The list box. */ + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = LISTHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "LISTBOX", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS | + LBS_USETABSTOPS, + WS_EX_CLIENTEDGE, + "", listid); + + /* The button+static+edit. */ + percent = xpos = 0; + for (i = 0; i < 3; i++) { + r.left = xpos + GAPBETWEEN; + percent += percents[i]; + xpos = (cp->width + GAPBETWEEN) * percent / 100; + r.right = xpos - r.left; + r.top = cp->ypos; + r.bottom = (i==0 ? PUSHBTNHEIGHT : + i==1 ? STATICHEIGHT : + EDITHEIGHT); + r.top += (height-r.bottom)/2; + if (i==0) { + doctl(cp, r, "BUTTON", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, + 0, btext, bid); + } else if (i==1) { + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_CENTER, + 0, s2text, s2id); + } else if (i==2) { + doctl(cp, r, "EDIT", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE, "", eid); + } + } + cp->ypos += height + GAPBETWEEN; +} + +/* + * A special control (horrors!). The colour editor. A static line; + * then on the left, a list box, and on the right, a sequence of + * two-part statics followed by a button. + */ +void colouredit(struct ctlpos *cp, char *stext, int sid, int listid, + char *btext, int bid, ...) { + RECT r; + int y; + va_list ap; + int lwid, rwid, rpos; + const int LISTHEIGHT = 66; + + /* The static control. */ + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = cp->width; r.bottom = STATICHEIGHT; + cp->ypos += r.bottom + GAPWITHIN; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid); + + rpos = GAPBETWEEN + 2 * (cp->width + GAPBETWEEN) / 3; + lwid = rpos - 2*GAPBETWEEN; + rwid = cp->width + GAPBETWEEN - rpos; + + /* The list box. */ + r.left = GAPBETWEEN; r.top = cp->ypos; + r.right = lwid; r.bottom = LISTHEIGHT; + doctl(cp, r, "LISTBOX", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS | + LBS_USETABSTOPS, + WS_EX_CLIENTEDGE, + "", listid); + + /* The statics. */ + y = cp->ypos; + va_start(ap, bid); + while (1) { + char *ltext; + int lid, rid; + ltext = va_arg(ap, char *); + if (!ltext) break; + lid = va_arg(ap, int); + rid = va_arg(ap, int); + r.top = y; r.bottom = STATICHEIGHT; + y += r.bottom + GAPWITHIN; + r.left = rpos; r.right = rwid/2; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, ltext, lid); + r.left = rpos + r.right; r.right = rwid - r.right; + doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0, "", rid); + } + va_end(ap); + + /* The button. */ + r.top = y + 2*GAPWITHIN; r.bottom = PUSHBTNHEIGHT; + r.left = rpos; r.right = rwid; + doctl(cp, r, "BUTTON", + WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, + 0, btext, bid); + + cp->ypos += LISTHEIGHT + GAPBETWEEN; +} + static int GeneralPanelProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { + case WM_SETFONT: + { + HFONT hfont = (HFONT)wParam; + HFONT oldfont; + HDC hdc; + TEXTMETRIC tm; + LONG units; + + hdc = GetDC(hwnd); + oldfont = SelectObject(hdc, hfont); + GetTextMetrics(hdc, &tm); + units = (tm.tmHeight << 16) | tm.tmAveCharWidth; + SelectObject(hdc, oldfont); + DeleteDC(hdc); + SetWindowLong(hwnd, GWL_USERDATA, units); + SetWindowLong(hwnd, DWL_USER, wParam); + } + return 0; case WM_INITDIALOG: SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); return 1; -/* case WM_CTLCOLORDLG: */ -/* return (int) GetStockObject (LTGRAY_BRUSH); */ -/* case WM_CTLCOLORSTATIC: */ -/* case WM_CTLCOLORBTN: */ -/* SetBkColor ((HDC)wParam, RGB(192,192,192)); */ -/* return (int) GetStockObject (LTGRAY_BRUSH); */ case WM_CLOSE: DestroyWindow (hwnd); return 1; @@ -414,65 +1046,131 @@ static int GeneralPanelProc (HWND hwnd, UINT msg, return 0; } +static char savedsession[2048]; + static int CALLBACK ConnectionProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { int i; + struct ctlpos cp; + enum { controlstartvalue = 1000, + IDC_HOSTSTATIC, + IDC_HOST, + IDC_PORTSTATIC, + IDC_PORT, + IDC_PROTSTATIC, + IDC_PROTRAW, + IDC_PROTTELNET, + IDC_PROTSSH, + IDC_SESSSTATIC, + IDC_SESSEDIT, + IDC_SESSLIST, + IDC_SESSLOAD, + IDC_SESSSAVE, + IDC_SESSDEL, + IDC_CLOSEEXIT, + IDC_CLOSEWARN + }; switch (msg) { case WM_INITDIALOG: - SetDlgItemText (hwnd, IDC0_HOST, cfg.host); - SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE); + /* Accelerators used: [aco] dehlnprstwx */ + ctlposinit(&cp, hwnd); + multiedit(&cp, + "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75, + "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL); + radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3, + "&Raw", IDC_PROTRAW, + "&Telnet", IDC_PROTTELNET, +#ifdef FWHACK + "SS&H/hack", +#else + "SS&H", +#endif + IDC_PROTSSH, NULL); + sesssaver(&cp, "Stor&ed Sessions", + IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST, + "&Load", IDC_SESSLOAD, + "&Save", IDC_SESSSAVE, + "&Delete", IDC_SESSDEL, NULL); + checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT); + checkbox(&cp, "&Warn on Close", IDC_CLOSEWARN); + + SetDlgItemText (hwnd, IDC_HOST, cfg.host); + SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession); + SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE); for (i = 0; i < nsessions; i++) - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING, + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING, 0, (LPARAM) (sessions[i])); - CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH, - cfg.protocol==PROT_SSH ? IDC0_PROTSSH : IDC0_PROTTELNET); - CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit); + CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH, + cfg.protocol==PROT_SSH ? IDC_PROTSSH : + cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW ); + CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit); + CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close); break; + case WM_LBUTTONUP: + /* + * Button release should trigger WM_OK if there was a + * previous double click on the session list. + */ + ReleaseCapture(); + if (readytogo) + SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0); + break; case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC0_PROTTELNET: - case IDC0_PROTSSH: + case IDC_PROTTELNET: + case IDC_PROTSSH: + case IDC_PROTRAW: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { - int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH); - cfg.protocol = i ? PROT_SSH : PROT_TELNET; + int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH); + int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET); + cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ; if ((cfg.protocol == PROT_SSH && cfg.port == 23) || (cfg.protocol == PROT_TELNET && cfg.port == 22)) { cfg.port = i ? 22 : 23; - SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE); + SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE); } } break; - case IDC0_HOST: + case IDC_HOST: if (HIWORD(wParam) == EN_CHANGE) - GetDlgItemText (hwnd, IDC0_HOST, cfg.host, + GetDlgItemText (hwnd, IDC_HOST, cfg.host, sizeof(cfg.host)-1); break; - case IDC0_PORT: + case IDC_PORT: if (HIWORD(wParam) == EN_CHANGE) - MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port); + MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port); break; - case IDC0_CLOSEEXIT: + case IDC_CLOSEEXIT: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) - cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT); + cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT); break; - case IDC0_SESSEDIT: - if (HIWORD(wParam) == EN_CHANGE) - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL, + case IDC_CLOSEWARN: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN); + break; + case IDC_SESSEDIT: + if (HIWORD(wParam) == EN_CHANGE) { + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL, (WPARAM) -1, 0); + GetDlgItemText (hwnd, IDC_SESSEDIT, + savedsession, sizeof(savedsession)-1); + savedsession[sizeof(savedsession)-1] = '\0'; + } break; - case IDC0_SESSSAVE: + case IDC_SESSSAVE: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { /* * Save a session */ char str[2048]; - GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1); + GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1); if (!*str) { - int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST, + int n = SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_GETCURSEL, 0, 0); if (n == LB_ERR) { MessageBeep(0); @@ -483,26 +1181,26 @@ static int CALLBACK ConnectionProc (HWND hwnd, UINT msg, save_settings (str, !!strcmp(str, "Default Settings")); get_sesslist (FALSE); get_sesslist (TRUE); - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT, + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT, 0, 0); for (i = 0; i < nsessions; i++) - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING, + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING, 0, (LPARAM) (sessions[i])); - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL, + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL, (WPARAM) -1, 0); } break; - case IDC0_SESSLIST: - case IDC0_SESSLOAD: - if (LOWORD(wParam) == IDC0_SESSLOAD && + case IDC_SESSLIST: + case IDC_SESSLOAD: + if (LOWORD(wParam) == IDC_SESSLOAD && HIWORD(wParam) != BN_CLICKED && HIWORD(wParam) != BN_DOUBLECLICKED) break; - if (LOWORD(wParam) == IDC0_SESSLIST && + if (LOWORD(wParam) == IDC_SESSLIST && HIWORD(wParam) != LBN_DBLCLK) break; { - int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST, + int n = SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_GETCURSEL, 0, 0); if (n == LB_ERR) { MessageBeep(0); @@ -510,44 +1208,47 @@ static int CALLBACK ConnectionProc (HWND hwnd, UINT msg, } load_settings (sessions[n], !!strcmp(sessions[n], "Default Settings")); - SetDlgItemText (hwnd, IDC0_HOST, cfg.host); - SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE); - CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH, - (cfg.protocol==PROT_SSH ? IDC0_PROTSSH : - IDC0_PROTTELNET)); - CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit); - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL, + SetDlgItemText (hwnd, IDC_HOST, cfg.host); + SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE); + CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH, + (cfg.protocol==PROT_SSH ? IDC_PROTSSH : + cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW)); + CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit); + CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close); + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL, (WPARAM) -1, 0); } - if (LOWORD(wParam) == IDC0_SESSLIST) { + if (LOWORD(wParam) == IDC_SESSLIST) { /* * A double-click on a saved session should * actually start the session, not just load it. * Unless it's Default Settings or some other * host-less set of saved settings. */ - if (*cfg.host) - SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0); + if (*cfg.host) { + readytogo = TRUE; + SetCapture(hwnd); + } } break; - case IDC0_SESSDEL: + case IDC_SESSDEL: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { - int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST, + int n = SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_GETCURSEL, 0, 0); if (n == LB_ERR || n == 0) { MessageBeep(0); break; } - del_session(sessions[n]); + del_settings(sessions[n]); get_sesslist (FALSE); get_sesslist (TRUE); - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT, + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT, 0, 0); for (i = 0; i < nsessions; i++) - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING, + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING, 0, (LPARAM) (sessions[i])); - SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL, + SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL, (WPARAM) -1, 0); } } @@ -556,43 +1257,128 @@ static int CALLBACK ConnectionProc (HWND hwnd, UINT msg, } static int CALLBACK KeyboardProc (HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) { + WPARAM wParam, LPARAM lParam) { + struct ctlpos cp; + enum { controlstartvalue = 1000, + IDC_DELSTATIC, + IDC_DEL008, + IDC_DEL127, + IDC_HOMESTATIC, + IDC_HOMETILDE, + IDC_HOMERXVT, + IDC_FUNCSTATIC, + IDC_FUNCTILDE, + IDC_FUNCLINUX, + IDC_FUNCXTERM, + IDC_KPSTATIC, + IDC_KPNORMAL, + IDC_KPAPPLIC, + IDC_KPNH, + IDC_CURSTATIC, + IDC_CURNORMAL, + IDC_CURAPPLIC, + IDC_ALTF4, + IDC_ALTSPACE, + IDC_LDISCTERM, + IDC_SCROLLKEY + }; + switch (msg) { case WM_INITDIALOG: - CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127, - cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008); - CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT, - cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE); - CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCLINUX, - cfg.linux_funkeys ? IDC1_FUNCLINUX : IDC1_FUNCTILDE); - CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC, - cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL); - CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPAPPLIC, - cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL); + /* Accelerators used: [aco] 4?ehiklmnprsuvxy */ + ctlposinit(&cp, hwnd); + radioline(&cp, "Action of Backspace:", IDC_DELSTATIC, 2, + "Control-&H", IDC_DEL008, + "Control-&? (127)", IDC_DEL127, NULL); + radioline(&cp, "Action of Home and End:", IDC_HOMESTATIC, 2, + "&Standard", IDC_HOMETILDE, + "&rxvt", IDC_HOMERXVT, NULL); + radioline(&cp, "Function key and keypad layout:", IDC_FUNCSTATIC, 3, + "&VT400", IDC_FUNCTILDE, + "&Linux", IDC_FUNCLINUX, + "&Xterm R6", IDC_FUNCXTERM, NULL); + radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2, + "&Normal", IDC_CURNORMAL, + "A&pplication", IDC_CURAPPLIC, NULL); + radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3, + "Nor&mal", IDC_KPNORMAL, + "Appl&ication", IDC_KPAPPLIC, + "N&etHack", IDC_KPNH, NULL); + checkbox(&cp, "ALT-F&4 is special (closes window)", IDC_ALTF4); + checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC_ALTSPACE); + checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM); + checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY); + + CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127, + cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008); + CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT, + cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE); + CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM, + cfg.funky_type ? + (cfg.funky_type==2 ? IDC_FUNCXTERM + : IDC_FUNCLINUX ) + : IDC_FUNCTILDE); + CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC, + cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL); + CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH, + cfg.nethack_keypad ? IDC_KPNH : + cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL); + CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4); + CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space); + CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term); + CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key); break; case WM_COMMAND: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) switch (LOWORD(wParam)) { - case IDC1_DEL008: - case IDC1_DEL127: - cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127); + case IDC_DEL008: + case IDC_DEL127: + cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127); break; - case IDC1_HOMETILDE: - case IDC1_HOMERXVT: - cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT); + case IDC_HOMETILDE: + case IDC_HOMERXVT: + cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT); break; - case IDC1_FUNCTILDE: - case IDC1_FUNCLINUX: - cfg.linux_funkeys = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX); + case IDC_FUNCXTERM: + cfg.funky_type = 2; break; - case IDC1_KPNORMAL: - case IDC1_KPAPPLIC: - cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC); + case IDC_FUNCTILDE: + case IDC_FUNCLINUX: + cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX); break; - case IDC1_CURNORMAL: - case IDC1_CURAPPLIC: - cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC); + case IDC_KPNORMAL: + case IDC_KPAPPLIC: + cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC); + cfg.nethack_keypad = FALSE; + break; + case IDC_KPNH: + cfg.app_keypad = FALSE; + cfg.nethack_keypad = TRUE; + break; + case IDC_CURNORMAL: + case IDC_CURAPPLIC: + cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC); + break; + case IDC_ALTF4: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4); + break; + case IDC_ALTSPACE: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE); + break; + case IDC_LDISCTERM: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM); + break; + case IDC_SCROLLKEY: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY); break; } } @@ -613,67 +1399,92 @@ static void fmtfont (char *buf) { static int CALLBACK TerminalProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + struct ctlpos cp; CHOOSEFONT cf; LOGFONT lf; char fontstatic[256]; + enum { controlstartvalue = 1000, + IDC_WRAPMODE, + IDC_DECOM, + IDC_DIMSTATIC, + IDC_ROWSSTATIC, + IDC_ROWSEDIT, + IDC_COLSSTATIC, + IDC_COLSEDIT, + IDC_SAVESTATIC, + IDC_SAVEEDIT, + IDC_FONTSTATIC, + IDC_CHOOSEFONT, + IDC_LFHASCR, + IDC_BEEP, + IDC_BCE, + IDC_BLINKTEXT + }; switch (msg) { case WM_INITDIALOG: - CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode); - CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always); - CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om); - CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr); - SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE); - SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE); - SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE); + /* Accelerators used: [aco] dghlmnprsw */ + ctlposinit(&cp, hwnd); + multiedit(&cp, + "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 33, + "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 33, + "&Scrollback", IDC_SAVESTATIC, IDC_SAVEEDIT, 33, + NULL); + staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT); + checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE); + checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM); + checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR); + checkbox(&cp, "Bee&p enabled", IDC_BEEP); + checkbox(&cp, "Use Back&ground colour erase", IDC_BCE); + checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT); + + CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode); + CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om); + CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr); + SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE); + SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE); + SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE); fmtfont (fontstatic); - SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic); - CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN, - cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS : - cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI : - cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY : - IDC2_VTPOORMAN); + SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic); + CheckDlgButton (hwnd, IDC_BEEP, cfg.beep); + CheckDlgButton (hwnd, IDC_BCE, cfg.bce); + CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext); break; case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC2_WRAPMODE: + case IDC_WRAPMODE: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) - cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE); + cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE); break; - case IDC2_WINNAME: + case IDC_DECOM: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) - cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME); + cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM); break; - case IDC2_DECOM: + case IDC_LFHASCR: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) - cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM); + cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR); break; - case IDC2_LFHASCR: - if (HIWORD(wParam) == BN_CLICKED || - HIWORD(wParam) == BN_DOUBLECLICKED) - cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR); - break; - case IDC2_ROWSEDIT: + case IDC_ROWSEDIT: if (HIWORD(wParam) == EN_CHANGE) - MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height); + MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height); break; - case IDC2_COLSEDIT: + case IDC_COLSEDIT: if (HIWORD(wParam) == EN_CHANGE) - MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width); + MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width); break; - case IDC2_SAVEEDIT: + case IDC_SAVEEDIT: if (HIWORD(wParam) == EN_CHANGE) - MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines); + MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines); break; - case IDC2_CHOOSEFONT: + case IDC_CHOOSEFONT: lf.lfHeight = cfg.fontheight; lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0; lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0; lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0); - lf.lfCharSet = ANSI_CHARSET; + lf.lfCharSet = cfg.fontcharset; lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; @@ -691,20 +1502,89 @@ static int CALLBACK TerminalProc (HWND hwnd, UINT msg, strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1); cfg.font[sizeof(cfg.font)-1] = '\0'; cfg.fontisbold = (lf.lfWeight == FW_BOLD); + cfg.fontcharset = lf.lfCharSet; cfg.fontheight = lf.lfHeight; fmtfont (fontstatic); - SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic); + SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic); } break; - case IDC2_VTXWINDOWS: - case IDC2_VTOEMANSI: - case IDC2_VTOEMONLY: - case IDC2_VTPOORMAN: - cfg.vtmode = - (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS : - IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI : - IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY : - VT_POORMAN); + case IDC_BEEP: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP); + break; + case IDC_BLINKTEXT: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT); + break; + case IDC_BCE: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE); + break; + } + break; + } + return GeneralPanelProc (hwnd, msg, wParam, lParam); +} + +static int CALLBACK WindowProc (HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam) { + struct ctlpos cp; + enum { controlstartvalue = 1000, + IDC_WINNAME, + IDC_BLINKCUR, + IDC_SCROLLBAR, + IDC_LOCKSIZE, + IDC_WINTITLE, + IDC_WINEDIT + }; + + switch (msg) { + case WM_INITDIALOG: + /* Accelerators used: [aco] bikty */ + ctlposinit(&cp, hwnd); + multiedit(&cp, + "Initial window &title:", IDC_WINTITLE, IDC_WINEDIT, 100, + NULL); + checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME); + checkbox(&cp, "&Blinking cursor", IDC_BLINKCUR); + checkbox(&cp, "Displa&y scrollbar", IDC_SCROLLBAR); + checkbox(&cp, "Loc&k Window size", IDC_LOCKSIZE); + + SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle); + CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always); + CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur); + CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar); + CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize); + break; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_WINNAME: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME); + break; + case IDC_BLINKCUR: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR); + break; + case IDC_SCROLLBAR: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR); + break; + case IDC_LOCKSIZE: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE); + break; + case IDC_WINEDIT: + if (HIWORD(wParam) == EN_CHANGE) + GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle, + sizeof(cfg.wintitle)-1); break; } break; @@ -715,57 +1595,91 @@ static int CALLBACK TerminalProc (HWND hwnd, UINT msg, static int CALLBACK TelnetProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { int i; + struct ctlpos cp; + enum { controlstartvalue = 1000, + IDC_TTSTATIC, + IDC_TTEDIT, + IDC_TSSTATIC, + IDC_TSEDIT, + IDC_LOGSTATIC, + IDC_LOGEDIT, + IDC_ENVSTATIC, + IDC_VARSTATIC, + IDC_VAREDIT, + IDC_VALSTATIC, + IDC_VALEDIT, + IDC_ENVLIST, + IDC_ENVADD, + IDC_ENVREMOVE, + IDC_EMSTATIC, + IDC_EMBSD, + IDC_EMRFC + }; switch (msg) { case WM_INITDIALOG: - SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype); - SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed); - SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username); + /* Accelerators used: [aco] bdflrstuv */ + ctlposinit(&cp, hwnd); + staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT); + staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT); + staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT); + envsetter(&cp, "Environment variables:", IDC_ENVSTATIC, + "&Variable", IDC_VARSTATIC, IDC_VAREDIT, + "Va&lue", IDC_VALSTATIC, IDC_VALEDIT, + IDC_ENVLIST, + "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE); + radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2, + "&BSD (commonplace)", IDC_EMBSD, + "R&FC 1408 (unusual)", IDC_EMRFC, NULL); + + SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype); + SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed); + SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username); { char *p = cfg.environmt; while (*p) { - SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0, + SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0, (LPARAM) p); p += strlen(p)+1; } } - CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC, - cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD); + CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC, + cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD); break; case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC3_TTEDIT: + case IDC_TTEDIT: if (HIWORD(wParam) == EN_CHANGE) - GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype, + GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype, sizeof(cfg.termtype)-1); break; - case IDC3_TSEDIT: + case IDC_TSEDIT: if (HIWORD(wParam) == EN_CHANGE) - GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed, + GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed, sizeof(cfg.termspeed)-1); break; - case IDC3_LOGEDIT: + case IDC_LOGEDIT: if (HIWORD(wParam) == EN_CHANGE) - GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username, + GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username, sizeof(cfg.username)-1); break; - case IDC3_EMBSD: - case IDC3_EMRFC: - cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC); + case IDC_EMBSD: + case IDC_EMRFC: + cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC); break; - case IDC3_ENVADD: + case IDC_ENVADD: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { char str[sizeof(cfg.environmt)]; char *p; - GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1); + GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1); if (!*str) { MessageBeep(0); break; } p = str + strlen(str); *p++ = '\t'; - GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str)); + GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str)); if (!*p) { MessageBeep(0); break; @@ -778,27 +1692,27 @@ static int CALLBACK TelnetProc (HWND hwnd, UINT msg, if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) { strcpy (p, str); p[strlen(str)+1] = '\0'; - SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, + SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0, (LPARAM)str); - SetDlgItemText (hwnd, IDC3_VAREDIT, ""); - SetDlgItemText (hwnd, IDC3_VALEDIT, ""); + SetDlgItemText (hwnd, IDC_VAREDIT, ""); + SetDlgItemText (hwnd, IDC_VALEDIT, ""); } else { MessageBox(hwnd, "Environment too big", "PuTTY Error", MB_OK | MB_ICONERROR); } } break; - case IDC3_ENVREMOVE: + case IDC_ENVREMOVE: if (HIWORD(wParam) != BN_CLICKED && HIWORD(wParam) != BN_DOUBLECLICKED) break; - i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0); + i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0); if (i == LB_ERR) MessageBeep (0); else { char *p, *q; - SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING, + SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING, i, 0); p = cfg.environmt; while (i > 0) { @@ -830,28 +1744,152 @@ static int CALLBACK TelnetProc (HWND hwnd, UINT msg, static int CALLBACK SshProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + struct ctlpos cp; + OPENFILENAME of; + char filename[sizeof(cfg.keyfile)]; + enum { controlstartvalue = 1000, + IDC_TTSTATIC, + IDC_TTEDIT, + IDC_LOGSTATIC, + IDC_LOGEDIT, + IDC_NOPTY, + IDC_CIPHERSTATIC, + IDC_CIPHER3DES, + IDC_CIPHERBLOWF, + IDC_CIPHERDES, + IDC_AUTHTIS, + IDC_PKSTATIC, + IDC_PKEDIT, + IDC_PKBUTTON, + IDC_SSHPROTSTATIC, + IDC_SSHPROT1, + IDC_SSHPROT2, + IDC_AGENTFWD, + IDC_CMDSTATIC, + IDC_CMDEDIT + }; + switch (msg) { case WM_INITDIALOG: - SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype); - SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username); - CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty); + /* Accelerators used: [aco] 123abdkmprtuw */ + ctlposinit(&cp, hwnd); + staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT); + staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT); + multiedit(&cp, + "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100, + NULL); + checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY); + checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication", + IDC_AUTHTIS); + checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD); + editbutton(&cp, "Private &key file for authentication:", + IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON); + radioline(&cp, "Preferred SSH protocol version:", + IDC_SSHPROTSTATIC, 2, + "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL); + radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3, + "&3DES", IDC_CIPHER3DES, + "&Blowfish", IDC_CIPHERBLOWF, + "&DES", IDC_CIPHERDES, NULL); + + SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype); + SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username); + CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty); + CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd); + CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES, + cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF : + cfg.cipher == CIPHER_DES ? IDC_CIPHERDES : + IDC_CIPHER3DES); + CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2, + cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2); + CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth); + SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile); + SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd); break; case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC3_TTEDIT: + case IDC_TTEDIT: if (HIWORD(wParam) == EN_CHANGE) - GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype, + GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype, sizeof(cfg.termtype)-1); break; - case IDC3_LOGEDIT: + case IDC_LOGEDIT: if (HIWORD(wParam) == EN_CHANGE) - GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username, + GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username, sizeof(cfg.username)-1); break; - case IDC3_NOPTY: + case IDC_NOPTY: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY); + break; + case IDC_AGENTFWD: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD); + break; + case IDC_CIPHER3DES: + case IDC_CIPHERBLOWF: + case IDC_CIPHERDES: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) { + if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES)) + cfg.cipher = CIPHER_3DES; + else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF)) + cfg.cipher = CIPHER_BLOWFISH; + else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES)) + cfg.cipher = CIPHER_DES; + } + break; + case IDC_SSHPROT1: + case IDC_SSHPROT2: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) { + if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1)) + cfg.sshprot = 1; + else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2)) + cfg.sshprot = 2; + } + break; + case IDC_AUTHTIS: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) - cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY); + cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS); + break; + case IDC_PKEDIT: + if (HIWORD(wParam) == EN_CHANGE) + GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile, + sizeof(cfg.keyfile)-1); + break; + case IDC_CMDEDIT: + if (HIWORD(wParam) == EN_CHANGE) + GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd, + sizeof(cfg.remote_cmd)-1); + break; + case IDC_PKBUTTON: + /* + * FIXME: this crashes. Find out why. + */ + memset(&of, 0, sizeof(of)); +#ifdef OPENFILENAME_SIZE_VERSION_400 + of.lStructSize = OPENFILENAME_SIZE_VERSION_400; +#else + of.lStructSize = sizeof(of); +#endif + of.hwndOwner = hwnd; + of.lpstrFilter = "All Files\0*\0\0\0"; + of.lpstrCustomFilter = NULL; + of.nFilterIndex = 1; + of.lpstrFile = filename; strcpy(filename, cfg.keyfile); + of.nMaxFile = sizeof(filename); + of.lpstrFileTitle = NULL; + of.lpstrInitialDir = NULL; + of.lpstrTitle = "Select Public Key File"; + of.Flags = 0; + if (GetOpenFileName(&of)) { + strcpy(cfg.keyfile, filename); + SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile); + } break; } break; @@ -861,15 +1899,36 @@ static int CALLBACK SshProc (HWND hwnd, UINT msg, static int CALLBACK SelectionProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + struct ctlpos cp; int i; + enum { controlstartvalue = 1000, + IDC_MBSTATIC, + IDC_MBWINDOWS, + IDC_MBXTERM, + IDC_CCSTATIC, + IDC_CCLIST, + IDC_CCSET, + IDC_CCSTATIC2, + IDC_CCEDIT + }; switch (msg) { case WM_INITDIALOG: - CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM, - cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS); + /* Accelerators used: [aco] stwx */ + ctlposinit(&cp, hwnd); + radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC, + "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS, + "&xterm (Right extends, Middle pastes)", IDC_MBXTERM, + NULL); + charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST, + "&Set", IDC_CCSET, IDC_CCEDIT, + "&to class", IDC_CCSTATIC2); + + CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM, + cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS); { static int tabs[4] = {25, 61, 96, 128}; - SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4, + SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4, (LPARAM) tabs); } for (i=0; i<256; i++) { @@ -877,36 +1936,36 @@ static int CALLBACK SelectionProc (HWND hwnd, UINT msg, sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i, (i>=0x21 && i != 0x7F) ? i : ' ', cfg.wordness[i]); - SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0, + SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0, (LPARAM) str); } break; case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC4_MBWINDOWS: - case IDC4_MBXTERM: - cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM); + case IDC_MBWINDOWS: + case IDC_MBXTERM: + cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM); break; - case IDC4_CCSET: + case IDC_CCSET: { BOOL ok; int i; - int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE); + int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE); if (!ok) MessageBeep (0); else { for (i=0; i<256; i++) - if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL, + if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL, i, 0)) { char str[100]; cfg.wordness[i] = n; - SendDlgItemMessage (hwnd, IDC4_CCLIST, + SendDlgItemMessage (hwnd, IDC_CCLIST, LB_DELETESTRING, i, 0); sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i, (i>=0x21 && i != 0x7F) ? i : ' ', cfg.wordness[i]); - SendDlgItemMessage (hwnd, IDC4_CCLIST, + SendDlgItemMessage (hwnd, IDC_CCLIST, LB_INSERTSTRING, i, (LPARAM)str); } @@ -939,73 +1998,99 @@ static int CALLBACK ColourProc (HWND hwnd, UINT msg, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE }; + struct ctlpos cp; + enum { controlstartvalue = 1000, + IDC_BOLDCOLOUR, + IDC_PALETTE, + IDC_STATIC, + IDC_LIST, + IDC_RSTATIC, + IDC_GSTATIC, + IDC_BSTATIC, + IDC_RVALUE, + IDC_GVALUE, + IDC_BVALUE, + IDC_CHANGE + }; + switch (msg) { case WM_INITDIALOG: - CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour); - CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette); + /* Accelerators used: [aco] bmlu */ + ctlposinit(&cp, hwnd); + checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR); + checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE); + colouredit(&cp, "Select a colo&ur and click to modify it:", + IDC_STATIC, IDC_LIST, + "&Modify...", IDC_CHANGE, + "Red:", IDC_RSTATIC, IDC_RVALUE, + "Green:", IDC_GSTATIC, IDC_GVALUE, + "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL); + + CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour); + CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette); { int i; for (i=0; i<22; i++) if (cfg.bold_colour || permanent[i]) - SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0, + SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0, (LPARAM) colours[i]); } - SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0); - SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE); - SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE); - SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE); + SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0); + SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE); + SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE); + SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE); break; case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC5_BOLDCOLOUR: + case IDC_BOLDCOLOUR: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { int n, i; - cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR); - n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0); + cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR); + n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0); if (cfg.bold_colour && n!=22) { for (i=0; i<22; i++) if (!permanent[i]) - SendDlgItemMessage (hwnd, IDC5_LIST, + SendDlgItemMessage (hwnd, IDC_LIST, LB_INSERTSTRING, i, (LPARAM) colours[i]); } else if (!cfg.bold_colour && n!=12) { for (i=22; i-- ;) if (!permanent[i]) - SendDlgItemMessage (hwnd, IDC5_LIST, + SendDlgItemMessage (hwnd, IDC_LIST, LB_DELETESTRING, i, 0); } } break; - case IDC5_PALETTE: + case IDC_PALETTE: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) - cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE); + cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE); break; - case IDC5_LIST: + case IDC_LIST: if (HIWORD(wParam) == LBN_DBLCLK || HIWORD(wParam) == LBN_SELCHANGE) { - int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL, + int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL, 0, 0); if (!cfg.bold_colour) i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2); - SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE); - SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE); - SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE); + SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE); + SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE); + SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE); } break; - case IDC5_CHANGE: + case IDC_CHANGE: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { static CHOOSECOLOR cc; static DWORD custom[16] = {0}; /* zero initialisers */ - int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL, + int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL, 0, 0); if (!cfg.bold_colour) i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2); cc.lStructSize = sizeof(cc); cc.hwndOwner = hwnd; - cc.hInstance = hinst; + cc.hInstance = (HWND)hinst; cc.lpCustColors = custom; cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1], cfg.colours[i][2]); @@ -1017,11 +2102,11 @@ static int CALLBACK ColourProc (HWND hwnd, UINT msg, (unsigned char) (cc.rgbResult >> 8) & 0xFF; cfg.colours[i][2] = (unsigned char) (cc.rgbResult >> 16) & 0xFF; - SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], + SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE); - SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], + SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE); - SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], + SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE); } } @@ -1032,31 +2117,120 @@ static int CALLBACK ColourProc (HWND hwnd, UINT msg, return GeneralPanelProc (hwnd, msg, wParam, lParam); } -static DTemplate negot, main, reconf, panels[NPANELS]; +static int CALLBACK TranslationProc (HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam) { + struct ctlpos cp; + enum { controlstartvalue = 1000, + IDC_XLATSTATIC, + IDC_NOXLAT, + IDC_KOI8WIN1251, + IDC_88592WIN1250, + IDC_CAPSLOCKCYR, + IDC_VTSTATIC, + IDC_VTXWINDOWS, + IDC_VTOEMANSI, + IDC_VTOEMONLY, + IDC_VTPOORMAN + }; + + switch (msg) { + case WM_INITDIALOG: + /* Accelerators used: [aco] beiknpsx */ + ctlposinit(&cp, hwnd); + radiobig(&cp, + "Handling of VT100 line drawing characters:", IDC_VTSTATIC, + "Font has &XWindows encoding", IDC_VTXWINDOWS, + "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI, + "Use font in O&EM mode only", IDC_VTOEMONLY, + "&Poor man's line drawing (""+"", ""-"" and ""|"")", + IDC_VTPOORMAN, NULL); + radiobig(&cp, + "Character set translation:", IDC_XLATSTATIC, + "&None", IDC_NOXLAT, + "&KOI8 / Win-1251", IDC_KOI8WIN1251, + "&ISO-8859-2 / Win-1250", IDC_88592WIN1250, NULL); + checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC_CAPSLOCKCYR); + + CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592WIN1250, + cfg.xlat_88592w1250 ? IDC_88592WIN1250 : + cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 : + IDC_NOXLAT); + CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr); + CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN, + cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS : + cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI : + cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY : + IDC_VTPOORMAN); + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_NOXLAT: + case IDC_KOI8WIN1251: + case IDC_88592WIN1250: + cfg.xlat_enablekoiwin = + IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251); + cfg.xlat_88592w1250 = + IsDlgButtonChecked (hwnd, IDC_88592WIN1250); + break; + case IDC_CAPSLOCKCYR: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) { + cfg.xlat_capslockcyr = + IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR); + } + break; + case IDC_VTXWINDOWS: + case IDC_VTOEMANSI: + case IDC_VTOEMONLY: + case IDC_VTPOORMAN: + cfg.vtmode = + (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS : + IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI : + IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY : + VT_POORMAN); + break; + } + } + return GeneralPanelProc (hwnd, msg, wParam, lParam); +} + static DLGPROC panelproc[NPANELS] = { - ConnectionProc, KeyboardProc, TerminalProc, - TelnetProc, SshProc, SelectionProc, ColourProc -}; -static char *panelids[NPANELS] = { - MAKEINTRESOURCE(IDD_PANEL0), - MAKEINTRESOURCE(IDD_PANEL1), - MAKEINTRESOURCE(IDD_PANEL2), - MAKEINTRESOURCE(IDD_PANEL3), - MAKEINTRESOURCE(IDD_PANEL35), - MAKEINTRESOURCE(IDD_PANEL4), - MAKEINTRESOURCE(IDD_PANEL5) + ConnectionProc, KeyboardProc, TerminalProc, WindowProc, + TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc }; + static char *names[NPANELS] = { - "Connection", "Keyboard", "Terminal", "Telnet", "SSH", "Selection", "Colours" + "Connection", "Keyboard", "Terminal", "Window", "Telnet", + "SSH", "Selection", "Colours", "Translation" }; -static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6 }; -static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6 }; +static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8}; +static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8}; + +static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) { + RECT r; + HWND ret; + WPARAM font; + r.left = x; r.top = y; + r.right = r.left + w; r.bottom = r.top + h; + MapDialogRect(hwnd, &r); + ret = CreateWindowEx(WS_EX_CONTROLPARENT, + WC_DIALOG, "", /* no title */ + WS_CHILD | WS_VISIBLE | DS_SETFONT, + r.left, r.top, + r.right-r.left, r.bottom-r.top, + hwnd, (HMENU)IDC_SUBDLG, + hinst, NULL); + SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]); + font = SendMessage(hwnd, WM_GETFONT, 0, 0); + SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0)); + SendMessage (ret, WM_INITDIALOG, 0, 0); + return ret; +} static int GenericMainDlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, int npanels, int *panelnums, HWND *page) { - HWND hw; + HWND hw, tabctl; switch (msg) { case WM_INITDIALOG: @@ -1069,25 +2243,48 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg, (rs.bottom + rs.top + rd.top - rd.bottom)/2, rd.right-rd.left, rd.bottom-rd.top, TRUE); } + { + RECT r; + r.left = 3; r.right = r.left + 174; + r.top = 3; r.bottom = r.top + 193; + MapDialogRect(hwnd, &r); + tabctl = CreateWindowEx(0, WC_TABCONTROL, "", + WS_CHILD | WS_VISIBLE | + WS_TABSTOP | TCS_MULTILINE, + r.left, r.top, + r.right-r.left, r.bottom-r.top, + hwnd, (HMENU)IDC_TAB, hinst, NULL); + + if (!tabctl) { + struct ctlpos cp; + ctlposinit2(&cp, hwnd); + ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST, + IDC_TABSTATIC2); + } else { + WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0); + SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0)); + } + } *page = NULL; - { /* initialise the tab control */ + if (tabctl) { /* initialise the tab control */ TC_ITEMHEADER tab; int i; - hw = GetDlgItem (hwnd, IDC_TAB); for (i=0; ihwndFrom); if (*page) DestroyWindow (*page); -/* *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp, - hwnd, panelproc[panelnums[i]]);*/ - *page = CreateDialog (hinst, panelids[panelnums[i]], - hwnd, panelproc[panelnums[i]]); - SetWindowLong (*page, GWL_EXSTYLE, - GetWindowLong (*page, GWL_EXSTYLE) | - WS_EX_CONTROLPARENT); + *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]); SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */ return 0; } break; -/* case WM_CTLCOLORDLG: */ -/* return (int) GetStockObject (LTGRAY_BRUSH); */ case WM_COMMAND: switch (LOWORD(wParam)) { + case IDC_TABLIST: + if (HIWORD(wParam) == CBN_SELCHANGE) { + HWND tablist = GetDlgItem (hwnd, IDC_TABLIST); + int i = SendMessage (tablist, CB_GETCURSEL, 0, 0); + if (*page) + DestroyWindow (*page); + *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]); + SetFocus(tablist); /* ensure focus stays */ + return 0; + } + break; case IDOK: if (*cfg.host) EndDialog (hwnd, 1); @@ -1125,39 +2325,28 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg, case WM_CLOSE: EndDialog (hwnd, 0); return 0; + + /* Grrr Explorer will maximize Dialogs! */ + case WM_SIZE: + if (wParam == SIZE_MAXIMIZED) + force_normal(hwnd); + return 0; } return 0; } static int CALLBACK MainDlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { -#if 0 - HWND hw; - int i; -#endif static HWND page = NULL; if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) { -#if 0 - /* - * If the Connection panel is active and the Session List - * box is selected, we treat a press of Open to have an - * implicit press of Load preceding it. - */ - hw = GetDlgItem (hwnd, IDC_TAB); - i = TabCtrl_GetCurSel(hw); - if (panelproc[mainp[i]] == ConnectionProc && - page && implicit_load_ok) { - SendMessage (page, WM_COMMAND, - MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0); - } -#endif } if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) { EnableWindow(hwnd, 0); DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), GetParent(hwnd), AboutProc); EnableWindow(hwnd, 1); + SetActiveWindow(hwnd); } return GenericMainDlgProc (hwnd, msg, wParam, lParam, MAIN_NPANELS, mainp, &page); @@ -1170,30 +2359,33 @@ static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg, RECONF_NPANELS, reconfp, &page); } -static void get_sesslist(int allocate) { +void get_sesslist(int allocate) { + static char otherbuf[2048]; static char *buffer; - int buflen, bufsize, i, ret; - char otherbuf[2048]; - char *p; - HKEY subkey1; + int buflen, bufsize, i; + char *p, *ret; + void *handle; if (allocate) { - if (RegCreateKey(HKEY_CURRENT_USER, - puttystr, &subkey1) != ERROR_SUCCESS) + + if ((handle = enum_settings_start()) == NULL) return; buflen = bufsize = 0; buffer = NULL; - i = 0; do { - ret = RegEnumKey(subkey1, i++, otherbuf, sizeof(otherbuf)); - if (ret == ERROR_SUCCESS) { - bufsize = buflen + 2048; - buffer = srealloc(buffer, bufsize); - unmungestr(otherbuf, buffer+buflen); + ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf)); + if (ret) { + int len = strlen(otherbuf)+1; + if (bufsize < buflen+len) { + bufsize = buflen + len + 2048; + buffer = srealloc(buffer, bufsize); + } + strcpy(buffer+buflen, otherbuf); buflen += strlen(buffer+buflen)+1; } - } while (ret == ERROR_SUCCESS); + } while (ret); + enum_settings_finish(handle); buffer = srealloc(buffer, buflen+1); buffer[buflen] = '\0'; @@ -1226,6 +2418,7 @@ int do_config (void) { int ret; get_sesslist(TRUE); + savedsession[0] = '\0'; ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc); get_sesslist(FALSE); @@ -1240,6 +2433,9 @@ int do_reconfig (HWND hwnd) { ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc); if (!ret) cfg = backup_cfg; /* structure copy */ + else + force_normal(hwnd); + return ret; } @@ -1250,20 +2446,24 @@ void do_defaults (char *session) { load_settings ("Default Settings", FALSE); } -void lognegot (char *string) { - if (nnegots >= negsize) { +void logevent (char *string) { + if (nevents >= negsize) { negsize += 64; - negots = srealloc (negots, negsize * sizeof(*negots)); + events = srealloc (events, negsize * sizeof(*events)); } - negots[nnegots] = smalloc(1+strlen(string)); - strcpy (negots[nnegots], string); - nnegots++; - if (logbox) + events[nevents] = smalloc(1+strlen(string)); + strcpy (events[nevents], string); + nevents++; + if (logbox) { + int count; SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING, 0, (LPARAM)string); + count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0); + SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0); + } } -void shownegot (HWND hwnd) { +void showeventlog (HWND hwnd) { if (!logbox) { logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX), hwnd, LogProc); @@ -1279,74 +2479,70 @@ void showabout (HWND hwnd) { } } -void verify_ssh_host_key(char *host, struct RSAKey *key) { - char *keystr, *otherstr, *mungedhost; - int len; - HKEY rkey; +void verify_ssh_host_key(char *host, int port, char *keytype, + char *keystr, char *fingerprint) { + int ret; - /* - * Format the key into a string. - */ - len = rsastr_len(key); - keystr = malloc(len); - if (!keystr) - fatalbox("Out of memory"); - rsastr_fmt(keystr, key); + static const char absentmsg[] = + "The server's host key is not cached in the registry. You\n" + "have no guarantee that the server is the computer you\n" + "think it is.\n" + "The server's key fingerprint is:\n" + "%s\n" + "If you trust this host, hit Yes to add the key to\n" + "PuTTY's cache and carry on connecting.\n" + "If you do not trust this host, hit No to abandon the\n" + "connection.\n"; + + static const char wrongmsg[] = + "WARNING - POTENTIAL SECURITY BREACH!\n" + "\n" + "The server's host key does not match the one PuTTY has\n" + "cached in the registry. This means that either the\n" + "server administrator has changed the host key, or you\n" + "have actually connected to another computer pretending\n" + "to be the server.\n" + "The new key fingerprint is:\n" + "%s\n" + "If you were expecting this change and trust the new key,\n" + "hit Yes to update PuTTY's cache and continue connecting.\n" + "If you want to carry on connecting but without updating\n" + "the cache, hit No.\n" + "If you want to abandon the connection completely, hit\n" + "Cancel. Hitting Cancel is the ONLY guaranteed safe\n" + "choice.\n"; + + static const char mbtitle[] = "PuTTY Security Alert"; + + + char message[160+ /* sensible fingerprint max size */ + (sizeof(absentmsg) > sizeof(wrongmsg) ? + sizeof(absentmsg) : sizeof(wrongmsg))]; /* - * Now read a saved key in from the registry and see what it - * says. + * Verify the key against the registry. */ - otherstr = malloc(len); - mungedhost = malloc(3*strlen(host)+1); - if (!otherstr || !mungedhost) - fatalbox("Out of memory"); - - mungestr(host, mungedhost); - - if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys", - &rkey) != ERROR_SUCCESS) { - if (MessageBox(NULL, "PuTTY was unable to open the host key cache\n" - "in the registry. There is thus no way to tell\n" - "if the remote host is what you think it is.\n" - "Connect anyway?", "PuTTY Problem", - MB_ICONWARNING | MB_YESNO) == IDNO) - exit(0); - } else { - DWORD readlen = len; - DWORD type; - int ret; - - ret = RegQueryValueEx(rkey, mungedhost, NULL, - &type, otherstr, &readlen); - - if (ret == ERROR_MORE_DATA || - (ret == ERROR_SUCCESS && type == REG_SZ && - strcmp(otherstr, keystr))) { - if (MessageBox(NULL, - "This host's host key is different from the\n" - "one cached in the registry! Someone may be\n" - "impersonating this host for malicious reasons;\n" - "alternatively, the host key may have changed\n" - "due to sloppy system administration.\n" - "Replace key in registry and connect?", - "PuTTY: Security Warning", - MB_ICONWARNING | MB_YESNO) == IDNO) - exit(0); - RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr, - strlen(keystr)+1); - } else if (ret != ERROR_SUCCESS || type != REG_SZ) { - if (MessageBox(NULL, - "This host's host key is not cached in the\n" - "registry. Do you want to add it to the cache\n" - "and carry on connecting?", - "PuTTY: New Host", - MB_ICONWARNING | MB_YESNO) == IDNO) - exit(0); - RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr, - strlen(keystr)+1); - } - - RegCloseKey(rkey); + ret = verify_host_key(host, port, keytype, keystr); + + if (ret == 0) /* success - key matched OK */ + return; + if (ret == 2) { /* key was different */ + int mbret; + sprintf(message, wrongmsg, fingerprint); + mbret = MessageBox(NULL, message, mbtitle, + MB_ICONWARNING | MB_YESNOCANCEL); + if (mbret == IDYES) + store_host_key(host, port, keytype, keystr); + if (mbret == IDCANCEL) + exit(0); + } + if (ret == 1) { /* key was absent */ + int mbret; + sprintf(message, absentmsg, fingerprint); + mbret = MessageBox(NULL, message, mbtitle, + MB_ICONWARNING | MB_YESNO); + if (mbret == IDNO) + exit(0); + store_host_key(host, port, keytype, keystr); } }