--- trunk/Src/wptKeylist.cpp 2005/10/12 10:04:26 25 +++ trunk/Src/wptKeylist.cpp 2006/04/10 07:38:06 197 @@ -1,1085 +1,1189 @@ -/* wptKeylist.cpp - Keylist element - * Copyright (C) 2001-2005 Timo Schulz - * Copyright (C) 2004 Andreas Jobs - * - * This file is part of WinPT. - * - * WinPT is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * WinPT is distributed in the hope that it will be useful, - * 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 - */ -#include -#include -#include - -#include "wptCommonCtl.h" -#include "wptTypes.h" -#include "wptGPG.h" -#include "wptKeylist.h" -#include "wptKeyManager.h" -#include "wptW32API.h" -#include "wptNLS.h" -#include "wptErrors.h" -#include "wptUTF8.h" -#include "wptRegistry.h" -#include "wptContext.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; -}; - -static int find_secret_key( gpgme_key_t key ); - - -static key_array_s* -key_array_new( size_t items ) -{ - key_array_s *ka; - size_t j; - - if( items == 0 ) - return NULL; - ka = new key_array_s[items + 1]; - if( ka == NULL ) - return NULL; - for ( j = 0; j < items; j++ ) - ka[j].checked = 0; - return ka; -} /* key_array_new */ - - -static void -key_array_release( key_array_s *ka ) -{ - free_if_alloc( ka ); -} /* key_array_release */ - - -static int -key_array_search( key_array_s *ka, size_t 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 ) ) - return 1; - } - - return 0; -} /* key_array_search */ - - -gpgme_user_id_t -get_nth_userid (gpgme_key_t key, int idx) -{ - gpgme_user_id_t t; - - if (!key->uids) - return NULL; - t = key->uids; - while (idx-- && t->next) - t = t->next; - return t; -} - - -int -count_userids (gpgme_key_t key) -{ - gpgme_user_id_t u; - int n = 1; - - u = key->uids; - if (!u) - return 0; - while (u->next) { - u = u->next; - n++; - } - return n; -} - - -gpgme_subkey_t -get_nth_key (gpgme_key_t key, int idx) -{ - gpgme_subkey_t t; - - if (!key->subkeys) - return NULL; - t = key->subkeys; - while (idx-- && t->next) - t = t->next; - return t; -} - -int -count_subkeys (gpgme_key_t key) -{ - gpgme_subkey_t k; - int n = 1; - - k = key->subkeys; - if (!k) - return 0; - while (k->next) { - k = k->next; - n++; - } - return n; -} - - -gpgme_key_sig_t -get_selfsig (gpgme_user_id_t uid, const char *keyid, int first) -{ - gpgme_key_sig_t s, self_sig=NULL; - long timestamp=0; - - for (s = uid->signatures; s; s = s->next) { - if (!strcmp (s->keyid+8, keyid) && s->timestamp > timestamp) { - self_sig = s; - timestamp = s->timestamp; - if (first) - break; - } - } - return self_sig; -} - - - -const char* -get_key_algo (gpgme_key_t key, int keyidx) -{ - static char algo_id[128]; - gpgme_subkey_t k; - char alg[32]; - const char *subalg; - int n=0; - - 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); - 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); - subalg = get_key_pubalgo (k->pubkey_algo); - _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; - - if (timestamp == 0 || timestamp == -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 */ - - -const char* -get_key_expire_date (long timestamp) -{ - static char timebuf[64]; - struct tm *warp; - - if( !timestamp ) - return _("Never"); - 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_expire_date */ - - -const char* -get_key_type (gpgme_key_t key) -{ - if (find_secret_key (key)) - return _("Key Pair"); - return _("Public Key"); -} /* get_key_type */ - - -const char* -get_key_size (gpgme_key_t key, int keyidx) -{ - static char size_id[64]; - gpgme_subkey_t k; - int n, size_main, size_sub; - - if (keyidx > 0) { - k = get_nth_key (key, keyidx-1); - size_main = k->length; - _snprintf (size_id, DIM (size_id)-1, "%d", size_main); - return size_id; - } - size_main = key->subkeys->length; - n = count_subkeys (key); - 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 ); - return size_id; - } - _snprintf( size_id, sizeof (size_id) - 1, "%d", size_main ); - return size_id; -} /* get_key_size */ - - -const char* -get_key_pubalgo (gpgme_pubkey_algo_t alg) -{ - switch (alg) { - case GPGME_PK_DSA: return "DSA"; - case GPGME_PK_ELG: - case GPGME_PK_ELG_E: return "ELG"; - case GPGME_PK_RSA: return "RSA"; - } - return "???"; -} - -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; - - memset (fpr_md, 0, sizeof (fpr_md)); - fpr = key->subkeys->fpr; - if (!fpr || !*fpr) { - memset (tmp, '0', 40); - fpr = tmp; - } - if (strlen (fpr) == 32) { - strcat (fpr_md, " "); - for (i=0; i < strlen (fpr)/2; i++) { - sprintf (t, "%c%c ", fpr[2*i], fpr[2*i+1]); - strcat (fpr_md, t); - } - } - else { - strcat (fpr_md, " "); - for (i = 0; i < strlen (fpr) / 4; i++) { - sprintf (t, "%c%c%c%c ", fpr[4*i], fpr[4*i+1], fpr[4*i+2], fpr[4*i+3]); - strcat (fpr_md, t); - } - } - return fpr_md; -} /* get_key_fpr */ - - -const char * -get_key_trust2 (gpgme_key_t key, int val, int uididx, int listmode) -{ - if (key) - val = key->owner_trust; /* uididx?? */ - switch (val) { - case GPGME_VALIDITY_UNKNOWN: - case GPGME_VALIDITY_UNDEFINED: - return "None"; - case GPGME_VALIDITY_NEVER: - return "Never"; - case GPGME_VALIDITY_MARGINAL: - return "Marginal"; - case GPGME_VALIDITY_FULL: - case GPGME_VALIDITY_ULTIMATE: - return "Full"; - } - return ""; -} - - -const char * -get_key_trust (gpgme_key_t key, int uididx, int listmode) -{ - return get_key_trust2 (key, 0, uididx, listmode); -} - - -const char * -get_key_trust_str (int val) -{ - return get_key_trust2 (NULL, val, 0, 0); -} - - -char* -get_key_status (gpgme_key_t key, int uididx, int listmode) -{ - gpgme_user_id_t u; - char fmt[64], * p; - const char * attr; - int i = 0; - u32 key_attr =0; - - if (uididx < 0 || count_userids (key) > uididx) - uididx = 0; - memset (fmt, 0, sizeof (fmt)); - if (listmode) { - if (key->revoked) - sprintf (fmt, "Revoked"); - else if (key->expired) - sprintf (fmt, "Expired"); - else if (key->disabled) - sprintf (fmt, "Disabled"); - /* if the key has a special status, we don't continue to figure out - what any user-id validities. */ - if (strlen (fmt) > 0) - return m_strdup (fmt); - } - u = get_nth_userid (key, uididx); - key_attr = u->validity; - attr = get_key_trust2 (NULL, key_attr, 0, 0); - p = new char[strlen( attr ) + 2]; - if (!p) - BUG (NULL); - sprintf (p, "%s", attr); - return p; -} /* get_key_status */ - - -/* Integer comparsion of @a and @b. - Return values: same as in strcmp. */ -static inline int -int_cmp (int a, int b) -{ - if (a == b) return 0; - else if (a > b) return 1; - else return -1; - return 0; -} - - -/* List view sorting callback. */ -static int CALLBACK -keylist_cmp_cb (LPARAM first, LPARAM second, LPARAM sortby) -{ - gpgme_key_t a, b; - int cmpresult = 0; - - a = (gpgme_key_t)first; - b = (gpgme_key_t)second; - if (!a || !b) - BUG (NULL); - - switch (sortby & ~KEYLIST_SORT_DESC) { - case KEY_SORT_USERID: +/* wptKeylist.cpp - Keylist element + * Copyright (C) 2001-2006 Timo Schulz + * Copyright (C) 2004 Andreas Jobs + * + * This file is part of WinPT. + * + * WinPT is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * WinPT is distributed in the hope that it will be useful, + * 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 +#endif + +#include +#include +#include + +#include "wptCommonCtl.h" +#include "wptTypes.h" +#include "wptGPG.h" +#include "wptKeylist.h" +#include "wptKeyManager.h" +#include "wptW32API.h" +#include "wptNLS.h" +#include "wptErrors.h" +#include "wptUTF8.h" +#include "wptRegistry.h" +#include "wptContext.h" +#include "wptVersion.h" +#include "resource.h" + +#define key_is_useable(key) (!(key)->revoked && !(key)->expired && !(key)->disabled) + +struct key_array_s { + char keyid[32]; + int checked; +}; + +static int find_secret_key (gpgme_key_t key); + + +static key_array_s* +key_array_new (int items) +{ + key_array_s *ka; + int j; + + if (items == 0) + return NULL; + ka = new key_array_s[items + 1]; + if (!ka) + BUG (NULL); + for (j = 0; j < items; j++) + ka[j].checked = 0; + return ka; +} + + +static void +key_array_release (key_array_s *ka) +{ + 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, int items, const char *keyid) +{ + int j; + + for (j = 0; j < items; j++) { + if (!strcmp (keyid, ka[j].keyid )) + return 1; + } + return 0; +} + + +gpgme_user_id_t +get_nth_userid (gpgme_key_t key, int idx) +{ + gpgme_user_id_t t; + + if (!key->uids) + return NULL; + t = key->uids; + while (idx-- && t->next) + t = t->next; + return t; +} + + +int +count_userids (gpgme_key_t key) +{ + gpgme_user_id_t u; + int n = 1; + + u = key->uids; + if (!u) + return 0; + while (u->next) { + u = u->next; + n++; + } + return n; +} + + +gpgme_subkey_t +get_nth_key (gpgme_key_t key, int idx) +{ + gpgme_subkey_t t; + + if (!key->subkeys) + return NULL; + t = key->subkeys; + while (idx-- && t->next) + t = t->next; + return t; +} + + +int +count_subkeys (gpgme_key_t key) +{ + gpgme_subkey_t k; + int n = 1; + + k = key->subkeys; + if (!k) + return 0; + while (k->next) { + k = k->next; + n++; + } + return n; +} + + +/* 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) +{ + gpgme_key_sig_t s, self_sig=NULL; + long timestamp=0; + int off = 0; + + if (strlen (keyid) == 8) + off = 8; + + for (s = uid->signatures; s; s = s->next) { + if (!strcmp (s->keyid+off, keyid) && s->timestamp > timestamp) { + self_sig = s; + timestamp = s->timestamp; + if (first) + break; + } + } + return self_sig; +} + + + +const char* +get_key_algo (gpgme_key_t key, int keyidx) +{ + static char algo_id[128]; + gpgme_subkey_t k; + char alg[32]; + const char *subalg; + int n=0; + + 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); + 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); + subalg = get_key_pubalgo (k->pubkey_algo); + _snprintf (algo_id, DIM (algo_id)-1, "%s/%s", alg, subalg); + return algo_id; + } + return get_key_pubalgo (key->subkeys->pubkey_algo); +} + + +const char* +get_key_created (long timestamp) +{ + static char timebuf[128]; + struct tm *warp; + const char *dat; + + if (timestamp < 1) + return "????" "-??" "-??"; + dat = get_locale_date (timestamp, timebuf, sizeof (timebuf)-1); + if (dat) + return dat; + warp = localtime (×tamp); + _snprintf (timebuf, sizeof timebuf - 1, "%04d-%02d-%02d", + warp->tm_year + 1900, warp->tm_mon + 1, warp->tm_mday); + return timebuf; +} + + +/* Return a string presentation of the time @timestamp. */ +const char* +get_key_expire_date (long timestamp) +{ + static char timebuf[64]; + struct tm *warp; + const char *dat; + + if (timestamp == 0) + return _("Never"); + dat = get_locale_date (timestamp, timebuf, sizeof (timebuf)-1); + if (dat) + return dat; + warp = localtime (×tamp); + _snprintf (timebuf, sizeof timebuf -1, "%04d-%02d-%02d", + warp->tm_year + 1900, warp->tm_mon + 1, warp->tm_mday); + return timebuf; +} + + +const char* +get_key_type (gpgme_key_t key) +{ + int type = find_secret_key (key); + + if (type == 1) + return _("Key Pair"); + else if (type == 2) + return _("Key Pair (Card)"); + return _("Public Key"); +} + + +const char* +get_key_size (gpgme_key_t key, int keyidx) +{ + static char size_id[64]; + gpgme_subkey_t k; + int n, size_main, size_sub; + + if (keyidx > 0) { + k = get_nth_key (key, keyidx-1); + size_main = k->length; + _snprintf (size_id, DIM (size_id)-1, "%d", size_main); + return size_id; + } + size_main = key->subkeys->length; + n = count_subkeys (key); + 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); + return size_id; + } + _snprintf( size_id, sizeof (size_id) - 1, "%d", size_main ); + return size_id; +} + + +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* +get_key_pubalgo (gpgme_pubkey_algo_t alg) +{ + switch (alg) { + case GPGME_PK_DSA: return "DSA"; + case GPGME_PK_ELG: + case GPGME_PK_ELG_E: return "ELG"; + case GPGME_PK_RSA: return "RSA"; + default: return "???"; + } + return "???"; +} + +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; + + memset (fpr_md, 0, sizeof (fpr_md)); + fpr = key->subkeys->fpr; + if (!fpr || !*fpr) { + memset (tmp, '0', 40); + fpr = tmp; + } + if (strlen (fpr) == 32) { + strcat (fpr_md, " "); + for (i=0; i < strlen (fpr)/2; i++) { + sprintf (t, "%c%c ", fpr[2*i], fpr[2*i+1]); + strcat (fpr_md, t); + } + } + else { + strcat (fpr_md, " "); + for (i = 0; i < strlen (fpr) / 4; i++) { + sprintf (t, "%c%c%c%c ", fpr[4*i], fpr[4*i+1], fpr[4*i+2], fpr[4*i+3]); + strcat (fpr_md, t); + } + } + return fpr_md; +} + + +const char* +get_key_trust2 (gpgme_key_t key, int val, int uididx, int listmode) +{ + if (key) + val = key->owner_trust; /* uididx?? */ + switch (val) { + case GPGME_VALIDITY_UNKNOWN: + case GPGME_VALIDITY_UNDEFINED: + return _("None"); + case GPGME_VALIDITY_NEVER: + return _("Never"); + case GPGME_VALIDITY_MARGINAL: + return _("Marginal"); + case GPGME_VALIDITY_FULL: + case GPGME_VALIDITY_ULTIMATE: + return _("Full"); + } + return ""; +} + + +const char* +get_key_trust (gpgme_key_t key, int uididx, int listmode) +{ + return get_key_trust2 (key, 0, uididx, listmode); +} + + +const char* +get_key_trust_str (int val) +{ + return get_key_trust2 (NULL, val, 0, 0); +} + + +/* Return the status of the key @key. */ +char* +get_key_status (gpgme_key_t key, int uididx, int listmode) +{ + gpgme_user_id_t u; + const char *attr; + u32 key_attr =0; + + if (uididx < 0 || count_userids (key) > uididx) + uididx = 0; + if (listmode) { + const char *s; + if (key->revoked) + s = _("Revoked"); + else if (key->expired) + s = _("Expired"); + else if (key->disabled) + s = _("Disabled"); + else + s = ""; + /* if the key has a special status, we don't continue to figure out + the user-id validities. */ + if (*s) + return m_strdup (s); + } + u = get_nth_userid (key, uididx); + key_attr = u->validity; + attr = get_key_trust2 (NULL, key_attr, 0, 0); + return m_strdup (attr); +} + + +/* 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 *p; + + /* XXX: problems with the German translation. */ + state = ""; + if (key->disabled) + state = _("Disabled"); + if (key->expired) + state = _("Expired"); + if (key->revoked) + state = _("Revoked"); + alg = "OpenPGP"; + if (strlen (key->subkeys->fpr) == 32) + alg = "RSA Legacy"; + type = _("public key"); + if (!get_seckey (key->subkeys->keyid+8, &sk)) + type = _("key pair"); + p = new char[strlen (state) + strlen (alg) + strlen (type) + 4 + 1]; + if (!p) + BUG (0); + sprintf (p, "%s %s %s", state, alg, type); + return p; +} + + +/* Integer comparsion of @a and @b. + Return values: same as in strcmp. */ +static inline int +int_cmp (int a, int b) +{ + if (a == b) return 0; + else if (a > b) return 1; + else return -1; + return 0; +} + + +/* To allow to sort the keys, we need to take care of + the expired/revoke status also. */ +static int +get_ext_validity (gpgme_key_t k) +{ + if (k->revoked) + 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; +} + + +/* List view sorting callback. */ +static int CALLBACK +keylist_cmp_cb (LPARAM first, LPARAM second, LPARAM sortby) +{ + gpgme_key_t a, b; + int cmpresult = 0; + + a = (gpgme_key_t)first; + b = (gpgme_key_t)second; + if (!a || !b) + BUG (NULL); + + switch (sortby & ~KEYLIST_SORT_DESC) { + case KEY_SORT_USERID: cmpresult = strcmpi (a->uids->uid, b->uids->uid); - break; - - case KEY_SORT_KEYID: - cmpresult = strcmpi (a->subkeys->keyid+8, - b->subkeys->keyid+8); - break; - - case KEY_SORT_VALIDITY: /* XXX: handle expire, revoked */ - cmpresult = int_cmp (a->uids->validity, b->uids->validity); - break; - - case KEY_SORT_OTRUST: /* XXX: handle expire, revoked */ - cmpresult = int_cmp (a->owner_trust, b->owner_trust); - break; - - case KEY_SORT_IS_SECRET: - get_seckey (a->subkeys->keyid, &a); - get_seckey (b->subkeys->keyid, &b); - cmpresult = int_cmp (a? a->secret : 0, b? b->secret : 0); - break; - - case KEY_SORT_LEN: - cmpresult = int_cmp (a->subkeys->length, - b->subkeys->length); - break; - - case KEY_SORT_CREATED: - cmpresult = int_cmp (a->subkeys->timestamp, - b->subkeys->timestamp); - break; - - case KEY_SORT_ALGO: - cmpresult = int_cmp (a->subkeys->pubkey_algo, - b->subkeys->pubkey_algo); - break; - - default: - cmpresult = strcmpi (a->uids->uid, b->uids->uid); - break; - } - if (sortby & KEYLIST_SORT_DESC) - return (~cmpresult + 1); - else - return cmpresult; -} - - -static const char* -calc_validity (gpg_group_t grp) -{ - int level = 0, valid; - 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"); -} /* calc_validity */ - - -int -keylist_add_groups( listview_ctrl_t lv ) -{ -#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 */ - - -static int -keylist_build( listview_ctrl_t *r_lv, HWND ctrl, int mode ) -{ - listview_ctrl_t lv; - listview_column_t col; - int j, n = 0; - int kl_nolist = 0, rc = 0; - - rc = listview_new( &lv ); - if( rc ) - return rc; - - lv->ctrl = ctrl; - if( (mode & KEYLIST_ENCRYPT) || (mode & KEYLIST_ENCRYPT_MIN) ) { - col = klist_enc; - n = KLIST_ENC_ITEMS; - } - else if( (mode & KEYLIST_SIGN) ) { - col = klist_enc; - n = KLIST_ENC_ITEMS - 1; - } - else { - col = klist; - n = KLIST_ITEMS; - } - - for( j = 0; j < n; j++ ) - listview_add_column( lv, &col[j] ); - listview_set_ext_style( lv ); - *r_lv = lv; - - return 0; -} /* keylist_build */ - - -static void -keylist_load_keycache (listview_ctrl_t lv, 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; - - if (pubkc && seckc) { - gpg_keycache_rewind (pubkc); - while (!gpg_keycache_next_key (pubkc, 0, &key)) { - keyid = key->subkeys->keyid; - if (keyid && !gpg_keycache_find_key (seckc, keyid, 0, &skey)) - keylist_add_key (lv, mode, 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); - } - } -} /* keylist_load_keycache */ - - -listview_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_load */ - - -int -keylist_reload( listview_ctrl_t lv, gpg_keycache_t pubkc, int mode, int sortby ) -{ - listview_del_all( lv ); - keylist_load_keycache( lv, mode, pubkc, NULL ); - keylist_sort( lv, sortby ); - return 0; -} /* keylist_reload */ - - -void -keylist_delete( listview_ctrl_t lv ) -{ - if( lv ) { - listview_release( lv ); - } -} /* keylist_delete */ - - -static int -find_secret_key( gpgme_key_t key ) -{ - const char * keyid; - gpgme_key_t skey; - - keyid = key->subkeys->keyid; - if (!keyid) - return 0; - get_seckey (keyid, &skey); - return skey? 1 : 0; -} /* find_secret_key */ - - -static int -do_addkey (listview_ctrl_t lv, gpgme_key_t key, int uididx, int keyidx, int list) -{ - LV_ITEM lvi; - gpgme_user_id_t u; - gpgme_subkey_t k; - char fmt[128]; - const char *attr; - u32 key_attr; - 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", - key->uids->name, key->subkeys->keyid); - return 0; - } - - - if (listview_add_item2 (lv, " ", (void *)key)) - return WPTERR_GENERAL; - - attr = key->uids->uid; - memset( &lvi, 0, sizeof lvi ); - lvi.mask = LVIF_TEXT | LVIF_PARAM; - lvi.pszText = (char *)attr; - lvi.lParam = (LPARAM )key; - 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; - 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) */ - u = get_nth_userid (key, uididx); - attr = key->uids->uid; - } - 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); - } - } - 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 (list > 0) { - attr = find_secret_key (key)? "pub/sec" : "pub"; - if (strchr( attr, '/')) { - struct winpt_key_s k; - winpt_get_seckey (key->subkeys->keyid, &k); - if (k.ext->gloflags.divert_to_card) - attr = "pub/crd"; - } - listview_add_sub_item( lv, 0, idx++, attr ); - } - if (lv->cols >= 2) { - attr = get_key_size (key, list == -1? keyidx+1 : 0); - if (attr) - listview_add_sub_item (lv, 0, idx++, attr); - } - if (lv->cols >= 3) { - attr = get_key_algo (key, list == -1? keyidx+1 : 0); - if (attr) - listview_add_sub_item( lv, 0, idx++, attr); - } - if( lv->cols >= 4 ) { - char * status = get_key_status( key, uididx, list > 0? 1 : 0 ); - if (!status) - return WPTERR_GENERAL; - listview_add_sub_item( lv, 0, idx++, status ); - free_if_alloc( status ); - } - if (lv->cols >= 5) { - const char * s = get_key_trust (key, uididx, list > 0? 1 : 0); - listview_add_sub_item (lv, 0, idx++, s); - } - 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 ); - } - } - - return 0; -} /* do_addkey */ - - -void -keylist_upd_key (listview_ctrl_t lv, int pos, gpgme_key_t key) -{ - const char *s; - char tmp[32]; - - listview_set_item2 (lv, pos, (void *)key); - /* the only mode we support is KYLIST_LIST in the Key Manager */ - - s = key->uids->uid; - if (s) - listview_add_sub_item (lv, pos, 0, s); - - s = key->subkeys->keyid; - if (s) { - sprintf (tmp, "0x%s", s+8); - listview_add_sub_item (lv, pos, 1, tmp); - } - - s = find_secret_key (key)? "pub/sec" : "pub"; - listview_add_sub_item (lv, pos, 2, s); - - s = get_key_size (key, 0); - if (s) - listview_add_sub_item (lv, pos, 3, s); - - s = get_key_algo (key, 0); - if (s) - listview_add_sub_item (lv, pos, 4, s); - - s = get_key_status (key, 0, 1); - if (s) - listview_add_sub_item (lv, pos, 5, s); - - s = get_key_trust (key, 0, 1); - if (s) - listview_add_sub_item (lv, pos, 6, s); - - long t = key->subkeys->timestamp; - s = get_key_created (t); - if (s) - listview_add_sub_item (lv, pos, 7, s); -} - - -int -keylist_add_key (listview_ctrl_t lv, int mode, gpgme_key_t key) -{ - int uids, rc = 0, i, n = 0; - gpgme_subkey_t k; - - 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); - continue; /* Don't use invalid keys */ - } - - if (mode & KEYLIST_ALL) { - uids = count_userids (key); - rc = do_addkey (lv, key, uids, i, 0); - if( rc ) - return rc; - } - else if (mode & KEYLIST_LIST) - return do_addkey (lv, 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); - if (rc) - return rc; - } - else { - for( uids = 0; uids < count_userids (key); uids++ ) { - rc = do_addkey( lv, 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); - return rc; - } - } - else if (mode & KEYLIST_SIGN) { - if ( k->can_sign - && find_secret_key( key ) - && key_is_useable (k)) - { - rc = do_addkey (lv, key, -1, i, -1); - if( rc ) - return rc; - } - } - } - - return rc; -} /* keylist_add_key */ - - -int -keylist_sort (listview_ctrl_t lv, int sortby) -{ - return listview_sort_items (lv, sortby, keylist_cmp_cb); -} - - -/* 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; -} - - -/* Extract all selected recipients from the list @lv and return them - as a vector. @r_force_trust is >= 1 if one of the recipients is not - 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) -{ - 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]; - key_array_s *ka = NULL; - gpgme_key_t *keybuf; - - n = listview_count_items( lv, 0 ); - - ka = key_array_new( n ); - if (!ka) - BUG (NULL); - - keybuf = (gpgme_key_t*)calloc (n, 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; - force_trust++; - ka[ka_pos].checked = 1; - strcpy (ka[ka_pos++].keyid, 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; - count++; - } - } - } - key_array_release (ka); - if (r_force_trust) - *r_force_trust = force_trust; - if (r_count) - *r_count = count; - return keybuf; -} - - -static int -keylist_get_keyflags (const char *buf, size_t buflen) -{ - int c = 0, flags = 0; - - 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; - } - - return flags; -} /* keylist_get_keyflags */ - - -gpgme_key_t* -keylist_enum_recipients (listview_ctrl_t lv, int listype, int *r_count) -{ - gpgme_key_t* rset; - gpgme_key_t k; - int i, n, id, k_pos=0; - char keyid[32], t[128], t2[128]; - - n = listview_count_items (lv, 0); - if (!n) - return 0; - rset = (gpgme_key_t*)calloc (n, sizeof (gpgme_key_t)); - if (!rset) - BUG (NULL); - for( i = 0; i < n; i++ ) { - if( !listview_get_item_state( lv, i ) ) - continue; - listview_get_item_text( lv, i, 1, keyid, sizeof keyid - 1 ); - 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; - } - break; - } - get_pubkey (keyid, &k); - rset[k_pos++] = k; - } - if (r_count) - *r_count = k_pos; - return rset; -} /* keylist_enum_recipients */ - - -void -seclist_destroy (keylist_t * list) -{ - keylist_t l2; - while (*list) { - l2 = (*list)->next; - safe_free (*list); - *list = l2; - } - list = NULL; -} /* seclist_destroy */ - - -void -seclist_init (HWND dlg, int ctlid, int flags, keylist_t * ret_list) -{ - gpg_keycache_t kc = NULL; - gpgme_key_t key = NULL; - HWND kb; - keylist_t list=NULL, l, l2; - long pos = 0; - - SendDlgItemMessage (dlg, ctlid, CB_RESETCONTENT, 0, 0); - kb = GetDlgItem (dlg, ctlid); - kc = keycache_get_ctx (0); - if (!kc) - BUG (0); - gpg_keycache_rewind (kc); - - while (!gpg_keycache_next_key (kc, 1, &key)) { - char * inf = NULL, * uid = NULL; - const char * id; - const char * keyid; - int algo; - size_t size = 0; - - 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; /* fixme: error? */ - if (!key_is_useable (key->subkeys)) - continue; - - 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); - l = (struct keylist_s *)calloc (1, sizeof * l); - if (!l) - BUG (0); - l->key = key; - if (!list) - list = l; - else { - for( l2 = list; l2->next; l2 = l2->next ) - ; - 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 ); - *ret_list = list; -} - - -/* Select a secret key from the combo box with the ID @ctlid. - Return the code on success in @ret_key. */ -int -seclist_select_key (HWND dlg, int ctlid, gpgme_key_t *ret_key) -{ - int pos; - DWORD k = 0; - - pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0); - if (pos == CB_ERR) { - msg_box (dlg, _("No key was selected."), _("Secret Key List"), MB_ERR); - *ret_key = NULL; - } - else { - k = SendDlgItemMessage (dlg, ctlid, CB_GETITEMDATA, pos, 0); - *ret_key = (gpgme_key_t)k; - } - return k? 0 : -1; -} + break; + + case KEY_SORT_KEYID: + cmpresult = strcmpi (a->subkeys->keyid+8, + b->subkeys->keyid+8); + break; + + case KEY_SORT_VALIDITY: + cmpresult = int_cmp (get_ext_validity (a), + get_ext_validity (b)); + break; + + case KEY_SORT_OTRUST: + cmpresult = int_cmp (a->owner_trust, b->owner_trust); + break; + + case KEY_SORT_IS_SECRET: + get_seckey (a->subkeys->keyid, &a); + get_seckey (b->subkeys->keyid, &b); + cmpresult = int_cmp (a? a->secret : 0, b? b->secret : 0); + break; + + case KEY_SORT_LEN: + cmpresult = int_cmp (a->subkeys->length, + b->subkeys->length); + break; + + case KEY_SORT_CREATED: + cmpresult = int_cmp (a->subkeys->timestamp, + b->subkeys->timestamp); + break; + + case KEY_SORT_ALGO: + cmpresult = int_cmp (a->subkeys->pubkey_algo, + b->subkeys->pubkey_algo); + break; + + default: + cmpresult = strcmpi (a->uids->uid, b->uids->uid); + break; + } + if (sortby & KEYLIST_SORT_DESC) + return (~cmpresult + 1); + else + return cmpresult; +} + + +int +keylist_add_groups (listview_ctrl_t lv) +{ + return 0; +} + + +/* Create a listview for listing keys. Use the mode given in @mode + and the control is given in @ctrl. */ +static int +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[2]; + listview_ctrl_t lv; + listview_column_t col; + int j, n = 0, ext_chk = 0; + int rc = 0; + + rc = listview_new (&lv); + if (rc) + return rc; + + lv->ctrl = ctrl; + if (mode & KEYLIST_ENCRYPT_MIN) { + col = klist_enc; + n = (DIM(klist_enc) -1); + ext_chk = 1; + } + else if ((mode & KEYLIST_SIGN)) { + col = klist_enc; + n = (DIM(klist_enc) - 1) - 1; + ext_chk = 1; + } + else { + col = klist; + n = (DIM(klist) - 1); + } + + for (j = 0; j < n; j++) + listview_add_column (lv, &col[j]); + listview_set_ext_style (lv); + if (ext_chk) + listview_set_chkbox_style (lv); + ico[0] = LoadIcon (glob_hinst, (LPCTSTR)IDI_PUBKEY); + ico[1] = LoadIcon (glob_hinst, (LPCTSTR)IDI_KEYPAIR); + listview_set_image_list (lv, 22, 14, ico, 2); + listview_del_all_items (lv); + + *r_lv = lv; + return 0; +} + + +static void +keylist_load_keycache (listview_ctrl_t lv, 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; + + if (pubkc && seckc) { + gpg_keycache_rewind (pubkc); + while (!gpg_keycache_next_key (pubkc, 0, &key)) { + keyid = key->subkeys->keyid; + if (keyid && !gpg_keycache_find_key (seckc, keyid, 0, &skey)) + keylist_add_key (lv, mode, 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); + } + } +} + + +/* Load the list view @ctrl with the keys from the cache. + Return value: list view context on success. */ +listview_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_MIN) + keylist_add_groups (lv); + return lv; +} + + +/* Reload the given key list control @lv. */ +int +keylist_reload (listview_ctrl_t lv, gpg_keycache_t pubkc, int mode, int sortby) +{ + listview_del_all_items (lv); + keylist_load_keycache (lv, mode, pubkc, NULL); + keylist_sort (lv, sortby); + return 0; +} + + +void +keylist_delete (listview_ctrl_t lv) +{ + if (lv) { + listview_release (lv); + } +} + + +/* Return if there is a secret for @key. + 0 means success. */ +static int +find_secret_key (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; +} + + +static int +do_addkey (listview_ctrl_t lv, gpgme_key_t key, int uididx, int keyidx, int list) +{ + LV_ITEM lvi; + gpgme_user_id_t u; + gpgme_subkey_t k; + char fmt[128], *p; + const char *attr; + u32 key_attr; + 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", + key->uids->name, key->subkeys->keyid); + return 0; + } + + if (listview_add_item2 (lv, " ", (void *)key)) + return WPTERR_GENERAL; + + attr = key->uids->uid; + memset (&lvi, 0, sizeof lvi); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + lvi.pszText = (char *)attr; + lvi.iImage = find_secret_key (key)? 1 : 0; + lvi.lParam = (LPARAM )key; + 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; + uididx = 0; + } + else { + u = get_nth_userid (key, uididx); + if (!u || u->revoked || uididx < 0) + uididx = 0; + u = get_nth_userid (key, uididx); + attr = u->uid; + } + 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_native (attr); + if (uid) { + listview_add_sub_item (lv, 0, idx++, uid); + free (uid); + } + } + 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 (list > 0) { + key_attr = find_secret_key (key); + if (!key_attr) + attr = "pub"; + else + attr = key_attr == 1? "pub/sec" : "pub/crd"; + listview_add_sub_item (lv, 0, idx++, attr); + } + if (lv->cols >= 2) { + attr = get_key_size (key, list == -1? keyidx+1 : 0); + if (attr) + listview_add_sub_item (lv, 0, idx++, attr); + } + if (lv->cols >= 3) { + attr = get_key_algo (key, list == -1? keyidx+1 : 0); + if (attr) + 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); + 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 ) { + 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 ); + } + } + + return 0; +} + + +/* Update a single column @col but for each element in the + listview @lv. */ +void +keylist_upd_col (listview_ctrl_t lv, int col) +{ + gpgme_key_t key; + const char *s; + char buf[32], *p; + int i; + + for (i=0; i < listview_count_items (lv, 0); i++) { + key = (gpgme_key_t)listview_get_item2 (lv, i); + if (!key) + continue; + switch (col) { + case KM_COL_KEYID: + _snprintf (buf, sizeof (buf)-1, "0x%s", key->subkeys->keyid+8); + listview_add_sub_item (lv, i, col, buf); + break; + + case KM_COL_CIPHER: + s = get_key_algo (key, 0); + listview_add_sub_item (lv, i, col, s); + break; + + case KM_COL_TYPE: + s = find_secret_key (key)? "pub/sec" : "pub"; + listview_add_sub_item (lv, i, col, s); + break; + + case KM_COL_CREAT: + s = get_key_created (key->subkeys->timestamp); + listview_add_sub_item (lv, i, col, s); + break; + + case KM_COL_DESC: + p = get_key_desc (key); + listview_add_sub_item (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 (listview_ctrl_t lv, int pos, gpgme_key_t key) +{ + const char *s; + char *uid, *p; + char tmp[32]; + + listview_set_item2 (lv, pos, (void *)key); + /* the only mode we support is KYLIST_LIST in the Key Manager */ + + s = key->uids->uid; + if (s) { + uid = utf8_to_native (s); + listview_add_sub_item (lv, pos, KM_COL_UID, uid); + free (uid); + } + + s = key->subkeys->keyid; + if (s) { + sprintf (tmp, "0x%s", s+8); + listview_add_sub_item (lv, pos, KM_COL_KEYID, tmp); + } + + s = find_secret_key (key)? "pub/sec" : "pub"; + listview_add_sub_item (lv, pos, KM_COL_TYPE, s); + + s = get_key_size (key, 0); + if (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, KM_COL_CIPHER, 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, KM_COL_TRUST, s); + + long t = key->subkeys->timestamp; + s = get_key_created (t); + if (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; + gpgme_subkey_t k; + + /* if the entire key is disabled, just return. */ + if (key->disabled && !(mode & KEYLIST_LIST)) + return 0; + + 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); + continue; /* Don't use invalid keys */ + } + + if (mode & KEYLIST_ALL) { + uids = count_userids (key); + rc = do_addkey (lv, key, uids, i, 0); + if (rc) + return rc; + } + else if (mode & KEYLIST_LIST) + return do_addkey (lv, 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); + if (rc) + return rc; + } + else { + for (uids = 0; uids < count_userids (key); uids++) { + rc = do_addkey (lv, 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); + return rc; + } + } + else if (mode & KEYLIST_SIGN) { + if (k->can_sign + && find_secret_key (key) + && key_is_useable (k)) { + rc = do_addkey (lv, key, -1, i, -1); + if (rc) + return rc; + } + } + } + + return rc; +} + + +int +keylist_sort (listview_ctrl_t lv, int sortby) +{ + return listview_sort_items (lv, sortby, keylist_cmp_cb); +} + + +/* Check that the validity @validity is at least >= marginal. */ +static int +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; +} + + +/* Extract all selected recipients from the list @lv and return them + as a vector. @r_force_trust is >= 1 if one of the recipients is not + 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) +{ + key_array_s *ka = NULL; + gpgme_key_t *keybuf, key; + int count = 0, force_trust = 0; + int n, j, ka_pos = 0, rc = 0; + int k_pos=0; + + n = listview_count_items (lv, 0); + + ka = key_array_new (n); + if (!ka) + BUG (NULL); + + keybuf = (gpgme_key_t*)calloc (n+1, sizeof (gpgme_key_t)); + if (!keybuf) + BUG (NULL); + + for (j = 0; j < n; j++) { + if (listview_get_item_state (lv, j) || n == 1) { + key = (gpgme_key_t)listview_get_item2 (lv, j); + if (!key) + BUG (0); + if (!key_check_validity (key) && + !key_array_search (ka, ka_pos, key->subkeys->keyid)) { + char *utf8_uid = utf8_to_native (key->uids->uid); + char *warn = new char[512+strlen (utf8_uid) + 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?"), utf8_uid); + if (reg_prefs.always_trust) + rc = IDYES; + else + rc = msg_box (NULL, warn, _("Recipients"), MB_ERR_ASK); + if (rc == IDYES) { + keybuf[k_pos++] = key; + force_trust++; + ka[ka_pos].checked = 1; + strcpy (ka[ka_pos++].keyid, key->subkeys->keyid); + count++; + } + safe_free (utf8_uid); + free_if_alloc (warn); + } + else { + keybuf[k_pos++] = key; + count++; + } + } + } + key_array_release (ka); + if (r_force_trust) + *r_force_trust = force_trust; + if (r_count) + *r_count = count; + return keybuf; +} + + +static int +keylist_get_keyflags (gpgme_key_t key) +{ + int flags = KEYFLAG_NONE; + + if (key->revoked) + flags |= KEYFLAG_REVOKED; + if (key->expired) + flags |= KEYFLAG_EXPIRED; + if (key->disabled) + flags |= KEYFLAG_DISABLED; + + return flags; +} + + +gpgme_key_t* +keylist_enum_recipients (listview_ctrl_t lv, int listype, int *r_count) +{ + gpgme_key_t *rset; + gpgme_key_t key; + int i, n, id, k_pos=0; + + n = listview_count_items (lv, 0); + if (!n) + return 0; + rset = (gpgme_key_t*)calloc (n+1, sizeof (gpgme_key_t)); + if (!rset) + BUG (NULL); + for (i = 0; i < n; i++) { + if (!listview_get_item_state (lv, i)) + continue; + key = (gpgme_key_t)listview_get_item2 (lv, i); + if (!key) + BUG (0); + switch (listype) { + case KEYLIST_LIST: + 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?"), + key->uids->uid); + if (id == IDNO) + continue; + } + break; + } + rset[k_pos++] = key; + } + if (r_count) + *r_count = k_pos; + return rset; +} + + +void +seclist_destroy (keylist_t *list) +{ + keylist_t l2; + while (*list) { + l2 = (*list)->next; + safe_free (*list); + *list = l2; + } + list = NULL; +} + + +void +seclist_init (HWND dlg, int ctlid, int flags, keylist_t * ret_list) +{ + gpg_keycache_t kc = NULL; + gpgme_key_t key = NULL; + HWND kb; + keylist_t list=NULL, l, l2; + long pos = 0; + + SendDlgItemMessage (dlg, ctlid, CB_RESETCONTENT, 0, 0); + kb = GetDlgItem (dlg, ctlid); + kc = keycache_get_ctx (0); + if (!kc) + BUG (0); + gpg_keycache_rewind (kc); + + while (!gpg_keycache_next_key (kc, 1, &key)) { + char *inf = NULL, *uid = NULL; + const char *id; + const char *keyid; + int algo; + size_t size = 0; + + 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; + + uid = utf8_to_native (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); + l = (struct keylist_s *)calloc (1, sizeof * l); + if (!l) + BUG (0); + l->key = key; + if (!list) + list = l; + else { + for( l2 = list; l2->next; l2 = l2->next ) + ; + 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); + *ret_list = list; +} + + +/* Select a secret key from the combo box with the ID @ctlid. + Return the code on success in @ret_key. */ +int +seclist_select_key (HWND dlg, int ctlid, gpgme_key_t *ret_key) +{ + int pos; + DWORD k = 0; + + pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0); + if (pos == CB_ERR) { + msg_box (dlg, _("No key was selected."), _("Secret Key List"), MB_ERR); + *ret_key = NULL; + } + else { + k = SendDlgItemMessage (dlg, ctlid, CB_GETITEMDATA, pos, 0); + *ret_key = (gpgme_key_t)k; + } + return k? 0 : -1; +}