X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=windows%2Fwindlg.c;h=826876e3cbd30bc713ae02b106187b2d65afe4a4;hb=2eb952ca31aa13d1f6f429305fbb6f43a9a28c56;hp=ba67ef5659872b965257b63d9958531cb2f3fc07;hpb=b0bf176dfb87a3839ad4beff1f5dc1237e3f7645;p=PuTTY.git diff --git a/windows/windlg.c b/windows/windlg.c index ba67ef56..826876e3 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -1,3 +1,7 @@ +/* + * windlg.c - dialogs for PuTTY(tel), including the configuration dialog. + */ + #include #include #include @@ -40,11 +44,7 @@ static struct dlgparam dp; static char **events = NULL; static int nevents = 0, negsize = 0; -static int requested_help; - -extern Config cfg; /* defined in window.c */ - -struct sesslist sesslist; /* exported to window.c */ +extern Conf *conf; /* defined in window.c */ #define PRINTER_DISABLED_STRING "None (printing disabled)" @@ -170,6 +170,37 @@ static int CALLBACK LicenceProc(HWND hwnd, UINT msg, char *str = dupprintf("%s Licence", appname); SetWindowText(hwnd, str); sfree(str); + + SetDlgItemText(hwnd, IDA_TEXT, + "Copyright 1997-2015 Simon Tatham.\r\n\r\n" + + "Portions copyright Robert de Bath, Joris van Rantwijk, Delian " + "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas " + "Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, " + "Markus Kuhn, Colin Watson, Christopher Staite, and CORE SDI S.A.\r\n\r\n" + + "Permission is hereby granted, free of charge, to any person " + "obtaining a copy of this software and associated documentation " + "files (the ""Software""), to deal in the Software without restriction, " + "including without limitation the rights to use, copy, modify, merge, " + "publish, distribute, sublicense, and/or sell copies of the Software, " + "and to permit persons to whom the Software is furnished to do so, " + "subject to the following conditions:\r\n\r\n" + + "The above copyright notice and this permission notice shall be " + "included in all copies or substantial portions of the Software.\r\n\r\n" + + "THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT " + "WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, " + "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " + "MERCHANTABILITY, FITNESS FOR A PARTICULAR " + "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE " + "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES " + "OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, " + "TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN " + "CONNECTION WITH THE SOFTWARE OR THE USE OR " + "OTHER DEALINGS IN THE SOFTWARE." +); } return 1; case WM_COMMAND: @@ -197,8 +228,14 @@ static int CALLBACK AboutProc(HWND hwnd, UINT msg, str = dupprintf("About %s", appname); SetWindowText(hwnd, str); sfree(str); - SetDlgItemText(hwnd, IDA_TEXT1, appname); - SetDlgItemText(hwnd, IDA_VERSION, ver); + { + char *text = dupprintf + ("%s\r\n\r\n%s\r\n\r\n%s", + appname, ver, + "\251 1997-2015 Simon Tatham. All rights reserved."); + SetDlgItemText(hwnd, IDA_TEXT, text); + sfree(text); + } return 1; case WM_COMMAND: switch (LOWORD(wParam)) { @@ -229,6 +266,57 @@ static int CALLBACK AboutProc(HWND hwnd, UINT msg, return 0; } +static int SaneDialogBox(HINSTANCE hinst, + LPCTSTR tmpl, + HWND hwndparent, + DLGPROC lpDialogFunc) +{ + WNDCLASS wc; + HWND hwnd; + MSG msg; + int flags; + int ret; + int gm; + + wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW; + wc.lpfnWndProc = DefDlgProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = DLGWINDOWEXTRA + 2*sizeof(LONG_PTR); + wc.hInstance = hinst; + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1); + wc.lpszMenuName = NULL; + wc.lpszClassName = "PuTTYConfigBox"; + RegisterClass(&wc); + + hwnd = CreateDialog(hinst, tmpl, hwndparent, lpDialogFunc); + + SetWindowLongPtr(hwnd, BOXFLAGS, 0); /* flags */ + SetWindowLongPtr(hwnd, BOXRESULT, 0); /* result from SaneEndDialog */ + + while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) { + flags=GetWindowLongPtr(hwnd, BOXFLAGS); + if (!(flags & DF_END) && !IsDialogMessage(hwnd, &msg)) + DispatchMessage(&msg); + if (flags & DF_END) + break; + } + + if (gm == 0) + PostQuitMessage(msg.wParam); /* We got a WM_QUIT, pass it on */ + + ret=GetWindowLongPtr(hwnd, BOXRESULT); + DestroyWindow(hwnd); + return ret; +} + +static void SaneEndDialog(HWND hwnd, int ret) +{ + SetWindowLongPtr(hwnd, BOXRESULT, ret); + SetWindowLongPtr(hwnd, BOXFLAGS, DF_END); +} + /* * Null dialog procedure. */ @@ -271,7 +359,7 @@ static HTREEITEM treeview_insert(struct treeview_faff *faff, newitem = TreeView_InsertItem(faff->treeview, &ins); if (level > 0) TreeView_Expand(faff->treeview, faff->lastat[level - 1], - TVE_EXPAND); + (level > 1 ? TVE_COLLAPSE : TVE_EXPAND)); faff->lastat[level] = newitem; for (i = level + 1; i < 4; i++) faff->lastat[i] = NULL; @@ -300,7 +388,7 @@ static void create_controls(HWND hwnd, char *path) * Otherwise, we're creating the controls for a particular * panel. */ - ctlposinit(&cp, hwnd, 80, 3, 13); + ctlposinit(&cp, hwnd, 100, 3, 13); wc = &ctrls_panel; base_id = IDCX_PANELBASE; } @@ -313,6 +401,8 @@ static void create_controls(HWND hwnd, char *path) /* * This function is the configuration box. + * (Being a dialog procedure, in general it returns 0 if the default + * dialog processing should be performed, and 1 if it should not.) */ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -326,16 +416,16 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, dp.hwnd = hwnd; create_controls(hwnd, ""); /* Open and Cancel buttons etc */ SetWindowText(hwnd, dp.wintitle); - SetWindowLong(hwnd, GWL_USERDATA, 0); - if (help_path) - SetWindowLong(hwnd, GWL_EXSTYLE, - GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_CONTEXTHELP); + SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); + if (has_help()) + SetWindowLongPtr(hwnd, GWL_EXSTYLE, + GetWindowLongPtr(hwnd, GWL_EXSTYLE) | + WS_EX_CONTEXTHELP); else { HWND item = GetDlgItem(hwnd, IDC_HELPBTN); if (item) DestroyWindow(item); } - requested_help = FALSE; SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(IDI_CFGICON))); /* @@ -361,7 +451,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, HWND tvstatic; r.left = 3; - r.right = r.left + 75; + r.right = r.left + 95; r.top = 3; r.bottom = r.top + 10; MapDialogRect(hwnd, &r); @@ -375,7 +465,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0)); r.left = 3; - r.right = r.left + 75; + r.right = r.left + 95; r.top = 13; r.bottom = r.top + 219; MapDialogRect(hwnd, &r); @@ -401,6 +491,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, HTREEITEM hfirst = NULL; int i; char *path = NULL; + char *firstpath = NULL; for (i = 0; i < ctrlbox->nctrlsets; i++) { struct controlset *s = ctrlbox->ctrlsets[i]; @@ -433,18 +524,27 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, c++; item = treeview_insert(&tvfaff, j, c, s->pathname); - if (!hfirst) + if (!hfirst) { hfirst = item; + firstpath = s->pathname; + } path = s->pathname; } /* - * Put the treeview selection on to the Session panel. - * This should also cause creation of the relevant - * controls. + * Put the treeview selection on to the first panel in the + * ctrlbox. */ TreeView_SelectItem(treeview, hfirst); + + /* + * And create the actual control set for that panel, to + * match the initial treeview selection. + */ + assert(firstpath); /* config.c must have given us _something_ */ + create_controls(hwnd, firstpath); + dlg_refresh(NULL, &dp); /* and set up control values */ } /* @@ -463,7 +563,19 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, } } - SetWindowLong(hwnd, GWL_USERDATA, 1); + /* + * Now we've finished creating our initial set of controls, + * it's safe to actually show the window without risking setup + * flicker. + */ + ShowWindow(hwnd, SW_SHOWNORMAL); + + /* + * Set the flag that activates a couple of the other message + * handlers below, which were disabled until now to avoid + * spurious firing during the above setup procedure. + */ + SetWindowLongPtr(hwnd, GWLP_USERDATA, 1); return 0; case WM_LBUTTONUP: /* @@ -477,10 +589,21 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, case WM_NOTIFY: if (LOWORD(wParam) == IDCX_TREEVIEW && ((LPNMHDR) lParam)->code == TVN_SELCHANGED) { - HTREEITEM i = - TreeView_GetSelection(((LPNMHDR) lParam)->hwndFrom); + /* + * Selection-change events on the treeview cause us to do + * a flurry of control deletion and creation - but only + * after WM_INITDIALOG has finished. The initial + * selection-change event(s) during treeview setup are + * ignored. + */ + HTREEITEM i; TVITEM item; char buffer[64]; + + if (GetWindowLongPtr(hwnd, GWLP_USERDATA) != 1) + return 0; + + i = TreeView_GetSelection(((LPNMHDR) lParam)->hwndFrom); SendMessage (hwnd, WM_SETREDRAW, FALSE, 0); @@ -524,7 +647,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, /* * Only process WM_COMMAND once the dialog is fully formed. */ - if (GetWindowLong(hwnd, GWL_USERDATA) == 1) { + if (GetWindowLongPtr(hwnd, GWLP_USERDATA) == 1) { ret = winctrl_handle_command(&dp, msg, wParam, lParam); if (dp.ended && GetCapture() != hwnd) SaneEndDialog(hwnd, dp.endresult ? 1 : 0); @@ -532,19 +655,12 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg, ret = 0; return ret; case WM_HELP: - if (help_path) { - if (winctrl_context_help(&dp, hwnd, - ((LPHELPINFO)lParam)->iCtrlId)) - requested_help = TRUE; - else - MessageBeep(0); - } + if (!winctrl_context_help(&dp, hwnd, + ((LPHELPINFO)lParam)->iCtrlId)) + MessageBeep(0); break; case WM_CLOSE: - if (requested_help) { - WinHelp(hwnd, help_path, HELP_QUIT, 0); - requested_help = FALSE; - } + quit_help(hwnd); SaneEndDialog(hwnd, 0); return 0; @@ -568,12 +684,7 @@ void modal_about_box(HWND hwnd) void show_help(HWND hwnd) { - if (help_path) { - WinHelp(hwnd, help_path, - help_has_contents ? HELP_FINDER : HELP_CONTENTS, - 0); - requested_help = TRUE; - } + launch_help(hwnd, NULL); } void defuse_showwindow(void) @@ -598,8 +709,8 @@ int do_config(void) int ret; ctrlbox = ctrl_new_box(); - setup_config_box(ctrlbox, &sesslist, FALSE, 0, 0); - win_setup_config_box(ctrlbox, &dp.hwnd, (help_path != NULL), FALSE); + setup_config_box(ctrlbox, FALSE, 0, 0); + win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), FALSE, 0); dp_init(&dp); winctrl_init(&ctrls_base); winctrl_init(&ctrls_panel); @@ -607,14 +718,13 @@ int do_config(void) dp_add_tree(&dp, &ctrls_panel); dp.wintitle = dupprintf("%s Configuration", appname); dp.errtitle = dupprintf("%s Error", appname); - dp.data = &cfg; + dp.data = conf; + dlg_auto_set_fixed_pitch_flag(&dp); dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */ - get_sesslist(&sesslist, TRUE); ret = SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, GenericMainDlgProc); - get_sesslist(&sesslist, FALSE); ctrl_free_box(ctrlbox); winctrl_cleanup(&ctrls_panel); @@ -626,14 +736,15 @@ int do_config(void) int do_reconfig(HWND hwnd, int protcfginfo) { - Config backup_cfg; - int ret; + Conf *backup_conf; + int ret, protocol; - backup_cfg = cfg; /* structure copy */ + backup_conf = conf_copy(conf); ctrlbox = ctrl_new_box(); - setup_config_box(ctrlbox, &sesslist, TRUE, cfg.protocol, protcfginfo); - win_setup_config_box(ctrlbox, &dp.hwnd, (help_path != NULL), TRUE); + protocol = conf_get_int(conf, CONF_protocol); + setup_config_box(ctrlbox, TRUE, protocol, protcfginfo); + win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), TRUE, protocol); dp_init(&dp); winctrl_init(&ctrls_base); winctrl_init(&ctrls_panel); @@ -641,7 +752,8 @@ int do_reconfig(HWND hwnd, int protcfginfo) dp_add_tree(&dp, &ctrls_panel); dp.wintitle = dupprintf("%s Reconfiguration", appname); dp.errtitle = dupprintf("%s Error", appname); - dp.data = &cfg; + dp.data = conf; + dlg_auto_set_fixed_pitch_flag(&dp); dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */ ret = SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, @@ -653,7 +765,9 @@ int do_reconfig(HWND hwnd, int protcfginfo) dp_cleanup(&dp); if (!ret) - cfg = backup_cfg; /* structure copy */ + conf_copy_into(conf, backup_conf); + + conf_free(backup_conf); return ret; } @@ -661,7 +775,7 @@ int do_reconfig(HWND hwnd, int protcfginfo) void logevent(void *frontend, const char *string) { char timebuf[40]; - time_t t; + struct tm tm; log_eventlog(logctx, string); @@ -670,9 +784,8 @@ void logevent(void *frontend, const char *string) events = sresize(events, negsize, char *); } - time(&t); - strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t", - localtime(&t)); + tm=ltime(); + strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t", &tm); events[nevents] = snewn(strlen(timebuf) + strlen(string) + 1, char); strcpy(events[nevents], timebuf); @@ -702,8 +815,9 @@ void showabout(HWND hwnd) DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc); } -void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, - char *keystr, char *fingerprint) +int verify_ssh_host_key(void *frontend, char *host, int port, + const char *keytype, char *keystr, char *fingerprint, + void (*callback)(void *ctx, int result), void *ctx) { int ret; @@ -745,42 +859,48 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, ret = verify_host_key(host, port, keytype, keystr); if (ret == 0) /* success - key matched OK */ - return; - if (ret == 2) { /* key was different */ + return 1; + else if (ret == 2) { /* key was different */ int mbret; - char *message, *title; - message = dupprintf(wrongmsg, appname, keytype, fingerprint, appname); - title = dupprintf(mbtitle, appname); - mbret = MessageBox(NULL, message, title, - MB_ICONWARNING | MB_YESNOCANCEL); - sfree(message); - sfree(title); - if (mbret == IDYES) + char *text = dupprintf(wrongmsg, appname, keytype, fingerprint, + appname); + char *caption = dupprintf(mbtitle, appname); + mbret = message_box(text, caption, + MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3, + HELPCTXID(errors_hostkey_changed)); + assert(mbret==IDYES || mbret==IDNO || mbret==IDCANCEL); + sfree(text); + sfree(caption); + if (mbret == IDYES) { store_host_key(host, port, keytype, keystr); - if (mbret == IDCANCEL) - cleanup_exit(0); - } - if (ret == 1) { /* key was absent */ + return 1; + } else if (mbret == IDNO) + return 1; + } else if (ret == 1) { /* key was absent */ int mbret; - char *message, *title; - message = dupprintf(absentmsg, keytype, fingerprint, appname); - title = dupprintf(mbtitle, appname); - mbret = MessageBox(NULL, message, title, - MB_ICONWARNING | MB_YESNOCANCEL); - sfree(message); - sfree(title); - if (mbret == IDYES) + char *text = dupprintf(absentmsg, keytype, fingerprint, appname); + char *caption = dupprintf(mbtitle, appname); + mbret = message_box(text, caption, + MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3, + HELPCTXID(errors_hostkey_absent)); + assert(mbret==IDYES || mbret==IDNO || mbret==IDCANCEL); + sfree(text); + sfree(caption); + if (mbret == IDYES) { store_host_key(host, port, keytype, keystr); - if (mbret == IDCANCEL) - cleanup_exit(0); + return 1; + } else if (mbret == IDNO) + return 1; } + return 0; /* abandon the connection */ } /* * Ask whether the selected algorithm is acceptable (since it was * below the configured 'warn' threshold). */ -void askalg(void *frontend, const char *algtype, const char *algname) +int askalg(void *frontend, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { static const char mbtitle[] = "%s Security Alert"; static const char msg[] = @@ -794,20 +914,22 @@ void askalg(void *frontend, const char *algtype, const char *algname) message = dupprintf(msg, algtype, algname); title = dupprintf(mbtitle, appname); mbret = MessageBox(NULL, message, title, - MB_ICONWARNING | MB_YESNO); + MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2); + socket_reselect_all(); sfree(message); sfree(title); if (mbret == IDYES) - return; + return 1; else - cleanup_exit(0); + return 0; } /* * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ -int askappend(void *frontend, Filename filename) +int askappend(void *frontend, Filename *filename, + void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = "The session log file \"%.*s\" already exists.\n" @@ -820,11 +942,13 @@ int askappend(void *frontend, Filename filename) char *mbtitle; int mbret; - message = dupprintf(msgtemplate, FILENAME_MAX, filename.path); + message = dupprintf(msgtemplate, FILENAME_MAX, filename->path); mbtitle = dupprintf("%s Log to File", appname); mbret = MessageBox(NULL, message, mbtitle, - MB_ICONQUESTION | MB_YESNOCANCEL); + MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON3); + + socket_reselect_all(); sfree(message); sfree(mbtitle); @@ -851,7 +975,7 @@ void old_keyfile_warning(void) { static const char mbtitle[] = "%s Key File Warning"; static const char message[] = - "You are loading an SSH 2 private key which has an\n" + "You are loading an SSH-2 private key which has an\n" "old version of the file format. This means your key\n" "file is not fully tamperproof. Future versions of\n" "%s may stop supporting this private key format,\n" @@ -867,6 +991,8 @@ void old_keyfile_warning(void) MessageBox(NULL, msg, title, MB_OK); + socket_reselect_all(); + sfree(msg); sfree(title); }