X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/7c7f68933f946bc20ddc5842b7c61d82fd7ebce7..9d07b2dbb00ae3ad178ec06d560ba54c1ad08b87:/puttygen.c diff --git a/puttygen.c b/puttygen.c index 4ac0fef9..be7a2b90 100644 --- a/puttygen.c +++ b/puttygen.c @@ -18,6 +18,8 @@ #define DEFAULT_KEYSIZE 1024 +static int requested_help; + /* ---------------------------------------------------------------------- * Progress report code. This is really horrible :-) */ @@ -330,6 +332,7 @@ struct MainDlgState { unsigned *entropy; struct RSAKey key; struct dss_key dsskey; + HMENU filemenu, keymenu, exportmenu; }; static void hidemany(HWND hwnd, const int *ids, int hideit) @@ -406,6 +409,26 @@ static int save_ssh1_pubkey(char *filename, struct RSAKey *key) return 1; } +/* + * Warn about the obsolescent key file format. + */ +void old_keyfile_warning(void) +{ + static const char mbtitle[] = "PuTTY Key File Warning"; + static const char message[] = + "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" + "PuTTY may stop supporting this private key format,\n" + "so we recommend you convert your key to the new\n" + "format.\n" + "\n" + "Once the key is loaded into PuTTYgen, you can perform\n" + "this conversion simply by saving it again."; + + MessageBox(NULL, message, mbtitle, MB_OK); +} + static int save_ssh2_pubkey(char *filename, struct ssh2_userkey *key) { unsigned char *pub_blob; @@ -453,43 +476,138 @@ static int save_ssh2_pubkey(char *filename, struct ssh2_userkey *key) return 1; } +enum { + controlidstart = 100, + IDC_QUIT, + IDC_TITLE, + IDC_BOX_KEY, + IDC_NOKEY, + IDC_GENERATING, + IDC_PROGRESS, + IDC_PKSTATIC, IDC_KEYDISPLAY, + IDC_FPSTATIC, IDC_FINGERPRINT, + IDC_COMMENTSTATIC, IDC_COMMENTEDIT, + IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT, + IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, + IDC_BOX_ACTIONS, + IDC_GENSTATIC, IDC_GENERATE, + IDC_LOADSTATIC, IDC_LOAD, + IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB, + IDC_BOX_PARAMS, + IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA, + IDC_BITSSTATIC, IDC_BITS, + IDC_ABOUT, + IDC_GIVEHELP, + IDC_IMPORT, IDC_EXPORT_OPENSSH, IDC_EXPORT_SSHCOM +}; + +static const int nokey_ids[] = { IDC_NOKEY, 0 }; +static const int generating_ids[] = { IDC_GENERATING, IDC_PROGRESS, 0 }; +static const int gotkey_ids[] = { + IDC_PKSTATIC, IDC_KEYDISPLAY, + IDC_FPSTATIC, IDC_FINGERPRINT, + IDC_COMMENTSTATIC, IDC_COMMENTEDIT, + IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT, + IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 0 +}; + +/* + * Small UI helper function to switch the state of the main dialog + * by enabling and disabling controls and menu items. + */ +void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) +{ + int type; + + switch (status) { + case 0: /* no key */ + hidemany(hwnd, nokey_ids, FALSE); + hidemany(hwnd, generating_ids, TRUE); + hidemany(hwnd, gotkey_ids, TRUE); + EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1); + EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1); + EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0); + EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1); + EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1); + EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->exportmenu, IDC_EXPORT_OPENSSH, + MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->exportmenu, IDC_EXPORT_SSHCOM, + MF_GRAYED|MF_BYCOMMAND); + break; + case 1: /* generating key */ + hidemany(hwnd, nokey_ids, TRUE); + hidemany(hwnd, generating_ids, FALSE); + hidemany(hwnd, gotkey_ids, TRUE); + EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0); + EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0); + EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0); + EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0); + EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0); + EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_GENERATE, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->exportmenu, IDC_EXPORT_OPENSSH, + MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->exportmenu, IDC_EXPORT_SSHCOM, + MF_GRAYED|MF_BYCOMMAND); + break; + case 2: + hidemany(hwnd, nokey_ids, TRUE); + hidemany(hwnd, generating_ids, TRUE); + hidemany(hwnd, gotkey_ids, FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1); + EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1); + EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1); + EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1); + EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1); + EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA,MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND); + /* + * Enable export menu items if and only if the key type + * supports this kind of export. + */ + type = state->ssh2 ? SSH_KEYTYPE_SSH2 : SSH_KEYTYPE_SSH1; +#define do_export_menuitem(x,y) \ + EnableMenuItem(state->exportmenu, x, MF_BYCOMMAND | \ + (import_target_type(y)==type?MF_ENABLED:MF_GRAYED)) + do_export_menuitem(IDC_EXPORT_OPENSSH, SSH_KEYTYPE_OPENSSH); + do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM); +#undef do_export_menuitem + break; + } +} + /* * Dialog-box function for the main PuTTYgen dialog box. */ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - enum { - controlidstart = 100, - IDC_TITLE, - IDC_BOX_KEY, - IDC_NOKEY, - IDC_GENERATING, - IDC_PROGRESS, - IDC_PKSTATIC, IDC_KEYDISPLAY, - IDC_FPSTATIC, IDC_FINGERPRINT, - IDC_COMMENTSTATIC, IDC_COMMENTEDIT, - IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT, - IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, - IDC_BOX_ACTIONS, - IDC_GENSTATIC, IDC_GENERATE, - IDC_LOADSTATIC, IDC_LOAD, - IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB, - IDC_BOX_PARAMS, - IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA, - IDC_BITSSTATIC, IDC_BITS, - IDC_ABOUT, - }; - static const int nokey_ids[] = { IDC_NOKEY, 0 }; - static const int generating_ids[] = - { IDC_GENERATING, IDC_PROGRESS, 0 }; - static const int gotkey_ids[] = { - IDC_PKSTATIC, IDC_KEYDISPLAY, - IDC_FPSTATIC, IDC_FINGERPRINT, - IDC_COMMENTSTATIC, IDC_COMMENTEDIT, - IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT, - IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 0 - }; static const char generating_msg[] = "Please wait while a key is generated..."; static const char entropy_msg[] = @@ -498,6 +616,64 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, switch (msg) { case WM_INITDIALOG: + if (help_path) + SetWindowLong(hwnd, GWL_EXSTYLE, + GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_CONTEXTHELP); + else { + /* + * If we add a Help button, this is where we destroy it + * if the help file isn't present. + */ + } + requested_help = FALSE; + + state = smalloc(sizeof(*state)); + state->generation_thread_exists = FALSE; + state->collecting_entropy = FALSE; + state->entropy = NULL; + state->key_exists = FALSE; + SetWindowLong(hwnd, GWL_USERDATA, (LONG) state); + { + HMENU menu, menu1; + + menu = CreateMenu(); + + menu1 = CreateMenu(); + AppendMenu(menu1, MF_ENABLED, IDC_LOAD, "&Load private key"); + AppendMenu(menu1, MF_ENABLED, IDC_SAVEPUB, "Save p&ublic key"); + AppendMenu(menu1, MF_ENABLED, IDC_SAVE, "&Save private key"); + AppendMenu(menu1, MF_SEPARATOR, 0, 0); + AppendMenu(menu1, MF_ENABLED, IDC_QUIT, "E&xit"); + AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&File"); + state->filemenu = menu1; + + menu1 = CreateMenu(); + AppendMenu(menu1, MF_ENABLED, IDC_GENERATE, "&Generate key pair"); + AppendMenu(menu1, MF_SEPARATOR, 0, 0); + AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH1, "SSH&1 key (RSA)"); + AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2RSA, "SSH2 &RSA key"); + AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2DSA, "SSH2 &DSA key"); + AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Key"); + state->keymenu = menu1; + + menu1 = CreateMenu(); + AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH, + "Export &OpenSSH key"); + AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM, + "Export &ssh.com key"); + AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, + "&Export"); + state->exportmenu = menu1; + + menu1 = CreateMenu(); + AppendMenu(menu1, MF_ENABLED, IDC_ABOUT, "&About"); + if (help_path) + AppendMenu(menu1, MF_ENABLED, IDC_GIVEHELP, "&Help"); + AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Help"); + + SetMenu(hwnd, menu); + } + /* * Centre the window. */ @@ -513,20 +689,12 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, rd.right - rd.left, rd.bottom - rd.top, TRUE); } - state = smalloc(sizeof(*state)); - state->generation_thread_exists = FALSE; - state->collecting_entropy = FALSE; - state->entropy = NULL; - state->key_exists = FALSE; - SetWindowLong(hwnd, GWL_USERDATA, (LONG) state); { struct ctlpos cp, cp2; /* Accelerators used: acglops1rbd */ ctlposinit(&cp, hwnd, 4, 4, 4); - bartitle(&cp, "Public and private key generation for PuTTY", - IDC_TITLE); beginbox(&cp, "Key", IDC_BOX_KEY); cp2 = cp; statictext(&cp2, "No key.", 1, IDC_NOKEY); @@ -567,6 +735,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, endbox(&cp); } CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA, IDC_KEYSSH1); + CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA, + IDC_KEYSSH1, MF_BYCOMMAND); SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE); /* @@ -575,11 +745,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, * buttons, because with no key we obviously can't save * anything. */ - hidemany(hwnd, nokey_ids, FALSE); - hidemany(hwnd, generating_ids, TRUE); - hidemany(hwnd, gotkey_ids, TRUE); - EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0); - EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0); + ui_set_state(hwnd, state, 0); return 1; case WM_MOUSEMOVE: @@ -629,6 +795,22 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, break; case WM_COMMAND: switch (LOWORD(wParam)) { + case IDC_KEYSSH1: + case IDC_KEYSSH2RSA: + case IDC_KEYSSH2DSA: + { + state = (struct MainDlgState *) + GetWindowLong(hwnd, GWL_USERDATA); + if (!IsDlgButtonChecked(hwnd, LOWORD(wParam))) + CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA, + LOWORD(wParam)); + CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA, + LOWORD(wParam), MF_BYCOMMAND); + } + break; + case IDC_QUIT: + PostMessage(hwnd, WM_CLOSE, 0, 0); + break; case IDC_COMMENTEDIT: if (HIWORD(wParam) == EN_CHANGE) { state = (struct MainDlgState *) @@ -656,6 +838,16 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, EnableWindow(hwnd, 1); SetActiveWindow(hwnd); return 0; + case IDC_GIVEHELP: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) { + if (help_path) { + WinHelp(hwnd, help_path, HELP_COMMAND, + (DWORD)"JI(`',`puttygen.general')"); + requested_help = TRUE; + } + } + return 0; case IDC_GENERATE: state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA); @@ -679,19 +871,9 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, state->keysize = 256; SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE); } - hidemany(hwnd, nokey_ids, TRUE); - hidemany(hwnd, generating_ids, FALSE); - hidemany(hwnd, gotkey_ids, TRUE); - EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0); - EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0); - EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0); - EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0); - EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0); - state->key_exists = FALSE; + ui_set_state(hwnd, state, 1); SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg); + state->key_exists = FALSE; state->collecting_entropy = TRUE; /* @@ -719,12 +901,39 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, } break; case IDC_SAVE: + case IDC_EXPORT_OPENSSH: + case IDC_EXPORT_SSHCOM: state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA); if (state->key_exists) { char filename[FILENAME_MAX]; char passphrase[PASSPHRASE_MAXLEN]; char passphrase2[PASSPHRASE_MAXLEN]; + int type, realtype; + + if (state->ssh2) + realtype = SSH_KEYTYPE_SSH2; + else + realtype = SSH_KEYTYPE_SSH1; + + if (LOWORD(wParam) == IDC_EXPORT_OPENSSH) + type = SSH_KEYTYPE_OPENSSH; + else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM) + type = SSH_KEYTYPE_SSHCOM; + else + type = realtype; + + if (type != realtype && + import_target_type(type) != realtype) { + char msg[256]; + sprintf(msg, "Cannot export an SSH%d key in an SSH%d" + " format", (state->ssh2 ? 2 : 1), + (state->ssh2 ? 1 : 2)); + MessageBox(hwnd, msg, + "PuTTYgen Error", MB_OK | MB_ICONERROR); + break; + } + GetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, passphrase, sizeof(passphrase)); GetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, @@ -759,13 +968,22 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, if (ret != IDYES) break; } + if (state->ssh2) { - ret = ssh2_save_userkey(filename, &state->ssh2key, - *passphrase ? passphrase : - NULL); + if (type != realtype) + ret = export_ssh2(filename, type, &state->ssh2key, + *passphrase ? passphrase : NULL); + else + ret = ssh2_save_userkey(filename, &state->ssh2key, + *passphrase ? passphrase : + NULL); } else { - ret = saversakey(filename, &state->key, - *passphrase ? passphrase : NULL); + if (type != realtype) + ret = export_ssh1(filename, type, &state->key, + *passphrase ? passphrase : NULL); + else + ret = saversakey(filename, &state->key, + *passphrase ? passphrase : NULL); } if (ret <= 0) { MessageBox(hwnd, "Unable to save key file", @@ -813,26 +1031,40 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, if (prompt_keyfile(hwnd, "Load private key:", filename, 0)) { char passphrase[PASSPHRASE_MAXLEN]; int needs_pass; - int ver; + int type, realtype; int ret; char *comment; struct PassphraseProcStruct pps; struct RSAKey newkey1; struct ssh2_userkey *newkey2 = NULL; - ver = keyfile_version(filename); - if (ver == 0) { - MessageBox(NULL, "Couldn't load private key.", + type = realtype = key_type(filename); + if (type != SSH_KEYTYPE_SSH1 && + type != SSH_KEYTYPE_SSH2 && + !import_possible(type)) { + char msg[256]; + sprintf(msg, "Couldn't load private key (%s)", + key_type_to_str(type)); + MessageBox(NULL, msg, "PuTTYgen Error", MB_OK | MB_ICONERROR); break; } + if (type != SSH_KEYTYPE_SSH1 && + type != SSH_KEYTYPE_SSH2) { + realtype = type; + type = import_target_type(type); + } + comment = NULL; - if (ver == 1) + if (realtype == SSH_KEYTYPE_SSH1) needs_pass = rsakey_encrypted(filename, &comment); - else + else if (realtype == SSH_KEYTYPE_SSH2) needs_pass = ssh2_userkey_encrypted(filename, &comment); + else + needs_pass = import_encrypted(filename, realtype, + &comment); pps.passphrase = passphrase; pps.comment = comment; do { @@ -848,12 +1080,20 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, } } else *passphrase = '\0'; - if (ver == 1) - ret = - loadrsakey(filename, &newkey1, passphrase); - else { - newkey2 = - ssh2_load_userkey(filename, passphrase); + if (type == SSH_KEYTYPE_SSH1) { + if (realtype == type) + ret = loadrsakey(filename, &newkey1, + passphrase); + else + ret = import_ssh1(filename, realtype, + &newkey1, passphrase); + } else { + if (realtype == type) + newkey2 = ssh2_load_userkey(filename, + passphrase); + else + newkey2 = import_ssh2(filename, realtype, + passphrase); if (newkey2 == SSH2_WRONG_PASSPHRASE) ret = -1; else if (!newkey2) @@ -868,14 +1108,6 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, MessageBox(NULL, "Couldn't load private key.", "PuTTYgen Error", MB_OK | MB_ICONERROR); } else if (ret == 1) { - EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1); - EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1); - EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1); - EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1); - EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1); /* * Now update the key controls with all the * key data. @@ -885,7 +1117,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, passphrase); SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, passphrase); - if (ver == 1) { + if (type == SSH_KEYTYPE_SSH1) { char buf[128]; char *savecomment; @@ -940,9 +1172,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, * Finally, hide the progress bar and show * the key data. */ - hidemany(hwnd, nokey_ids, TRUE); - hidemany(hwnd, generating_ids, TRUE); - hidemany(hwnd, gotkey_ids, FALSE); + ui_set_state(hwnd, state, 2); state->key_exists = TRUE; } } @@ -957,14 +1187,6 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESSRANGE)); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0); - EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1); - EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1); - EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1); - EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1); - EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1); - EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1); if (state->ssh2) { if (state->is_dsa) { state->ssh2key.data = &state->dsskey; @@ -1043,23 +1265,100 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, /* * Finally, hide the progress bar and show the key data. */ - hidemany(hwnd, nokey_ids, TRUE); - hidemany(hwnd, generating_ids, TRUE); - hidemany(hwnd, gotkey_ids, FALSE); + ui_set_state(hwnd, state, 2); break; + case WM_HELP: + if (help_path) { + int id = ((LPHELPINFO)lParam)->iCtrlId; + char *cmd = NULL; + switch (id) { + case IDC_GENERATING: + case IDC_PROGRESS: + case IDC_GENSTATIC: + case IDC_GENERATE: + cmd = "JI(`',`puttygen.generate')"; break; + case IDC_PKSTATIC: + case IDC_KEYDISPLAY: + cmd = "JI(`',`puttygen.pastekey')"; break; + case IDC_FPSTATIC: + case IDC_FINGERPRINT: + cmd = "JI(`',`puttygen.fingerprint')"; break; + case IDC_COMMENTSTATIC: + case IDC_COMMENTEDIT: + cmd = "JI(`',`puttygen.comment')"; break; + case IDC_PASSPHRASE1STATIC: + case IDC_PASSPHRASE1EDIT: + case IDC_PASSPHRASE2STATIC: + case IDC_PASSPHRASE2EDIT: + cmd = "JI(`',`puttygen.passphrase')"; break; + case IDC_LOADSTATIC: + case IDC_LOAD: + cmd = "JI(`',`puttygen.load')"; break; + case IDC_SAVESTATIC: + case IDC_SAVE: + cmd = "JI(`',`puttygen.savepriv')"; break; + case IDC_SAVEPUB: + cmd = "JI(`',`puttygen.savepub')"; break; + case IDC_TYPESTATIC: + case IDC_KEYSSH1: + case IDC_KEYSSH2RSA: + case IDC_KEYSSH2DSA: + cmd = "JI(`',`puttygen.keytype')"; break; + case IDC_BITSSTATIC: + case IDC_BITS: + cmd = "JI(`',`puttygen.bits')"; break; + case IDC_EXPORT_OPENSSH: + case IDC_EXPORT_SSHCOM: + cmd = "JI(`',`puttygen.export')"; break; + } + if (cmd) { + WinHelp(hwnd, help_path, HELP_COMMAND, (DWORD)cmd); + requested_help = TRUE; + } else { + MessageBeep(0); + } + } + break; case WM_CLOSE: state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA); sfree(state); + if (requested_help) { + WinHelp(hwnd, help_path, HELP_QUIT, 0); + requested_help = FALSE; + } EndDialog(hwnd, 1); return 0; } return 0; } +void cleanup_exit(int code) { exit(code); } + int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { InitCommonControls(); hinst = inst; + + /* + * See if we can find our Help file. + */ + { + char b[2048], *p, *q, *r; + FILE *fp; + GetModuleFileName(NULL, b, sizeof(b) - 1); + r = b; + p = strrchr(b, '\\'); + if (p && p >= r) r = p+1; + q = strrchr(b, ':'); + if (q && q >= r) r = q+1; + strcpy(r, "putty.hlp"); + if ( (fp = fopen(b, "r")) != NULL) { + help_path = dupstr(b); + fclose(fp); + } else + help_path = NULL; + } + random_init(); return DialogBox(hinst, MAKEINTRESOURCE(201), NULL, MainDlgProc) != IDOK;