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

Annotation of /trunk/Src/wptKeyEditDlgs.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 400 - (hide annotations)
Sun Jan 29 12:27:40 2012 UTC (13 years, 1 month ago) by twoaday
File size: 60229 byte(s)


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26