/* * Update the visible key list. */ void keylist_update(void) { struct RSAKey *rkey; struct ssh2_userkey *skey; int i; if (keylist) { SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0); for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) { char listentry[512], *p; /* * Replace two spaces in the fingerprint with tabs, for * nice alignment in the box. */ strcpy(listentry, "ssh1\t"); p = listentry + strlen(listentry); rsa_fingerprint(p, sizeof(listentry) - (p - listentry), rkey); p = strchr(listentry, ' '); if (p) *p = '\t'; p = strchr(listentry, ' '); if (p) *p = '\t'; SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); } for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) { char *listentry, *p; int pos; /* * Replace spaces with tabs in the fingerprint prefix, for * nice alignment in the list box, until we encounter a : * meaning we're into the fingerprint proper. */ p = ssh2_fingerprint(skey->alg, skey->data); listentry = dupprintf("%s\t%s", p, skey->comment); sfree(p); pos = 0; while (1) { pos += strcspn(listentry + pos, " :"); if (listentry[pos] == ':' || !listentry[pos]) break; listentry[pos++] = '\t'; } SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); sfree(listentry); } SendDlgItemMessage(keylist, 100, LB_SETCURSEL, (WPARAM) - 1, 0); } }
/* * Dialog-box function for the key list box. */ static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { struct RSAKey *rkey; struct ssh2_userkey *skey; switch (msg) { case WM_INITDIALOG: /* * Centre the window. */ { /* centre the window */ RECT rs, rd; HWND hw; hw = GetDesktopWindow(); if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd)) MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, rd.right - rd.left, rd.bottom - rd.top, TRUE); } if (has_help()) SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_CONTEXTHELP); else { HWND item = GetDlgItem(hwnd, 103); /* the Help button */ if (item) DestroyWindow(item); } keylist = hwnd; { static int tabs[] = {35, 75, 250}; SendDlgItemMessage(hwnd, 100, LB_SETTABSTOPS, sizeof(tabs) / sizeof(*tabs), (LPARAM)tabs); } keylist_update(); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: keylist = NULL; DestroyWindow(hwnd); return 0; case 101: /* add key */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { if (passphrase_box) { MessageBeep(MB_ICONERROR); SetForegroundWindow(passphrase_box); break; } prompt_add_keyfile(); } return 0; case 102: /* remove key */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { int i; int rCount, sCount; int *selectedArray; /* our counter within the array of selected items */ int itemNum; /* get the number of items selected in the list */ int numSelected = SendDlgItemMessage(hwnd, 100, LB_GETSELCOUNT, 0, 0); /* none selected? that was silly */ if (numSelected == 0) { MessageBeep(0); break; } /* get item indices in an array */ selectedArray = snewn(numSelected, int); SendDlgItemMessage( hwnd, 100, LB_GETSELITEMS, numSelected, (WPARAM)selectedArray); itemNum = numSelected - 1; rCount = pageant_count_ssh1_keys(); sCount = pageant_count_ssh2_keys(); /* go through the non-rsakeys until we've covered them all, * and/or we're out of selected items to check. note that * we go *backwards*, to avoid complications from deleting * things hence altering the offset of subsequent items */ for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) { skey = pageant_nth_ssh2_key(i); if (selectedArray[itemNum] == rCount + i) { pageant_delete_ssh2_key(skey); skey->alg->freekey(skey->data); sfree(skey); itemNum--; } } /* do the same for the rsa keys */ for (i = rCount - 1; (itemNum >= 0) && (i >= 0); i--) { rkey = pageant_nth_ssh1_key(i); if (selectedArray[itemNum] == i) { pageant_delete_ssh1_key(rkey); freersakey(rkey); sfree(rkey); itemNum--; } } sfree(selectedArray); keylist_update(); } return 0; case 103: /* help */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { launch_help(hwnd, WINHELP_CTX_pageant_general); } return 0; } return 0; case WM_HELP: { int id = ((LPHELPINFO)lParam)->iCtrlId; const char *topic = NULL; switch (id) { case 100: topic = WINHELP_CTX_pageant_keylist; break; case 101: topic = WINHELP_CTX_pageant_addkey; break; case 102: topic = WINHELP_CTX_pageant_remkey; break; } if (topic) { launch_help(hwnd, topic); } else { MessageBeep(0); } } break; case WM_CLOSE: keylist = NULL; DestroyWindow(hwnd); return 0; }
/* * Update the visible key list. */ void keylist_update(void) { struct RSAKey *rkey; struct ssh2_userkey *skey; int i; if (keylist) { SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0); for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) { char listentry[512], *p; /* * Replace two spaces in the fingerprint with tabs, for * nice alignment in the box. */ strcpy(listentry, "ssh1\t"); p = listentry + strlen(listentry); rsa_fingerprint(p, sizeof(listentry) - (p - listentry), rkey); p = strchr(listentry, ' '); if (p) *p = '\t'; p = strchr(listentry, ' '); if (p) *p = '\t'; SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM)listentry); } for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) { char *listentry, *p; int pos; /* * For nice alignment in the list box, we would ideally * want every entry to align to the tab stop settings, and * have a column for algorithm name, one for bit count, * one for hex fingerprint, and one for key comment. * * Unfortunately, some of the algorithm names are so long * that they overflow into the bit-count field. * Fortunately, at the moment, those are _precisely_ the * algorithm names that don't need a bit count displayed * anyway (because for NIST-style ECDSA the bit count is * mentioned in the algorithm name, and for ssh-ed25519 * there is only one possible value anyway). So we fudge * this by simply omitting the bit count field in that * situation. * * This is fragile not only in the face of further key * types that don't follow this pattern, but also in the * face of font metrics changes - the Windows semantics * for list box tab stops is that \t aligns to the next * one you haven't already exceeded, so I have to guess * when the key type will overflow past the bit-count tab * stop and leave out a tab character. Urgh. */ p = ssh2_fingerprint(skey->alg, skey->data); listentry = dupprintf("%s\t%s", p, skey->comment); sfree(p); pos = 0; while (1) { pos += strcspn(listentry + pos, " :"); if (listentry[pos] == ':' || !listentry[pos]) break; listentry[pos++] = '\t'; } if (skey->alg != &ssh_dss && skey->alg != &ssh_rsa) { /* * Remove the bit-count field, which is between the * first and second \t. */ int outpos; pos = 0; while (listentry[pos] && listentry[pos] != '\t') pos++; outpos = pos; pos++; while (listentry[pos] && listentry[pos] != '\t') pos++; while (1) { if ((listentry[outpos] = listentry[pos]) == '\0') break; outpos++; pos++; } } SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM)listentry); sfree(listentry); } SendDlgItemMessage(keylist, 100, LB_SETCURSEL, (WPARAM)-1, 0); } }