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

Contents of /trunk/Src/wptKeyEditDlgs.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 444 - (show annotations)
Sat Apr 14 17:08:57 2012 UTC (12 years, 10 months ago) by twoaday
File size: 60168 byte(s)


1 /* wptKeyEditDlgs.cpp - GPG key edit dialogs
2 * Copyright (C) 2002-2009, 2011 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <windows.h>
21 #include <commctrl.h>
22 #include <time.h>
23 #include <assert.h>
24
25 #include "resource.h"
26 #include "wptTypes.h"
27 #include "wptW32API.h"
28 #include "wptVersion.h"
29 #include "wptGPG.h"
30 #include "wptCommonCtl.h"
31 #include "wptContext.h"
32 #include "wptDlgs.h"
33 #include "wptNLS.h"
34 #include "wptUTF8.h"
35 #include "wptErrors.h"
36 #include "wptKeylist.h"
37 #include "wptKeyManager.h"
38 #include "wptRegistry.h"
39 #include "wptKeyEdit.h"
40 #include "wptKeyserver.h"
41 #include "StringBuffer.h"
42
43
44 /* All edit key commands. */
45 enum keyedit_commands {
46 CMD_ADDKEY = 0,
47 CMD_ADDUID,
48 CMD_ADDPHOTO,
49 CMD_ADDREVOKER,
50 CMD_DELUID,
51 CMD_DELKEY,
52 CMD_EXPIRE,
53 CMD_SHOWPREF,
54 CMD_SETPREF,
55 CMD_PASSWD,
56 CMD_PRIMARY,
57 CMD_TRUST,
58 CMD_REVUID,
59 CMD_REVKEY,
60 CMD_DISABLE,
61 CMD_ENABLE,
62 CMD_SIGN,
63 CMD_LSIGN,
64 CMD_CHECK,
65 CMD_CLEAN,
66 CMD_MINIMIZE
67 };
68
69 struct cmdlist_s {
70 const char *name;
71 unsigned int need_pair:1;
72 int id;
73 } cmdlist[] = {
74 {"ADDKEY", 1, CMD_ADDKEY},
75 {"ADDUID", 1, CMD_ADDUID},
76 {"ADDPHOTO", 1, CMD_ADDPHOTO},
77 {"ADDREVOKER", 1, CMD_ADDREVOKER},
78 {"DELUID", 1, CMD_DELUID},
79 {"DELKEY", 1, CMD_DELKEY},
80 {"EXPIRE", 1, CMD_EXPIRE},
81 {"SHOWPREF", 0, CMD_SHOWPREF},
82 {"PASSWD", 1, CMD_PASSWD},
83 {"PRIMARY", 1, CMD_PRIMARY},
84 {"TRUST", 0, CMD_TRUST},
85 {"REVUID", 1, CMD_REVUID},
86 {"REVKEY", 1, CMD_REVKEY},
87 {"DISABLE", 0, CMD_DISABLE},
88 {"ENABLE", 0, CMD_ENABLE},
89 {"SIGN", 0, CMD_SIGN},
90 {"LSIGN", 0, CMD_LSIGN},
91 {"CHECK", 0, CMD_CHECK},
92 {"CLEAN", 0, CMD_CLEAN},
93 {"MINIMIZE", 0, CMD_MINIMIZE},
94 {NULL, 0}
95 };
96
97
98 /* Symbolic ids for the subkey columns. */
99 enum subk_col_t {
100 SUBK_COL_DESC = 0,
101 SUBK_COL_KEYID = 1,
102 SUBK_COL_CREATION = 2,
103 SUBK_COL_EXPIRES = 3,
104 SUBK_COL_STATUS = 4,
105 SUBK_COL_C_FLAG = 5,
106 SUBK_COL_S_FLAG = 6,
107 SUBK_COL_E_FLAG = 7,
108 SUBK_COL_A_FLAG = 8
109 };
110
111 /* Symbolic ids for the userid columns. */
112 enum uid_col_t {
113 UID_COL_VALID = 0,
114 UID_COL_NAME = 1,
115 UID_COL_EMAIL = 2,
116 UID_COL_CREATION = 3
117 };
118
119 /* Key edit callback context. */
120 struct keyedit_cb_s {
121 HWND parent; /* parent window handle. */
122 const char *keyid; /* key ID of the key. */
123 const char *pass; /* pointer to the passphrase. */
124 listview_ctrl_t lv;
125 int lv_pos;
126 void *opaque;
127 unsigned int finished:1;
128 unsigned int is_protected:1;
129 };
130 typedef struct keyedit_cb_s *keyedit_cb_t;
131
132
133 /* Key generation callback context. */
134 struct keygen_cb_s {
135 int bits;
136 int algo;
137 DWORD expire; /* date of expiration or '0' for infinite valid. */
138 char *fpr;
139 char *name;
140 char *comment;
141 char *email;
142 };
143 typedef struct keygen_cb_s *keygen_cb_t;
144
145 /* Subclass context for the subkey list. */
146 static subclass_s keyedit_subkey_proc;
147
148 /* Subclass context for the user-id list. */
149 static subclass_s keyedit_uid_proc;
150
151 int keygen_check_date (SYSTEMTIME *st);
152 void get_userid_preflist (const char *old_prefs, char **r_prefs, int *r_flags);
153 char* get_subkey_keyid (const char *keyid);
154 void ComboBox_AddString_utf8 (HWND cb, const char *txt);
155
156 void set_gpg_auto_passphrase_cb (passphrase_cb_s *cb, const char *title);
157 gpgme_error_t passphrase_cb (void *hook, const char *uid_hint,
158 const char *passphrase_info,
159 int prev_was_bad, int fd);
160
161 /* Associate each key with a combo box entry.
162 Skip the key in @k. */
163 static void
164 do_init_keylist (HWND dlg, const char *keyid)
165 {
166 gpg_keycache_t pub;
167 gpgme_key_t key;
168 const char *s, *kid;
169 int i, n;
170
171 pub = keycache_get_ctx (1);
172 gpg_keycache_rewind (pub);
173 while (!gpg_keycache_next_key (pub, 0, &key)) {
174 if (!key_is_useable (key) || key->invalid)
175 continue;
176 s = key->uids->uid;
177 kid = key->subkeys->keyid;
178 if (!s || !strcmp (kid+8, keyid))
179 continue;
180 ComboBox_AddString_utf8 (GetDlgItem (dlg, IDC_ADDREV_KEYLIST), s);
181 }
182
183 gpg_keycache_rewind (pub);
184 /* In the second loop, we set a key pointer for each element. */
185 n = SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_GETCOUNT, 0, 0);
186 for (i = 0; i < n; i++) {
187 gpg_keycache_next_key (pub, 0, &key);
188 SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETITEMDATA,
189 (WPARAM)(int)i, (LPARAM)key);
190 }
191 SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETCURSEL, 0, 0);
192 }
193
194
195 /* Add a new user-id to the list view @lv. */
196 static void
197 do_add_new_userid (listview_ctrl_t lv,
198 const char *utf8_name, const char *email,
199 const char *utf8_comment)
200 {
201 StringBuffer p;
202 char *native;
203
204 if (utf8_comment != NULL)
205 p = p + utf8_name + " (" + utf8_comment + ")";
206 else
207 p = p + utf8_name;
208 native = utf8_to_native (p.getBuffer ());
209
210 listview_add_item (lv, "");
211 listview_add_sub_item (lv, 0, UID_COL_VALID, _("Ultimate" ));
212 listview_add_sub_item (lv, 0, UID_COL_NAME, native);
213 listview_add_sub_item (lv, 0, UID_COL_EMAIL, email && *email? email : "");
214 listview_add_sub_item (lv, 0, UID_COL_CREATION,
215 get_key_created (time (NULL)));
216 free_if_alloc (native);
217 }
218
219
220 static void
221 do_add_new_subkey (listview_ctrl_t lv, keygen_cb_t keygen, unsigned int flags)
222 {
223 char info[128], keyid[32];
224 const char *expdate, *s, *kid;
225 int n;
226
227 expdate = keygen->expire? get_key_expire_date (keygen->expire) : _("Never");
228 _snprintf (info, DIM (info)-1, "%d-bit %s", keygen->bits,
229 get_key_pubalgo ((gpgme_pubkey_algo_t)keygen->algo));
230 kid = get_keyid_from_fpr (keygen->fpr);
231 _snprintf (keyid, DIM (keyid)-1, "0x%s", kid);
232 s = get_key_created (time (NULL));
233 n = listview_count_items (lv, 0);
234 listview_add_item_pos (lv, n);
235 listview_add_sub_item (lv, n, SUBK_COL_DESC, info);
236 listview_add_sub_item (lv, n, SUBK_COL_KEYID, keyid);
237 listview_add_sub_item (lv, n, SUBK_COL_CREATION, s);
238 listview_add_sub_item (lv, n, SUBK_COL_EXPIRES, expdate);
239 if (flags & KM_FLAG_REVOKED)
240 s = _("Revoked");
241 else if (flags & KM_FLAG_EXPIRED)
242 s = _("Expired");
243 else
244 s = _("OK");
245 listview_add_sub_item (lv, n, SUBK_COL_STATUS, s);
246 }
247
248
249 /* Try to find the GPG edit key index which belongs to the user ID
250 given by the email address @email, @name is used as a fallback.
251 If @r_inf != NULL, the info context will be returned.
252 Return value: index of the user ID or -1 on error. */
253 static int
254 do_find_userid (const char *keyid, const char *email,
255 const char *name, gpg_uid_info_t *r_inf)
256 {
257 GpgKeyEdit ke;
258 gpgme_error_t err;
259 gpg_uid_info_t inf, ui;
260 int pos = -1;
261
262 ke.setKeyID (keyid);
263 err = ke.getUseridInfo (&inf);
264 if (err) {
265 log_box (_("user ID"), MB_ERR,
266 _("Could not get key information for: \"%s\":\n%s"),
267 name, gpgme_strerror (err));
268 return -1;
269 }
270
271 for (ui = inf; ui; ui = ui->next) {
272 if (name && email && ui->email && ui->name) {
273 if (!strcmp (ui->email, email) &&
274 !strncmp (ui->name, name, strlen (name))) {
275 pos = ui->index;
276 break;
277 }
278 continue;
279 }
280 if (email && ui->email) {
281 if (!strcmp (ui->email, email)) {
282 pos = ui->index;
283 break;
284 }
285 /* The email address is more unique, use the name just
286 as the fallbck when no email address is available. */
287 continue;
288 }
289 if (ui->name && name && !strcmp (ui->name, name)) {
290 pos = ui->index;
291 break;
292 }
293 }
294 if (r_inf)
295 *r_inf = inf;
296 else
297 gpg_uid_info_release (inf);
298 return pos;
299 }
300
301
302 /* Return true if @fname is a JPEG file. */
303 bool
304 is_jpg_file (const char *fname)
305 {
306 FILE *fp = fopen (fname, "rb");
307 if (!fp)
308 return false;
309
310 BYTE buf[10];
311 size_t n = fread (buf, 1, DIM (buf), fp);
312 fclose (fp);
313 if (n < DIM (buf))
314 return false;
315 return buf[6] == 'J' && buf[7] == 'F' &&
316 buf[8] == 'I' && buf[9] == 'F';
317 }
318
319
320 /* Dialog box procedure to add a photo. */
321 BOOL CALLBACK
322 keyedit_addphoto_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
323 {
324 static keyedit_cb_t cb;
325 gpgme_error_t err;
326 const char *s;
327 char file[128];
328 int id;
329
330 switch (msg) {
331 case WM_INITDIALOG:
332 cb = (keyedit_cb_t)lparam;
333 if (!cb)
334 BUG (NULL);
335 SetDlgItemText (dlg, IDC_ADDPHOTO_INF, _("Remember that the image is stored within your public key. If you use a very large picture, your key will become very large as well! Keeping the image close to 240x288 is advised."));
336 SetDlgItemText (dlg, IDC_ADDPHOTO_FILEINF, _("Pick an image to use for your photo ID.\nThe image must be a JPEG file."));
337 SetDlgItemText (dlg, IDC_ADDPHOTO_PWDINF, _("Passphrase"));
338 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
339 SetWindowText (dlg, _("Add Photo ID"));
340 SetForegroundWindow (dlg);
341 break;
342
343 case WM_DESTROY:
344 balloon_msg_disable ();
345 break;
346
347 case WM_COMMAND:
348 switch (LOWORD (wparam)) {
349 case IDC_ADDPHOTO_SELFILE:
350 s = get_fileopen_dlg (dlg, _("Select Image File"),
351 "JPEG Files (*.jpg, *.jpeg)\0*.jpg;*.jpeg\0\0",
352 NULL);
353 if (s && !is_jpg_file (s)) {
354 log_box (_("Add Photo ID"), MB_ERR,
355 _("'%s' is not a valid JPEG file."), s);
356 return FALSE;
357 }
358 if (s && *s)
359 SetDlgItemText (dlg, IDC_ADDPHOTO_FILE, s);
360 break;
361
362 case IDOK:
363 if (!GetDlgItemText (dlg, IDC_ADDPHOTO_FILE, file, DIM (file)-1)){
364 show_balloon_msg (GetDlgItem (dlg, IDC_ADDPHOTO_FILE),
365 _("Please enter a file name."), IDI_ERROR);
366 return FALSE;
367 }
368 if (get_file_size (file) == 0 || get_file_size (file) > 6144) {
369 id = msg_box (dlg, _("The JPEG is really large.\n"
370 "Are you sure you want to use it?"),
371 _("Add Photo ID"), MB_YESNO|MB_INFO);
372 if (id == IDNO)
373 return TRUE;
374 }
375
376 {
377 GpgKeyEdit ke;
378 passphrase_cb_s pcb;
379
380 set_gpg_auto_passphrase_cb (&pcb, _("Add Revoker"));
381
382 ke.setPassphraseCallback (passphrase_cb, (void*)&pcb);
383 ke.setKeyID (cb->keyid);
384 err = ke.addPhotoid (file);
385
386 release_gpg_passphrase_cb (&pcb);
387 }
388 if (err) {
389 msg_box (dlg, gpgme_strerror (err), _("Add Photo ID"), MB_ERR);
390 return FALSE;
391 }
392 else {
393 cb->finished = 1;
394 msg_box (dlg, _("Photo successfully added."),
395 _("GnuPG Status"), MB_OK);
396 }
397 EndDialog (dlg, TRUE);
398 break;
399
400 case IDCANCEL:
401 EndDialog (dlg, FALSE);
402 break;
403 }
404 break;
405 }
406 return FALSE;
407 }
408
409
410 /* Dialog box procedure to add a designated revoker. */
411 BOOL CALLBACK
412 keyedit_addrevoker_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
413 {
414 static keyedit_cb_t cb;
415 gpgme_error_t err;
416 char *uid=NULL;
417
418 switch (msg) {
419 case WM_INITDIALOG:
420 cb = (keyedit_cb_t)lparam;
421 if (!cb)
422 BUG (NULL);
423 do_init_keylist (dlg, cb->keyid);
424 SetDlgItemText (dlg, IDC_ADDREV_INF,
425 _("Appointing a key as designated revoker cannot be undone."));
426 SetDlgItemText (dlg, IDC_ADDREV_KEYINF, _("Public key:"));
427 SetDlgItemText (dlg, IDC_ADDREV_PWDINF, _("Passphrase"));
428 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
429 SetWindowText (dlg, _("Add Revoker"));
430 SetForegroundWindow (dlg);
431 center_window (dlg, cb->parent);
432 break;
433
434 case WM_DESTROY:
435 balloon_msg_disable ();
436 break;
437
438 case WM_COMMAND:
439 switch (LOWORD (wparam)) {
440 case IDOK:
441 if (!GetDlgItemText_utf8 (dlg, IDC_ADDREV_KEYLIST, &uid)) {
442 show_balloon_msg (GetDlgItem (dlg, IDC_ADDREV_KEYLIST),
443 _("Please select a user ID."), IDI_ERROR);
444 return FALSE;
445 }
446
447 {
448 GpgKeyEdit ke;
449 passphrase_cb_s pcb;
450
451 set_gpg_auto_passphrase_cb (&pcb, _("Add Revoker"));
452
453 ke.setPassphraseCallback (passphrase_cb, (void*)&pcb);
454 ke.setKeyID (cb->keyid);
455 err = ke.addDesignatedRevoker (uid);
456
457 release_gpg_passphrase_cb (&pcb);
458 }
459
460 safe_free (uid);
461 if (err) {
462 msg_box (dlg, gpgme_strerror (err), _("Add Revoker"), MB_ERR);
463 return TRUE;
464 }
465 else {
466 cb->finished = 1;
467 msg_box (dlg, _("Revoker successfully addded."),
468 _("GnuPG Status"), MB_OK);
469 }
470 EndDialog (dlg, TRUE);
471 break;
472
473 case IDCANCEL:
474 EndDialog (dlg, FALSE);
475 break;
476 }
477 break;
478 }
479 return FALSE;
480 }
481
482
483 /* Dialog box procedure to add a new user-ID. */
484 BOOL CALLBACK
485 keyedit_adduid_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
486 {
487 static keyedit_cb_t ctx;
488 keygen_cb_t keygen;
489 gpgme_error_t err;
490 char *utf8_name = NULL;
491 char *utf8_comment = NULL;
492 char email[128];
493 int rc;
494
495 switch (msg) {
496 case WM_INITDIALOG:
497 ctx = (keyedit_cb_t)lparam;
498 if (!ctx)
499 dlg_fatal_error(dlg, "Could not get dialog param!");
500 SetWindowText (dlg, _("Add user ID"));
501 SetDlgItemText (dlg, IDC_ADDUID_INFNAME, _("&Name:"));
502 SetDlgItemText (dlg, IDC_ADDUID_INFEMAIL, _("&Email:"));
503 SetDlgItemText (dlg, IDC_ADDUID_INFCOMMENT, _("&Comment:"));
504 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
505 SetForegroundWindow (dlg);
506 center_window (dlg, ctx->parent);
507 return FALSE;
508
509 case WM_DESTROY:
510 balloon_msg_disable ();
511 break;
512
513 case WM_COMMAND:
514 switch ( LOWORD( wparam ) ) {
515 case IDOK:
516 keygen = (keygen_cb_t)ctx->opaque;
517 rc = GetDlgItemText_utf8 (dlg, IDC_ADDUID_NAME, &utf8_name);
518 if (!rc || rc < 5) {
519 show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_NAME),
520 _("Please enter a name (min. 5 chars.)"),
521 IDI_ERROR);
522 free_if_alloc (utf8_name);
523 return FALSE;
524 }
525 if (strchr (utf8_name, '@')) {
526 show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_NAME),
527 _("Please enter the email address in the email field and not in the name field"),
528 IDI_WARNING);
529 free_if_alloc (utf8_name);
530 return FALSE;
531 }
532
533 if( !GetDlgItemText (dlg, IDC_ADDUID_EMAIL, email, DIM (email) -1)) {
534 show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_EMAIL),
535 _("Please enter an email address."),IDI_ERROR);
536 free_if_alloc (utf8_name);
537 return FALSE;
538 }
539 if (check_email_address (email)) {
540 show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_EMAIL),
541 _("Invalid email address."), IDI_ERROR);
542 free_if_alloc (utf8_name);
543 return FALSE;
544 }
545
546 rc = GetDlgItemText_utf8 (dlg, IDC_ADDUID_COMMENT, &utf8_comment);
547 {
548 GpgKeyEdit ke;
549 passphrase_cb_s pcb;
550
551 set_gpg_auto_passphrase_cb (&pcb, _("Add Revoker"));
552
553 ke.setPassphraseCallback (passphrase_cb, (void*)&pcb);
554 ke.setKeyID (ctx->keyid);
555 err = ke.addUserid (utf8_name, utf8_comment, email);
556
557 release_gpg_passphrase_cb (&pcb);
558 }
559 if (err)
560 msg_box (dlg, gpgme_strerror (err), _("UserID"), MB_ERR);
561 else {
562 msg_box (dlg, _("user ID successfully added."), _("GnuPG Status"), MB_OK);
563 ctx->finished = 1;
564 /* The caller releases this items later. */
565 keygen->name = utf8_name;
566 keygen->comment = utf8_comment;
567 keygen->email = m_strdup (email);
568 }
569 EndDialog (dlg, TRUE);
570 return TRUE;
571
572 case IDCANCEL:
573 EndDialog (dlg, FALSE);
574 return FALSE;
575 }
576 break;
577 }
578
579 return FALSE;
580 }
581
582
583 /* Initalize a combo box with default key sizes. */
584 static void
585 init_keysize_box (HWND dlg, int ctlid)
586 {
587 /* Array with standard key-length in bits. */
588 const char *sizelist[] = {
589 "2048", "3072", "4096", NULL
590 };
591
592 for (int i=0; sizelist[i] != NULL; i++)
593 SendDlgItemMessage (dlg, ctlid, CB_ADDSTRING, 0,
594 (LPARAM)(char*)sizelist[i]);
595 SendDlgItemMessage (dlg, ctlid, CB_SETCURSEL, (WPARAM)0, 0);
596 }
597
598
599 static int
600 get_keysize_from_box (HWND dlg, int ctlid)
601 {
602 int pos;
603 char buf[32];
604
605 pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0);
606 if (pos == CB_ERR)
607 return -1;
608 SendDlgItemMessage (dlg, ctlid, CB_GETLBTEXT, pos, (LPARAM)(char*)buf);
609 return atoi (buf);
610 }
611
612
613 /* Create a time_t from a system time @st. */
614 time_t
615 w32_mktime (SYSTEMTIME *st)
616 {
617 struct tm tm;
618
619 memset (&tm, 0, sizeof (tm));
620 tm.tm_year = st->wYear-1900;
621 tm.tm_mday = st->wDay;
622 tm.tm_mon = st->wMonth-1;
623 return mktime (&tm);
624 }
625
626
627 /* Helper to map dialog indexes to GPG addkey commands */
628 struct subkey_menu_t {
629 int index;
630 const char *text;
631 int gpg_index;
632 gpgme_pubkey_algo_t algo;
633 };
634 subkey_menu_t SUBKEY_MENU[] = {
635 {0, _("DSA (sign only)"), 3, GPGME_PK_DSA},
636 {1, _("RSA (sign only)"), 4, GPGME_PK_RSA_S},
637 {2, _("ElGamal (encrypt only)"), 5, GPGME_PK_ELG_E},
638 {3, _("RSA (encrypt only)"), 6, GPGME_PK_RSA_E}
639 };
640 #define N_SUBKEY_MENU 4
641
642
643 /* Dialog procedure for adding a new secondary key. */
644 BOOL CALLBACK
645 keyedit_addsubkey_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
646 {
647 static keyedit_cb_t ctx;
648 keygen_cb_t keygen;
649 gpgme_error_t err;
650 SYSTEMTIME st;
651 HWND hwnd;
652 int index, size, valid;
653
654 switch (msg) {
655 case WM_INITDIALOG:
656 ctx = (keyedit_cb_t)lparam;
657 if (!ctx)
658 BUG (NULL);
659 SetWindowText (dlg, _("Add Subkey"));
660 SetDlgItemText (dlg, IDC_ADDSUBKEY_INFALGO, _("Key type:"));
661 SetDlgItemText (dlg, IDC_ADDSUBKEY_INFSIZE, _("Size in bits:"));
662 SetDlgItemText (dlg, IDC_ADDSUBKEY_INFVALID, _("Key expiration:"));
663 SetDlgItemText (dlg, IDC_ADDSUBKEY_EXPIRE, _("&Never"));
664 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
665
666 hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
667 for (int i=0; i < N_SUBKEY_MENU; i++) {
668 listbox_add_string (hwnd, SUBKEY_MENU[i].text);
669 }
670 CheckDlgButton (dlg, IDC_ADDSUBKEY_EXPIRE, BST_CHECKED);
671 EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
672 EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_SIZE), TRUE);
673 init_keysize_box (dlg, IDC_ADDSUBKEY_SIZE);
674 SetForegroundWindow (dlg);
675 center_window (dlg, ctx->parent);
676 return FALSE;
677
678 case WM_DESTROY:
679 balloon_msg_disable ();
680 break;
681
682 case WM_COMMAND:
683 if (HIWORD (wparam) == BN_CLICKED &&
684 LOWORD (wparam) == IDC_ADDSUBKEY_EXPIRE) {
685 int on = IsDlgButtonChecked (dlg, IDC_ADDSUBKEY_EXPIRE);
686 EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), on? FALSE: TRUE);
687 }
688
689 switch (LOWORD (wparam)) {
690 case IDOK:
691 keygen = (keygen_cb_t)ctx->opaque;
692 if (!keygen)
693 BUG (NULL);
694 /* Map combo box numbers to GPG answers. */
695 hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
696 index = listbox_get_cursel (hwnd);
697 if (index < 0 || index > N_SUBKEY_MENU) {
698 show_balloon_msg (GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO),
699 _("Please select one entry."), IDI_ERROR);
700 return FALSE;
701 }
702 size = get_keysize_from_box (dlg, IDC_ADDSUBKEY_SIZE);
703
704 DateTime_GetSystemtime (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), &st);
705 valid = w32_mktime (&st) - time (NULL);
706 valid /= 86400;
707 if (valid > 0)
708 keygen->expire = time (NULL) + valid*24*60*60;
709 keygen->bits = size;
710 keygen->algo = SUBKEY_MENU[index].algo;
711
712 {
713 GpgKeyEdit ke;
714 passphrase_cb_s pcb;
715
716 set_gpg_auto_passphrase_cb (&pcb, _("Add Subkey"));
717
718 ke.setPassphraseCallback (passphrase_cb, (void*)&pcb);
719 ke.setKeyID (ctx->keyid);
720 ke.setCallback (keygen_cb, NULL);
721 keygen_cb_dlg_create ();
722 err = ke.addSubkey ((gpgme_pubkey_algo_t)SUBKEY_MENU[index].gpg_index, size, valid);
723
724 release_gpg_passphrase_cb (&pcb);
725 }
726 keygen->fpr = get_subkey_keyid (ctx->keyid);
727 keygen_cb_dlg_destroy (1);
728 if (err)
729 msg_box (dlg, gpgme_strerror (err), _("Add Subkey"), MB_ERR);
730 else {
731 msg_box (dlg, _("Subkey successfully added."), _("GnuPG Status"), MB_OK);
732 ctx->finished = 1;
733 }
734 EndDialog (dlg, TRUE);
735 return TRUE;
736
737 case IDCANCEL:
738 EndDialog (dlg, FALSE);
739 return FALSE;
740 }
741 break;
742 }
743
744 return FALSE;
745 }
746
747
748 BOOL
749 keyedit_add_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
750 {
751 keyedit_cb_s cb;
752 keygen_cb_s keygen;
753
754 if (!k->key_pair) {
755 msg_box (dlg, _("There is no secret key available!"),
756 _("Add user ID"), MB_ERR);
757 return FALSE;
758 }
759
760 memset (&keygen, 0, sizeof (keygen));
761 memset (&cb, 0, sizeof (cb));
762 cb.parent = dlg;
763 cb.opaque = &keygen;
764 cb.keyid = k->keyid;
765 dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDUID,
766 dlg, keyedit_adduid_dlg_proc,
767 (LPARAM)&cb, _("Add user ID"),
768 IDS_WINPT_KEYEDIT_ADDUID);
769 if (lv != NULL && cb.finished)
770 do_add_new_userid (lv, keygen.name, keygen.email, keygen.comment);
771 if (cb.finished)
772 k->update = 1;
773
774 free_if_alloc (keygen.name);
775 free_if_alloc (keygen.email);
776 free_if_alloc (keygen.comment);
777 return TRUE;
778 }
779
780
781 /* Return the keyID of the last subkey. */
782 char*
783 get_subkey_keyid (const char *keyid)
784 {
785 gpgme_error_t err;
786 gpgme_key_t key;
787 gpgme_ctx_t ctx;
788 gpgme_subkey_t subk;
789 char *kid = NULL;
790
791 err = gpgme_new (&ctx);
792 if (err)
793 return NULL;
794 err = gpgme_get_key (ctx, keyid, &key, 0);
795 gpgme_release (ctx);
796 if (err)
797 return NULL;
798 subk = get_nth_key (key, count_subkeys (key));
799 if (subk != NULL)
800 kid = strdup (subk->keyid);
801 gpgme_key_release (key);
802 return kid;
803 }
804
805
806 BOOL
807 keyedit_add_subkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
808 {
809 keyedit_cb_s cb;
810 keygen_cb_s keygen;
811
812 if (!k->key_pair) {
813 msg_box (dlg, _("There is no secret key available!"), _("Add Subkey"), MB_ERR);
814 return FALSE;
815 }
816
817 memset (&keygen, 0, sizeof (keygen));
818 memset (&cb, 0, sizeof (cb));
819 cb.keyid = k->keyid;
820 cb.opaque = &keygen;
821 dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDSUBKEY,
822 dlg, keyedit_addsubkey_dlg_proc,
823 (LPARAM)&cb, _("Add Subkey"),
824 IDS_WINPT_KEYEDIT_ADDSUBKEY);
825 if (lv != NULL && cb.finished)
826 do_add_new_subkey (lv, &keygen, 0);
827 if (cb.finished)
828 k->update = 1;
829
830 safe_free (keygen.fpr);
831 return cb.finished? TRUE: FALSE;
832 }
833
834
835 /* Set the preferred keyserver of the given key @k. */
836 BOOL
837 keyedit_set_pref_keyserver (winpt_key_t k, HWND dlg)
838 {
839 GpgKeyEdit ke;
840 gpgme_error_t err;
841 struct URL_ctx_s *url;
842 char *pass = NULL;
843
844 url = (struct URL_ctx_s *)get_keyserver_URL_dlg (dlg);
845 if (url == NULL || url->cancel == 1) {
846 delete url;
847 return FALSE;
848 }
849
850 pass = request_key_passphrase (k->ctx, _("Key Edit"), &url->cancel);
851 if (url->cancel) {
852 delete url;
853 return FALSE;
854 }
855
856 ke.setKeyID (k->keyid);
857 if (k->is_protected)
858 ke.setPassphrase (pass);
859 else
860 ke.setNoPassphrase (true);
861 err = ke.setPreferredKeyserver (-1, url->url);
862 if (!err)
863 msg_box (dlg, _("Preferred keyserver successfully set."),
864 _("Key Edit"), MB_OK);
865 else
866 msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
867
868 keyserver_set_default (url->url, 0);
869 sfree_if_alloc (pass);
870 delete url;
871 return err == 0? 0 : WPTERR_GENERAL;
872 }
873
874
875 /* Add a photo-ID to the key specified in @k. @dlg is the handle of
876 the calling dialog. */
877 BOOL
878 keyedit_add_photo (winpt_key_t k, HWND dlg)
879 {
880 keyedit_cb_s cb;
881
882 if (!k->key_pair) {
883 msg_box (dlg, _("There is no secret key available!"),
884 _("Add Photo ID"), MB_ERR);
885 return FALSE;
886 }
887
888 memset (&cb, 0, sizeof (cb));
889 cb.parent = dlg;
890 cb.keyid = k->keyid;
891 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDPHOTO, dlg,
892 keyedit_addphoto_dlg_proc, (LPARAM)&cb);
893
894 if (cb.finished)
895 k->update = 1;
896 return TRUE;
897 }
898
899
900 BOOL
901 keyedit_add_revoker (winpt_key_t k, HWND dlg)
902 {
903 keyedit_cb_s cb;
904
905 if (!k->key_pair) {
906 msg_box (dlg, _("There is no secret key available!"), _("Add Revoker"), MB_ERR);
907 return FALSE;
908 }
909
910 memset (&cb, 0, sizeof (cb));
911 cb.parent = dlg;
912 cb.keyid = k->keyid;
913 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDREV, dlg,
914 keyedit_addrevoker_dlg_proc, (LPARAM)&cb);
915 if (cb.finished)
916 k->update = 1;
917 return TRUE;
918 }
919
920
921 /* Change ownertrust of the given key @key.
922 Return TRUE if the ownertrust was changed. */
923 BOOL
924 keyedit_change_ownertrust (winpt_key_t key, HWND dlg)
925 {
926 int rc;
927
928 rc = dialog_box_param (glob_hinst,
929 (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,
930 dlg, keyedit_ownertrust_dlg_proc,
931 (LPARAM)key, _("Change Ownertrust"),
932 IDS_WINPT_KEYEDIT_OWNERTRUST);
933 if (rc == TRUE) {
934 msg_box (dlg, _("Key status changed."), _("Key Edit"), MB_OK);
935 key->update = 1;
936 }
937 return rc;
938 }
939
940
941 /* Check if the given key is supposed to have IDEA
942 for secret key protection. */
943 static int
944 is_idea_protect_algo (const char *keyid)
945 {
946 winpt_key_s k;
947 const unsigned char *sym_prefs;
948 size_t n;
949
950 memset (&k, 0, sizeof (k));
951 if (winpt_get_pubkey (keyid, &k))
952 BUG (NULL);
953 if (!k.is_v3)
954 return 0;
955 sym_prefs = k.ext->sym_prefs;
956 /* Assume that only v3 keys have no symmetric cipher
957 preferences and thus IDEA is explicit. */
958 if (!sym_prefs)
959 return 1;
960 for (n = 0; sym_prefs[n]; n++)
961 ;
962 if ((n == 0 || n == 1) && *sym_prefs == 0x01)
963 return 1;
964 return 0;
965 }
966
967
968 BOOL
969 keyedit_change_passwd (winpt_key_t k, HWND dlg)
970 {
971 gpgme_error_t err;
972 GpgKeyEdit ke;
973 char *old_pass = NULL;
974 char *new_pass = NULL;
975 int cancel = 0;
976
977 if (!k->key_pair) {
978 msg_box (dlg, _("There is no secret key available!"),
979 _("Key Edit"), MB_ERR);
980 return FALSE;
981 }
982
983 if (!idea_available && is_idea_protect_algo (k->keyid)) {
984 msg_box (dlg, _("Cannot change passphrase because the key\n"
985 "is protected with the IDEA encryption algorithm."),
986 _("Key Edit"), MB_ERR);
987 return FALSE;
988 }
989
990 if (k->is_protected) {
991 old_pass = request_passphrase (_("Current (old) Passphrase"),
992 PASSDLG_INIT, &cancel);
993 if (cancel)
994 return FALSE;
995 }
996 new_pass = request_passphrase2 (_("New Passphrase" ),
997 PASSDLG_INIT|PASSDLG_WARN_UTF8, &cancel);
998 if (cancel) {
999 sfree_if_alloc (old_pass);
1000 return FALSE;
1001 }
1002
1003 if (strlen (new_pass) == 0) {
1004 cancel = msg_box (dlg, _("Are you sure that you really don't want a passphrase?\n"
1005 "This is propably a bad idea, continue?"),
1006 _("Key Edit"), MB_WARN_ASK);
1007 if (cancel != IDYES) {
1008 sfree_if_alloc (old_pass);
1009 sfree_if_alloc (new_pass);
1010 return FALSE;
1011 }
1012 }
1013
1014 ke.setKeyID (k->keyid);
1015 ke.setPassphrase (k->is_protected? old_pass : NULL);
1016 if (!k->is_protected)
1017 ke.setNoPassphrase (true);
1018 err = ke.changePassphrase (new_pass, 1);
1019 if (err)
1020 msg_box (dlg, gpgme_strerror (err), _("Change Password"), MB_ERR);
1021 else
1022 msg_box (dlg, _("Passphrase successfully changed."), _("GnuPG Status"), MB_OK);
1023 sfree_if_alloc (old_pass);
1024 sfree_if_alloc (new_pass);
1025
1026 return TRUE;
1027 }
1028
1029
1030 /* Initialize sub key list from key @k and return
1031 the new listview control. */
1032 listview_ctrl_t
1033 subkey_list_init (HWND dlg, winpt_key_t k)
1034 {
1035 LV_ITEM lvi;
1036 gpgme_subkey_t sub;
1037 struct listview_column_s cols[] = {
1038 {0, 80, (char *)_("Description")},
1039 {1, 78, (char *)_("Key ID")},
1040 {2, 72, (char *)_("Creation")},
1041 {3, 72, (char *)_("Expires")},
1042 {4, 64, (char *)_("Status")},
1043 {5, 16, (char *) "C"/*ertify*/},
1044 {6, 16, (char *) "S"/*ign*/},
1045 {7, 16, (char *) "E"/*ncrypt*/},
1046 {8, 16, (char *) "A"/*uth*/},
1047 {0, 0, 0}
1048 };
1049 listview_ctrl_t lv;
1050 char buf[256], tmp[128];
1051 const char *t;
1052 int nkeys = 0, i;
1053
1054 nkeys = count_subkeys (k->ctx);
1055 if (!nkeys)
1056 BUG (NULL); /* should never happen. */
1057
1058 listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
1059 for (i = 0; cols[i].fieldname != NULL; i++)
1060 listview_add_column (lv, &cols[i]);
1061
1062 for (i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next) {
1063 listview_add_item (lv, "");
1064 listview_add_sub_item (lv, 0, 1, "");
1065 memset (&lvi, 0, sizeof (lvi));
1066 lvi.mask = LVIF_PARAM;
1067 lvi.lParam = (LPARAM)sub;
1068 if (ListView_SetItem (lv->ctrl, &lvi) == FALSE)
1069 BUG (NULL);
1070 }
1071
1072 listview_set_ext_style (lv);
1073 for (i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next) {
1074 _snprintf (buf, DIM (buf)-1, "%d-bit %s", sub->length,
1075 get_key_pubalgo (sub->pubkey_algo));
1076 listview_add_sub_item (lv, i, SUBK_COL_DESC, buf);
1077 t = sub->keyid;
1078 assert (t != NULL);
1079 _snprintf (tmp, DIM (tmp)-1, "0x%s", t+8);
1080 listview_add_sub_item (lv, i, SUBK_COL_KEYID, tmp);
1081
1082 t = get_key_created (sub->timestamp);
1083 if (!t)
1084 t = "????" "-??" "-??";
1085 listview_add_sub_item (lv, i, SUBK_COL_CREATION, t);
1086
1087 if (sub->expires) {
1088 t = get_key_created (sub->expires);
1089 listview_add_sub_item (lv, i, SUBK_COL_EXPIRES, t);
1090 }
1091 else
1092 listview_add_sub_item (lv, i, SUBK_COL_EXPIRES, _("Never"));
1093 if (sub->expired)
1094 t = _("Expired");
1095 else if (sub->revoked)
1096 t = _("Revoked");
1097 else
1098 t = _("OK");
1099 listview_add_sub_item (lv, i, SUBK_COL_STATUS, t);
1100
1101 if (sub->can_certify) t = "*"; else t = "";
1102 listview_add_sub_item (lv, i, SUBK_COL_C_FLAG, t);
1103 if (sub->can_sign) t = "*"; else t = "";
1104 listview_add_sub_item (lv, i, SUBK_COL_S_FLAG, t);
1105 if (sub->can_encrypt) t = "*"; else t = "";
1106 listview_add_sub_item (lv, i, SUBK_COL_E_FLAG, t);
1107 if (sub->can_authenticate) t = "*"; else t = "";
1108 listview_add_sub_item (lv, i, SUBK_COL_A_FLAG, t);
1109 }
1110 return lv;
1111 }
1112
1113
1114 static listview_ctrl_t
1115 userid_list_init (HWND dlg, winpt_key_t k)
1116 {
1117 listview_ctrl_t lv = NULL;
1118 gpgme_key_sig_t ks;
1119 struct native_uid_s *u;
1120 int nuids = 0, j, u_attr;
1121 struct listview_column_s cols[] = {
1122 {0, 72, (char *)_("Validity")},
1123 {1, 150, (char *)_("Name")},
1124 {2, 110, (char *)_("Email")},
1125 {3, 76, (char *)_("Creation")},
1126 {0, 0, 0}
1127 };
1128 const char *attr;
1129
1130 nuids = count_userids (k->ctx);
1131 if (!nuids)
1132 BUG (NULL); /* should never happen. */
1133
1134 listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST));
1135 for (j = 0; cols[j].fieldname != NULL; j++)
1136 listview_add_column (lv, &cols[j]);
1137
1138 for (j = 0; j < nuids; j++) {
1139 listview_add_item (lv, " ");
1140 listview_add_sub_item (lv, 0, 1, " " );
1141 }
1142
1143 listview_set_ext_style (lv);
1144 for (j = 0, u=k->ext->uids; j < nuids; u=u->next, j++) {
1145 if (u->revoked)
1146 attr = _("Revoked");
1147 else {
1148 u_attr = (int)u->validity;
1149 attr = get_key_trust2 (NULL, u_attr, 0, 0);
1150 }
1151 listview_add_sub_item (lv, j, UID_COL_VALID, (char *)attr);
1152 /* XXX: add comment if available */
1153 listview_add_sub_item (lv, j, UID_COL_NAME,
1154 u->name? u->name : _("Invalid user ID"));
1155 if (u->email)
1156 listview_add_sub_item (lv, j, UID_COL_EMAIL, u->email);
1157
1158 ks = get_selfsig (u->signatures, k->keyid, 1);
1159 if (ks)
1160 listview_add_sub_item (lv, j, UID_COL_CREATION,
1161 get_key_created (ks->timestamp));
1162 }
1163 if (!k->key_pair) {
1164 CheckDlgButton (dlg, IDC_KEYUID_ADD, BST_INDETERMINATE);
1165 CheckDlgButton (dlg, IDC_KEYUID_REVOKE, BST_INDETERMINATE);
1166 }
1167 return lv;
1168 }
1169
1170
1171 static void
1172 do_init_cmdlist (HWND dlg, int is_keypair)
1173 {
1174 const char *s;
1175 int i;
1176
1177 for (i = 0; (s=cmdlist[i].name); i++) {
1178 if (is_keypair)
1179 SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1180 (LPARAM)(char *)s);
1181 else if (!cmdlist[i].need_pair)
1182 SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1183 (LPARAM)(char *)s);
1184 }
1185 SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_SETCURSEL, 0, 0);
1186 }
1187
1188
1189 /* Return 1 if the requested command is RFC2440. */
1190 static int
1191 is_cmd_openpgp (int cmdid)
1192 {
1193 switch (cmdid) {
1194 case CMD_ADDKEY:
1195 case CMD_ADDPHOTO:
1196 case CMD_ADDREVOKER:
1197 case CMD_SETPREF:
1198 return 1;
1199 }
1200 return 0;
1201 }
1202
1203
1204 /* Display a message box with a short description of the commands. */
1205 static void
1206 do_show_help (HWND dlg)
1207 {
1208 const char *help;
1209
1210 help =
1211 _(
1212 "ADDUID\t\t\tadd a user ID\r\n"
1213 "ADDPHOTO\t\t\tadd a photo ID\r\n"
1214 "DELUID\t\t\tdelete a user ID\r\n"
1215 "ADDKEY\t\t\tadd a secondary key\r\n"
1216 "DELKEY\t\t\tdelete a secondary key\r\n"
1217 "ADDREVOKER\t\t\tadd a revocation key\r\n"
1218 "EXPIRE\t\t\tchange the expire date\r\n"
1219 "SHOWPREF\t\t\tlist preferences (verbose)\r\n"
1220 "PASSWD\t\t\tchange the passphrase\r\n"
1221 "PRIMARY\t\t\tflag user ID as primary\r\n"
1222 "TRUST\t\t\tchange the ownertrust\r\n"
1223 "REVUID\t\t\trevoke a user ID\r\n"
1224 "REVKEY\t\t\trevoke a secondary key\r\n"
1225 "DISABLE\t\t\tdisable a key\r\n"
1226 "ENABLE\t\t\tenable a key\r\n"
1227 "SIGN\t\t\tsign a user-id (exportable)\r\n"
1228 "LSIGN\t\t\tsign a user-id (non-exportable)\r\n"
1229 "CLEAN\t\t\tremove unusable signatures from key\r\n"
1230 "MINIMIZE\t\t\tremove all signatures from key\r\n"
1231 );
1232 msg_box (dlg, help, _("Key Edit Help"), MB_OK);
1233 }
1234
1235
1236 static gpgme_subkey_t
1237 get_subkey_bypos (const char *keyid, int idx)
1238 {
1239 gpgme_key_t key;
1240
1241 if (get_pubkey (keyid, &key))
1242 return NULL;
1243 return get_nth_key (key, idx);
1244 }
1245
1246
1247
1248 static int
1249 do_editkey_delkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1250 {
1251 gpgme_error_t err;
1252 gpgme_subkey_t subk;
1253 GpgKeyEdit ke;
1254 int pos, id;
1255 const char *warn;
1256 char tmp[64];
1257
1258 if (!k->key_pair)
1259 return FALSE;
1260
1261 if (listview_count_items (lv, 0) == 1) {
1262 show_balloon_msg (lv->ctrl, _("Primary key can not be deleted!"),
1263 IDI_ERROR);
1264 return FALSE;
1265 }
1266 pos = listview_get_curr_pos (lv);
1267 if (pos == -1) {
1268 show_balloon_msg (lv->ctrl, _("Please select a key."), IDI_ERROR);
1269 return FALSE;
1270 }
1271 if (pos == 0) {
1272 show_balloon_msg (lv->ctrl, _("Primary key can not be deleted!"),
1273 IDI_ERROR);
1274 return FALSE;
1275 }
1276
1277 listview_get_item_text (lv, pos, 0, tmp, DIM (tmp) -1);
1278 subk = get_subkey_bypos (k->keyid, pos);
1279 /* Issue different warning for the different key capabilities. */
1280 if (subk->can_encrypt)
1281 warn = _("Anything encrypted to the selected subkey cannot be\n"
1282 "decrypted any longer.");
1283 else if (subk->can_sign || subk->can_certify)
1284 warn = _("Anything signed by the selected subkey cannot be\n"
1285 "verified any longer.");
1286 else
1287 warn = ""; /* just get rid of the warning. */
1288
1289 id = log_box (_("Key Edit"), MB_YESNO|MB_ICONWARNING,
1290 _("\"Subkey %s, ID 0x%s.\"\n\n%s\n\n"
1291 "Do you really want to DELETE this subkey?"),
1292 tmp, subk->keyid+8, warn);
1293 if (id == IDNO)
1294 return FALSE;
1295
1296 ke.setKeyID (k->keyid);
1297 err = ke.delKey (pos);
1298 if (err)
1299 msg_box (dlg, gpgme_strerror (err), _("Delete Subkey"), MB_ERR);
1300 else {
1301 listview_del_item (lv, pos);
1302 k->update = 1;
1303 status_box (dlg, _("Subkey successfully deleted."), _("GnuPG Status"));
1304 }
1305 return err? FALSE : TRUE;
1306 }
1307
1308
1309 /* Set the expiration date for the selected key in list view @lv.
1310 Return value: TRUE on success. */
1311 static int
1312 do_editkey_expire (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1313 {
1314 gpgme_error_t err;
1315 GpgKeyEdit ke;
1316 date_s udd = {0};
1317 char buf[256], * pass = NULL;
1318 time_t exp;
1319 int pos, cancel = 0;
1320
1321 if (!k->key_pair) {
1322 msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1323 return FALSE;
1324 }
1325 pos = listview_get_curr_pos (lv);
1326 if (pos == -1) {
1327 msg_box (dlg, _("Please select a key."), _("Key Edit"), MB_ERR);
1328 return FALSE;
1329 }
1330
1331 /* If a key already expired, it is possible the user wants to
1332 set a new expiration date.. */
1333 listview_get_item_text (lv, pos, SUBK_COL_STATUS, buf, DIM (buf)-1);
1334 if (!strcmp (buf, _("Expired"))) {
1335 cancel = msg_box (dlg, _("Key already expired.\n\n"
1336 "Do you want to change the expiration date?"),
1337 _("Key Edit"), MB_QUEST_ASK);
1338 if (cancel == IDNO)
1339 return FALSE;
1340 cancel = 0;
1341 }
1342
1343 memset (&udd, 0, sizeof (udd));
1344 udd.text = _("Key Expiration Date");
1345 dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_DATE, dlg,
1346 date_dlg_proc, (LPARAM)&udd,
1347 _("Key Expiration Date"), IDS_WINPT_DATE);
1348 if (udd.cancel == 1)
1349 return FALSE;
1350 if (!keygen_check_date (&udd.st)) {
1351 msg_box (dlg, _("The date you have chosen has already passed."),
1352 _("Key Edit"), MB_ERR);
1353 return FALSE;
1354 }
1355 if (k->is_protected) {
1356 pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
1357 if (cancel)
1358 return FALSE;
1359 }
1360 exp = w32_mktime (&udd.st);
1361
1362 ke.setKeyID (k->keyid);
1363 if (k->is_protected)
1364 ke.setPassphrase (pass);
1365 else
1366 ke.setNoPassphrase (true);
1367 err = ke.setKeyExpireDate (pos, exp, false);
1368 if (err)
1369 msg_box (dlg, gpgme_strerror (err), _("Expire Subkey"), MB_ERR);
1370 else {
1371 _snprintf (buf, DIM (buf)-1, "%s", get_key_created (exp));
1372 listview_add_sub_item (lv, pos, SUBK_COL_EXPIRES, buf);
1373 k->update = 1;
1374 msg_box (dlg, _("Subkey expire date successfully set."),
1375 _("GnuPG Status"), MB_OK);
1376 }
1377 sfree_if_alloc (pass);
1378 return TRUE;
1379 }
1380
1381
1382 /* Revoke the selected key in the list view @lv. @k contains
1383 control information about the global key.
1384 Return value: TRUE on success. */
1385 static int
1386 do_editkey_revoke (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1387 {
1388 gpgme_error_t err;
1389 GpgKeyEdit ke;
1390 char buf[256];
1391 char *pass = NULL;
1392 int j, cancel = 0;
1393
1394 if (!k->key_pair) {
1395 msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1396 return FALSE;
1397 }
1398
1399 if ((j = listview_get_curr_pos (lv)) == -1) {
1400 msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1401 return FALSE;
1402 }
1403 else if (listview_count_items (lv, 0) == 1) {
1404 msg_box( dlg, _("No subkeys were found, if you want to revoke the\n"
1405 "whole key, please use the Key Manager command directly.\n\n"
1406 "This command is only available to revoke single subkeys"),
1407 _("Key Edit"), MB_INFO );
1408 return FALSE;
1409 }
1410
1411 listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, DIM (buf)-1);
1412 if (!strcmp (buf, _("Revoked"))) {
1413 msg_box (dlg, _("Key already revoked."), _("Key Edit"), MB_ERR);
1414 return FALSE;
1415 }
1416
1417 if (k->is_protected) {
1418 pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
1419 if (cancel)
1420 return FALSE;
1421 }
1422
1423 ke.setKeyID (k->keyid);
1424 if (k->is_protected)
1425 ke.setPassphrase (pass);
1426 else
1427 ke.setNoPassphrase (true);
1428 err = ke.revokeSubkey (j, 0, NULL);
1429 if (err)
1430 msg_box( dlg, gpgme_strerror (err), _("Revoke Subkey"), MB_ERR);
1431 else {
1432 listview_add_sub_item (lv, j, SUBK_COL_STATUS, _("Revoked"));
1433 k->update = 1;
1434 msg_box( dlg, _("Subkey successfully revoked."), _("GnuPG Status"), MB_OK );
1435 }
1436 sfree_if_alloc (pass);
1437 return TRUE;
1438 }
1439
1440
1441 /* Revoked the selected userid in list view @lv.
1442 Return value: TRUE on success. */
1443 int
1444 do_editkey_revuid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1445 {
1446 gpgme_error_t err;
1447 GpgKeyEdit ke;
1448 char buf[128], email[128];
1449 char inf[512];
1450 char *pass = NULL;
1451 int cancel = 0, id = 0, j;
1452
1453 if (!k->key_pair) {
1454 msg_box (dlg, _("There is no secret key available!"),
1455 _("Revoke user ID"), MB_ERR);
1456 return FALSE;
1457 }
1458
1459 if (listview_count_items (lv, 0) == 1) {
1460 msg_box (dlg, _("Key has only one user ID."), _("Key Edit"), MB_ERR);
1461 return FALSE;
1462 }
1463
1464 if( (j = listview_get_curr_pos( lv )) == -1 ) {
1465 msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
1466 return FALSE;
1467 }
1468
1469 listview_get_item_text( lv, j, UID_COL_VALID, buf, DIM (buf) - 1);
1470 if (strstr (buf, _("Revoked"))) {
1471 msg_box (dlg, _("This user ID has been already revoked."),
1472 _("Key Edit"), MB_INFO);
1473 return FALSE;
1474 }
1475
1476 listview_get_item_text (lv, j, UID_COL_NAME, buf, DIM (buf) -1);
1477 _snprintf (inf, DIM (inf) -1, _("user ID \"%s\".\n\n"
1478 "Do you really want to revoke this user ID?"), buf);
1479 if (msg_box (dlg, inf, _("Key Edit"), MB_WARN_ASK) == IDNO)
1480 return FALSE;
1481 if (k->is_protected) {
1482 pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
1483 if (cancel)
1484 return FALSE;
1485 }
1486 listview_get_item_text (lv, j, UID_COL_EMAIL, email, DIM (email)-1);
1487 listview_get_item_text (lv, j, UID_COL_NAME, buf, DIM (buf)-1);
1488 id = do_find_userid (k->keyid, email, buf, NULL);
1489 if (id == -1)
1490 BUG (NULL);
1491
1492 ke.setKeyID (k->keyid);
1493 if (k->is_protected)
1494 ke.setPassphrase (pass);
1495 else
1496 ke.setNoPassphrase (true);
1497 err = ke.revokeUserid (id);
1498 if (err)
1499 msg_box (dlg, gpgme_strerror (err), _("Revoke User ID"), MB_ERR);
1500 else {
1501 listview_add_sub_item (lv, j, 0, _("Revoked"));
1502 k->update = 1;
1503 status_box (dlg, _("User ID successfully revoked"), _("GnuPG Status"));
1504 }
1505 sfree_if_alloc (pass);
1506 return err? FALSE : TRUE;
1507 }
1508
1509
1510 static int
1511 do_editkey_primary (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1512 {
1513 gpgme_error_t err;
1514 GpgKeyEdit ke;
1515 int j, id, cancel=0;
1516 char valid[32];
1517 char buf[256], *pass = NULL;
1518
1519 if (listview_count_items (lv, 0) == 1)
1520 return TRUE;
1521 if ((j = listview_get_curr_pos (lv)) == -1) {
1522 msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1523 return FALSE;
1524 }
1525 listview_get_item_text (lv, j, UID_COL_VALID, valid, DIM (valid)-1);
1526 if (!strcmp (valid, _("Revoked")))
1527 return FALSE;
1528 listview_get_item_text (lv, j, UID_COL_EMAIL, buf, DIM (buf)-1);
1529 id = do_find_userid (k->keyid, buf, NULL, NULL);
1530 if (id == -1)
1531 BUG (NULL);
1532 if (k->is_protected) {
1533 pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
1534 if (cancel)
1535 return FALSE;
1536 }
1537
1538 ke.setKeyID (k->keyid);
1539 if (k->is_protected)
1540 ke.setPassphrase (pass);
1541 else
1542 ke.setNoPassphrase (true);
1543 err = ke.setPrimaryUserid (id);
1544 if (err)
1545 msg_box (dlg, gpgme_strerror (err), _("Primary"), MB_ERR);
1546 else {
1547 k->update = 1;
1548 status_box (dlg, _("User ID successfully flagged"), _("GnuPG Status"));
1549 }
1550
1551 sfree_if_alloc (pass);
1552 return err? FALSE : TRUE;
1553 }
1554
1555
1556
1557 #define CIPHER 11
1558 #define HASH 11
1559 #define COMPR 4
1560
1561 static int
1562 parse_preflist (HWND dlg, const char *list)
1563 {
1564 char buf[128] = {0};
1565 char *p, *pbuf = buf;
1566 const char *ciphers[CIPHER] = {"", "IDEA", "3DES",
1567 "CAST5", "BLOWFISH", "", "",
1568 "AES", "AES192", "AES256", "TWOFISH"};
1569 const char *hash[HASH] = {"", "MD5", "SHA1", "RMD160", "",
1570 "", "", "", "SHA256", "SHA384", "SHA512"};
1571 const char *compress[COMPR] = {"", "ZIP", "ZLIB", "BZIP2"};
1572 int n=0;
1573
1574 strncpy (buf, list, 127);
1575 p = strtok (pbuf, " ");
1576 while (p != NULL) {
1577 int algid = atol (p+1);
1578 n++;
1579 switch (*p) {
1580 case 'S':
1581 SendDlgItemMessage (dlg, IDC_SHOWPREF_CIPHERS, LB_ADDSTRING, 0,
1582 (LPARAM)(const char*)ciphers[algid % CIPHER]);
1583 break;
1584
1585 case 'H':
1586 SendDlgItemMessage (dlg, IDC_SHOWPREF_HASH, LB_ADDSTRING, 0,
1587 (LPARAM)(const char*)hash[algid % HASH]);
1588 break;
1589
1590 case 'Z':
1591 SendDlgItemMessage (dlg, IDC_SHOWPREF_ZIP, LB_ADDSTRING, 0,
1592 (LPARAM)(const char*)compress[algid % COMPR]);
1593 break;
1594
1595 default:
1596 n--;
1597 }
1598 p = strtok (NULL, " ");
1599 }
1600 return n;
1601 }
1602
1603
1604 /* Dialog box procedure to show the key preferences. */
1605 BOOL CALLBACK
1606 showpref_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1607 {
1608 static keyedit_cb_t cb = NULL;
1609 gpg_uid_info_t inf=NULL, u;
1610 char buf[128];
1611 int pos;
1612
1613 switch (msg) {
1614 case WM_INITDIALOG:
1615 cb = (keyedit_cb_t)lparam;
1616 if (!cb)
1617 BUG (NULL);
1618 listview_get_item_text (cb->lv, cb->lv_pos,
1619 UID_COL_EMAIL, buf, DIM (buf)-1);
1620 pos = do_find_userid (cb->keyid, buf, NULL, &inf);
1621 if (pos < 0 || !inf) {
1622 gpg_uid_info_release (inf);
1623 EndDialog (dlg, FALSE);
1624 break;
1625 }
1626 for (u=inf; u; u = u->next) {
1627 if (u->index == pos && u->prefs && *u->prefs) {
1628 _snprintf (buf, DIM (buf)-1, "%s", u->name);
1629 SetDlgItemText (dlg, IDC_SHOWPREF_INFO, buf);
1630 if (parse_preflist (dlg, u->prefs) <= 0)
1631 pos = -1;
1632 if (u->flags.mdc)
1633 CheckDlgButton (dlg, IDC_SHOWPREF_MDC, BST_CHECKED);
1634 break;
1635 }
1636 }
1637 gpg_uid_info_release (inf);
1638 if (pos == -1) {
1639 msg_box (dlg, _("No preferences available."), _("Key Edit"), MB_ERR);
1640 EndDialog (dlg, FALSE);
1641 break;
1642 }
1643 SetDlgItemText (dlg, IDC_SHOWPREF_MDC, _("MDC feature"));
1644 SetDlgItemText (dlg, IDC_SHOWPREF_PREFINF, _("Preferences"));
1645 SetDlgItemText (dlg, IDC_SHOWPREF_UIDHINT, _("user ID:"));
1646 SetWindowText (dlg, _("Key Preferences"));
1647 SetForegroundWindow (dlg);
1648 center_window (dlg, cb->parent);
1649 break;
1650
1651 case WM_COMMAND:
1652 switch (LOWORD (wparam)) {
1653 case IDOK:
1654 EndDialog (dlg, TRUE);
1655 break;
1656
1657 case IDCANCEL:
1658 EndDialog (dlg, FALSE);
1659 break;
1660 }
1661 break;
1662 }
1663 return FALSE;
1664 }
1665
1666
1667 static int
1668 do_editkey_showpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1669 {
1670 struct keyedit_cb_s cb;
1671 char status[32];
1672
1673 if (k->is_v3)
1674 return TRUE;
1675
1676 if (listview_get_curr_pos (lv) == -1) {
1677 msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1678 return FALSE;
1679 }
1680 memset (&cb, 0, sizeof (cb));
1681 cb.parent = dlg;
1682 cb.opaque = k->ctx;
1683 cb.keyid = k->keyid;
1684 cb.lv = lv;
1685 cb.lv_pos = listview_get_curr_pos (lv);
1686
1687 listview_get_item_text (lv, cb.lv_pos, UID_COL_VALID,
1688 status, DIM (status)-1);
1689 if (!strcmp (status, _("Revoked")))
1690 return TRUE;
1691
1692 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_SHOWPREF, dlg,
1693 showpref_dlg_proc, (LPARAM)&cb);
1694 return TRUE;
1695 }
1696
1697
1698 static int
1699 do_editkey_deluid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1700 {
1701 gpgme_error_t err;
1702 GpgKeyEdit ke;
1703 char email[128], name[128];
1704 char inf[384];
1705 int pos, id = 0;
1706
1707 if (!k->key_pair)
1708 return FALSE;
1709
1710 if (listview_count_items (lv, 0) == 1) {
1711 msg_box (dlg, _("Primary user ID can not be deleted!"),
1712 _("Key Edit"), MB_ERR);
1713 return FALSE;
1714 }
1715 pos = listview_get_curr_pos (lv);
1716 if (pos == -1) {
1717 msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1718 return FALSE;
1719 }
1720
1721 listview_get_item_text (lv, pos, UID_COL_NAME, name, DIM(name) -1);
1722 _snprintf (inf, DIM (inf)-1, _("user ID \"%s\".\n\n"
1723 "All signatures on this user ID will be also deleted."
1724 "\n\n"
1725 "Do you really want to DELETE this user ID?"),
1726 name);
1727 if (msg_box (dlg, inf, _("Key Edit"), MB_YESNO|MB_ICONWARNING) == IDNO)
1728 return FALSE;
1729
1730 listview_get_item_text (lv, pos, UID_COL_EMAIL, email, DIM (email)-1);
1731 listview_get_item_text (lv, pos, UID_COL_NAME, name, DIM (name)-1);
1732 id = do_find_userid (k->keyid, email, name, NULL);
1733 if (id == -1)
1734 BUG (NULL);
1735
1736 ke.setKeyID (k->keyid);
1737 err = ke.delUserid (id);
1738 if (err)
1739 msg_box (dlg, gpgme_strerror (err), _("Delete User ID"), MB_ERR);
1740 else {
1741 listview_del_item (lv, pos);
1742 k->update = 1;
1743 status_box (dlg, _("User ID successfully deleted"), _("GnuPG Status"));
1744 }
1745 return err? FALSE : TRUE;
1746 }
1747
1748
1749 /* Subclass routine for the subkey listview control to allow shortcuts. */
1750 static BOOL CALLBACK
1751 subkey_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1752 {
1753 int virt_key = 0;
1754 winpt_key_t key;
1755
1756 switch (msg) {
1757 case WM_KEYUP:
1758 virt_key = (int)wparam;
1759 key = (winpt_key_t)keyedit_subkey_proc.opaque;
1760 if (!key || !key->key_pair)
1761 break;
1762
1763 switch (virt_key) {
1764 case VK_DELETE:
1765 SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1766 CB_SETCURSEL, CMD_DELKEY, 0);
1767 send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
1768 break;
1769
1770 case VK_INSERT:
1771 SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1772 CB_SETCURSEL, CMD_ADDKEY, 0);
1773 send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
1774 break;
1775 }
1776 }
1777 return CallWindowProc (keyedit_subkey_proc.old, dlg, msg, wparam, lparam);
1778 }
1779
1780
1781 static BOOL CALLBACK
1782 uid_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1783 {
1784 int virt_key = 0;
1785 winpt_key_t key;
1786
1787 switch (msg) {
1788 case WM_KEYUP:
1789 virt_key = (int)wparam;
1790 key = (winpt_key_t)keyedit_uid_proc.opaque;
1791 if (!key || !key->key_pair)
1792 break;
1793
1794 switch (virt_key) {
1795 case VK_DELETE:
1796 SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1797 CB_SETCURSEL, CMD_DELUID, 0);
1798 send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1799 break;
1800
1801 case VK_INSERT:
1802 SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1803 CB_SETCURSEL, CMD_ADDUID, 0);
1804 send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1805 break;
1806 }
1807 }
1808 return CallWindowProc (keyedit_uid_proc.old, dlg, msg, wparam, lparam);
1809 }
1810
1811
1812 /* Enable the key @k when @enable is 1, disable it otherwise. */
1813 static void
1814 do_editkey_enable_disable (winpt_key_t k, HWND dlg,
1815 listview_ctrl_t lv, int enable)
1816 {
1817 gpgme_error_t err;
1818 gpgme_key_t key;
1819 GpgKeyEdit ke;
1820
1821 // FIXME: We had to duplicate the code here since the key manager
1822 // code uses the listview to get the pointer to the key!
1823 key = k->ctx;
1824 ke.setKeyID (key->subkeys->keyid);
1825
1826 err = enable? ke.enable () : ke.disable ();
1827 if (!err) {
1828 show_msg (dlg, 1500, _("Key status changed."));
1829 k->update = 1;
1830 }
1831 else
1832 msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
1833 }
1834
1835
1836 static void
1837 do_editkey_minimize (winpt_key_t k, HWND dlg)
1838 {
1839 gpgme_error_t err;
1840 GpgKeyEdit ke;
1841
1842 ke.setKeyID (k->keyid);
1843 err = ke.minimizeKey ();
1844 if (err)
1845 msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
1846 else {
1847 msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
1848 k->update = 1;
1849 }
1850 }
1851
1852
1853 static void
1854 do_editkey_clean (winpt_key_t k, HWND dlg)
1855 {
1856 gpgme_error_t err;
1857 GpgKeyEdit ke;
1858
1859 ke.setKeyID (k->keyid);
1860 err = ke.cleanKey ();
1861 if (err)
1862 msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
1863 else {
1864 msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
1865 k->update = 1;
1866 }
1867 }
1868
1869
1870 /* Start the dialog to list and display the status of all
1871 signatures for this key. */
1872 static void
1873 do_editkey_check (winpt_key_t k, HWND dlg)
1874 {
1875 if (!k->ctx)
1876 get_pubkey (k->keyid, &k->ctx);
1877 if (!k->uid && k->ctx)
1878 k->uid = k->ctx->uids->uid;
1879 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYSIG_TREE, dlg,
1880 sigtree_dlg_proc, (LPARAM)k);
1881 }
1882
1883
1884 static int
1885 do_editkey_sign_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv, int mode)
1886 {
1887 gpgme_error_t err;
1888 winpt_key_s signer;
1889 GpgKeyEdit ke;
1890 char *pass = NULL;
1891 char *defkey;
1892 char email[64], name[128], valid[32];
1893 int uid_index;
1894 int cancel = 0;
1895
1896 uid_index = listview_get_curr_pos (lv);
1897 if (uid_index == -1) {
1898 msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1899 return FALSE;
1900 }
1901 listview_get_item_text (lv, uid_index, UID_COL_VALID, valid, DIM (valid)-1);
1902 if (!strcmp (valid, _("Revoked")))
1903 return TRUE;
1904 if (mode == CMD_SIGN) {
1905 cancel = msg_box (dlg, _("Do you really want to make this sig exportable?"),
1906 _("Key Edit"), MB_QUEST_ASK);
1907 if (cancel == IDNO)
1908 return FALSE;
1909 }
1910 listview_get_item_text (lv, uid_index, UID_COL_EMAIL, email, DIM (email)-1);
1911 listview_get_item_text (lv, uid_index, UID_COL_NAME, name, DIM (name)-1);
1912 uid_index = do_find_userid (k->keyid, email, name, NULL);
1913
1914 defkey = get_gnupg_default_key ();
1915 memset (&signer, 0, sizeof (signer));
1916 if (winpt_get_seckey (defkey, &signer)) {
1917 log_debug ("do_editkey_sign_userid: no default secret key.\r\n");
1918 free_if_alloc (defkey);
1919 return FALSE;
1920 }
1921 if (signer.is_protected) {
1922 pass = request_key_passphrase (signer.ctx, _("Key Edit"), &cancel);
1923 if (cancel)
1924 return FALSE;
1925 }
1926 ke.setKeyID (k->keyid);
1927 if (signer.is_protected)
1928 ke.setPassphrase (pass);
1929 else
1930 ke.setNoPassphrase (true);
1931 ke.setLocalUser (signer.ctx);
1932 err = ke.signUserid (uid_index,
1933 mode == CMD_SIGN? GPG_EDITKEY_SIGN : GPG_EDITKEY_LSIGN,
1934 0, NULL);
1935 if (!err) {
1936 msg_box (dlg, _("Key successfully signed."), _("Key Edit"), MB_OK);
1937 k->update = 1;
1938 }
1939 else
1940 msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
1941
1942 sfree_if_alloc (pass);
1943 return !err? TRUE : FALSE;
1944 }
1945
1946
1947 static int
1948 lookup_cmd (HWND dlg)
1949 {
1950 char buf[64];
1951 int i;
1952
1953 i = SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_GETCURSEL, 0, 0);
1954 if (i == LB_ERR)
1955 return LB_ERR;
1956 GetDlgItemText (dlg, IDC_KEYEDIT_CMD, buf, DIM (buf)-1);
1957 for (i=0; cmdlist[i].name != NULL; i++) {
1958 if (!strcmp (buf, cmdlist[i].name))
1959 return cmdlist[i].id;
1960 }
1961 return LB_ERR;
1962 }
1963
1964
1965
1966 gpgme_error_t key_get_revokers (winpt_key_t key, int reload,
1967 gpg_desig_rev_t *r_rev);
1968
1969 /* Check if the key supports designated revokers and if
1970 secret keys exist to generate such a revoke cert. */
1971 static bool
1972 check_desig_rev (winpt_key_t key)
1973 {
1974 gpg_desig_rev_t rev, u;
1975 struct winpt_key_s sk;
1976
1977 if (!key->ext->gloflags.has_desig_rev)
1978 return false;
1979 key_get_revokers (key, 0, &rev);
1980 for (u = rev; u; u = u->next) {
1981 memset (&sk, 0, sizeof (sk));
1982 if (!winpt_get_seckey (u->fpr+32, &sk))
1983 return true;
1984 }
1985 return false;
1986 }
1987
1988
1989 /* Use the gpg --desig-revoker command to create a revocation
1990 cert for a key that lists our key as a designated revoker. */
1991 static void
1992 gen_desig_revoke_cert (winpt_key_t key, HWND dlg)
1993 {
1994 const char *warn;
1995 char *inf, *p;
1996 int id;
1997
1998 inf = km_key_get_info (key, 0);
1999 warn = _("Your keys is listed as a designated revoker for the key\n\n"
2000 "%s\n\n"
2001 "Are you sure you want to create a revocation certificate\n"
2002 "which allows you to revoke the key listed above?");
2003 p = new char[strlen (inf)+1+strlen (warn)+1];
2004 sprintf (p, warn, inf);
2005 free_if_alloc (inf);
2006
2007 id = msg_box (dlg, p, _("Key Edit"), MB_YESNO|MB_ICONWARNING);
2008 free_if_alloc (p);
2009 if (id == IDNO)
2010 return;
2011
2012 key->internal = 1;
2013 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKE, dlg,
2014 key_revoke_dlg_proc, (LPARAM)key);
2015 }
2016
2017
2018 /* Create tooltip control for the listview header. */
2019 static HWND
2020 create_header_tooltip (HWND dlg)
2021 {
2022 TOOLINFO ti;
2023 HWND tt;
2024
2025 tt = CreateWindow (TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP|TTS_BALLOON ,
2026 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2027 CW_USEDEFAULT,
2028 NULL, (HMENU) NULL, glob_hinst, NULL);
2029 if (!tt)
2030 BUG (NULL);
2031 memset (&ti, 0, sizeof (ti));
2032 ti.cbSize = sizeof (TOOLINFO);
2033 ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
2034 ti.hwnd = dlg;
2035 ti.uId = (UINT) ListView_GetHeader (GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
2036 ti.hinst = 0;
2037 ti.lpszText = (char*)_("Capabilties: C = Certify, S = Sign, E = Encrypt, A = Authenticate");
2038 SendMessage(tt, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
2039 return tt;
2040 }
2041
2042
2043 #define TTM_POPUP (WM_USER+34)
2044
2045 /* Dialog box procedure for the edit key dialog. */
2046 BOOL CALLBACK
2047 keyedit_main_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
2048 {
2049 static winpt_key_t k;
2050 static listview_ctrl_t lvsub = NULL;
2051 static listview_ctrl_t lvuid = NULL;
2052 static HWND tt = NULL;
2053 int cmd;
2054 HWND item;
2055
2056 switch (msg) {
2057 case WM_INITDIALOG:
2058 k = (winpt_key_t)lparam;
2059 if (!k)
2060 BUG (NULL);
2061 do_init_cmdlist (dlg, k->key_pair);
2062 lvsub = subkey_list_init (dlg, k);
2063 lvuid = userid_list_init (dlg, k);
2064 item = GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST);
2065 keyedit_subkey_proc.opaque = (void*)k;
2066 keyedit_subkey_proc.dlg = dlg;
2067 keyedit_subkey_proc.current = (WNDPROC)subkey_subclass_proc;
2068 keyedit_subkey_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
2069 if (keyedit_subkey_proc.old) {
2070 if (!SetWindowLong (item, GWL_WNDPROC,
2071 (LONG)keyedit_subkey_proc.current)) {
2072 msg_box (dlg, "Could not set subkey window procedure.",
2073 _("Key Edit"), MB_ERR);
2074 BUG (NULL);
2075 }
2076 }
2077 tt = create_header_tooltip (dlg);
2078
2079 item = GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST);
2080 keyedit_uid_proc.opaque = (void*)k;
2081 keyedit_uid_proc.dlg = dlg;
2082 keyedit_uid_proc.current = (WNDPROC)uid_subclass_proc;
2083 keyedit_uid_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
2084 if (keyedit_uid_proc.old) {
2085 if (!SetWindowLong (item, GWL_WNDPROC,
2086 (LONG)keyedit_uid_proc.current)) {
2087 msg_box (dlg, "Could not set user ID window procedure.",
2088 _("Key Edit"), MB_ERR);
2089 BUG (NULL);
2090 }
2091 }
2092 if (k->ctx->revoked || k->ctx->expired) {
2093 EnableWindow (GetDlgItem (dlg, IDC_KEYEDIT_CMD), FALSE);
2094 EnableWindow (GetDlgItem (dlg, IDOK), FALSE);
2095 }
2096 SetDlgItemText (dlg, IDC_KEYEDIT_CMDINF, _("Command>"));
2097 SetDlgItemText (dlg, IDCANCEL, _("&Close"));
2098 SetDlgItemText (dlg, IDC_KEYEDIT_HELP, _("&Help"));
2099 SetDlgItemText (dlg, IDC_KEYEDIT_REVOKE, _("&Revoke..."));
2100 SetDlgItemText (dlg, IDOK, _("&OK"));
2101 if (!check_desig_rev (k))
2102 ShowWindow (GetDlgItem (dlg, IDC_KEYEDIT_REVOKE), SW_HIDE);
2103 if (k->is_v3)
2104 SetWindowText (dlg, _("Key Edit (PGP 2.6.x mode)"));
2105 else
2106 SetWindowText (dlg, _("Key Edit"));
2107 SetForegroundWindow (dlg);
2108 center_window (dlg, NULL);
2109 return TRUE;
2110
2111 case WM_DESTROY:
2112 if (lvsub) {
2113 listview_release (lvsub);
2114 lvsub = NULL;
2115 }
2116 if (lvuid) {
2117 listview_release (lvuid);
2118 lvuid = NULL;
2119 }
2120 if (tt != NULL)
2121 DestroyWindow (tt);
2122
2123 balloon_msg_disable ();
2124 break;
2125
2126 case WM_NOTIFY:
2127 NMHDR *notify;
2128 notify = (NMHDR *)lparam;
2129 if (!notify || notify->idFrom != IDC_KEYEDIT_UIDLIST)
2130 break;
2131 if (notify->code == NM_DBLCLK)
2132 do_editkey_showpref (k, dlg, lvuid);
2133 else if (notify->code == NM_RCLICK && k->key_pair) {
2134 if (listview_count_items (lvuid, 0) == 1)
2135 break;
2136 HMENU hm = LoadMenu (glob_hinst, MAKEINTRESOURCE (IDR_WINPT_KEYEDIT));
2137 HMENU popup = GetSubMenu (hm, 0);
2138 POINT p;
2139
2140 set_menu_text (popup, ID_KEYEDIT_UID_PRIM, _("Flag user ID as &primary"));
2141 set_menu_text (popup, ID_KEYEDIT_UID_DEL, _("&Delete user ID"));
2142 set_menu_text (popup, ID_KEYEDIT_UID_REV, _("&Revoke user ID"));
2143 GetCursorPos (&p);
2144 TrackPopupMenu (popup, TPM_RIGHTALIGN, p.x, p.y, 0, dlg, NULL);
2145 DestroyMenu (hm);
2146 DestroyMenu (popup);
2147 }
2148 break;
2149
2150 case WM_COMMAND:
2151 switch (LOWORD (wparam)) {
2152 case IDOK:
2153 cmd = lookup_cmd (dlg);
2154 if (cmd == LB_ERR) {
2155 msg_box (dlg, _("Please select a command."), _("Key Edit"), MB_INFO);
2156 return FALSE;
2157 }
2158 if (k->is_v3 && is_cmd_openpgp (cmd)) {
2159 msg_box (dlg, _("This command cannot be used with PGP 2 (v3) keys.\n"),
2160 _("Key Edit"), MB_ERR);
2161 return FALSE;
2162 }
2163 switch (cmd) {
2164 case CMD_SHOWPREF: do_editkey_showpref (k, dlg, lvuid); break;
2165 case CMD_DELKEY: do_editkey_delkey (k, dlg, lvsub); break;
2166 case CMD_ADDKEY: keyedit_add_subkey (k, dlg, lvsub); break;
2167 case CMD_EXPIRE: do_editkey_expire (k, dlg, lvsub); break;
2168 case CMD_REVKEY: do_editkey_revoke (k, dlg, lvsub); break;
2169 case CMD_SETPREF:/*do_editkey_setpref (k, dlg, lvuid);*/ break;
2170 case CMD_ADDUID: keyedit_add_userid( k, dlg, lvuid ); break;
2171 case CMD_ADDREVOKER: keyedit_add_revoker( k, dlg ); break;
2172 case CMD_ADDPHOTO: keyedit_add_photo( k, dlg ); break;
2173 case CMD_REVUID: do_editkey_revuid( k, dlg, lvuid ); break;
2174 case CMD_DELUID: do_editkey_deluid( k, dlg, lvuid ); break;
2175 case CMD_PASSWD: keyedit_change_passwd (k, dlg); break;
2176 case CMD_PRIMARY: do_editkey_primary (k, dlg, lvuid); break;
2177 case CMD_ENABLE: do_editkey_enable_disable (k, dlg, lvsub, 1); break;
2178 case CMD_DISABLE: do_editkey_enable_disable (k, dlg, lvsub, 0); break;
2179 case CMD_CHECK: do_editkey_check (k, dlg); break;
2180 case CMD_TRUST: keyedit_change_ownertrust (k, dlg); break;
2181 case CMD_SIGN:
2182 case CMD_LSIGN: do_editkey_sign_userid (k, dlg,
2183 lvuid, cmd);
2184 break;
2185 case CMD_CLEAN: do_editkey_clean (k, dlg); break;
2186 case CMD_MINIMIZE: do_editkey_minimize (k, dlg); break;
2187 }
2188 break;
2189
2190 case IDCANCEL:
2191 EndDialog (dlg, FALSE);
2192 break;
2193
2194 case IDC_KEYEDIT_HELP:
2195 do_show_help (dlg);
2196 break;
2197
2198 case IDC_KEYEDIT_REVOKE:
2199 gen_desig_revoke_cert (k, dlg);
2200 break;
2201
2202 case ID_KEYEDIT_UID_PRIM:
2203 do_editkey_primary (k, dlg, lvuid);
2204 break;
2205
2206 case ID_KEYEDIT_UID_DEL:
2207 do_editkey_deluid (k, dlg, lvuid);
2208 break;
2209
2210 case ID_KEYEDIT_UID_REV:
2211 do_editkey_revuid (k, dlg, lvuid);
2212 break;
2213 }
2214 break;
2215 }
2216 return FALSE;
2217 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26