/[winpt]/trunk/Src/wptKeylist.cpp
ViewVC logotype

Contents of /trunk/Src/wptKeylist.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 328 - (show annotations)
Fri Sep 25 16:07:38 2009 UTC (15 years, 5 months ago) by twoaday
File size: 30243 byte(s)


1 /* wptKeylist.cpp - Keylist element
2 * Copyright (C) 2001-2006, 2009 Timo Schulz
3 * Copyright (C) 2004 Andreas Jobs
4 *
5 * This file is part of WinPT.
6 *
7 * WinPT is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * WinPT is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #include <windows.h>
22 #include <commctrl.h>
23 #include <time.h>
24
25 #include "wptCommonCtl.h"
26 #include "wptTypes.h"
27 #include "wptGPG.h"
28 #include "wptKeylist.h"
29 #include "wptKeyManager.h"
30 #include "wptW32API.h"
31 #include "wptNLS.h"
32 #include "wptErrors.h"
33 #include "wptUTF8.h"
34 #include "wptRegistry.h"
35 #include "wptContext.h"
36 #include "wptVersion.h"
37 #include "resource.h"
38 #include "StringBuffer.h"
39
40
41 struct key_array_s {
42 char keyid[32];
43 int checked;
44 };
45
46
47 static key_array_s*
48 key_array_new (DWORD items)
49 {
50 key_array_s *ka;
51
52 if (items == 0)
53 BUG (NULL);
54 ka = new key_array_s[items + 1];
55 if (!ka)
56 BUG (NULL);
57 for (DWORD i = 0; i < items; i++)
58 ka[i].checked = 0;
59 return ka;
60 }
61
62 static void
63 key_array_release (key_array_s *ka)
64 {
65 free_if_alloc (ka);
66 }
67
68
69 /* Check if the keyid @keyid is in the key array @ka.
70 Return value: 1 if it exists, 0 otherwise. */
71 static int
72 key_array_search (key_array_s *ka, DWORD items, const char *keyid)
73 {
74 for (DWORD i = 0; i < items; i++) {
75 if (!stricmp (keyid, ka[i].keyid))
76 return 1;
77 }
78 return 0;
79 }
80
81
82 /* Return if there is a secret for @key.
83 0 means success. */
84 static int
85 find_secret_key (gpgme_key_t key)
86 {
87 winpt_key_s skey;
88
89 if (!key->subkeys->keyid)
90 return 0;
91 memset (&skey, 0, sizeof (skey));
92 if (winpt_get_seckey (key->subkeys->keyid, &skey))
93 return 0;
94 if (skey.ext && skey.ext->gloflags.divert_to_card)
95 return 2;
96 return skey.ctx? 1 : 0;
97 }
98
99
100 /* Update the gpgme key pointer of a single entry. */
101 static void
102 update_key (keylist_ctrl_t kl, int pos,
103 gpgme_key_t key)
104 {
105 if ((size_t)pos > kl->nkeys)
106 BUG (0);
107 kl->keys[pos] = key;
108 }
109
110
111 /* If @re_sorted == 0, then all keys from the key list control
112 are stored as references in the array.
113 Otherwise we just re-order the references in the array. */
114 static size_t
115 update_keys (keylist_ctrl_t kl, int re_sorted,
116 gpgme_key_t **r_list)
117 {
118 gpgme_key_t *rset;
119 gpgme_key_t key;
120 listview_ctrl_t lv = kl->lv;
121 struct keycache_s *c;
122 size_t k_pos;
123 int nkeys;
124
125 nkeys = listview_count_items (lv, 0);
126 if (!nkeys)
127 BUG (0);
128
129 if (!re_sorted) {
130 rset = (gpgme_key_t*)calloc (nkeys+1, sizeof (gpgme_key_t));
131 *r_list = rset;
132 }
133 else
134 rset = *r_list;
135 k_pos = 0;
136 for (int i = 0; i < nkeys; i++) {
137 key = km_get_key_ptr (kl, i, &c);
138 rset[k_pos++] = key;
139 }
140 return k_pos;
141 }
142
143
144 gpgme_user_id_t
145 get_nth_userid (gpgme_key_t key, int idx)
146 {
147 gpgme_user_id_t t;
148
149 if (!key->uids)
150 return NULL;
151 t = key->uids;
152 while (idx-- && t->next)
153 t = t->next;
154 return t;
155 }
156
157
158 int
159 count_userids (gpgme_key_t key)
160 {
161 gpgme_user_id_t u;
162 int n = 1;
163
164 u = key->uids;
165 if (!u)
166 return 0;
167 while (u->next) {
168 u = u->next;
169 n++;
170 }
171 return n;
172 }
173
174
175 gpgme_subkey_t
176 get_nth_key (gpgme_key_t key, int idx)
177 {
178 gpgme_subkey_t t;
179
180 if (!key->subkeys)
181 return NULL;
182 t = key->subkeys;
183 while (idx-- && t->next)
184 t = t->next;
185 return t;
186 }
187
188
189 int
190 count_subkeys (gpgme_key_t key)
191 {
192 gpgme_subkey_t k;
193 int n = 1;
194
195 k = key->subkeys;
196 if (!k)
197 return 0;
198 while (k->next) {
199 k = k->next;
200 n++;
201 }
202 return n;
203 }
204
205
206 /* Return the self signature of the key @keyid.
207 If first is set, the first self sig will be returned. */
208 gpgme_key_sig_t
209 get_selfsig (gpgme_key_sig_t sigs, const char *keyid, int first)
210 {
211 gpgme_key_sig_t s, self_sig=NULL;
212 long timestamp=0;
213 int off = 0;
214
215 if (strlen (keyid) == 8)
216 off = 8;
217
218 for (s = sigs; s; s = s->next) {
219 if (!strcmp (s->keyid+off, keyid) && s->timestamp > timestamp) {
220 self_sig = s;
221 timestamp = s->timestamp;
222 if (first) /* do not search for later self sigs. */
223 break;
224 }
225 }
226 return self_sig;
227 }
228
229
230 const char*
231 get_key_algo (gpgme_key_t key, int keyidx)
232 {
233 static char algo_id[128];
234 gpgme_subkey_t k;
235 char alg[32];
236 const char *subalg;
237 int n;
238
239 if (keyidx > 0) {
240 k = get_nth_key (key, keyidx-1);
241 subalg = get_key_pubalgo (k->pubkey_algo);
242 _snprintf (algo_id, DIM (algo_id)-1, "%s", subalg);
243 return algo_id;
244 }
245 strcpy (alg, get_key_pubalgo (key->subkeys->pubkey_algo));
246 n = count_subkeys (key);
247 if (n > 1) {
248 do {
249 k = get_nth_key (key, --n);
250 if (k->revoked || k->expired)
251 continue;
252 else
253 break;
254 } while (n > 0);
255 subalg = get_key_pubalgo (k->pubkey_algo);
256 if (k == key->subkeys)
257 _snprintf (algo_id, DIM (algo_id)-1, "%s", subalg);
258 else
259 _snprintf (algo_id, DIM (algo_id)-1, "%s/%s", alg, subalg);
260 return algo_id;
261 }
262 return get_key_pubalgo (key->subkeys->pubkey_algo);
263 }
264
265
266 const char*
267 get_key_created (long timestamp)
268 {
269 static char timebuf[128];
270
271 if (timestamp < 1)
272 return "????" "-??" "-??";
273 if (!get_locale_date (timestamp, timebuf, DIM (timebuf)-1))
274 return "????" "-??" "-??";
275 return timebuf;
276 }
277
278
279 /* Return a string presentation of the time @timestamp. */
280 const char*
281 get_key_expire_date (long timestamp)
282 {
283 static char timebuf[64];
284
285 if (timestamp == 0)
286 return _("Never");
287 if (!get_locale_date (timestamp, timebuf, DIM (timebuf)-1))
288 return "????" "-??" "-??";
289 return timebuf;
290 }
291
292
293 const char*
294 get_key_type (gpgme_key_t key)
295 {
296 int type = find_secret_key (key);
297
298 if (type == 1)
299 return _("Key Pair");
300 else if (type == 2)
301 return _("Key Pair (Card)");
302 return _("Public Key");
303 }
304
305
306 const char*
307 get_key_size (gpgme_key_t key, int keyidx)
308 {
309 static char size_id[64];
310 gpgme_subkey_t k;
311 int n, size_main, size_sub;
312
313 if (keyidx > 0) {
314 k = get_nth_key (key, keyidx-1);
315 size_main = k->length;
316 _snprintf (size_id, DIM (size_id)-1, "%d", size_main);
317 return size_id;
318 }
319 size_main = key->subkeys->length;
320 n = count_subkeys (key);
321 if (n > 1) {
322 k = get_nth_key (key, n-1);
323 size_sub = k->length;
324 _snprintf (size_id, DIM (size_id) - 1, "%d/%d",
325 size_main, size_sub);
326 return size_id;
327 }
328 _snprintf (size_id, DIM (size_id) - 1, "%d", size_main);
329 return size_id;
330 }
331
332
333 const char*
334 get_key_pubalgo2 (gpgme_pubkey_algo_t alg)
335 {
336 switch (alg) {
337 case GPGME_PK_DSA: return "D";
338 case GPGME_PK_RSA: return "R";
339 case GPGME_PK_ELG: return "G";
340 default: return "?";
341 }
342 return "?";
343 }
344
345
346 const char*
347 get_key_pubalgo (gpgme_pubkey_algo_t alg)
348 {
349 switch (alg) {
350 case GPGME_PK_DSA: return "DSA";
351 case GPGME_PK_ELG:
352 case GPGME_PK_ELG_E: return "ELG";
353 case 0: /* XXX: do we still need this?? */
354 case GPGME_PK_RSA:
355 case GPGME_PK_RSA_S:
356 case GPGME_PK_RSA_E: return "RSA";
357 default: return "???";
358 }
359 return "???";
360 }
361
362
363 const char*
364 get_key_fpr (gpgme_key_t key)
365 {
366 static char fpr_md[64];
367 const char *fpr;
368 char t[16], tmp[40];
369 size_t i;
370
371 memset (fpr_md, 0, sizeof (fpr_md));
372 fpr = key->subkeys->fpr;
373 if (!fpr || !*fpr) {
374 memset (tmp, '0', 40);
375 fpr = tmp;
376 }
377 if (strlen (fpr) == 32) {
378 strcat (fpr_md, " ");
379 for (i=0; i < strlen (fpr)/2; i++) {
380 sprintf (t, "%c%c ", fpr[2*i], fpr[2*i+1]);
381 strcat (fpr_md, t);
382 }
383 }
384 else {
385 strcat (fpr_md, " ");
386 for (i = 0; i < strlen (fpr) / 4; i++) {
387 sprintf (t, "%c%c%c%c ", fpr[4*i], fpr[4*i+1], fpr[4*i+2], fpr[4*i+3]);
388 strcat (fpr_md, t);
389 }
390 }
391 return fpr_md;
392 }
393
394
395 /* Extract the key ID from the fingerprint.
396 A long ID will be converted into a short ID. */
397 const char*
398 get_keyid_from_fpr (const char *fpr)
399 {
400 if (!fpr)
401 return "????????";
402 if (strlen (fpr) == 40)
403 fpr += 32;
404 else if (strlen (fpr) == 32)
405 fpr += 24;
406 else if (strlen (fpr) == 16)
407 fpr += 8;
408 else
409 return "????????";
410 return fpr;
411 }
412
413
414 const char*
415 get_key_trust2 (gpgme_key_t key, int val, int uididx, int listmode)
416 {
417 if (key)
418 val = key->owner_trust; /* uididx?? */
419 switch (val) {
420 case GPGME_VALIDITY_UNKNOWN:
421 case GPGME_VALIDITY_UNDEFINED:
422 return _("None");
423 case GPGME_VALIDITY_NEVER:
424 return _("Never");
425 case GPGME_VALIDITY_MARGINAL:
426 return _("Marginal");
427 case GPGME_VALIDITY_FULL:
428 return _("Full");
429 case GPGME_VALIDITY_ULTIMATE:
430 return _("Ultimate");
431 }
432 return "";
433 }
434
435
436 const char*
437 get_key_trust (gpgme_key_t key, int uididx, int listmode)
438 {
439 return get_key_trust2 (key, 0, uididx, listmode);
440 }
441
442
443 const char*
444 get_key_trust_str (int val)
445 {
446 return get_key_trust2 (NULL, val, 0, 0);
447 }
448
449
450 /* Return the status of the key @key. */
451 char*
452 get_key_status (gpgme_key_t key, int uididx, int listmode)
453 {
454 gpgme_user_id_t u;
455 const char *attr;
456 u32 key_attr =0;
457
458 if (uididx < 0 || count_userids (key) > uididx)
459 uididx = 0;
460 if (listmode) {
461 const char *s;
462 if (key->revoked)
463 s = _("Revoked");
464 else if (key->expired)
465 s = _("Expired");
466 else if (key->disabled)
467 s = _("Disabled");
468 else
469 s = "";
470 /* if the key has a special status, we don't continue to figure out
471 the user-id validities. */
472 if (*s)
473 return m_strdup (s);
474 }
475 u = get_nth_userid (key, uididx);
476 key_attr = u->validity;
477 attr = get_key_trust2 (NULL, key_attr, 0, 0);
478 return m_strdup (attr);
479 }
480
481
482 /* Return human readable description of the key @key. */
483 char*
484 get_key_desc (gpgme_key_t key)
485 {
486 gpgme_key_t sk;
487 const char *state, *alg, *type;
488 char *desc;
489 StringBuffer p;
490
491 state = "";
492 if (key->disabled)
493 state = _("Disabled");
494 if (key->expired)
495 state = _("Expired");
496 if (key->revoked)
497 state = _("Revoked");
498
499 /* If the fingerprint has 32 octets, we assume MD5 and thus
500 an old, version 3, RSA key which is called 'Legacy' by other
501 OpenPGP programs. */
502 if (strlen (key->subkeys->fpr) == 32)
503 alg = "RSA Legacy";
504 else
505 alg = "OpenPGP";
506 type = _("public key");
507 if (!get_seckey (key->subkeys->keyid+8, &sk))
508 type = _("key pair");
509 p = state;
510 p = p + " " + alg + " " + type;
511 desc = m_strdup (p.getBuffer ());
512 return desc;
513 }
514
515
516 /* Integer comparsion of @a and @b.
517 Return values: same as in strcmp. */
518 static inline int
519 int_cmp (int a, int b)
520 {
521 if (a == b) return 0;
522 else if (a > b) return 1;
523 else return -1;
524 return 0;
525 }
526
527
528 /* To allow to sort the keys, we need to take care of
529 the expired/revoke status also. */
530 static int
531 get_ext_validity (gpgme_key_t k)
532 {
533 if (k->revoked)
534 return GPGME_VALIDITY_ULTIMATE+1;
535 else if (k->expired)
536 return GPGME_VALIDITY_ULTIMATE+2;
537 else if (k->disabled)
538 return GPGME_VALIDITY_ULTIMATE+3;
539 return k->uids->validity;
540 }
541
542
543 /* List view sorting callback. */
544 static int CALLBACK
545 keylist_cmp_cb (LPARAM first, LPARAM second, LPARAM sortby)
546 {
547 struct keycache_s *aa, *bb;
548 gpgme_key_t a, b;
549 int cmpresult = 0;
550
551 aa = (struct keycache_s *)first;
552 bb = (struct keycache_s *)second;
553 if (!aa || !bb)
554 BUG (NULL);
555 a = aa->key;
556 b = bb->key;
557
558 switch (sortby & ~KEYLIST_SORT_DESC) {
559 case KEY_SORT_USERID:
560 cmpresult = strcmpi (a->uids->uid, b->uids->uid);
561 break;
562
563 case KEY_SORT_KEYID:
564 cmpresult = strcmpi (a->subkeys->keyid+8,
565 b->subkeys->keyid+8);
566 break;
567
568 case KEY_SORT_VALIDITY:
569 cmpresult = int_cmp (get_ext_validity (a),
570 get_ext_validity (b));
571 break;
572
573 case KEY_SORT_OTRUST:
574 cmpresult = int_cmp (a->owner_trust, b->owner_trust);
575 break;
576
577 case KEY_SORT_IS_SECRET:
578 get_seckey (a->subkeys->keyid, &a);
579 get_seckey (b->subkeys->keyid, &b);
580 cmpresult = int_cmp (a? a->secret : 0, b? b->secret : 0);
581 break;
582
583 case KEY_SORT_LEN:
584 cmpresult = int_cmp (a->subkeys->length,
585 b->subkeys->length);
586 break;
587
588 case KEY_SORT_CREATED:
589 cmpresult = int_cmp (a->subkeys->timestamp,
590 b->subkeys->timestamp);
591 break;
592
593 case KEY_SORT_ALGO:
594 cmpresult = int_cmp (a->subkeys->pubkey_algo,
595 b->subkeys->pubkey_algo);
596 break;
597
598 default:
599 cmpresult = strcmpi (a->uids->uid, b->uids->uid);
600 break;
601 }
602 if (sortby & KEYLIST_SORT_DESC)
603 return (~cmpresult + 1);
604 else
605 return cmpresult;
606 }
607
608
609 int
610 keylist_add_groups (keylist_ctrl_t kl)
611 {
612 return 0;
613 }
614
615
616 /* Synchronize the key array with the contents
617 of the keylist. */
618 void
619 keylist_sync (keylist_ctrl_t kl)
620 {
621 free (kl->keys);
622 kl->nkeys = update_keys (kl, 0, &kl->keys);
623 }
624
625
626 /* Create a listview for listing keys. Use the mode given in @mode
627 and the control is given in @ctrl. */
628 static void
629 keylist_build (listview_ctrl_t *r_lv, HWND ctrl, int mode)
630 {
631 struct listview_column_s klist_enc[] = {
632 {0, 242, (char *)_("User ID")},
633 {1, 80, (char *)_("Key ID")},
634 {3, 46, (char *)_("Size")},
635 {4, 50, (char *)_("Cipher")},
636 {5, 70, (char *)_("Validity")},
637 {0, 0, NULL}
638 };
639 struct listview_column_s klist[] = {
640 {0, 240, (char *)_("User ID")},
641 {1, 78, (char *)_("Key ID")},
642 {2, 52, (char *)_("Type")},
643 {3, 66, (char *)_("Size")},
644 {4, 60, (char *)_("Cipher")},
645 {5, 66, (char *)_("Validity")},
646 {6, 58, (char *)_("Trust")},
647 {7, 72, (char *)_("Creation")},
648 {0, 0, NULL}
649 };
650 HICON ico[6];
651 listview_ctrl_t lv;
652 listview_column_t col;
653 int ncols = 0, ext_chkbox = 0;
654
655 listview_new (&lv, ctrl);
656 if (mode & KEYLIST_ENCRYPT_MIN) {
657 col = klist_enc;
658 ncols = (DIM (klist_enc) - 1);
659 ext_chkbox = 1;
660 }
661 else if (mode & KEYLIST_SIGN) {
662 col = klist_enc;
663 ncols = (DIM (klist_enc) - 1) - 1;
664 ext_chkbox = 1;
665 }
666 else {
667 col = klist;
668 ncols = (DIM (klist) - 1);
669 }
670
671 for (int j = 0; j < ncols; j++)
672 listview_add_column (lv, &col[j]);
673 listview_set_ext_style (lv);
674 if (ext_chkbox)
675 listview_set_chkbox_style (lv);
676 ico[0] = LoadIcon (glob_hinst, (LPCTSTR)IDI_PUBKEY);
677 ico[1] = LoadIcon (glob_hinst, (LPCTSTR)IDI_KEYPAIR);
678 ico[2] = LoadIcon (glob_hinst, (LPCTSTR)IDI_REV_KEYPAIR);
679 ico[3] = LoadIcon (glob_hinst, (LPCTSTR)IDI_REV_PUBKEY);
680 ico[4] = LoadIcon (glob_hinst, (LPCTSTR)IDI_SORT_DOWNARROW);
681 ico[5] = LoadIcon (glob_hinst, (LPCTSTR)IDI_SORT_UPARROW);
682 listview_set_image_list (lv, 22, 14, ico, 6);
683 listview_del_all_items (lv);
684 listview_set_grid_style (lv);
685 *r_lv = lv;
686 }
687
688
689 static void
690 keylist_load_keycache (keylist_ctrl_t kl, int mode,
691 gpg_keycache_t pubkc, gpg_keycache_t seckc)
692 {
693 gpgme_key_t key, skey;
694 struct keycache_s *c;
695 const char *keyid;
696
697 gpg_keycache_rewind (pubkc);
698 if (pubkc && seckc) {
699 while (!gpg_keycache_next_key2 (pubkc, 0, &c, &key)) {
700 keyid = key->subkeys->keyid;
701 if (keyid && !gpg_keycache_find_key (seckc, keyid, 0, &skey))
702 keylist_add_key (kl, mode, c, key);
703 }
704 }
705 else if (pubkc) {
706 while (!gpg_keycache_next_key2 (pubkc, 0, &c, &key))
707 keylist_add_key (kl, mode, c, key);
708 }
709 }
710
711
712 /* Load the list view @ctrl with the keys from the cache.
713 Return value: list view context on success. */
714 keylist_ctrl_t
715 keylist_load (HWND ctrl, gpg_keycache_t pubkc, gpg_keycache_t seckc,
716 int mode, int sortby)
717 {
718 keylist_ctrl_t kl;
719
720 kl = new keylist_ctrl_s;
721 keylist_build (&kl->lv, ctrl, mode);
722 keylist_load_keycache (kl, mode, pubkc, seckc);
723 kl->nkeys = update_keys (kl, 0, &kl->keys);
724 keylist_sort (kl, sortby);
725 return kl;
726 }
727
728
729 /* Reload the given key list control @lv. */
730 int
731 keylist_reload (keylist_ctrl_t kl, gpg_keycache_t pubkc, int mode, int sortby)
732 {
733 listview_del_all_items (kl->lv);
734 keylist_load_keycache (kl, mode, pubkc, NULL);
735 /* It is possible that the list shrinks or increases so we need to
736 rebuild the list again. */
737 free (kl->keys); kl->keys = NULL;
738 kl->nkeys = update_keys (kl, 0, &kl->keys);
739 keylist_sort (kl, sortby);
740 return 0;
741 }
742
743
744 void
745 keylist_delete (keylist_ctrl_t kl)
746 {
747 if (!kl)
748 return;
749 if (kl->keys != NULL) {
750 free (kl->keys);
751 kl->keys = NULL;
752 }
753 if (kl->lv != NULL) {
754 listview_release (kl->lv);
755 kl->lv = NULL;
756 }
757 }
758
759
760
761
762 /* Enumeration for possible key icons. */
763 enum key_icontype_t {
764 IMG_KEY_PUB = 0,
765 IMG_KEY_PAIR = 1,
766 IMG_KEY_PAIR_REV = 2,
767 IMG_KEY_PUB_REV = 3
768 };
769
770
771 static int
772 key_get_image_id (gpgme_key_t key)
773 {
774 if (find_secret_key (key))
775 return key->revoked ? IMG_KEY_PAIR_REV :IMG_KEY_PAIR;
776 if (key->revoked)
777 return IMG_KEY_PUB_REV;
778 return IMG_KEY_PUB;
779 }
780
781
782 static int
783 do_addkey (listview_ctrl_t lv, struct keycache_s *ctx, gpgme_key_t key,
784 int uididx, int keyidx, int list)
785 {
786 gpgme_user_id_t u;
787 gpgme_subkey_t k;
788 LV_ITEM lvi;
789 char *p;
790 const char *attr;
791 int idx = 0;
792
793 /* we check the pubkey algorithm here to make sure that no ElGamal
794 sign+encrypt key is used in _any_ mode */
795 if (list != 1 && key->subkeys->pubkey_algo == GPGME_PK_ELG) {
796 log_debug ("ElGamal (E+S) key found: %s (%s)\n",
797 key->uids->name, key->subkeys->keyid);
798 return 0;
799 }
800
801 if (listview_add_item2 (lv, " ", (void *)ctx))
802 return WPTERR_GENERAL;
803
804 attr = ctx->uids->uid;
805 memset (&lvi, 0, sizeof lvi);
806 lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
807 lvi.pszText = (char *)attr;
808 lvi.iImage = key_get_image_id (key);
809 lvi.lParam = (LPARAM )ctx;
810 if (ListView_SetItem (lv->ctrl, &lvi) == FALSE)
811 return WPTERR_GENERAL;
812
813 if (uididx == -1) { /* request the primary user-id of the key. */
814 attr = ctx->uids->uid;
815 uididx = 0;
816 }
817 else {
818 u = get_nth_userid (key, uididx);
819 if (!u || u->revoked || uididx < 0)
820 uididx = 0;
821 u = get_nth_userid (key, uididx);
822 attr = u->uid;
823 }
824 if (attr == NULL || strlen (attr) < 5) { /* normal userids are > 5 chars */
825 attr = _("Invalid User ID");
826 listview_add_sub_item (lv, 0, idx++, attr);
827 }
828 else
829 listview_add_sub_item (lv, 0, idx++, attr);
830 k = get_nth_key (key, keyidx);
831 if (k && k->keyid != NULL) {
832 char keyid[16+1];
833
834 _snprintf (keyid, DIM (keyid) -1, "0x%s", k->keyid + 8);
835 listview_add_sub_item (lv, 0, idx++, keyid);
836 }
837 if (list > 0) {
838 DWORD key_attr = find_secret_key (key);
839 if (!key_attr)
840 attr = "pub";
841 else
842 attr = key_attr == 1? "pub/sec" : "pub/crd";
843 listview_add_sub_item (lv, 0, idx++, attr);
844 }
845 if (lv->cols >= 2) {
846 attr = get_key_size (key, list == -1? keyidx+1 : 0);
847 if (attr != NULL)
848 listview_add_sub_item (lv, 0, idx++, attr);
849 }
850 if (lv->cols >= 3) {
851 attr = get_key_algo (key, list == -1? keyidx+1 : 0);
852 if (attr != NULL)
853 listview_add_sub_item( lv, 0, idx++, attr);
854 }
855 if (lv->cols >= 4) {
856 p = get_key_status (key, uididx, list > 0? 1 : 0);
857 if (p != NULL)
858 listview_add_sub_item (lv, 0, idx++, p);
859 free_if_alloc (p);
860 }
861 if (lv->cols >= 5) {
862 attr = get_key_trust (key, uididx, list > 0? 1 : 0);
863 listview_add_sub_item (lv, 0, idx++, attr);
864 }
865 if (lv->cols >= 6) {
866 k = get_nth_key (key, keyidx);
867 if (k->timestamp > 0) {
868 attr = get_key_created (k->timestamp);
869 listview_add_sub_item (lv, 0, idx++, attr);
870 }
871 }
872
873 return 0;
874 }
875
876
877 /* Update a single column @col but for each element in the
878 listview @lv. */
879 void
880 keylist_upd_col (keylist_ctrl_t kl, int col)
881 {
882 gpgme_key_t key;
883 const char *s;
884 char buf[32], *p;
885
886 for (int i=0; i < listview_count_items (kl->lv, 0); i++) {
887 key = km_get_key_ptr (kl, i, NULL);
888 if (!key)
889 continue;
890 switch (col) {
891 case KM_COL_KEYID:
892 _snprintf (buf, DIM (buf)-1, "0x%s", key->subkeys->keyid+8);
893 listview_add_sub_item (kl->lv, i, col, buf);
894 break;
895
896 case KM_COL_CIPHER:
897 s = get_key_algo (key, 0);
898 listview_add_sub_item (kl->lv, i, col, s);
899 break;
900
901 case KM_COL_TYPE:
902 s = find_secret_key (key)? "pub/sec" : "pub";
903 listview_add_sub_item (kl->lv, i, col, s);
904 break;
905
906 case KM_COL_CREAT:
907 s = get_key_created (key->subkeys->timestamp);
908 listview_add_sub_item (kl->lv, i, col, s);
909 break;
910
911 case KM_COL_DESC:
912 p = get_key_desc (key);
913 listview_add_sub_item (kl->lv, i, col, p);
914 free_if_alloc (p);
915 break;
916 }
917 }
918 }
919
920
921 /* Update the listview item at position @pos with the data from
922 the key @key. */
923 void
924 keylist_upd_key (keylist_ctrl_t kl, int pos,
925 struct keycache_s *ctx, gpgme_key_t key)
926 {
927 listview_ctrl_t lv = kl->lv;
928 char *p;
929 char tmp[32];
930
931 listview_set_item2 (lv, pos, (void *)ctx);
932 update_key (kl, pos, key);
933 /* the only mode we support is KEYLIST_LIST in the Key Manager */
934
935 const char *s = ctx->uids->uid;
936 if (s)
937 listview_add_sub_item (lv, pos, KM_COL_UID, s);
938
939 s = key->subkeys->keyid;
940 if (s) {
941 sprintf (tmp, "0x%s", s+8);
942 listview_add_sub_item (lv, pos, KM_COL_KEYID, tmp);
943 }
944
945 s = find_secret_key (key)? "pub/sec" : "pub";
946 listview_add_sub_item (lv, pos, KM_COL_TYPE, s);
947
948 s = get_key_size (key, 0);
949 if (s)
950 listview_add_sub_item (lv, pos, KM_COL_SIZE, s);
951
952 s = get_key_algo (key, 0);
953 if (s)
954 listview_add_sub_item (lv, pos, KM_COL_CIPHER, s);
955
956 p = get_key_status (key, 0, 1);
957 if (p) {
958 listview_add_sub_item (lv, pos, KM_COL_VALID, p);
959 free_if_alloc (p);
960 }
961
962 s = get_key_trust (key, 0, 1);
963 if (s)
964 listview_add_sub_item (lv, pos, KM_COL_TRUST, s);
965
966 long t = key->subkeys->timestamp;
967 s = get_key_created (t);
968 if (s)
969 listview_add_sub_item (lv, pos, KM_COL_CREAT, s);
970 }
971
972
973 int
974 keylist_add_key (keylist_ctrl_t kl, int mode,
975 struct keycache_s *ctx, gpgme_key_t key)
976 {
977 gpgme_subkey_t k;
978 listview_ctrl_t lv = kl->lv;
979 int uids, rc, i;
980
981 /* if the entire key is disabled, just return. */
982 if (key->disabled && !(mode & KEYLIST_LIST))
983 return 0;
984
985 for (k = key->subkeys, i = 0; i < count_subkeys (key); i++, k = k->next) {
986 if (k->invalid) {
987 log_debug ("keylist_add_key: invalid key \"%s\"\n",
988 key->uids->name);
989 continue; /* Don't use invalid keys */
990 }
991
992 if (mode & KEYLIST_ALL) {
993 uids = count_userids (key);
994 rc = do_addkey (lv, ctx, key, uids, i, 0);
995 if (rc)
996 return rc;
997 }
998 else if (mode & KEYLIST_LIST)
999 return do_addkey (lv, ctx, key, -1, i, 1);
1000 else if (mode & KEYLIST_ENCRYPT) {
1001 if (k->can_encrypt && key_is_useable (k)) {
1002 if (mode & KEYLIST_FLAG_FILE) {
1003 rc = do_addkey (lv, ctx, key, -1, i, -1);
1004 if (rc)
1005 return rc;
1006 }
1007 else {
1008 for (uids = 0; uids < count_userids (key); uids++) {
1009 rc = do_addkey (lv, ctx, key, uids, i, -1);
1010 if (rc)
1011 return rc;
1012 }
1013 }
1014 }
1015 }
1016 else if (mode & KEYLIST_ENCRYPT_MIN) {
1017 if (k->can_encrypt && key_is_useable (k)) {
1018 rc = do_addkey (lv, ctx, key, -1, i, -1);
1019 return rc;
1020 }
1021 }
1022 else if (mode & KEYLIST_SIGN) {
1023 if (k->can_sign
1024 && find_secret_key (key)
1025 && key_is_useable (k)) {
1026 rc = do_addkey (lv, ctx, key, -1, i, -1);
1027 if (rc)
1028 return rc;
1029 }
1030 }
1031 }
1032
1033 return 0;
1034 }
1035
1036
1037 int
1038 keylist_sort (keylist_ctrl_t kl, int sortby)
1039 {
1040 int ret = listview_sort_items (kl->lv, sortby, keylist_cmp_cb);
1041 kl->nkeys = update_keys (kl, 1, &kl->keys);
1042 return ret;
1043 }
1044
1045
1046 /* Check that the validity @validity is at least >= marginal. */
1047 static int
1048 key_check_validity (gpgme_key_t key)
1049 {
1050 gpgme_user_id_t u;
1051
1052 for (u=key->uids; u; u =u->next) {
1053 if (u->validity >= GPGME_VALIDITY_MARGINAL)
1054 return -1;
1055 }
1056
1057 return 0;
1058 }
1059
1060
1061 /* Extract all selected recipients from the list @lv and return them
1062 as a vector. @r_force_trust is >= 1 if one of the recipients is not
1063 fully trusted. @r_count returns the number of selected keys.
1064 Return value: the key list on success, NULL otherwise. */
1065 gpgme_key_t*
1066 keylist_get_recipients (keylist_ctrl_t kl, int *r_force_trust, size_t *r_count)
1067
1068 {
1069 gpgme_key_t *keybuf, key;
1070 listview_ctrl_t lv = kl->lv;
1071 key_array_s *ka = NULL;
1072 keycache_s *c;
1073 size_t count = 0;
1074 int force_trust = 0;
1075 int nkeys, ka_pos = 0, rc = 0;
1076 int k_pos=0;
1077
1078 nkeys = listview_count_items (lv, 0);
1079 ka = key_array_new (nkeys);
1080 keybuf = (gpgme_key_t*)calloc (nkeys+1, sizeof (gpgme_key_t));
1081 if (!keybuf)
1082 BUG (NULL);
1083
1084 for (int j = 0; j < nkeys; j++) {
1085 if (listview_get_item_state (lv, j) || nkeys == 1) {
1086 key = km_get_key_ptr (kl, j, &c);
1087 if (!key)
1088 BUG (0);
1089 if (!key_check_validity (key) &&
1090 !key_array_search (ka, ka_pos, key->subkeys->keyid)) {
1091 StringBuffer warn;
1092 warn = warn + c->uids->uid + ":\n\n";
1093 warn = warn +_("It is NOT certain that the key belongs to the person\n"
1094 "named in the user ID. If you *really* know what you are\n"
1095 "doing, you may answer the next question with no\n"
1096 "\nSkip this key?");
1097 rc = msg_box (NULL, warn.getBuffer(), _("Warning"), MB_WARN_ASK);
1098 if (reg_prefs.always_trust || rc == IDNO) {
1099 keybuf[k_pos++] = key;
1100 force_trust++;
1101 ka[ka_pos].checked = 1;
1102 strcpy (ka[ka_pos++].keyid, key->subkeys->keyid);
1103 count++;
1104 }
1105 }
1106 else {
1107 keybuf[k_pos++] = key;
1108 count++;
1109 }
1110 }
1111 }
1112 key_array_release (ka);
1113 if (r_force_trust)
1114 *r_force_trust = force_trust;
1115 if (r_count)
1116 *r_count = count;
1117 return keybuf;
1118 }
1119
1120
1121 static int
1122 keylist_get_keyflags (gpgme_key_t key)
1123 {
1124 int flags = KEYFLAG_NONE;
1125
1126 if (key->revoked)
1127 flags |= KEYFLAG_REVOKED;
1128 if (key->expired)
1129 flags |= KEYFLAG_EXPIRED;
1130 if (key->disabled)
1131 flags |= KEYFLAG_DISABLED;
1132
1133 return flags;
1134 }
1135
1136
1137
1138 gpgme_key_t*
1139 keylist_enum_recipients (keylist_ctrl_t kl, int listype, size_t *r_count)
1140 {
1141 gpgme_key_t *rset;
1142 gpgme_key_t key;
1143 listview_ctrl_t lv = kl->lv;
1144 struct keycache_s *c;
1145 size_t k_pos;
1146 int nkeys, id;
1147
1148 nkeys = listview_count_items (lv, 0);
1149 if (!nkeys)
1150 return 0;
1151 rset = (gpgme_key_t*)calloc (nkeys+1, sizeof (gpgme_key_t));
1152 if (!rset)
1153 BUG (NULL);
1154 k_pos = 0;
1155 for (int i = 0; i < nkeys; i++) {
1156 if (!listview_get_item_state (lv, i))
1157 continue;
1158 key = km_get_key_ptr (kl, i, &c);
1159 switch (listype) {
1160 case KEYLIST_LIST:
1161 if (keylist_get_keyflags (key) & KEYFLAG_REVOKED) {
1162 id = printf_box (_("Recipients"), MB_INFO|MB_YESNO,
1163 _("KeyID %s.\nDo you really want to export a revoked key?"),
1164 c->uids->uid);
1165 if (id == IDNO)
1166 continue;
1167 }
1168 break;
1169 }
1170 rset[k_pos++] = key;
1171 }
1172 if (r_count)
1173 *r_count = k_pos;
1174 return rset;
1175 }
1176
1177
1178 void
1179 seclist_destroy (keylist_t *list)
1180 {
1181 keylist_t l2;
1182
1183 while (*list) {
1184 l2 = (*list)->next;
1185 safe_free (*list);
1186 *list = l2;
1187 }
1188 *list = NULL;
1189 }
1190
1191
1192 void
1193 seclist_init (HWND dlg, int ctlid, int flags, keylist_t *ret_list)
1194 {
1195 gpg_keycache_t kc;
1196 gpgme_key_t key = NULL;
1197 HWND kb;
1198 keylist_t list=NULL, l, l2;
1199 long pos;
1200
1201 SendDlgItemMessage (dlg, ctlid, CB_RESETCONTENT, 0, 0);
1202 kb = GetDlgItem (dlg, ctlid);
1203 kc = keycache_get_ctx (0);
1204 if (!kc)
1205 BUG (0);
1206 gpg_keycache_rewind (kc);
1207
1208 while (!gpg_keycache_next_key (kc, 1, &key)) {
1209 StringBuffer inf;
1210 char *uid;
1211 const char *id;
1212
1213 if (key->disabled || !key_is_useable (key->subkeys))
1214 continue;
1215
1216 if (flags & KEYLIST_FLAG_SHORT)
1217 id = key->uids->name;
1218 else
1219 id = key->uids->uid;
1220 if (!id || !key->subkeys->keyid)
1221 continue;
1222
1223 uid = utf8_to_native (id);
1224 inf = uid;
1225 inf = inf + " (" + get_key_pubalgo (key->subkeys->pubkey_algo) + "/";
1226 inf = inf + "0x" + (key->subkeys->keyid+8) + ")";
1227
1228 combox_add_string (kb, inf.getBuffer ());
1229 safe_free (uid);
1230 l = (struct keylist_s *)calloc (1, sizeof * l);
1231 if (!l)
1232 BUG (0);
1233 l->key = key;
1234 if (!list)
1235 list = l;
1236 else {
1237 for( l2 = list; l2->next; l2 = l2->next )
1238 ;
1239 l2->next = l;
1240 }
1241 }
1242 for (pos = 0, l2=list; pos < SendMessage (kb, CB_GETCOUNT, 0, 0);
1243 pos++, l2=l2->next)
1244 SendMessage (kb, CB_SETITEMDATA, pos, (LPARAM)(DWORD)l2->key);
1245 SendMessage (kb, CB_SETCURSEL, 0, 0);
1246 *ret_list = list;
1247 }
1248
1249
1250 /* Select a secret key from the combo box with the ID @ctlid.
1251 Return the code on success in @ret_key. */
1252 int
1253 seclist_select_key (HWND dlg, int ctlid, gpgme_key_t *ret_key)
1254 {
1255 int pos;
1256 DWORD k = 0;
1257
1258 pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0);
1259 if (pos == CB_ERR) {
1260 msg_box (dlg, _("No key was selected."), _("Secret Key List"), MB_ERR);
1261 *ret_key = NULL;
1262 }
1263 else {
1264 k = SendDlgItemMessage (dlg, ctlid, CB_GETITEMDATA, pos, 0);
1265 *ret_key = (gpgme_key_t)k;
1266 }
1267 return k? 0 : -1;
1268 }
1269
1270
1271 LRESULT
1272 keylist_listview_notify (HWND hwnd, gpgme_key_t *keys,
1273 int ctlid, LPARAM lparam)
1274 {
1275 LPNMHDR lpnmh = (LPNMHDR) lparam;
1276
1277 if (!lpnmh)
1278 BUG (NULL);
1279
1280 /* Make sure the message is for the control and
1281 that we have a key list. */
1282 if (lpnmh->idFrom != (DWORD)ctlid || keys == NULL)
1283 return 0;
1284
1285 switch (lpnmh->code) {
1286 case NM_CUSTOMDRAW:
1287 LPNMLVCUSTOMDRAW lplvcd;
1288 lplvcd = (LPNMLVCUSTOMDRAW)lparam;
1289 if (lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT)
1290 return CDRF_NOTIFYITEMDRAW;
1291
1292 if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {
1293 LRESULT ret = CDRF_DODEFAULT;
1294 int pos = lplvcd->nmcd.dwItemSpec;
1295 HWND lv = GetDlgItem (hwnd, ctlid);
1296 gpgme_key_t key = keys[pos];
1297
1298 if (key != NULL) {
1299 HFONT hfont = (HFONT)SendMessage (lv, WM_GETFONT, 0, 0);
1300 LOGFONT lf;
1301 if (!GetObject (hfont, sizeof (lf), &lf))
1302 BUG (NULL);
1303 if (key->revoked)
1304 lf.lfStrikeOut = TRUE;
1305 else if (key->expired)
1306 lf.lfItalic = TRUE;
1307 if (find_secret_key (key))
1308 lf.lfWeight = FW_SEMIBOLD;
1309 hfont = CreateFontIndirect (&lf);
1310 SelectObject (lplvcd->nmcd.hdc, hfont);
1311 if (pos & 1)
1312 lplvcd->clrTextBk = RGB (0xE5, 0xE5, 0xE5);
1313 ret = CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT;
1314 }
1315 return ret;
1316 }
1317
1318 if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT) {
1319 HFONT hfont = (HFONT)GetStockObject (DEFAULT_GUI_FONT);
1320 hfont = (HFONT)SelectObject (lplvcd->nmcd.hdc, hfont);
1321 DeleteObject (hfont);
1322 return CDRF_DODEFAULT;
1323 }
1324 return CDRF_DODEFAULT;
1325 }
1326
1327 return 0;
1328 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26