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

Contents of /trunk/Src/wptKeyEditDlgs.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: 61390 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26