2 * windlg.c - dialogs for PuTTY(tel), including the configuration dialog.
23 #define TVINSERTSTRUCT TV_INSERTSTRUCT
24 #define TVITEM TV_ITEM
29 * These are the various bits of data required to handle the
30 * portable-dialog stuff in the config box. Having them at file
31 * scope in here isn't too bad a place to put them; if we were ever
32 * to need more than one config box per process we could always
33 * shift them to a per-config-box structure stored in GWL_USERDATA.
35 static struct controlbox *ctrlbox;
37 * ctrls_base holds the OK and Cancel buttons: the controls which
38 * are present in all dialog panels. ctrls_panel holds the ones
39 * which change from panel to panel.
41 static struct winctrls ctrls_base, ctrls_panel;
42 static struct dlgparam dp;
44 static char **events = NULL;
45 static int nevents = 0, negsize = 0;
47 extern Conf *conf; /* defined in window.c */
49 #define PRINTER_DISABLED_STRING "None (printing disabled)"
51 void force_normal(HWND hwnd)
53 static int recurse = 0;
61 wp.length = sizeof(wp);
62 if (GetWindowPlacement(hwnd, &wp) && wp.showCmd == SW_SHOWMAXIMIZED) {
63 wp.showCmd = SW_SHOWNORMAL;
64 SetWindowPlacement(hwnd, &wp);
69 static int CALLBACK LogProc(HWND hwnd, UINT msg,
70 WPARAM wParam, LPARAM lParam)
77 char *str = dupprintf("%s Event Log", appname);
78 SetWindowText(hwnd, str);
82 static int tabs[4] = { 78, 108 };
83 SendDlgItemMessage(hwnd, IDN_LIST, LB_SETTABSTOPS, 2,
86 for (i = 0; i < nevents; i++)
87 SendDlgItemMessage(hwnd, IDN_LIST, LB_ADDSTRING,
88 0, (LPARAM) events[i]);
91 switch (LOWORD(wParam)) {
95 SetActiveWindow(GetParent(hwnd));
99 if (HIWORD(wParam) == BN_CLICKED ||
100 HIWORD(wParam) == BN_DOUBLECLICKED) {
103 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
104 LB_GETSELCOUNT, 0, 0);
105 if (selcount == 0) { /* don't even try to copy zero items */
110 selitems = snewn(selcount, int);
112 int count = SendDlgItemMessage(hwnd, IDN_LIST,
119 static unsigned char sel_nl[] = SEL_NL;
121 if (count == 0) { /* can't copy zero stuff */
127 for (i = 0; i < count; i++)
129 strlen(events[selitems[i]]) + sizeof(sel_nl);
131 clipdata = snewn(size, char);
134 for (i = 0; i < count; i++) {
135 char *q = events[selitems[i]];
136 int qlen = strlen(q);
139 memcpy(p, sel_nl, sizeof(sel_nl));
142 write_aclip(NULL, clipdata, size, TRUE);
147 for (i = 0; i < nevents; i++)
148 SendDlgItemMessage(hwnd, IDN_LIST, LB_SETSEL,
157 SetActiveWindow(GetParent(hwnd));
164 static int CALLBACK LicenceProc(HWND hwnd, UINT msg,
165 WPARAM wParam, LPARAM lParam)
170 char *str = dupprintf("%s Licence", appname);
171 SetWindowText(hwnd, str);
174 SetDlgItemText(hwnd, IDA_TEXT,
175 "Copyright 1997-2015 Simon Tatham.\r\n\r\n"
177 "Portions copyright Robert de Bath, Joris van Rantwijk, Delian "
178 "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas "
179 "Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, "
180 "Markus Kuhn, Colin Watson, Christopher Staite, and CORE SDI S.A.\r\n\r\n"
182 "Permission is hereby granted, free of charge, to any person "
183 "obtaining a copy of this software and associated documentation "
184 "files (the ""Software""), to deal in the Software without restriction, "
185 "including without limitation the rights to use, copy, modify, merge, "
186 "publish, distribute, sublicense, and/or sell copies of the Software, "
187 "and to permit persons to whom the Software is furnished to do so, "
188 "subject to the following conditions:\r\n\r\n"
190 "The above copyright notice and this permission notice shall be "
191 "included in all copies or substantial portions of the Software.\r\n\r\n"
193 "THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT "
194 "WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, "
195 "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
196 "MERCHANTABILITY, FITNESS FOR A PARTICULAR "
197 "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE "
198 "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES "
199 "OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, "
200 "TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN "
201 "CONNECTION WITH THE SOFTWARE OR THE USE OR "
202 "OTHER DEALINGS IN THE SOFTWARE."
207 switch (LOWORD(wParam)) {
221 static int CALLBACK AboutProc(HWND hwnd, UINT msg,
222 WPARAM wParam, LPARAM lParam)
228 str = dupprintf("About %s", appname);
229 SetWindowText(hwnd, str);
232 char *text = dupprintf
233 ("%s\r\n\r\n%s\r\n\r\n%s",
235 "\251 1997-2015 Simon Tatham. All rights reserved.");
236 SetDlgItemText(hwnd, IDA_TEXT, text);
241 switch (LOWORD(wParam)) {
244 EndDialog(hwnd, TRUE);
247 EnableWindow(hwnd, 0);
248 DialogBox(hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
250 EnableWindow(hwnd, 1);
251 SetActiveWindow(hwnd);
255 /* Load web browser */
256 ShellExecute(hwnd, "open",
257 "http://www.chiark.greenend.org.uk/~sgtatham/putty/",
258 0, 0, SW_SHOWDEFAULT);
263 EndDialog(hwnd, TRUE);
269 static int SaneDialogBox(HINSTANCE hinst,
272 DLGPROC lpDialogFunc)
281 wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
282 wc.lpfnWndProc = DefDlgProc;
284 wc.cbWndExtra = DLGWINDOWEXTRA + 2*sizeof(LONG_PTR);
285 wc.hInstance = hinst;
287 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
288 wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1);
289 wc.lpszMenuName = NULL;
290 wc.lpszClassName = "PuTTYConfigBox";
293 hwnd = CreateDialog(hinst, tmpl, hwndparent, lpDialogFunc);
295 SetWindowLongPtr(hwnd, BOXFLAGS, 0); /* flags */
296 SetWindowLongPtr(hwnd, BOXRESULT, 0); /* result from SaneEndDialog */
298 while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
299 flags=GetWindowLongPtr(hwnd, BOXFLAGS);
300 if (!(flags & DF_END) && !IsDialogMessage(hwnd, &msg))
301 DispatchMessage(&msg);
307 PostQuitMessage(msg.wParam); /* We got a WM_QUIT, pass it on */
309 ret=GetWindowLongPtr(hwnd, BOXRESULT);
314 static void SaneEndDialog(HWND hwnd, int ret)
316 SetWindowLongPtr(hwnd, BOXRESULT, ret);
317 SetWindowLongPtr(hwnd, BOXFLAGS, DF_END);
321 * Null dialog procedure.
323 static int CALLBACK NullDlgProc(HWND hwnd, UINT msg,
324 WPARAM wParam, LPARAM lParam)
330 IDCX_ABOUT = IDC_ABOUT,
334 IDCX_PANELBASE = IDCX_STDBASE + 32
337 struct treeview_faff {
342 static HTREEITEM treeview_insert(struct treeview_faff *faff,
343 int level, char *text, char *path)
348 ins.hParent = (level > 0 ? faff->lastat[level - 1] : TVI_ROOT);
349 ins.hInsertAfter = faff->lastat[level];
350 #if _WIN32_IE >= 0x0400 && defined NONAMELESSUNION
351 #define INSITEM DUMMYUNIONNAME.item
355 ins.INSITEM.mask = TVIF_TEXT | TVIF_PARAM;
356 ins.INSITEM.pszText = text;
357 ins.INSITEM.cchTextMax = strlen(text)+1;
358 ins.INSITEM.lParam = (LPARAM)path;
359 newitem = TreeView_InsertItem(faff->treeview, &ins);
361 TreeView_Expand(faff->treeview, faff->lastat[level - 1],
362 (level > 1 ? TVE_COLLAPSE : TVE_EXPAND));
363 faff->lastat[level] = newitem;
364 for (i = level + 1; i < 4; i++)
365 faff->lastat[i] = NULL;
370 * Create the panelfuls of controls in the configuration box.
372 static void create_controls(HWND hwnd, char *path)
381 * Here we must create the basic standard controls.
383 ctlposinit(&cp, hwnd, 3, 3, 235);
385 base_id = IDCX_STDBASE;
388 * Otherwise, we're creating the controls for a particular
391 ctlposinit(&cp, hwnd, 100, 3, 13);
393 base_id = IDCX_PANELBASE;
396 for (index=-1; (index = ctrl_find_path(ctrlbox, path, index)) >= 0 ;) {
397 struct controlset *s = ctrlbox->ctrlsets[index];
398 winctrl_layout(&dp, wc, &cp, s, &base_id);
403 * This function is the configuration box.
404 * (Being a dialog procedure, in general it returns 0 if the default
405 * dialog processing should be performed, and 1 if it should not.)
407 static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
408 WPARAM wParam, LPARAM lParam)
411 struct treeview_faff tvfaff;
417 create_controls(hwnd, ""); /* Open and Cancel buttons etc */
418 SetWindowText(hwnd, dp.wintitle);
419 SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
421 SetWindowLongPtr(hwnd, GWL_EXSTYLE,
422 GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
425 HWND item = GetDlgItem(hwnd, IDC_HELPBTN);
429 SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG,
430 (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(IDI_CFGICON)));
434 { /* centre the window */
437 hw = GetDesktopWindow();
438 if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
440 (rs.right + rs.left + rd.left - rd.right) / 2,
441 (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
442 rd.right - rd.left, rd.bottom - rd.top, TRUE);
446 * Create the tree view.
454 r.right = r.left + 95;
456 r.bottom = r.top + 10;
457 MapDialogRect(hwnd, &r);
458 tvstatic = CreateWindowEx(0, "STATIC", "Cate&gory:",
459 WS_CHILD | WS_VISIBLE,
461 r.right - r.left, r.bottom - r.top,
462 hwnd, (HMENU) IDCX_TVSTATIC, hinst,
464 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
465 SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
468 r.right = r.left + 95;
470 r.bottom = r.top + 219;
471 MapDialogRect(hwnd, &r);
472 treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
473 WS_CHILD | WS_VISIBLE |
474 WS_TABSTOP | TVS_HASLINES |
475 TVS_DISABLEDRAGDROP | TVS_HASBUTTONS
477 TVS_SHOWSELALWAYS, r.left, r.top,
478 r.right - r.left, r.bottom - r.top,
479 hwnd, (HMENU) IDCX_TREEVIEW, hinst,
481 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
482 SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
483 tvfaff.treeview = treeview;
484 memset(tvfaff.lastat, 0, sizeof(tvfaff.lastat));
488 * Set up the tree view contents.
491 HTREEITEM hfirst = NULL;
494 char *firstpath = NULL;
496 for (i = 0; i < ctrlbox->nctrlsets; i++) {
497 struct controlset *s = ctrlbox->ctrlsets[i];
504 j = path ? ctrl_path_compare(s->pathname, path) : 0;
506 continue; /* same path, nothing to add to tree */
509 * We expect never to find an implicit path
510 * component. For example, we expect never to see
511 * A/B/C followed by A/D/E, because that would
512 * _implicitly_ create A/D. All our path prefixes
513 * are expected to contain actual controls and be
514 * selectable in the treeview; so we would expect
515 * to see A/D _explicitly_ before encountering
518 assert(j == ctrl_path_elements(s->pathname) - 1);
520 c = strrchr(s->pathname, '/');
526 item = treeview_insert(&tvfaff, j, c, s->pathname);
529 firstpath = s->pathname;
536 * Put the treeview selection on to the first panel in the
539 TreeView_SelectItem(treeview, hfirst);
542 * And create the actual control set for that panel, to
543 * match the initial treeview selection.
545 assert(firstpath); /* config.c must have given us _something_ */
546 create_controls(hwnd, firstpath);
547 dlg_refresh(NULL, &dp); /* and set up control values */
551 * Set focus into the first available control.
557 for (i = 0; (c = winctrl_findbyindex(&ctrls_panel, i)) != NULL;
560 dlg_set_focus(c->ctrl, &dp);
567 * Now we've finished creating our initial set of controls,
568 * it's safe to actually show the window without risking setup
571 ShowWindow(hwnd, SW_SHOWNORMAL);
574 * Set the flag that activates a couple of the other message
575 * handlers below, which were disabled until now to avoid
576 * spurious firing during the above setup procedure.
578 SetWindowLongPtr(hwnd, GWLP_USERDATA, 1);
582 * Button release should trigger WM_OK if there was a
583 * previous double click on the session list.
587 SaneEndDialog(hwnd, dp.endresult ? 1 : 0);
590 if (LOWORD(wParam) == IDCX_TREEVIEW &&
591 ((LPNMHDR) lParam)->code == TVN_SELCHANGED) {
593 * Selection-change events on the treeview cause us to do
594 * a flurry of control deletion and creation - but only
595 * after WM_INITDIALOG has finished. The initial
596 * selection-change event(s) during treeview setup are
603 if (GetWindowLongPtr(hwnd, GWLP_USERDATA) != 1)
606 i = TreeView_GetSelection(((LPNMHDR) lParam)->hwndFrom);
608 SendMessage (hwnd, WM_SETREDRAW, FALSE, 0);
611 item.pszText = buffer;
612 item.cchTextMax = sizeof(buffer);
613 item.mask = TVIF_TEXT | TVIF_PARAM;
614 TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &item);
616 /* Destroy all controls in the currently visible panel. */
621 while ((c = winctrl_findbyindex(&ctrls_panel, 0)) != NULL) {
622 for (k = 0; k < c->num_ids; k++) {
623 item = GetDlgItem(hwnd, c->base_id + k);
627 winctrl_rem_shortcuts(&dp, c);
628 winctrl_remove(&ctrls_panel, c);
633 create_controls(hwnd, (char *)item.lParam);
635 dlg_refresh(NULL, &dp); /* set up control values */
637 SendMessage (hwnd, WM_SETREDRAW, TRUE, 0);
638 InvalidateRect (hwnd, NULL, TRUE);
640 SetFocus(((LPNMHDR) lParam)->hwndFrom); /* ensure focus stays */
646 default: /* also handle drag list msg here */
648 * Only process WM_COMMAND once the dialog is fully formed.
650 if (GetWindowLongPtr(hwnd, GWLP_USERDATA) == 1) {
651 ret = winctrl_handle_command(&dp, msg, wParam, lParam);
652 if (dp.ended && GetCapture() != hwnd)
653 SaneEndDialog(hwnd, dp.endresult ? 1 : 0);
658 if (!winctrl_context_help(&dp, hwnd,
659 ((LPHELPINFO)lParam)->iCtrlId))
664 SaneEndDialog(hwnd, 0);
667 /* Grrr Explorer will maximize Dialogs! */
669 if (wParam == SIZE_MAXIMIZED)
677 void modal_about_box(HWND hwnd)
679 EnableWindow(hwnd, 0);
680 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
681 EnableWindow(hwnd, 1);
682 SetActiveWindow(hwnd);
685 void show_help(HWND hwnd)
687 launch_help(hwnd, NULL);
690 void defuse_showwindow(void)
693 * Work around the fact that the app's first call to ShowWindow
694 * will ignore the default in favour of the shell-provided
699 hwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
701 ShowWindow(hwnd, SW_HIDE);
702 SetActiveWindow(hwnd);
711 ctrlbox = ctrl_new_box();
712 setup_config_box(ctrlbox, FALSE, 0, 0);
713 win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), FALSE, 0);
715 winctrl_init(&ctrls_base);
716 winctrl_init(&ctrls_panel);
717 dp_add_tree(&dp, &ctrls_base);
718 dp_add_tree(&dp, &ctrls_panel);
719 dp.wintitle = dupprintf("%s Configuration", appname);
720 dp.errtitle = dupprintf("%s Error", appname);
722 dlg_auto_set_fixed_pitch_flag(&dp);
723 dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */
726 SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL,
729 ctrl_free_box(ctrlbox);
730 winctrl_cleanup(&ctrls_panel);
731 winctrl_cleanup(&ctrls_base);
737 int do_reconfig(HWND hwnd, int protcfginfo)
742 backup_conf = conf_copy(conf);
744 ctrlbox = ctrl_new_box();
745 protocol = conf_get_int(conf, CONF_protocol);
746 setup_config_box(ctrlbox, TRUE, protocol, protcfginfo);
747 win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), TRUE, protocol);
749 winctrl_init(&ctrls_base);
750 winctrl_init(&ctrls_panel);
751 dp_add_tree(&dp, &ctrls_base);
752 dp_add_tree(&dp, &ctrls_panel);
753 dp.wintitle = dupprintf("%s Reconfiguration", appname);
754 dp.errtitle = dupprintf("%s Error", appname);
756 dlg_auto_set_fixed_pitch_flag(&dp);
757 dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */
759 ret = SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL,
762 ctrl_free_box(ctrlbox);
763 winctrl_cleanup(&ctrls_base);
764 winctrl_cleanup(&ctrls_panel);
768 conf_copy_into(conf, backup_conf);
770 conf_free(backup_conf);
775 void logevent(void *frontend, const char *string)
780 log_eventlog(logctx, string);
782 if (nevents >= negsize) {
784 events = sresize(events, negsize, char *);
788 strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t", &tm);
790 events[nevents] = snewn(strlen(timebuf) + strlen(string) + 1, char);
791 strcpy(events[nevents], timebuf);
792 strcat(events[nevents], string);
795 SendDlgItemMessage(logbox, IDN_LIST, LB_ADDSTRING,
796 0, (LPARAM) events[nevents]);
797 count = SendDlgItemMessage(logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
798 SendDlgItemMessage(logbox, IDN_LIST, LB_SETTOPINDEX, count - 1, 0);
803 void showeventlog(HWND hwnd)
806 logbox = CreateDialog(hinst, MAKEINTRESOURCE(IDD_LOGBOX),
808 ShowWindow(logbox, SW_SHOWNORMAL);
810 SetActiveWindow(logbox);
813 void showabout(HWND hwnd)
815 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
818 int verify_ssh_host_key(void *frontend, char *host, int port,
819 const char *keytype, char *keystr, char *fingerprint,
820 void (*callback)(void *ctx, int result), void *ctx)
824 static const char absentmsg[] =
825 "The server's host key is not cached in the registry. You\n"
826 "have no guarantee that the server is the computer you\n"
828 "The server's %s key fingerprint is:\n"
830 "If you trust this host, hit Yes to add the key to\n"
831 "%s's cache and carry on connecting.\n"
832 "If you want to carry on connecting just once, without\n"
833 "adding the key to the cache, hit No.\n"
834 "If you do not trust this host, hit Cancel to abandon the\n"
837 static const char wrongmsg[] =
838 "WARNING - POTENTIAL SECURITY BREACH!\n"
840 "The server's host key does not match the one %s has\n"
841 "cached in the registry. This means that either the\n"
842 "server administrator has changed the host key, or you\n"
843 "have actually connected to another computer pretending\n"
844 "to be the server.\n"
845 "The new %s key fingerprint is:\n"
847 "If you were expecting this change and trust the new key,\n"
848 "hit Yes to update %s's cache and continue connecting.\n"
849 "If you want to carry on connecting but without updating\n"
850 "the cache, hit No.\n"
851 "If you want to abandon the connection completely, hit\n"
852 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n" "choice.\n";
854 static const char mbtitle[] = "%s Security Alert";
857 * Verify the key against the registry.
859 ret = verify_host_key(host, port, keytype, keystr);
861 if (ret == 0) /* success - key matched OK */
863 else if (ret == 2) { /* key was different */
865 char *text = dupprintf(wrongmsg, appname, keytype, fingerprint,
867 char *caption = dupprintf(mbtitle, appname);
868 mbret = message_box(text, caption,
869 MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3,
870 HELPCTXID(errors_hostkey_changed));
871 assert(mbret==IDYES || mbret==IDNO || mbret==IDCANCEL);
874 if (mbret == IDYES) {
875 store_host_key(host, port, keytype, keystr);
877 } else if (mbret == IDNO)
879 } else if (ret == 1) { /* key was absent */
881 char *text = dupprintf(absentmsg, keytype, fingerprint, appname);
882 char *caption = dupprintf(mbtitle, appname);
883 mbret = message_box(text, caption,
884 MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3,
885 HELPCTXID(errors_hostkey_absent));
886 assert(mbret==IDYES || mbret==IDNO || mbret==IDCANCEL);
889 if (mbret == IDYES) {
890 store_host_key(host, port, keytype, keystr);
892 } else if (mbret == IDNO)
895 return 0; /* abandon the connection */
899 * Ask whether the selected algorithm is acceptable (since it was
900 * below the configured 'warn' threshold).
902 int askalg(void *frontend, const char *algtype, const char *algname,
903 void (*callback)(void *ctx, int result), void *ctx)
905 static const char mbtitle[] = "%s Security Alert";
906 static const char msg[] =
907 "The first %s supported by the server\n"
908 "is %.64s, which is below the configured\n"
909 "warning threshold.\n"
910 "Do you want to continue with this connection?\n";
911 char *message, *title;
914 message = dupprintf(msg, algtype, algname);
915 title = dupprintf(mbtitle, appname);
916 mbret = MessageBox(NULL, message, title,
917 MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
918 socket_reselect_all();
928 * Ask whether to wipe a session log file before writing to it.
929 * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
931 int askappend(void *frontend, Filename *filename,
932 void (*callback)(void *ctx, int result), void *ctx)
934 static const char msgtemplate[] =
935 "The session log file \"%.*s\" already exists.\n"
936 "You can overwrite it with a new session log,\n"
937 "append your session log to the end of it,\n"
938 "or disable session logging for this session.\n"
939 "Hit Yes to wipe the file, No to append to it,\n"
940 "or Cancel to disable logging.";
945 message = dupprintf(msgtemplate, FILENAME_MAX, filename->path);
946 mbtitle = dupprintf("%s Log to File", appname);
948 mbret = MessageBox(NULL, message, mbtitle,
949 MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON3);
951 socket_reselect_all();
958 else if (mbret == IDNO)
965 * Warn about the obsolescent key file format.
967 * Uniquely among these functions, this one does _not_ expect a
968 * frontend handle. This means that if PuTTY is ported to a
969 * platform which requires frontend handles, this function will be
970 * an anomaly. Fortunately, the problem it addresses will not have
971 * been present on that platform, so it can plausibly be
972 * implemented as an empty function.
974 void old_keyfile_warning(void)
976 static const char mbtitle[] = "%s Key File Warning";
977 static const char message[] =
978 "You are loading an SSH-2 private key which has an\n"
979 "old version of the file format. This means your key\n"
980 "file is not fully tamperproof. Future versions of\n"
981 "%s may stop supporting this private key format,\n"
982 "so we recommend you convert your key to the new\n"
985 "You can perform this conversion by loading the key\n"
986 "into PuTTYgen and then saving it again.";
989 msg = dupprintf(message, appname);
990 title = dupprintf(mbtitle, appname);
992 MessageBox(NULL, msg, title, MB_OK);
994 socket_reselect_all();