+/*
+ * windlg.c - dialogs for PuTTY(tel), including the configuration dialog.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "win_res.h"
#include "storage.h"
#include "dialog.h"
+#include "licence.h"
#include <commctrl.h>
#include <commdlg.h>
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)"
char *str = dupprintf("%s Licence", appname);
SetWindowText(hwnd, str);
sfree(str);
+ SetDlgItemText(hwnd, IDA_TEXT, LICENCE_TEXT("\r\n\r\n"));
}
return 1;
case WM_COMMAND:
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 " SHORT_COPYRIGHT_DETAILS ". All rights reserved.");
+ SetDlgItemText(hwnd, IDA_TEXT, text);
+ sfree(text);
+ }
return 1;
case WM_COMMAND:
switch (LOWORD(wParam)) {
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.
*/
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;
/*
* 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)
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)));
/*
HTREEITEM hfirst = NULL;
int i;
char *path = NULL;
+ char *firstpath = NULL;
for (i = 0; i < ctrlbox->nctrlsets; i++) {
struct controlset *s = ctrlbox->ctrlsets[i];
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 */
}
/*
}
}
- 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:
/*
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);
/*
* 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);
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;
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)
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);
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);
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);
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,
dp_cleanup(&dp);
if (!ret)
- cfg = backup_cfg; /* structure copy */
+ conf_copy_into(conf, backup_conf);
+
+ conf_free(backup_conf);
return ret;
}
DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
}
-/* Helper function for verify_ssh_host_key(). */
-static VOID CALLBACK verify_ssh_host_key_help(LPHELPINFO lpHelpInfo)
-{
- if (help_path) {
- char *context = NULL;
-#define CHECK_CTX(name) \
- do { \
- if (lpHelpInfo->dwContextId == WINHELP_CTXID_ ## name) \
- context = WINHELP_CTX_ ## name; \
- } while (0)
- CHECK_CTX(errors_hostkey_absent);
- CHECK_CTX(errors_hostkey_changed);
-#undef CHECK_CTX
- if (context) {
- char *cmd = dupprintf("JI(`',`%s')", context);
- WinHelp(hwnd, help_path, HELP_COMMAND, (DWORD)cmd);
- sfree(cmd);
- requested_help = TRUE;
- }
- }
-}
-
-int 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;
static const char mbtitle[] = "%s Security Alert";
- UINT help_button = 0;
- MSGBOXPARAMS mbox;
-
- /*
- * We use MessageBoxIndirect() because it allows us to specify a
- * callback function for the Help button.
- */
- mbox.cbSize = sizeof(mbox);
- mbox.hwndOwner = hwnd;
- mbox.lpfnMsgBoxCallback = &verify_ssh_host_key_help;
- mbox.dwLanguageId = LANG_NEUTRAL;
-
- /* Do we have a help file? */
- if (help_path)
- help_button = MB_HELP;
-
/*
* Verify the key against the registry.
*/
if (ret == 0) /* success - key matched OK */
return 1;
- if (ret == 2) { /* key was different */
+ else if (ret == 2) { /* key was different */
int mbret;
- mbox.lpszText = dupprintf(wrongmsg, appname, keytype, fingerprint,
- appname);
- mbox.lpszCaption = dupprintf(mbtitle, appname);
- mbox.dwContextHelpId = HELPCTXID(errors_hostkey_changed);
- mbox.dwStyle = MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3 |
- help_button;
- mbret = MessageBoxIndirect(&mbox);
- sfree((void *)mbox.lpszText);
- sfree((void *)mbox.lpszCaption);
- 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)
- return 0;
- return 1;
- }
- if (ret == 1) { /* key was absent */
+ return 1;
+ } else if (mbret == IDNO)
+ return 1;
+ } else if (ret == 1) { /* key was absent */
int mbret;
- mbox.lpszText = dupprintf(absentmsg, keytype, fingerprint, appname);
- mbox.lpszCaption = dupprintf(mbtitle, appname);
- mbox.dwContextHelpId = HELPCTXID(errors_hostkey_absent);
- mbox.dwStyle = MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3 |
- help_button;
- mbret = MessageBoxIndirect(&mbox);
- sfree((void *)mbox.lpszText);
- sfree((void *)mbox.lpszCaption);
- 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)
- return 0;
- return 1;
+ return 1;
+ } else if (mbret == IDNO)
+ return 1;
}
+ return 0; /* abandon the connection */
}
/*
title = dupprintf(mbtitle, appname);
mbret = MessageBox(NULL, message, title,
MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
+ socket_reselect_all();
sfree(message);
sfree(title);
if (mbret == IDYES)
* 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[] =
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_DEFBUTTON3);
+ socket_reselect_all();
+
sfree(message);
sfree(mbtitle);
{
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"
MessageBox(NULL, msg, title, MB_OK);
+ socket_reselect_all();
+
sfree(msg);
sfree(title);
}