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

Contents of /trunk/Src/wptKeyEditDlgs.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 273 - (show annotations)
Fri Dec 8 10:22:17 2006 UTC (18 years, 2 months ago) by twoaday
File size: 62015 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26