--- trunk/Src/wptKeylist.cpp 2005/11/08 07:15:13 73 +++ trunk/Src/wptKeylist.cpp 2012/04/07 11:55:16 428 @@ -1,5 +1,5 @@ /* wptKeylist.cpp - Keylist element - * Copyright (C) 2001-2005 Timo Schulz + * Copyright (C) 2001-2006, 2009 Timo Schulz * Copyright (C) 2004 Andreas Jobs * * This file is part of WinPT. @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with WinPT; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include @@ -37,78 +33,112 @@ #include "wptUTF8.h" #include "wptRegistry.h" #include "wptContext.h" +#include "wptVersion.h" +#include "resource.h" +#include "StringBuffer.h" -#define key_is_useable(key) (!(key)->revoked && !(key)->expired && !(key)->disabled) - -static struct listview_column_s klist_enc[] = { - {0, 242, (char *)_("User ID")}, - {1, 80, (char *)_("Key ID")}, - {3, 46, (char *)_("Size")}, - {4, 50, (char *)_("Cipher")}, - {5, 70, (char *)_("Validity")}, - {0, 0, NULL} -}; -#define KLIST_ENC_ITEMS (DIM(klist_enc) -1) - -static struct listview_column_s klist[] = { - {0, 242, (char *)_("User ID")}, - {1, 78, (char *)_("Key ID")}, - {2, 52, (char *)_("Type")}, - {3, 68, (char *)_("Size")}, - {4, 66, (char *)_("Cipher")}, - {5, 70, (char *)_("Validity")}, - {6, 40, (char *)_("Trust")}, - {7, 72, (char *)_("Creation")}, - {0, 0, NULL} -}; -#define KLIST_ITEMS (DIM(klist) - 1) - struct key_array_s { char keyid[32]; - int checked; + int checked; }; -static int find_secret_key (gpgme_key_t key); - static key_array_s* -key_array_new( size_t items ) +key_array_new (DWORD items) { key_array_s *ka; - size_t j; - if( items == 0 ) - return NULL; + if (items == 0) + BUG (NULL); ka = new key_array_s[items + 1]; - if( ka == NULL ) - return NULL; - for ( j = 0; j < items; j++ ) - ka[j].checked = 0; + if (!ka) + BUG (NULL); + for (DWORD i = 0; i < items; i++) + ka[i].checked = 0; return ka; -} /* key_array_new */ - +} static void -key_array_release( key_array_s *ka ) +key_array_release (key_array_s *ka) { - free_if_alloc( ka ); -} /* key_array_release */ + free_if_alloc (ka); +} +/* Check if the keyid @keyid is in the key array @ka. + Return value: 1 if it exists, 0 otherwise. */ static int -key_array_search( key_array_s *ka, size_t items, const char *keyid ) +key_array_search (key_array_s *ka, DWORD items, const char *keyid) { - size_t j; - - /* fixme: we need a faster search method */ - for( j = 0; j < items; j++ ) { - if( !strcmp( keyid, ka[j].keyid ) ) + for (DWORD i = 0; i < items; i++) { + if (!stricmp (keyid, ka[i].keyid)) return 1; } - return 0; -} /* key_array_search */ +} + + +/* Return if there is a secret for @key. + 0 means success. */ +static int +find_secret_key (gpgme_key_t key) +{ + winpt_key_s skey; + + if (!key->subkeys->keyid) + return 0; + memset (&skey, 0, sizeof (skey)); + if (winpt_get_seckey (key->subkeys->keyid, &skey)) + return 0; + if (skey.ext && skey.ext->gloflags.divert_to_card) + return 2; + return skey.ctx? 1 : 0; +} + + +/* Update the gpgme key pointer of a single entry. */ +static void +update_key (keylist_ctrl_t kl, int pos, + gpgme_key_t key) +{ + if ((size_t)pos > kl->nkeys) + BUG (0); + kl->keys[pos] = key; +} + + +/* If @re_sorted == 0, then all keys from the key list control + are stored as references in the array. + Otherwise we just re-order the references in the array. */ +static size_t +update_keys (keylist_ctrl_t kl, int re_sorted, + gpgme_key_t **r_list) +{ + gpgme_key_t *rset; + gpgme_key_t key; + listview_ctrl_t lv = kl->lv; + struct keycache_s *c; + size_t k_pos; + int nkeys; + + nkeys = listview_count_items (lv, 0); + if (!nkeys) + BUG (0); + + if (!re_sorted) { + rset = (gpgme_key_t*)calloc (nkeys+1, sizeof (gpgme_key_t)); + *r_list = rset; + } + else + rset = *r_list; + k_pos = 0; + for (int i = 0; i < nkeys; i++) { + key = km_get_key_ptr (kl, i, &c); + rset[k_pos++] = key; + } + return k_pos; +} gpgme_user_id_t @@ -173,17 +203,23 @@ } +/* Return the self signature of the key @keyid. + If first is set, the first self sig will be returned. */ gpgme_key_sig_t -get_selfsig (gpgme_user_id_t uid, const char *keyid, int first) +get_selfsig (gpgme_key_sig_t sigs, const char *keyid, int first) { gpgme_key_sig_t s, self_sig=NULL; long timestamp=0; + int off = 0; - for (s = uid->signatures; s; s = s->next) { - if (!strcmp (s->keyid+8, keyid) && s->timestamp > timestamp) { + if (strlen (keyid) == 8) + off = 8; + + for (s = sigs; s; s = s->next) { + if (!strcmp (s->keyid+off, keyid) && s->timestamp > timestamp) { self_sig = s; timestamp = s->timestamp; - if (first) + if (first) /* do not search for later self sigs. */ break; } } @@ -191,7 +227,6 @@ } - const char* get_key_algo (gpgme_key_t key, int keyidx) { @@ -199,39 +234,46 @@ gpgme_subkey_t k; char alg[32]; const char *subalg; - int n=0; + int n; if (keyidx > 0) { k = get_nth_key (key, keyidx-1); subalg = get_key_pubalgo (k->pubkey_algo); - _snprintf( algo_id, DIM (algo_id)-1, "%s", subalg); + _snprintf (algo_id, DIM (algo_id)-1, "%s", subalg); return algo_id; } strcpy (alg, get_key_pubalgo (key->subkeys->pubkey_algo)); n = count_subkeys (key); if (n > 1) { - k = get_nth_key (key, n-1); + do { + k = get_nth_key (key, --n); + if (k->revoked || k->expired) + continue; + else + break; + } while (n > 0); subalg = get_key_pubalgo (k->pubkey_algo); - _snprintf (algo_id, DIM (algo_id)-1, "%s/%s", alg, subalg); + if (k == key->subkeys) + _snprintf (algo_id, DIM (algo_id)-1, "%s", subalg); + else + _snprintf (algo_id, DIM (algo_id)-1, "%s/%s", alg, subalg); return algo_id; } return get_key_pubalgo (key->subkeys->pubkey_algo); -} /* get_key_algo */ +} const char* get_key_created (long timestamp) { - static char timebuf[128]; - struct tm *warp; + static char timebuf[128]; - if (timestamp == 0 || timestamp == -1) + if (timestamp < 1) + return "????" "-??" "-??"; + if (!get_locale_date (timestamp, timebuf, DIM (timebuf)-1)) return "????" "-??" "-??"; - warp = localtime( ×tamp ); - _snprintf( timebuf, sizeof timebuf - 1, "%04d-%02d-%02d", - warp->tm_year + 1900, warp->tm_mon + 1, warp->tm_mday ); return timebuf; -} /* get_key_created */ +} /* Return a string presentation of the time @timestamp. */ @@ -239,13 +281,11 @@ get_key_expire_date (long timestamp) { static char timebuf[64]; - struct tm *warp; - if( !timestamp ) + if (timestamp == 0) return _("Never"); - warp = localtime( ×tamp ); - _snprintf (timebuf, sizeof timebuf -1, "%04d-%02d-%02d", - warp->tm_year + 1900, warp->tm_mon + 1, warp->tm_mday); + if (!get_locale_date (timestamp, timebuf, DIM (timebuf)-1)) + return "????" "-??" "-??"; return timebuf; } @@ -260,7 +300,7 @@ else if (type == 2) return _("Key Pair (Card)"); return _("Public Key"); -} /* get_key_type */ +} const char* @@ -281,12 +321,26 @@ if (n > 1) { k = get_nth_key (key, n-1); size_sub = k->length; - _snprintf( size_id, sizeof (size_id) - 1, "%d/%d", size_main, size_sub ); + _snprintf (size_id, DIM (size_id) - 1, "%d/%d", + size_main, size_sub); return size_id; } - _snprintf( size_id, sizeof (size_id) - 1, "%d", size_main ); + _snprintf (size_id, DIM (size_id) - 1, "%d", size_main); return size_id; -} /* get_key_size */ +} + + +const char* +get_key_pubalgo2 (gpgme_pubkey_algo_t alg) +{ + switch (alg) { + case GPGME_PK_DSA: return "D"; + case GPGME_PK_RSA: return "R"; + case GPGME_PK_ELG: return "G"; + default: return "?"; + } + return "?"; +} const char* @@ -296,19 +350,23 @@ case GPGME_PK_DSA: return "DSA"; case GPGME_PK_ELG: case GPGME_PK_ELG_E: return "ELG"; - case GPGME_PK_RSA: return "RSA"; + case 0: /* XXX: do we still need this?? */ + case GPGME_PK_RSA: + case GPGME_PK_RSA_S: + case GPGME_PK_RSA_E: return "RSA"; default: return "???"; } return "???"; } -const char * + +const char* get_key_fpr (gpgme_key_t key) { static char fpr_md[64]; const char *fpr; char t[16], tmp[40]; - size_t i=0; + size_t i; memset (fpr_md, 0, sizeof (fpr_md)); fpr = key->subkeys->fpr; @@ -331,10 +389,29 @@ } } return fpr_md; -} /* get_key_fpr */ +} -const char * +/* Extract the key ID from the fingerprint. + A long ID will be converted into a short ID. */ +const char* +get_keyid_from_fpr (const char *fpr) +{ + if (!fpr) + return "????????"; + if (strlen (fpr) == 40) + fpr += 32; + else if (strlen (fpr) == 32) + fpr += 24; + else if (strlen (fpr) == 16) + fpr += 8; + else + return "????????"; + return fpr; +} + + +const char* get_key_trust2 (gpgme_key_t key, int val, int uididx, int listmode) { if (key) @@ -342,27 +419,28 @@ switch (val) { case GPGME_VALIDITY_UNKNOWN: case GPGME_VALIDITY_UNDEFINED: - return "None"; + return _("None"); case GPGME_VALIDITY_NEVER: - return "Never"; + return _("Never"); case GPGME_VALIDITY_MARGINAL: - return "Marginal"; + return _("Marginal"); case GPGME_VALIDITY_FULL: + return _("Full"); case GPGME_VALIDITY_ULTIMATE: - return "Full"; + return _("Ultimate"); } return ""; } -const char * +const char* get_key_trust (gpgme_key_t key, int uididx, int listmode) { return get_key_trust2 (key, 0, uididx, listmode); } -const char * +const char* get_key_trust_str (int val) { return get_key_trust2 (NULL, val, 0, 0); @@ -380,19 +458,17 @@ if (uididx < 0 || count_userids (key) > uididx) uididx = 0; if (listmode) { - const char *s; - + const char *s; if (key->revoked) s = _("Revoked"); else if (key->expired) s = _("Expired"); else if (key->disabled) s = _("Disabled"); - else - s = ""; - + else + s = ""; /* if the key has a special status, we don't continue to figure out - what any user-id validities. */ + the user-id validities. */ if (*s) return m_strdup (s); } @@ -403,6 +479,40 @@ } +/* Return human readable description of the key @key. */ +char* +get_key_desc (gpgme_key_t key) +{ + gpgme_key_t sk; + const char *state, *alg, *type; + char *desc; + StringBuffer p; + + state = ""; + if (key->disabled) + state = _("Disabled"); + if (key->expired) + state = _("Expired"); + if (key->revoked) + state = _("Revoked"); + + /* If the fingerprint has 32 octets, we assume MD5 and thus + an old, version 3, RSA key which is called 'Legacy' by other + OpenPGP programs. */ + if (strlen (key->subkeys->fpr) == 32) + alg = "RSA Legacy"; + else + alg = "OpenPGP"; + type = _("public key"); + if (!get_seckey (key->subkeys->keyid+8, &sk)) + type = _("key pair"); + p = state; + p = p + " " + alg + " " + type; + desc = m_strdup (p.getBuffer ()); + return desc; +} + + /* Integer comparsion of @a and @b. Return values: same as in strcmp. */ static inline int @@ -424,6 +534,8 @@ return GPGME_VALIDITY_ULTIMATE+1; else if (k->expired) return GPGME_VALIDITY_ULTIMATE+2; + else if (k->disabled) + return GPGME_VALIDITY_ULTIMATE+3; return k->uids->validity; } @@ -432,13 +544,16 @@ static int CALLBACK keylist_cmp_cb (LPARAM first, LPARAM second, LPARAM sortby) { + struct keycache_s *aa, *bb; gpgme_key_t a, b; int cmpresult = 0; - a = (gpgme_key_t)first; - b = (gpgme_key_t)second; - if (!a || !b) + aa = (struct keycache_s *)first; + bb = (struct keycache_s *)second; + if (!aa || !bb) BUG (NULL); + a = aa->key; + b = bb->key; switch (sortby & ~KEYLIST_SORT_DESC) { case KEY_SORT_USERID: @@ -491,239 +606,236 @@ } -/* Return the validity of the group @grp. */ -static const char* -calc_validity (gpg_group_t grp) +int +keylist_add_groups (keylist_ctrl_t kl) { - int valid=0; - gpg_member_t mbr; - gpgme_key_t key; - - for (mbr = grp->list; mbr; mbr = mbr->next) { - if (get_pubkey (mbr->name, &key)) - continue; - valid = key->uids->validity; - switch (valid) { - case GPGME_VALIDITY_MARGINAL: - case GPGME_VALIDITY_NEVER: - case GPGME_VALIDITY_UNDEFINED: - return get_key_trust2 (NULL, valid, 0, 0); - } - } - return _("Full"); + return 0; } -int -keylist_add_groups( listview_ctrl_t lv ) +/* Synchronize the key array with the contents + of the keylist. */ +void +keylist_sync (keylist_ctrl_t kl) { -#if 0 - gpg_optfile_t gh; - gpg_group_t grp; - const char *valid; - - gh = km_groupdb_open( ); - if( !gh ) - return WPTERR_FILE_OPEN; - - for( grp = gh->grp; grp; grp = grp->next ) { - valid = calc_validity( grp ); - listview_add_item( lv, " " ); - listview_add_sub_item( lv, 0, 0, grp->name ); - listview_add_sub_item( lv, 0, 1, "gpg_group_t" ); - listview_add_sub_item( lv, 0, 2, "" ); - listview_add_sub_item( lv, 0, 3, "Unknown" ); - listview_add_sub_item( lv, 0, 4, valid?valid : "Unknown" ); - } -#endif - return 0; -} /* keylist_add_groups */ + free (kl->keys); + kl->nkeys = update_keys (kl, 0, &kl->keys); +} /* Create a listview for listing keys. Use the mode given in @mode and the control is given in @ctrl. */ -static int +static void keylist_build (listview_ctrl_t *r_lv, HWND ctrl, int mode) { + struct listview_column_s klist_enc[] = { + {0, 242, (char *)_("User ID")}, + {1, 80, (char *)_("Key ID")}, + {3, 46, (char *)_("Size")}, + {4, 50, (char *)_("Cipher")}, + {5, 70, (char *)_("Validity")}, + {0, 0, NULL} + }; + struct listview_column_s klist[] = { + {0, 240, (char *)_("User ID")}, + {1, 78, (char *)_("Key ID")}, + {2, 52, (char *)_("Type")}, + {3, 66, (char *)_("Size")}, + {4, 60, (char *)_("Cipher")}, + {5, 66, (char *)_("Validity")}, + {6, 58, (char *)_("Trust")}, + {7, 72, (char *)_("Creation")}, + {0, 0, NULL} + }; + HICON ico[6]; listview_ctrl_t lv; listview_column_t col; - int j, n = 0; - int rc = 0; + int ncols = 0, ext_chkbox = 0; - rc = listview_new (&lv); - if( rc ) - return rc; - - lv->ctrl = ctrl; - if ((mode & KEYLIST_ENCRYPT) || (mode & KEYLIST_ENCRYPT_MIN)) { + listview_new (&lv, ctrl); + if (mode & KEYLIST_ENCRYPT_MIN) { col = klist_enc; - n = KLIST_ENC_ITEMS; + ncols = (DIM (klist_enc) - 1); + ext_chkbox = 1; } - else if ((mode & KEYLIST_SIGN)) { + else if (mode & KEYLIST_SIGN) { col = klist_enc; - n = KLIST_ENC_ITEMS - 1; + ncols = (DIM (klist_enc) - 1) - 1; + ext_chkbox = 1; } else { col = klist; - n = KLIST_ITEMS; + ncols = (DIM (klist) - 1); } - for( j = 0; j < n; j++ ) - listview_add_column( lv, &col[j] ); - listview_set_ext_style( lv ); + for (int j = 0; j < ncols; j++) + listview_add_column (lv, &col[j]); + listview_set_ext_style (lv); + if (ext_chkbox) + listview_set_chkbox_style (lv); + ico[0] = LoadIcon (glob_hinst, (LPCTSTR)IDI_PUBKEY); + ico[1] = LoadIcon (glob_hinst, (LPCTSTR)IDI_KEYPAIR); + ico[2] = LoadIcon (glob_hinst, (LPCTSTR)IDI_REV_KEYPAIR); + ico[3] = LoadIcon (glob_hinst, (LPCTSTR)IDI_REV_PUBKEY); + ico[4] = LoadIcon (glob_hinst, (LPCTSTR)IDI_SORT_DOWNARROW); + ico[5] = LoadIcon (glob_hinst, (LPCTSTR)IDI_SORT_UPARROW); + listview_set_image_list (lv, 20, 16, ico, 6); + listview_del_all_items (lv); + listview_set_grid_style (lv); *r_lv = lv; - - return 0; } static void -keylist_load_keycache (listview_ctrl_t lv, int mode, +keylist_load_keycache (keylist_ctrl_t kl, int mode, gpg_keycache_t pubkc, gpg_keycache_t seckc) { - gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR); gpgme_key_t key, skey; - const char * keyid; + struct keycache_s *c; + const char *keyid; + gpg_keycache_rewind (pubkc); if (pubkc && seckc) { - gpg_keycache_rewind (pubkc); - while (!gpg_keycache_next_key (pubkc, 0, &key)) { + while (!gpg_keycache_next_key2 (pubkc, 0, &c, &key)) { keyid = key->subkeys->keyid; if (keyid && !gpg_keycache_find_key (seckc, keyid, 0, &skey)) - keylist_add_key (lv, mode, key); - } + keylist_add_key (kl, mode, c, key); + } } else if (pubkc) { - gpg_keycache_rewind (pubkc); - while (!err) { - err = gpg_keycache_next_key (pubkc, 0, &key); - if (!err) - keylist_add_key (lv, mode, key); - } + while (!gpg_keycache_next_key2 (pubkc, 0, &c, &key)) + keylist_add_key (kl, mode, c, key); } } /* Load the list view @ctrl with the keys from the cache. Return value: list view context on success. */ -listview_ctrl_t +keylist_ctrl_t keylist_load (HWND ctrl, gpg_keycache_t pubkc, gpg_keycache_t seckc, int mode, int sortby) { - listview_ctrl_t lv; - int rc = 0; - - rc = keylist_build (&lv, ctrl, mode); - if (rc) - return NULL; - keylist_load_keycache (lv, mode, pubkc, seckc); - keylist_sort (lv, sortby); - if ((mode & KEYLIST_ENCRYPT) || (mode & KEYLIST_ENCRYPT_MIN)) - keylist_add_groups (lv); - return lv; + keylist_ctrl_t kl; + + kl = new keylist_ctrl_s; + keylist_build (&kl->lv, ctrl, mode); + keylist_load_keycache (kl, mode, pubkc, seckc); + kl->nkeys = update_keys (kl, 0, &kl->keys); + keylist_sort (kl, sortby); + return kl; } /* Reload the given key list control @lv. */ int -keylist_reload (listview_ctrl_t lv, gpg_keycache_t pubkc, int mode, int sortby) +keylist_reload (keylist_ctrl_t kl, gpg_keycache_t pubkc, int mode, int sortby) { - listview_del_all (lv); - keylist_load_keycache( lv, mode, pubkc, NULL ); - keylist_sort (lv, sortby); + listview_del_all_items (kl->lv); + keylist_load_keycache (kl, mode, pubkc, NULL); + /* It is possible that the list shrinks or increases so we need to + rebuild the list again. */ + free (kl->keys); kl->keys = NULL; + kl->nkeys = update_keys (kl, 0, &kl->keys); + keylist_sort (kl, sortby); return 0; } void -keylist_delete (listview_ctrl_t lv) +keylist_delete (keylist_ctrl_t kl) { - if (lv) { - listview_release (lv); + if (!kl) + return; + if (kl->keys != NULL) { + free (kl->keys); + kl->keys = NULL; + } + if (kl->lv != NULL) { + listview_release (kl->lv); + kl->lv = NULL; } } -/* Return if there is a secret for @key. - 0 means success. */ + + +/* Enumeration for possible key icons. */ +enum key_icontype_t { + IMG_KEY_PUB = 0, + IMG_KEY_PAIR = 1, + IMG_KEY_PAIR_REV = 2, + IMG_KEY_PUB_REV = 3 +}; + + static int -find_secret_key (gpgme_key_t key) +key_get_image_id (gpgme_key_t key) { - const char *keyid; - winpt_key_s skey; - - memset (&skey, 0, sizeof (skey)); - keyid = key->subkeys->keyid; - if (!keyid) - return 0; - winpt_get_seckey (keyid, &skey); - if (skey.ext && skey.ext->gloflags.divert_to_card) - return 2; - return skey.ctx? 1 : 0; + if (find_secret_key (key)) + return key->revoked ? IMG_KEY_PAIR_REV :IMG_KEY_PAIR; + if (key->revoked) + return IMG_KEY_PUB_REV; + return IMG_KEY_PUB; } static int -do_addkey (listview_ctrl_t lv, gpgme_key_t key, int uididx, int keyidx, int list) -{ - LV_ITEM lvi; +do_addkey (listview_ctrl_t lv, struct keycache_s *ctx, gpgme_key_t key, + int uididx, int keyidx, int list) +{ gpgme_user_id_t u; gpgme_subkey_t k; - char fmt[128], *p; + LV_ITEM lvi; + char *p; const char *attr; - u32 key_attr; - int idx = 0; + int idx = 0; /* we check the pubkey algorithm here to make sure that no ElGamal sign+encrypt key is used in _any_ mode */ if (list != 1 && key->subkeys->pubkey_algo == GPGME_PK_ELG) { - log_debug ("ElGamal (E+S) key found: %s (%s)\n", + log_debug ("ElGamal (E+S) key found: %s (%s)\n", key->uids->name, key->subkeys->keyid); return 0; } - - if (listview_add_item2 (lv, " ", (void *)key)) + if (listview_add_item2 (lv, " ", (void *)ctx)) return WPTERR_GENERAL; - - attr = key->uids->uid; + + attr = ctx->uids->uid; memset (&lvi, 0, sizeof lvi); - lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; lvi.pszText = (char *)attr; - lvi.lParam = (LPARAM )key; - if (ListView_SetItem( lv->ctrl, &lvi ) == FALSE) + lvi.iImage = key_get_image_id (key); + lvi.lParam = (LPARAM )ctx; + if (ListView_SetItem (lv->ctrl, &lvi) == FALSE) return WPTERR_GENERAL; if (uididx == -1) { /* request the primary user-id of the key. */ - attr = key->uids->uid; + attr = ctx->uids->uid; uididx = 0; } else { u = get_nth_userid (key, uididx); if (!u || u->revoked || uididx < 0) - uididx = 0; /* fixme: this happen sometimes but it's illegal! (<0) */ + uididx = 0; u = get_nth_userid (key, uididx); - /*attr = key->uids->uid; XXX*/ attr = u->uid; } - if (attr == NULL || strlen (attr) < 5) { /* normal userids are >= 5 chars */ + if (attr == NULL || strlen (attr) < 5) { /* normal userids are > 5 chars */ attr = _("Invalid User ID"); listview_add_sub_item (lv, 0, idx++, attr); } - else { - char *uid = utf8_to_wincp (attr, strlen (attr)); - if (uid) { - listview_add_sub_item (lv, 0, idx++, uid); - free (uid); - } - } + else + listview_add_sub_item (lv, 0, idx++, attr); k = get_nth_key (key, keyidx); - if (k && k->keyid) { - _snprintf (fmt, sizeof fmt -1, "0x%s", k->keyid + 8); - listview_add_sub_item( lv, 0, idx++, fmt ); + if (k && k->keyid != NULL) { + char keyid[16+1]; + + _snprintf (keyid, DIM (keyid) -1, "0x%s", k->keyid + 8); + listview_add_sub_item (lv, 0, idx++, keyid); } if (list > 0) { - key_attr = find_secret_key (key); + DWORD key_attr = find_secret_key (key); if (!key_attr) attr = "pub"; else @@ -732,127 +844,178 @@ } if (lv->cols >= 2) { attr = get_key_size (key, list == -1? keyidx+1 : 0); - if (attr) + if (attr != NULL) listview_add_sub_item (lv, 0, idx++, attr); } if (lv->cols >= 3) { attr = get_key_algo (key, list == -1? keyidx+1 : 0); - if (attr) + if (attr != NULL) listview_add_sub_item( lv, 0, idx++, attr); } - if( lv->cols >= 4 ) { - p = get_key_status( key, uididx, list > 0? 1 : 0 ); - if (!p) - return WPTERR_GENERAL; - listview_add_sub_item (lv, 0, idx++, p); + if (lv->cols >= 4) { + p = get_key_status (key, uididx, list > 0? 1 : 0); + if (p != NULL) + listview_add_sub_item (lv, 0, idx++, p); free_if_alloc (p); } if (lv->cols >= 5) { attr = get_key_trust (key, uididx, list > 0? 1 : 0); listview_add_sub_item (lv, 0, idx++, attr); } - if( lv->cols >= 6 ) { + if (lv->cols >= 6) { k = get_nth_key (key, keyidx); - key_attr = k->timestamp; - if( key_attr ) { - attr = get_key_created (key_attr); - listview_add_sub_item( lv, 0, idx++, attr ); - } + if (k->timestamp > 0) { + attr = get_key_created (k->timestamp); + listview_add_sub_item (lv, 0, idx++, attr); + } } return 0; } +/* Update a single column @col but for each element in the + listview @lv. */ void -keylist_upd_key (listview_ctrl_t lv, int pos, gpgme_key_t key) +keylist_upd_col (keylist_ctrl_t kl, int col) { + gpgme_key_t key; const char *s; + char buf[32], *p; + + for (int i=0; i < listview_count_items (kl->lv, 0); i++) { + key = km_get_key_ptr (kl, i, NULL); + if (!key) + continue; + switch (col) { + case KM_COL_KEYID: + _snprintf (buf, DIM (buf)-1, "0x%s", key->subkeys->keyid+8); + listview_add_sub_item (kl->lv, i, col, buf); + break; + + case KM_COL_CIPHER: + s = get_key_algo (key, 0); + listview_add_sub_item (kl->lv, i, col, s); + break; + + case KM_COL_TYPE: + s = find_secret_key (key)? "pub/sec" : "pub"; + listview_add_sub_item (kl->lv, i, col, s); + break; + + case KM_COL_CREAT: + s = get_key_created (key->subkeys->timestamp); + listview_add_sub_item (kl->lv, i, col, s); + break; + + case KM_COL_DESC: + p = get_key_desc (key); + listview_add_sub_item (kl->lv, i, col, p); + free_if_alloc (p); + break; + } + } +} + + +/* Update the listview item at position @pos with the data from + the key @key. */ +void +keylist_upd_key (keylist_ctrl_t kl, int pos, + struct keycache_s *ctx, gpgme_key_t key) +{ + listview_ctrl_t lv = kl->lv; + char *p; char tmp[32]; - listview_set_item2 (lv, pos, (void *)key); - /* the only mode we support is KYLIST_LIST in the Key Manager */ + listview_set_item2 (lv, pos, (void *)ctx); + update_key (kl, pos, key); + /* the only mode we support is KEYLIST_LIST in the Key Manager */ - s = key->uids->uid; + const char *s = ctx->uids->uid; if (s) - listview_add_sub_item (lv, pos, 0, s); + listview_add_sub_item (lv, pos, KM_COL_UID, s); s = key->subkeys->keyid; if (s) { sprintf (tmp, "0x%s", s+8); - listview_add_sub_item (lv, pos, 1, tmp); + listview_add_sub_item (lv, pos, KM_COL_KEYID, tmp); } s = find_secret_key (key)? "pub/sec" : "pub"; - listview_add_sub_item (lv, pos, 2, s); + listview_add_sub_item (lv, pos, KM_COL_TYPE, s); s = get_key_size (key, 0); if (s) - listview_add_sub_item (lv, pos, 3, s); + listview_add_sub_item (lv, pos, KM_COL_SIZE, s); s = get_key_algo (key, 0); if (s) - listview_add_sub_item (lv, pos, 4, s); + listview_add_sub_item (lv, pos, KM_COL_CIPHER, s); - s = get_key_status (key, 0, 1); - if (s) - listview_add_sub_item (lv, pos, 5, s); + p = get_key_status (key, 0, 1); + if (p) { + listview_add_sub_item (lv, pos, KM_COL_VALID, p); + free_if_alloc (p); + } s = get_key_trust (key, 0, 1); if (s) - listview_add_sub_item (lv, pos, 6, s); + listview_add_sub_item (lv, pos, KM_COL_TRUST, s); long t = key->subkeys->timestamp; s = get_key_created (t); if (s) - listview_add_sub_item (lv, pos, 7, s); + listview_add_sub_item (lv, pos, KM_COL_CREAT, s); } int -keylist_add_key (listview_ctrl_t lv, int mode, gpgme_key_t key) -{ - int uids, rc = 0, i; +keylist_add_key (keylist_ctrl_t kl, int mode, + struct keycache_s *ctx, gpgme_key_t key) +{ gpgme_subkey_t k; + listview_ctrl_t lv = kl->lv; + int uids, rc, i; /* if the entire key is disabled, just return. */ - if (key->disabled) + if (key->disabled && !(mode & KEYLIST_LIST)) return 0; - for (k=key->subkeys, i = 0; i < count_subkeys (key); i++, k=k->next) { + for (k = key->subkeys, i = 0; i < count_subkeys (key); i++, k = k->next) { if (k->invalid) { - log_debug ("keylist_add_key: invalid key \"%s\"\n", key->uids->name); + log_debug ("keylist_add_key: invalid key \"%s\"\n", + key->uids->name); continue; /* Don't use invalid keys */ } if (mode & KEYLIST_ALL) { uids = count_userids (key); - rc = do_addkey (lv, key, uids, i, 0); - if( rc ) + rc = do_addkey (lv, ctx, key, uids, i, 0); + if (rc) return rc; } else if (mode & KEYLIST_LIST) - return do_addkey (lv, key, -1, i, 1); + return do_addkey (lv, ctx, key, -1, i, 1); else if (mode & KEYLIST_ENCRYPT) { if (k->can_encrypt && key_is_useable (k)) { if (mode & KEYLIST_FLAG_FILE) { - rc = do_addkey (lv, key, -1, i, -1); + rc = do_addkey (lv, ctx, key, -1, i, -1); if (rc) return rc; } else { - for( uids = 0; uids < count_userids (key); uids++ ) { - rc = do_addkey( lv, key, uids, i, -1 ); - if( rc ) + for (uids = 0; uids < count_userids (key); uids++) { + rc = do_addkey (lv, ctx, key, uids, i, -1); + if (rc) return rc; } } } } else if (mode & KEYLIST_ENCRYPT_MIN) { - if( k->can_encrypt && key_is_useable (k)) - { - rc = do_addkey (lv, key, -1, i, -1); + if (k->can_encrypt && key_is_useable (k)) { + rc = do_addkey (lv, ctx, key, -1, i, -1); return rc; } } @@ -860,34 +1023,38 @@ if (k->can_sign && find_secret_key (key) && key_is_useable (k)) { - rc = do_addkey (lv, key, -1, i, -1); + rc = do_addkey (lv, ctx, key, -1, i, -1); if (rc) return rc; } } } - return rc; -} /* keylist_add_key */ + return 0; +} int -keylist_sort (listview_ctrl_t lv, int sortby) -{ - return listview_sort_items (lv, sortby, keylist_cmp_cb); +keylist_sort (keylist_ctrl_t kl, int sortby) +{ + int ret = listview_sort_items (kl->lv, sortby, keylist_cmp_cb); + kl->nkeys = update_keys (kl, 1, &kl->keys); + return ret; } /* Check that the validity @validity is at least >= marginal. */ static int -key_check_validity (const char *validity) -{ - if (strstr (validity, "Unknown") || - strstr (validity, "Undefined") || - strstr (validity, "Never") || - strstr (validity, "None")) - return 0; - return 1; +key_check_validity (gpgme_key_t key) +{ + gpgme_user_id_t u; + + for (u=key->uids; u; u =u->next) { + if (u->validity >= GPGME_VALIDITY_MARGINAL) + return -1; + } + + return 0; } @@ -896,61 +1063,48 @@ fully trusted. @r_count returns the number of selected keys. Return value: the key list on success, NULL otherwise. */ gpgme_key_t* -keylist_get_recipients (listview_ctrl_t lv, int *r_force_trust, int *r_count) +keylist_get_recipients (keylist_ctrl_t kl, int *r_force_trust, size_t *r_count) + { - int count = 0, force_trust = 0; - int n, j, ka_pos = 0, rc = 0; - int k_pos=0; - char keyid[32], valid[32], id[100]; + gpgme_key_t *keybuf, key; + listview_ctrl_t lv = kl->lv; key_array_s *ka = NULL; - gpgme_key_t *keybuf; - - n = listview_count_items( lv, 0 ); - - ka = key_array_new( n ); - if (!ka) - BUG (NULL); + keycache_s *c; + size_t count = 0; + int force_trust = 0; + int nkeys, ka_pos = 0, rc = 0; + int k_pos=0; - keybuf = (gpgme_key_t*)calloc (n, sizeof (gpgme_key_t)); + nkeys = listview_count_items (lv, 0); + ka = key_array_new (nkeys); + keybuf = (gpgme_key_t*)calloc (nkeys+1, sizeof (gpgme_key_t)); if (!keybuf) BUG (NULL); - for( j = 0; j < n; j++ ) { - if( listview_get_item_state (lv, j) || n == 1) { - listview_get_item_text (lv, j, 0, id, sizeof id-1); - listview_get_item_text (lv, j, 1, keyid, sizeof keyid - 1); - listview_get_item_text (lv, j, 4, valid, sizeof valid -1); - if( !key_check_validity (valid) - && !key_array_search( ka, ka_pos, keyid )) { - char *warn = new char[512+strlen (id) + 1]; - if (!warn) - BUG (0); - sprintf (warn, - _("It is NOT certain that the key belongs to the person\n" - "named in the user ID. If you *really* know what you are\n" - "doing, you may answer the next question with yes\n" - "\n" - "Use \"%s\" anyway?"), id); - if (reg_prefs.always_trust) - rc = IDYES; - else - rc = msg_box (NULL, warn, _("Recipients"), MB_ERR_ASK); - if (rc == IDYES) { - gpgme_key_t k; - get_pubkey (keyid, &k); - keybuf[k_pos++] = k; + for (int j = 0; j < nkeys; j++) { + if (listview_get_item_state (lv, j) || nkeys == 1) { + key = km_get_key_ptr (kl, j, &c); + if (!key) + BUG (0); + if (!key_check_validity (key) && + !key_array_search (ka, ka_pos, key->subkeys->keyid)) { + StringBuffer warn; + warn = warn + c->uids->uid + ":\n\n"; + warn = warn +_("It is NOT certain that the key belongs to the person\n" + "named in the user ID. If you *really* know what you are\n" + "doing, you may answer the next question with no\n" + "\nSkip this key?"); + rc = msg_box (NULL, warn.getBuffer(), _("Warning"), MB_WARN_ASK); + if (reg_prefs.always_trust || rc == IDNO) { + keybuf[k_pos++] = key; force_trust++; ka[ka_pos].checked = 1; - strcpy (ka[ka_pos++].keyid, keyid); + strcpy (ka[ka_pos++].keyid, key->subkeys->keyid); count++; } - free_if_alloc (warn); } else { - gpgme_key_t k; - listview_get_item_text( lv, j, 1, keyid, sizeof keyid -1 ); - get_pubkey (keyid, &k); - keybuf[k_pos++] = k; + keybuf[k_pos++] = key; count++; } } @@ -965,87 +1119,84 @@ static int -keylist_get_keyflags (const char *buf, size_t buflen) +keylist_get_keyflags (gpgme_key_t key) { - int c = 0, flags = 0; + int flags = KEYFLAG_NONE; - if( *buf != '[' ) - return KEYFLAG_NONE; - while (buf && c != ']') - { - c = *buf++; - if (c == 'R') - flags |= KEYFLAG_REVOKED; - if (c == 'E') - flags |= KEYFLAG_EXPIRED; - if (c == 'D') - flags |= KEYFLAG_DISABLED; - } + if (key->revoked) + flags |= KEYFLAG_REVOKED; + if (key->expired) + flags |= KEYFLAG_EXPIRED; + if (key->disabled) + flags |= KEYFLAG_DISABLED; return flags; -} /* keylist_get_keyflags */ +} + gpgme_key_t* -keylist_enum_recipients (listview_ctrl_t lv, int listype, int *r_count) +keylist_enum_recipients (keylist_ctrl_t kl, int listype, size_t *r_count) { - gpgme_key_t* rset; - gpgme_key_t k; - int i, n, id, k_pos=0; - char keyid[32], t[128], t2[128]; + gpgme_key_t *rset; + gpgme_key_t key; + listview_ctrl_t lv = kl->lv; + struct keycache_s *c; + size_t k_pos; + int nkeys, id; - n = listview_count_items (lv, 0); - if (!n) + nkeys = listview_count_items (lv, 0); + if (!nkeys) return 0; - rset = (gpgme_key_t*)calloc (n, sizeof (gpgme_key_t)); + rset = (gpgme_key_t*)calloc (nkeys+1, sizeof (gpgme_key_t)); if (!rset) BUG (NULL); - for( i = 0; i < n; i++ ) { - if( !listview_get_item_state( lv, i ) ) + k_pos = 0; + for (int i = 0; i < nkeys; i++) { + if (!listview_get_item_state (lv, i)) continue; - listview_get_item_text( lv, i, 1, keyid, sizeof keyid - 1 ); - switch( listype ) { + key = km_get_key_ptr (kl, i, &c); + switch (listype) { case KEYLIST_LIST: - listview_get_item_text( lv, i, 5, t, sizeof t - 1 ); - if( keylist_get_keyflags( t, strlen( t ) ) & KEYFLAG_REVOKED ) { - _snprintf( t2, sizeof t2 -1, - _("KeyID %s.\nDo you really want to export a revoked key?"), keyid ); - id = msg_box( lv->ctrl, t2, _("Recipients"), MB_INFO|MB_YESNO ); - if( id == IDNO ) - continue; + if (keylist_get_keyflags (key) & KEYFLAG_REVOKED) { + id = printf_box (_("Recipients"), MB_INFO|MB_YESNO, + _("KeyID %s.\nDo you really want to export a revoked key?"), + c->uids->uid); + if (id == IDNO) + continue; } break; } - get_pubkey (keyid, &k); - rset[k_pos++] = k; + rset[k_pos++] = key; } if (r_count) *r_count = k_pos; return rset; -} /* keylist_enum_recipients */ +} void -seclist_destroy (keylist_t * list) +seclist_destroy (keylist_t *list) { keylist_t l2; + while (*list) { l2 = (*list)->next; safe_free (*list); *list = l2; } - list = NULL; -} /* seclist_destroy */ + *list = NULL; +} void -seclist_init (HWND dlg, int ctlid, int flags, keylist_t * ret_list) +seclist_init (HWND dlg, int ctlid, int flags, keylist_t *ret_list) { - gpg_keycache_t kc = NULL; + gpg_keycache_t kc; gpgme_key_t key = NULL; HWND kb; keylist_t list=NULL, l, l2; - long pos = 0; + long pos; SendDlgItemMessage (dlg, ctlid, CB_RESETCONTENT, 0, 0); kb = GetDlgItem (dlg, ctlid); @@ -1055,33 +1206,27 @@ gpg_keycache_rewind (kc); while (!gpg_keycache_next_key (kc, 1, &key)) { - char *inf = NULL, *uid = NULL; + StringBuffer inf; + char *uid; const char *id; - const char *keyid; - int algo; - size_t size = 0; + + if (key->disabled || !key_is_useable (key->subkeys)) + continue; if (flags & KEYLIST_FLAG_SHORT) id = key->uids->name; else id = key->uids->uid; - keyid = key->subkeys->keyid; - algo = key->subkeys->pubkey_algo; - if (!id || !keyid) - continue; - if (key->disabled || !key_is_useable (key->subkeys)) - continue; + if (!id || !key->subkeys->keyid) + continue; + + uid = utf8_to_native (id); + inf = uid; + inf = inf + " (" + get_key_pubalgo (key->subkeys->pubkey_algo) + "/"; + inf = inf + "0x" + (key->subkeys->keyid+8) + ")"; - uid = utf8_to_wincp (id, strlen (id)); - size = strlen( uid ) + strlen( keyid ) + 32; - inf = new char[size+1]; - if( !inf ) - BUG( NULL ); - _snprintf (inf, size, "%s (%s/0x%s)", uid, - get_key_pubalgo (key->subkeys->pubkey_algo), keyid + 8); - combox_add_string (kb, inf); - free_if_alloc (inf); - free (uid); + combox_add_string (kb, inf.getBuffer ()); + safe_free (uid); l = (struct keylist_s *)calloc (1, sizeof * l); if (!l) BUG (0); @@ -1094,12 +1239,13 @@ l2->next = l; } } - for( pos = 0, l2=list; pos < SendMessage( kb, CB_GETCOUNT, 0, 0 ); pos++, l2=l2->next ) - SendMessage( kb, CB_SETITEMDATA, pos, (LPARAM)(DWORD)l2->key ); - SendMessage( kb, CB_SETCURSEL, 0, 0 ); + for (pos = 0, l2=list; pos < SendMessage (kb, CB_GETCOUNT, 0, 0); + pos++, l2=l2->next) + SendMessage (kb, CB_SETITEMDATA, pos, (LPARAM)(DWORD)l2->key); + SendMessage (kb, CB_SETCURSEL, 0, 0); *ret_list = list; } - + /* Select a secret key from the combo box with the ID @ctlid. Return the code on success in @ret_key. */ @@ -1120,3 +1266,63 @@ } return k? 0 : -1; } + + +LRESULT +keylist_listview_notify (HWND hwnd, gpgme_key_t *keys, + int ctlid, LPARAM lparam) +{ + LPNMHDR lpnmh = (LPNMHDR) lparam; + + if (!lpnmh) + BUG (NULL); + + /* Make sure the message is for the control and + that we have a key list. */ + if (lpnmh->idFrom != (DWORD)ctlid || keys == NULL) + return 0; + + switch (lpnmh->code) { + case NM_CUSTOMDRAW: + LPNMLVCUSTOMDRAW lplvcd; + lplvcd = (LPNMLVCUSTOMDRAW)lparam; + if (lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT) + return CDRF_NOTIFYITEMDRAW; + + if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { + LRESULT ret = CDRF_DODEFAULT; + int pos = lplvcd->nmcd.dwItemSpec; + HWND lv = GetDlgItem (hwnd, ctlid); + gpgme_key_t key = keys[pos]; + + if (key != NULL) { + HFONT hfont = (HFONT)SendMessage (lv, WM_GETFONT, 0, 0); + LOGFONT lf; + if (!GetObject (hfont, sizeof (lf), &lf)) + BUG (NULL); + if (key->revoked) + lf.lfStrikeOut = TRUE; + else if (key->expired) + lf.lfItalic = TRUE; + if (find_secret_key (key)) + lf.lfWeight = FW_SEMIBOLD; + hfont = CreateFontIndirect (&lf); + SelectObject (lplvcd->nmcd.hdc, hfont); + if (pos & 1) + lplvcd->clrTextBk = RGB (0xE5, 0xE5, 0xE5); + ret = CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT; + } + return ret; + } + + if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT) { + HFONT hfont = (HFONT)GetStockObject (DEFAULT_GUI_FONT); + hfont = (HFONT)SelectObject (lplvcd->nmcd.hdc, hfont); + DeleteObject (hfont); + return CDRF_DODEFAULT; + } + return CDRF_DODEFAULT; + } + + return 0; +}