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

Annotation of /trunk/Src/wptKeyEditDlgs.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 392 - (hide annotations)
Sun Jan 15 18:05:11 2012 UTC (13 years, 1 month ago) by twoaday
File size: 60238 byte(s)
2012-01-15  Timo Schulz  <twoaday@gmx.net>
               
     * wptKeyEditDlgs.cpp (keyedit_addsubkey_dlg_proc):
     Invert logic to disable the calendar control for the
     key expiration date.
     * wptKeyPropsDialog.cpp (on_init_dialog): Localized
     missing string.


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 346 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     msg_box (dlg, _("There is no secret key available!"),
814     _("Add Subkey"), MB_ERR);
815     return FALSE;
816     }
817    
818     memset (&keygen, 0, sizeof (keygen));
819     memset (&cb, 0, sizeof (cb));
820     cb.keyid = k->keyid;
821     cb.opaque = &keygen;
822     dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDSUBKEY,
823     dlg, keyedit_addsubkey_dlg_proc,
824     (LPARAM)&cb, _("Add Subkey"),
825     IDS_WINPT_KEYEDIT_ADDSUBKEY);
826     if (lv != NULL && cb.finished)
827     do_add_new_subkey (lv, &keygen, 0);
828     if (cb.finished)
829     k->update = 1;
830    
831     safe_free (keygen.fpr);
832     return cb.finished? TRUE: FALSE;
833     }
834    
835    
836     /* Set the preferred keyserver of the given key @k. */
837     BOOL
838     keyedit_set_pref_keyserver (winpt_key_t k, HWND dlg)
839     {
840     GpgKeyEdit ke;
841     gpgme_error_t err;
842     struct URL_ctx_s *url;
843     char *pass = NULL;
844    
845     url = (struct URL_ctx_s *)get_keyserver_URL_dlg (dlg);
846     if (url == NULL || url->cancel == 1) {
847     delete url;
848     return FALSE;
849     }
850    
851     pass = request_key_passphrase (k->ctx, _("Key Edit"), &url->cancel);
852     if (url->cancel) {
853     delete url;
854     return FALSE;
855     }
856    
857     ke.setKeyID (k->keyid);
858     if (k->is_protected)
859     ke.setPassphrase (pass);
860     else
861     ke.setNoPassphrase (true);
862     err = ke.setPreferredKeyserver (-1, url->url);
863     if (!err)
864     msg_box (dlg, _("Preferred keyserver successfully set."),
865     _("Key Edit"), MB_OK);
866     else
867     msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
868    
869     keyserver_set_default (url->url, 0);
870     sfree_if_alloc (pass);
871     delete url;
872     return err == 0? 0 : WPTERR_GENERAL;
873     }
874    
875    
876     /* Add a photo-ID to the key specified in @k. @dlg is the handle of
877     the calling dialog. */
878     BOOL
879     keyedit_add_photo (winpt_key_t k, HWND dlg)
880     {
881     keyedit_cb_s cb;
882    
883     if (!k->key_pair) {
884     msg_box (dlg, _("There is no secret key available!"),
885     _("Add Photo ID"), MB_ERR);
886     return FALSE;
887     }
888    
889     memset (&cb, 0, sizeof (cb));
890     cb.parent = dlg;
891     cb.keyid = k->keyid;
892     DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDPHOTO, dlg,
893     keyedit_addphoto_dlg_proc, (LPARAM)&cb);
894    
895     if (cb.finished)
896     k->update = 1;
897     return TRUE;
898     }
899    
900    
901     BOOL
902     keyedit_add_revoker (winpt_key_t k, HWND dlg)
903     {
904     keyedit_cb_s cb;
905    
906     if (!k->key_pair) {
907     msg_box (dlg, _("There is no secret key available!"), _("Add Revoker"), MB_ERR);
908     return FALSE;
909     }
910    
911     memset (&cb, 0, sizeof (cb));
912     cb.parent = dlg;
913     cb.keyid = k->keyid;
914     DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDREV, dlg,
915     keyedit_addrevoker_dlg_proc, (LPARAM)&cb);
916     if (cb.finished)
917     k->update = 1;
918     return TRUE;
919     }
920    
921    
922     /* Change ownertrust of the given key @key.
923     Return TRUE if the ownertrust was changed. */
924     BOOL
925     keyedit_change_ownertrust (winpt_key_t key, HWND dlg)
926     {
927     int rc;
928    
929     rc = dialog_box_param (glob_hinst,
930     (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,
931     dlg, keyedit_ownertrust_dlg_proc,
932     (LPARAM)key, _("Change Ownertrust"),
933     IDS_WINPT_KEYEDIT_OWNERTRUST);
934     if (rc == TRUE) {
935     msg_box (dlg, _("Key status changed."), _("Key Edit"), MB_OK);
936     key->update = 1;
937     }
938     return rc;
939     }
940    
941    
942     /* Check if the given key is supposed to have IDEA
943     for secret key protection. */
944     static int
945     is_idea_protect_algo (const char *keyid)
946     {
947     winpt_key_s k;
948     const unsigned char *sym_prefs;
949     size_t n;
950    
951     memset (&k, 0, sizeof (k));
952     if (winpt_get_pubkey (keyid, &k))
953     BUG (NULL);
954     if (!k.is_v3)
955     return 0;
956     sym_prefs = k.ext->sym_prefs;
957     /* Assume that only v3 keys have no symmetric cipher
958     preferences and thus IDEA is explicit. */
959     if (!sym_prefs)
960     return 1;
961     for (n = 0; sym_prefs[n]; n++)
962     ;
963     if ((n == 0 || n == 1) && *sym_prefs == 0x01)
964     return 1;
965     return 0;
966     }
967    
968    
969     BOOL
970     keyedit_change_passwd (winpt_key_t k, HWND dlg)
971     {
972     gpgme_error_t err;
973     GpgKeyEdit ke;
974     char *old_pass = NULL;
975     char *new_pass = NULL;
976     int cancel = 0;
977    
978     if (!k->key_pair) {
979     msg_box (dlg, _("There is no secret key available!"),
980     _("Key Edit"), MB_ERR);
981     return FALSE;
982     }
983    
984     if (!idea_available && is_idea_protect_algo (k->keyid)) {
985     msg_box (dlg, _("Cannot change passphrase because the key\n"
986     "is protected with the IDEA encryption algorithm."),
987     _("Key Edit"), MB_ERR);
988     return FALSE;
989     }
990    
991     if (k->is_protected) {
992     old_pass = request_passphrase (_("Current (old) Passphrase"),
993     PASSDLG_INIT, &cancel);
994     if (cancel)
995     return FALSE;
996     }
997     new_pass = request_passphrase2 (_("New Passphrase" ),
998     PASSDLG_INIT|PASSDLG_WARN_UTF8, &cancel);
999     if (cancel) {
1000     sfree_if_alloc (old_pass);
1001     return FALSE;
1002     }
1003    
1004     if (strlen (new_pass) == 0) {
1005     cancel = msg_box (dlg, _("Are you sure that you really don't want a passphrase?\n"
1006     "This is propably a bad idea, continue?"),
1007     _("Key Edit"), MB_WARN_ASK);
1008     if (cancel != IDYES) {
1009     sfree_if_alloc (old_pass);
1010     sfree_if_alloc (new_pass);
1011     return FALSE;
1012     }
1013     }
1014    
1015     ke.setKeyID (k->keyid);
1016     ke.setPassphrase (k->is_protected? old_pass : NULL);
1017     if (!k->is_protected)
1018     ke.setNoPassphrase (true);
1019     err = ke.changePassphrase (new_pass, 1);
1020     if (err)
1021     msg_box (dlg, gpgme_strerror (err), _("Change Password"), MB_ERR);
1022     else
1023     msg_box (dlg, _("Passphrase successfully changed."), _("GnuPG Status"), MB_OK);
1024     sfree_if_alloc (old_pass);
1025     sfree_if_alloc (new_pass);
1026    
1027     return TRUE;
1028     }
1029    
1030    
1031     /* Initialize sub key list from key @k and return
1032     the new listview control. */
1033     listview_ctrl_t
1034     subkey_list_init (HWND dlg, winpt_key_t k)
1035     {
1036     LV_ITEM lvi;
1037     gpgme_subkey_t sub;
1038     struct listview_column_s cols[] = {
1039     {0, 80, (char *)_("Description")},
1040     {1, 78, (char *)_("Key ID")},
1041 twoaday 344 {2, 72, (char *)_("Creation")},
1042     {3, 72, (char *)_("Expires")},
1043 twoaday 340 {4, 64, (char *)_("Status")},
1044     {5, 16, (char *) "C"/*ertify*/},
1045     {6, 16, (char *) "S"/*ign*/},
1046     {7, 16, (char *) "E"/*ncrypt*/},
1047     {8, 16, (char *) "A"/*uth*/},
1048     {0, 0, 0}
1049     };
1050     listview_ctrl_t lv;
1051     char buf[256], tmp[128];
1052     const char *t;
1053     int nkeys = 0, i;
1054    
1055     nkeys = count_subkeys (k->ctx);
1056     if (!nkeys)
1057     BUG (NULL); /* should never happen. */
1058    
1059     listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
1060     for (i = 0; cols[i].fieldname != NULL; i++)
1061     listview_add_column (lv, &cols[i]);
1062    
1063     for (i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next) {
1064     listview_add_item (lv, "");
1065     listview_add_sub_item (lv, 0, 1, "");
1066     memset (&lvi, 0, sizeof (lvi));
1067     lvi.mask = LVIF_PARAM;
1068     lvi.lParam = (LPARAM)sub;
1069     if (ListView_SetItem (lv->ctrl, &lvi) == FALSE)
1070     BUG (NULL);
1071     }
1072    
1073     listview_set_ext_style (lv);
1074     for (i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next) {
1075     _snprintf (buf, DIM (buf)-1, "%d-bit %s", sub->length,
1076     get_key_pubalgo (sub->pubkey_algo));
1077     listview_add_sub_item (lv, i, SUBK_COL_DESC, buf);
1078     t = sub->keyid;
1079     assert (t != NULL);
1080     _snprintf (tmp, DIM (tmp)-1, "0x%s", t+8);
1081     listview_add_sub_item (lv, i, SUBK_COL_KEYID, tmp);
1082    
1083     t = get_key_created (sub->timestamp);
1084     if (!t)
1085     t = "????" "-??" "-??";
1086     listview_add_sub_item (lv, i, SUBK_COL_CREATION, t);
1087    
1088     if (sub->expires) {
1089     t = get_key_created (sub->expires);
1090     listview_add_sub_item (lv, i, SUBK_COL_EXPIRES, t);
1091     }
1092     else
1093     listview_add_sub_item (lv, i, SUBK_COL_EXPIRES, _("Never"));
1094     if (sub->expired)
1095     t = _("Expired");
1096     else if (sub->revoked)
1097     t = _("Revoked");
1098     else
1099     t = _("OK");
1100     listview_add_sub_item (lv, i, SUBK_COL_STATUS, t);
1101    
1102     if (sub->can_certify) t = "*"; else t = "";
1103     listview_add_sub_item (lv, i, SUBK_COL_C_FLAG, t);
1104     if (sub->can_sign) t = "*"; else t = "";
1105     listview_add_sub_item (lv, i, SUBK_COL_S_FLAG, t);
1106     if (sub->can_encrypt) t = "*"; else t = "";
1107     listview_add_sub_item (lv, i, SUBK_COL_E_FLAG, t);
1108     if (sub->can_authenticate) t = "*"; else t = "";
1109     listview_add_sub_item (lv, i, SUBK_COL_A_FLAG, t);
1110     }
1111     return lv;
1112     }
1113    
1114    
1115     static listview_ctrl_t
1116     userid_list_init (HWND dlg, winpt_key_t k)
1117     {
1118     listview_ctrl_t lv = NULL;
1119     gpgme_key_sig_t ks;
1120     struct native_uid_s *u;
1121     int nuids = 0, j, u_attr;
1122     struct listview_column_s cols[] = {
1123     {0, 72, (char *)_("Validity")},
1124     {1, 150, (char *)_("Name")},
1125     {2, 110, (char *)_("Email")},
1126     {3, 76, (char *)_("Creation")},
1127     {0, 0, 0}
1128     };
1129     const char *attr;
1130    
1131     nuids = count_userids (k->ctx);
1132     if (!nuids)
1133     BUG (NULL); /* should never happen. */
1134    
1135     listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST));
1136     for (j = 0; cols[j].fieldname != NULL; j++)
1137     listview_add_column (lv, &cols[j]);
1138    
1139     for (j = 0; j < nuids; j++) {
1140     listview_add_item (lv, " ");
1141     listview_add_sub_item (lv, 0, 1, " " );
1142     }
1143    
1144     listview_set_ext_style (lv);
1145     for (j = 0, u=k->ext->uids; j < nuids; u=u->next, j++) {
1146     if (u->revoked)
1147     attr = _("Revoked");
1148     else {
1149     u_attr = (int)u->validity;
1150     attr = get_key_trust2 (NULL, u_attr, 0, 0);
1151     }
1152     listview_add_sub_item (lv, j, UID_COL_VALID, (char *)attr);
1153     /* XXX: add comment if available */
1154     listview_add_sub_item (lv, j, UID_COL_NAME,
1155     u->name? u->name : _("Invalid user ID"));
1156     if (u->email)
1157     listview_add_sub_item (lv, j, UID_COL_EMAIL, u->email);
1158    
1159     ks = get_selfsig (u->signatures, k->keyid, 1);
1160     if (ks)
1161     listview_add_sub_item (lv, j, UID_COL_CREATION,
1162     get_key_created (ks->timestamp));
1163     }
1164     if (!k->key_pair) {
1165     CheckDlgButton (dlg, IDC_KEYUID_ADD, BST_INDETERMINATE);
1166     CheckDlgButton (dlg, IDC_KEYUID_REVOKE, BST_INDETERMINATE);
1167     }
1168     return lv;
1169     }
1170    
1171    
1172     static void
1173     do_init_cmdlist (HWND dlg, int is_keypair)
1174     {
1175     const char *s;
1176     int i;
1177    
1178     for (i = 0; (s=cmdlist[i].name); i++) {
1179     if (is_keypair)
1180     SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1181     (LPARAM)(char *)s);
1182     else if (!cmdlist[i].need_pair)
1183     SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1184     (LPARAM)(char *)s);
1185     }
1186     SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_SETCURSEL, 0, 0);
1187     }
1188    
1189    
1190     /* Return 1 if the requested command is RFC2440. */
1191     static int
1192     is_cmd_openpgp (int cmdid)
1193     {
1194     switch (cmdid) {
1195     case CMD_ADDKEY:
1196     case CMD_ADDPHOTO:
1197     case CMD_ADDREVOKER:
1198     case CMD_SETPREF:
1199     return 1;
1200     }
1201     return 0;
1202     }
1203    
1204    
1205     /* Display a message box with a short description of the commands. */
1206     static void
1207     do_show_help (HWND dlg)
1208     {
1209     const char *help;
1210    
1211     help =
1212     _(
1213     "ADDUID\t\t\tadd a user ID\r\n"
1214     "ADDPHOTO\t\t\tadd a photo ID\r\n"
1215     "DELUID\t\t\tdelete a user ID\r\n"
1216     "ADDKEY\t\t\tadd a secondary key\r\n"
1217     "DELKEY\t\t\tdelete a secondary key\r\n"
1218     "ADDREVOKER\t\t\tadd a revocation key\r\n"
1219     "EXPIRE\t\t\tchange the expire date\r\n"
1220     "SHOWPREF\t\t\tlist preferences (verbose)\r\n"
1221     "PASSWD\t\t\tchange the passphrase\r\n"
1222     "PRIMARY\t\t\tflag user ID as primary\r\n"
1223     "TRUST\t\t\tchange the ownertrust\r\n"
1224     "REVUID\t\t\trevoke a user ID\r\n"
1225     "REVKEY\t\t\trevoke a secondary key\r\n"
1226     "DISABLE\t\t\tdisable a key\r\n"
1227     "ENABLE\t\t\tenable a key\r\n"
1228     "SIGN\t\t\tsign a user-id (exportable)\r\n"
1229     "LSIGN\t\t\tsign a user-id (non-exportable)\r\n"
1230     "CLEAN\t\t\tremove unusable signatures from key\r\n"
1231     "MINIMIZE\t\t\tremove all signatures from key\r\n"
1232     );
1233     msg_box (dlg, help, _("Key Edit Help"), MB_OK);
1234     }
1235    
1236    
1237     static gpgme_subkey_t
1238     get_subkey_bypos (const char *keyid, int idx)
1239     {
1240     gpgme_key_t key;
1241    
1242     if (get_pubkey (keyid, &key))
1243     return NULL;
1244     return get_nth_key (key, idx);
1245     }
1246    
1247    
1248    
1249     static int
1250     do_editkey_delkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1251     {
1252     gpgme_error_t err;
1253     gpgme_subkey_t subk;
1254     GpgKeyEdit ke;
1255     int pos, id;
1256     const char *warn;
1257     char tmp[64];
1258    
1259     if (!k->key_pair)
1260     return FALSE;
1261    
1262     if (listview_count_items (lv, 0) == 1) {
1263     show_balloon_msg (lv->ctrl, _("Primary key can not be deleted!"),
1264     IDI_ERROR);
1265     return FALSE;
1266     }
1267     pos = listview_get_curr_pos (lv);
1268     if (pos == -1) {
1269     show_balloon_msg (lv->ctrl, _("Please select a key."), IDI_ERROR);
1270     return FALSE;
1271     }
1272     if (pos == 0) {
1273     show_balloon_msg (lv->ctrl, _("Primary key can not be deleted!"),
1274     IDI_ERROR);
1275     return FALSE;
1276     }
1277    
1278     listview_get_item_text (lv, pos, 0, tmp, DIM (tmp) -1);
1279     subk = get_subkey_bypos (k->keyid, pos);
1280     /* Issue different warning for the different key capabilities. */
1281     if (subk->can_encrypt)
1282     warn = _("Anything encrypted to the selected subkey cannot be\n"
1283     "decrypted any longer.");
1284     else if (subk->can_sign || subk->can_certify)
1285     warn = _("Anything signed by the selected subkey cannot be\n"
1286     "verified any longer.");
1287     else
1288     warn = ""; /* just get rid of the warning. */
1289    
1290     id = log_box (_("Key Edit"), MB_YESNO|MB_ICONWARNING,
1291     _("\"Subkey %s, ID 0x%s.\"\n\n%s\n\n"
1292     "Do you really want to DELETE this subkey?"),
1293     tmp, subk->keyid+8, warn);
1294     if (id == IDNO)
1295     return FALSE;
1296    
1297     ke.setKeyID (k->keyid);
1298     err = ke.delKey (pos);
1299     if (err)
1300     msg_box (dlg, gpgme_strerror (err), _("Delete Subkey"), MB_ERR);
1301     else {
1302     listview_del_item (lv, pos);
1303     k->update = 1;
1304     status_box (dlg, _("Subkey successfully deleted."), _("GnuPG Status"));
1305     }
1306     return err? FALSE : TRUE;
1307     }
1308    
1309    
1310     /* Set the expiration date for the selected key in list view @lv.
1311     Return value: TRUE on success. */
1312     static int
1313     do_editkey_expire (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1314     {
1315     gpgme_error_t err;
1316     GpgKeyEdit ke;
1317     date_s udd = {0};
1318     char buf[256], * pass = NULL;
1319     time_t exp;
1320     int pos, cancel = 0;
1321    
1322     if (!k->key_pair) {
1323     msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1324     return FALSE;
1325     }
1326     pos = listview_get_curr_pos (lv);
1327     if (pos == -1) {
1328     msg_box (dlg, _("Please select a key."), _("Key Edit"), MB_ERR);
1329     return FALSE;
1330     }
1331    
1332     /* If a key already expired, it is possible the user wants to
1333     set a new expiration date.. */
1334     listview_get_item_text (lv, pos, SUBK_COL_STATUS, buf, DIM (buf)-1);
1335     if (!strcmp (buf, _("Expired"))) {
1336     cancel = msg_box (dlg, _("Key already expired.\n\n"
1337     "Do you want to change the expiration date?"),
1338     _("Key Edit"), MB_QUEST_ASK);
1339     if (cancel == IDNO)
1340     return FALSE;
1341     cancel = 0;
1342     }
1343    
1344     memset (&udd, 0, sizeof (udd));
1345     udd.text = _("Key Expiration Date");
1346     dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_DATE, dlg,
1347     date_dlg_proc, (LPARAM)&udd,
1348     _("Key Expiration Date"), IDS_WINPT_DATE);
1349     if (udd.cancel == 1)
1350     return FALSE;
1351     if (!keygen_check_date (&udd.st)) {
1352     msg_box (dlg, _("The date you have chosen has already passed."),
1353     _("Key Edit"), MB_ERR);
1354     return FALSE;
1355     }
1356     if (k->is_protected) {
1357     pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
1358     if (cancel)
1359     return FALSE;
1360     }
1361     exp = w32_mktime (&udd.st);
1362    
1363     ke.setKeyID (k->keyid);
1364     if (k->is_protected)
1365     ke.setPassphrase (pass);
1366     else
1367     ke.setNoPassphrase (true);
1368     err = ke.setKeyExpireDate (pos, exp, false);
1369     if (err)
1370     msg_box (dlg, gpgme_strerror (err), _("Expire Subkey"), MB_ERR);
1371     else {
1372     _snprintf (buf, DIM (buf)-1, "%s", get_key_created (exp));
1373     listview_add_sub_item (lv, pos, SUBK_COL_EXPIRES, buf);
1374     k->update = 1;
1375     msg_box (dlg, _("Subkey expire date successfully set."),
1376     _("GnuPG Status"), MB_OK);
1377     }
1378     sfree_if_alloc (pass);
1379     return TRUE;
1380     }
1381    
1382    
1383     /* Revoke the selected key in the list view @lv. @k contains
1384     control information about the global key.
1385     Return value: TRUE on success. */
1386     static int
1387     do_editkey_revoke (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1388     {
1389     gpgme_error_t err;
1390     GpgKeyEdit ke;
1391     char buf[256];
1392     char *pass = NULL;
1393     int j, cancel = 0;
1394    
1395     if (!k->key_pair) {
1396     msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1397     return FALSE;
1398     }
1399    
1400     if ((j = listview_get_curr_pos (lv)) == -1) {
1401     msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1402     return FALSE;
1403     }
1404     else if (listview_count_items (lv, 0) == 1) {
1405     msg_box( dlg, _("No subkeys were found, if you want to revoke the\n"
1406     "whole key, please use the Key Manager command directly.\n\n"
1407     "This command is only available to revoke single subkeys"),
1408     _("Key Edit"), MB_INFO );
1409     return FALSE;
1410     }
1411    
1412     listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, DIM (buf)-1);
1413     if (!strcmp (buf, _("Revoked"))) {
1414     msg_box (dlg, _("Key already revoked."), _("Key Edit"), MB_ERR);
1415     return FALSE;
1416     }
1417    
1418     if (k->is_protected) {
1419     pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
1420     if (cancel)
1421     return FALSE;
1422     }
1423    
1424     ke.setKeyID (k->keyid);
1425     if (k->is_protected)
1426     ke.setPassphrase (pass);
1427     else
1428     ke.setNoPassphrase (true);
1429     err = ke.revokeSubkey (j, 0, NULL);
1430     if (err)
1431     msg_box( dlg, gpgme_strerror (err), _("Revoke Subkey"), MB_ERR);
1432     else {
1433     listview_add_sub_item (lv, j, SUBK_COL_STATUS, _("Revoked"));
1434     k->update = 1;
1435     msg_box( dlg, _("Subkey successfully revoked."), _("GnuPG Status"), MB_OK );
1436     }
1437     sfree_if_alloc (pass);
1438     return TRUE;
1439     }
1440    
1441    
1442     /* Revoked the selected userid in list view @lv.
1443     Return value: TRUE on success. */
1444     int
1445     do_editkey_revuid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1446     {
1447     gpgme_error_t err;
1448     GpgKeyEdit ke;
1449     char buf[128], email[128];
1450     char inf[512];
1451     char *pass = NULL;
1452     int cancel = 0, id = 0, j;
1453    
1454     if (!k->key_pair) {
1455     msg_box (dlg, _("There is no secret key available!"),
1456     _("Revoke user ID"), MB_ERR);
1457     return FALSE;
1458     }
1459    
1460     if (listview_count_items (lv, 0) == 1) {
1461     msg_box (dlg, _("Key has only one user ID."), _("Key Edit"), MB_ERR);
1462     return FALSE;
1463     }
1464    
1465     if( (j = listview_get_curr_pos( lv )) == -1 ) {
1466     msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
1467     return FALSE;
1468     }
1469    
1470     listview_get_item_text( lv, j, UID_COL_VALID, buf, DIM (buf) - 1);
1471     if (strstr (buf, _("Revoked"))) {
1472     msg_box (dlg, _("This user ID has been already revoked."),
1473     _("Key Edit"), MB_INFO);
1474     return FALSE;
1475     }
1476    
1477     listview_get_item_text (lv, j, UID_COL_NAME, buf, DIM (buf) -1);
1478     _snprintf (inf, DIM (inf) -1, _("user ID \"%s\".\n\n"
1479     "Do you really want to revoke this user ID?"), buf);
1480     if (msg_box (dlg, inf, _("Key Edit"), MB_WARN_ASK) == IDNO)
1481     return FALSE;
1482     if (k->is_protected) {
1483     pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
1484     if (cancel)
1485     return FALSE;
1486     }
1487     listview_get_item_text (lv, j, UID_COL_EMAIL, email, DIM (email)-1);
1488     listview_get_item_text (lv, j, UID_COL_NAME, buf, DIM (buf)-1);
1489     id = do_find_userid (k->keyid, email, buf, NULL);
1490     if (id == -1)
1491     BUG (NULL);
1492    
1493     ke.setKeyID (k->keyid);
1494     if (k->is_protected)
1495     ke.setPassphrase (pass);
1496     else
1497     ke.setNoPassphrase (true);
1498     err = ke.revokeUserid (id);
1499     if (err)
1500     msg_box (dlg, gpgme_strerror (err), _("Revoke User ID"), MB_ERR);
1501     else {
1502     listview_add_sub_item (lv, j, 0, _("Revoked"));
1503     k->update = 1;
1504     status_box (dlg, _("User ID successfully revoked"), _("GnuPG Status"));
1505     }
1506     sfree_if_alloc (pass);
1507     return err? FALSE : TRUE;
1508     }
1509    
1510    
1511     static int
1512     do_editkey_primary (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1513     {
1514     gpgme_error_t err;
1515     GpgKeyEdit ke;
1516     int j, id, cancel=0;
1517     char valid[32];
1518     char buf[256], *pass = NULL;
1519    
1520     if (listview_count_items (lv, 0) == 1)
1521     return TRUE;
1522     if ((j = listview_get_curr_pos (lv)) == -1) {
1523     msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1524     return FALSE;
1525     }
1526     listview_get_item_text (lv, j, UID_COL_VALID, valid, DIM (valid)-1);
1527     if (!strcmp (valid, _("Revoked")))
1528     return FALSE;
1529     listview_get_item_text (lv, j, UID_COL_EMAIL, buf, DIM (buf)-1);
1530     id = do_find_userid (k->keyid, buf, NULL, NULL);
1531     if (id == -1)
1532     BUG (NULL);
1533     if (k->is_protected) {
1534     pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
1535     if (cancel)
1536     return FALSE;
1537     }
1538    
1539     ke.setKeyID (k->keyid);
1540     if (k->is_protected)
1541     ke.setPassphrase (pass);
1542     else
1543     ke.setNoPassphrase (true);
1544     err = ke.setPrimaryUserid (id);
1545     if (err)
1546     msg_box (dlg, gpgme_strerror (err), _("Primary"), MB_ERR);
1547     else {
1548     k->update = 1;
1549     status_box (dlg, _("User ID successfully flagged"), _("GnuPG Status"));
1550     }
1551    
1552     sfree_if_alloc (pass);
1553     return err? FALSE : TRUE;
1554     }
1555    
1556    
1557    
1558     #define CIPHER 11
1559     #define HASH 11
1560     #define COMPR 4
1561    
1562     static int
1563     parse_preflist (HWND dlg, const char *list)
1564     {
1565     char buf[128] = {0};
1566     char *p, *pbuf = buf;
1567     const char *ciphers[CIPHER] = {"", "IDEA", "3DES",
1568     "CAST5", "BLOWFISH", "", "",
1569     "AES", "AES192", "AES256", "TWOFISH"};
1570     const char *hash[HASH] = {"", "MD5", "SHA1", "RMD160", "",
1571     "", "", "", "SHA256", "SHA384", "SHA512"};
1572     const char *compress[COMPR] = {"", "ZIP", "ZLIB", "BZIP2"};
1573     int n=0;
1574    
1575     strncpy (buf, list, 127);
1576     p = strtok (pbuf, " ");
1577     while (p != NULL) {
1578     int algid = atol (p+1);
1579     n++;
1580     switch (*p) {
1581     case 'S':
1582     SendDlgItemMessage (dlg, IDC_SHOWPREF_CIPHERS, LB_ADDSTRING, 0,
1583     (LPARAM)(const char*)ciphers[algid % CIPHER]);
1584     break;
1585    
1586     case 'H':
1587     SendDlgItemMessage (dlg, IDC_SHOWPREF_HASH, LB_ADDSTRING, 0,
1588     (LPARAM)(const char*)hash[algid % HASH]);
1589     break;
1590    
1591     case 'Z':
1592     SendDlgItemMessage (dlg, IDC_SHOWPREF_ZIP, LB_ADDSTRING, 0,
1593     (LPARAM)(const char*)compress[algid % COMPR]);
1594     break;
1595    
1596     default:
1597     n--;
1598     }
1599     p = strtok (NULL, " ");
1600     }
1601     return n;
1602     }
1603    
1604    
1605     /* Dialog box procedure to show the key preferences. */
1606     BOOL CALLBACK
1607     showpref_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1608     {
1609     static keyedit_cb_t cb = NULL;
1610     gpg_uid_info_t inf=NULL, u;
1611     gpgme_key_t key;
1612     char buf[128];
1613     int pos;
1614    
1615     switch (msg) {
1616     case WM_INITDIALOG:
1617     cb = (keyedit_cb_t)lparam;
1618     if (!cb)
1619     BUG (NULL);
1620     key = (gpgme_key_t)cb->opaque;
1621     listview_get_item_text (cb->lv, cb->lv_pos,
1622     UID_COL_EMAIL, buf, DIM (buf)-1);
1623     pos = do_find_userid (cb->keyid, buf, NULL, &inf);
1624     if (pos < 0 || !inf) {
1625     gpg_uid_info_release (inf);
1626     EndDialog (dlg, FALSE);
1627     break;
1628     }
1629     for (u=inf; u; u = u->next) {
1630     if (u->index == pos && u->prefs && *u->prefs) {
1631     _snprintf (buf, DIM (buf)-1, "%s", u->name);
1632     SetDlgItemText (dlg, IDC_SHOWPREF_INFO, buf);
1633     if (parse_preflist (dlg, u->prefs) <= 0)
1634     pos = -1;
1635     if (u->flags.mdc)
1636     CheckDlgButton (dlg, IDC_SHOWPREF_MDC, BST_CHECKED);
1637     break;
1638     }
1639     }
1640     gpg_uid_info_release (inf);
1641     if (pos == -1) {
1642     msg_box (dlg, _("No preferences available."), _("Key Edit"), MB_ERR);
1643     EndDialog (dlg, FALSE);
1644     break;
1645     }
1646     SetDlgItemText (dlg, IDC_SHOWPREF_MDC, _("MDC feature"));
1647     SetDlgItemText (dlg, IDC_SHOWPREF_PREFINF, _("Preferences"));
1648     SetDlgItemText (dlg, IDC_SHOWPREF_UIDHINT, _("user ID:"));
1649     SetWindowText (dlg, _("Key Preferences"));
1650     SetForegroundWindow (dlg);
1651     center_window (dlg, cb->parent);
1652     break;
1653    
1654     case WM_COMMAND:
1655     switch (LOWORD (wparam)) {
1656     case IDOK:
1657     EndDialog (dlg, TRUE);
1658     break;
1659    
1660     case IDCANCEL:
1661     EndDialog (dlg, FALSE);
1662     break;
1663     }
1664     break;
1665     }
1666     return FALSE;
1667     }
1668    
1669    
1670     static int
1671     do_editkey_showpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1672     {
1673     struct keyedit_cb_s cb;
1674     char status[32];
1675    
1676     if (k->is_v3)
1677     return TRUE;
1678    
1679     if (listview_get_curr_pos (lv) == -1) {
1680     msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1681     return FALSE;
1682     }
1683     memset (&cb, 0, sizeof (cb));
1684     cb.parent = dlg;
1685     cb.opaque = k->ctx;
1686     cb.keyid = k->keyid;
1687     cb.lv = lv;
1688     cb.lv_pos = listview_get_curr_pos (lv);
1689    
1690     listview_get_item_text (lv, cb.lv_pos, UID_COL_VALID,
1691     status, DIM (status)-1);
1692     if (!strcmp (status, _("Revoked")))
1693     return TRUE;
1694    
1695     DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_SHOWPREF, dlg,
1696     showpref_dlg_proc, (LPARAM)&cb);
1697     return TRUE;
1698     }
1699    
1700    
1701     static int
1702     do_editkey_deluid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1703     {
1704     gpgme_error_t err;
1705     GpgKeyEdit ke;
1706     char email[128], name[128];
1707     char inf[384];
1708     int pos, id = 0;
1709    
1710     if (!k->key_pair)
1711     return FALSE;
1712    
1713     if (listview_count_items (lv, 0) == 1) {
1714     msg_box (dlg, _("Primary user ID can not be deleted!"),
1715     _("Key Edit"), MB_ERR);
1716     return FALSE;
1717     }
1718     pos = listview_get_curr_pos (lv);
1719     if (pos == -1) {
1720     msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1721     return FALSE;
1722     }
1723    
1724     listview_get_item_text (lv, pos, UID_COL_NAME, name, DIM(name) -1);
1725     _snprintf (inf, DIM (inf)-1, _("user ID \"%s\".\n\n"
1726     "All signatures on this user ID will be also deleted."
1727     "\n\n"
1728     "Do you really want to DELETE this user ID?"),
1729     name);
1730     if (msg_box (dlg, inf, _("Key Edit"), MB_YESNO|MB_ICONWARNING) == IDNO)
1731     return FALSE;
1732    
1733     listview_get_item_text (lv, pos, UID_COL_EMAIL, email, DIM (email)-1);
1734     listview_get_item_text (lv, pos, UID_COL_NAME, name, DIM (name)-1);
1735     id = do_find_userid (k->keyid, email, name, NULL);
1736     if (id == -1)
1737     BUG (NULL);
1738    
1739     ke.setKeyID (k->keyid);
1740     err = ke.delUserid (id);
1741     if (err)
1742     msg_box (dlg, gpgme_strerror (err), _("Delete User ID"), MB_ERR);
1743     else {
1744     listview_del_item (lv, pos);
1745     k->update = 1;
1746     status_box (dlg, _("User ID successfully deleted"), _("GnuPG Status"));
1747     }
1748     return err? FALSE : TRUE;
1749     }
1750    
1751    
1752     /* Subclass routine for the subkey listview control to allow shortcuts. */
1753     static BOOL CALLBACK
1754     subkey_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1755     {
1756     int virt_key = 0;
1757     winpt_key_t key;
1758    
1759     switch (msg) {
1760     case WM_KEYUP:
1761     virt_key = (int)wparam;
1762     key = (winpt_key_t)keyedit_subkey_proc.opaque;
1763     if (!key || !key->key_pair)
1764     break;
1765    
1766     switch (virt_key) {
1767     case VK_DELETE:
1768     SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1769     CB_SETCURSEL, CMD_DELKEY, 0);
1770     send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
1771     break;
1772    
1773     case VK_INSERT:
1774     SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1775     CB_SETCURSEL, CMD_ADDKEY, 0);
1776     send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
1777     break;
1778     }
1779     }
1780     return CallWindowProc (keyedit_subkey_proc.old, dlg, msg, wparam, lparam);
1781     }
1782    
1783    
1784     static BOOL CALLBACK
1785     uid_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1786     {
1787     int virt_key = 0;
1788     winpt_key_t key;
1789    
1790     switch (msg) {
1791     case WM_KEYUP:
1792     virt_key = (int)wparam;
1793     key = (winpt_key_t)keyedit_uid_proc.opaque;
1794     if (!key || !key->key_pair)
1795     break;
1796    
1797     switch (virt_key) {
1798     case VK_DELETE:
1799     SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1800     CB_SETCURSEL, CMD_DELUID, 0);
1801     send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1802     break;
1803    
1804     case VK_INSERT:
1805     SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1806     CB_SETCURSEL, CMD_ADDUID, 0);
1807     send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1808     break;
1809     }
1810     }
1811     return CallWindowProc (keyedit_uid_proc.old, dlg, msg, wparam, lparam);
1812     }
1813    
1814    
1815     /* Enable the key @k when @enable is 1, disable it otherwise. */
1816     static void
1817     do_editkey_enable_disable (winpt_key_t k, HWND dlg,
1818     listview_ctrl_t lv, int enable)
1819     {
1820     gpgme_error_t err;
1821     gpgme_key_t key;
1822     GpgKeyEdit ke;
1823    
1824     // FIXME: We had to duplicate the code here since the key manager
1825     // code uses the listview to get the pointer to the key!
1826     key = k->ctx;
1827     ke.setKeyID (key->subkeys->keyid);
1828    
1829     err = enable? ke.enable () : ke.disable ();
1830     if (!err) {
1831     show_msg (dlg, 1500, _("Key status changed."));
1832     k->update = 1;
1833     }
1834     else
1835     msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
1836     }
1837    
1838    
1839     static void
1840     do_editkey_minimize (winpt_key_t k, HWND dlg)
1841     {
1842     gpgme_error_t err;
1843     GpgKeyEdit ke;
1844    
1845     ke.setKeyID (k->keyid);
1846     err = ke.minimizeKey ();
1847     if (err)
1848     msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
1849     else {
1850     msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
1851     k->update = 1;
1852     }
1853     }
1854    
1855    
1856     static void
1857     do_editkey_clean (winpt_key_t k, HWND dlg)
1858     {
1859     gpgme_error_t err;
1860     GpgKeyEdit ke;
1861    
1862     ke.setKeyID (k->keyid);
1863     err = ke.cleanKey ();
1864     if (err)
1865     msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
1866     else {
1867     msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
1868     k->update = 1;
1869     }
1870     }
1871    
1872    
1873     /* Start the dialog to list and display the status of all
1874     signatures for this key. */
1875     static void
1876     do_editkey_check (winpt_key_t k, HWND dlg)
1877     {
1878     if (!k->ctx)
1879     get_pubkey (k->keyid, &k->ctx);
1880     if (!k->uid && k->ctx)
1881     k->uid = k->ctx->uids->uid;
1882     DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYSIG_TREE, dlg,
1883     sigtree_dlg_proc, (LPARAM)k);
1884     }
1885    
1886    
1887     static int
1888     do_editkey_sign_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv, int mode)
1889     {
1890     gpgme_error_t err;
1891     winpt_key_s signer;
1892     GpgKeyEdit ke;
1893     char *pass = NULL;
1894     char *defkey;
1895     char email[64], name[128], valid[32];
1896     int uid_index;
1897     int cancel = 0;
1898    
1899     uid_index = listview_get_curr_pos (lv);
1900     if (uid_index == -1) {
1901     msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1902     return FALSE;
1903     }
1904     listview_get_item_text (lv, uid_index, UID_COL_VALID, valid, DIM (valid)-1);
1905     if (!strcmp (valid, _("Revoked")))
1906     return TRUE;
1907     if (mode == CMD_SIGN) {
1908     cancel = msg_box (dlg, _("Do you really want to make this sig exportable?"),
1909     _("Key Edit"), MB_QUEST_ASK);
1910     if (cancel == IDNO)
1911     return FALSE;
1912     }
1913     listview_get_item_text (lv, uid_index, UID_COL_EMAIL, email, DIM (email)-1);
1914     listview_get_item_text (lv, uid_index, UID_COL_NAME, name, DIM (name)-1);
1915     uid_index = do_find_userid (k->keyid, email, name, NULL);
1916    
1917     defkey = get_gnupg_default_key ();
1918     memset (&signer, 0, sizeof (signer));
1919     if (winpt_get_seckey (defkey, &signer)) {
1920     log_debug ("do_editkey_sign_userid: no default secret key.\r\n");
1921     free_if_alloc (defkey);
1922     return FALSE;
1923     }
1924     if (signer.is_protected) {
1925     pass = request_key_passphrase (signer.ctx, _("Key Edit"), &cancel);
1926     if (cancel)
1927     return FALSE;
1928     }
1929     ke.setKeyID (k->keyid);
1930     if (signer.is_protected)
1931     ke.setPassphrase (pass);
1932     else
1933     ke.setNoPassphrase (true);
1934     ke.setLocalUser (signer.ctx);
1935     err = ke.signUserid (uid_index,
1936     mode == CMD_SIGN? GPG_EDITKEY_SIGN : GPG_EDITKEY_LSIGN,
1937     0, NULL);
1938     if (!err) {
1939     msg_box (dlg, _("Key successfully signed."), _("Key Edit"), MB_OK);
1940     k->update = 1;
1941     }
1942     else
1943     msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
1944    
1945     sfree_if_alloc (pass);
1946     return !err? TRUE : FALSE;
1947     }
1948    
1949    
1950     static int
1951     lookup_cmd (HWND dlg)
1952     {
1953     char buf[64];
1954     int i;
1955    
1956     i = SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_GETCURSEL, 0, 0);
1957     if (i == LB_ERR)
1958     return LB_ERR;
1959     GetDlgItemText (dlg, IDC_KEYEDIT_CMD, buf, DIM (buf)-1);
1960     for (i=0; cmdlist[i].name != NULL; i++) {
1961     if (!strcmp (buf, cmdlist[i].name))
1962     return cmdlist[i].id;
1963     }
1964     return LB_ERR;
1965     }
1966    
1967    
1968    
1969     gpgme_error_t key_get_revokers (winpt_key_t key, int reload,
1970     gpg_desig_rev_t *r_rev);
1971    
1972     /* Check if the key supports designated revokers and if
1973     secret keys exist to generate such a revoke cert. */
1974     static bool
1975     check_desig_rev (winpt_key_t key)
1976     {
1977     gpg_desig_rev_t rev, u;
1978     struct winpt_key_s sk;
1979    
1980     if (!key->ext->gloflags.has_desig_rev)
1981     return false;
1982     key_get_revokers (key, 0, &rev);
1983     for (u = rev; u; u = u->next) {
1984     memset (&sk, 0, sizeof (sk));
1985     if (!winpt_get_seckey (u->fpr+32, &sk))
1986     return true;
1987     }
1988     return false;
1989     }
1990    
1991    
1992     /* Use the gpg --desig-revoker command to create a revocation
1993     cert for a key that lists our key as a designated revoker. */
1994     static void
1995     gen_desig_revoke_cert (winpt_key_t key, HWND dlg)
1996     {
1997     const char *warn;
1998     char *inf, *p;
1999     int id;
2000    
2001     inf = km_key_get_info (key, 0);
2002     warn = _("Your keys is listed as a designated revoker for the key\n\n"
2003     "%s\n\n"
2004     "Are you sure you want to create a revocation certificate\n"
2005     "which allows you to revoke the key listed above?");
2006     p = new char[strlen (inf)+1+strlen (warn)+1];
2007     sprintf (p, warn, inf);
2008     free_if_alloc (inf);
2009    
2010     id = msg_box (dlg, p, _("Key Edit"), MB_YESNO|MB_ICONWARNING);
2011     free_if_alloc (p);
2012     if (id == IDNO)
2013     return;
2014    
2015     key->internal = 1;
2016     DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKE, dlg,
2017     key_revoke_dlg_proc, (LPARAM)key);
2018     }
2019    
2020    
2021     /* Create tooltip control for the listview header. */
2022     static HWND
2023     create_header_tooltip (HWND dlg)
2024     {
2025     TOOLINFO ti;
2026     HWND tt;
2027    
2028     tt = CreateWindow (TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP|TTS_BALLOON ,
2029     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2030     CW_USEDEFAULT,
2031     NULL, (HMENU) NULL, glob_hinst, NULL);
2032     if (!tt)
2033     BUG (NULL);
2034     memset (&ti, 0, sizeof (ti));
2035     ti.cbSize = sizeof (TOOLINFO);
2036     ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
2037     ti.hwnd = dlg;
2038     ti.uId = (UINT) ListView_GetHeader (GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
2039     ti.hinst = 0;
2040     ti.lpszText = (char*)_("Capabilties: C = Certify, S = Sign, E = Encrypt, A = Authenticate");
2041     SendMessage(tt, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
2042     return tt;
2043     }
2044    
2045    
2046     #define TTM_POPUP (WM_USER+34)
2047    
2048     /* Dialog box procedure for the edit key dialog. */
2049     BOOL CALLBACK
2050     keyedit_main_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
2051     {
2052     static winpt_key_t k;
2053     static listview_ctrl_t lvsub = NULL;
2054     static listview_ctrl_t lvuid = NULL;
2055     static HWND tt = NULL;
2056     int cmd;
2057     HWND item;
2058    
2059     switch (msg) {
2060     case WM_INITDIALOG:
2061     k = (winpt_key_t)lparam;
2062     if (!k)
2063     BUG (NULL);
2064     do_init_cmdlist (dlg, k->key_pair);
2065     lvsub = subkey_list_init (dlg, k);
2066     lvuid = userid_list_init (dlg, k);
2067     item = GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST);
2068     keyedit_subkey_proc.opaque = (void*)k;
2069     keyedit_subkey_proc.dlg = dlg;
2070     keyedit_subkey_proc.current = (WNDPROC)subkey_subclass_proc;
2071     keyedit_subkey_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
2072     if (keyedit_subkey_proc.old) {
2073     if (!SetWindowLong (item, GWL_WNDPROC,
2074     (LONG)keyedit_subkey_proc.current)) {
2075     msg_box (dlg, "Could not set subkey window procedure.",
2076     _("Key Edit"), MB_ERR);
2077     BUG (NULL);
2078     }
2079     }
2080     tt = create_header_tooltip (dlg);
2081    
2082     item = GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST);
2083     keyedit_uid_proc.opaque = (void*)k;
2084     keyedit_uid_proc.dlg = dlg;
2085     keyedit_uid_proc.current = (WNDPROC)uid_subclass_proc;
2086     keyedit_uid_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
2087     if (keyedit_uid_proc.old) {
2088     if (!SetWindowLong (item, GWL_WNDPROC,
2089     (LONG)keyedit_uid_proc.current)) {
2090     msg_box (dlg, "Could not set user ID window procedure.",
2091     _("Key Edit"), MB_ERR);
2092     BUG (NULL);
2093     }
2094     }
2095     if (k->ctx->revoked || k->ctx->expired) {
2096     EnableWindow (GetDlgItem (dlg, IDC_KEYEDIT_CMD), FALSE);
2097     EnableWindow (GetDlgItem (dlg, IDOK), FALSE);
2098     }
2099     SetDlgItemText (dlg, IDC_KEYEDIT_CMDINF, _("Command>"));
2100     SetDlgItemText (dlg, IDCANCEL, _("&Close"));
2101     SetDlgItemText (dlg, IDC_KEYEDIT_HELP, _("&Help"));
2102     SetDlgItemText (dlg, IDC_KEYEDIT_REVOKE, _("&Revoke..."));
2103     SetDlgItemText (dlg, IDOK, _("&OK"));
2104     if (!check_desig_rev (k))
2105     ShowWindow (GetDlgItem (dlg, IDC_KEYEDIT_REVOKE), SW_HIDE);
2106     if (k->is_v3)
2107     SetWindowText (dlg, _("Key Edit (PGP 2.6.x mode)"));
2108     else
2109     SetWindowText (dlg, _("Key Edit"));
2110     SetForegroundWindow (dlg);
2111     center_window (dlg, NULL);
2112     return TRUE;
2113    
2114     case WM_DESTROY:
2115     if (lvsub) {
2116     listview_release (lvsub);
2117     lvsub = NULL;
2118     }
2119     if (lvuid) {
2120     listview_release (lvuid);
2121     lvuid = NULL;
2122     }
2123     if (tt != NULL)
2124     DestroyWindow (tt);
2125    
2126     balloon_msg_disable ();
2127     break;
2128    
2129     case WM_NOTIFY:
2130     NMHDR *notify;
2131     notify = (NMHDR *)lparam;
2132     if (!notify || notify->idFrom != IDC_KEYEDIT_UIDLIST)
2133     break;
2134     if (notify->code == NM_DBLCLK)
2135     do_editkey_showpref (k, dlg, lvuid);
2136     else if (notify->code == NM_RCLICK && k->key_pair) {
2137     if (listview_count_items (lvuid, 0) == 1)
2138     break;
2139     HMENU hm = LoadMenu (glob_hinst, MAKEINTRESOURCE (IDR_WINPT_KEYEDIT));
2140     HMENU popup = GetSubMenu (hm, 0);
2141     POINT p;
2142    
2143     set_menu_text (popup, ID_KEYEDIT_UID_PRIM, _("Flag user ID as &primary"));
2144     set_menu_text (popup, ID_KEYEDIT_UID_DEL, _("&Delete user ID"));
2145     set_menu_text (popup, ID_KEYEDIT_UID_REV, _("&Revoke user ID"));
2146     GetCursorPos (&p);
2147     TrackPopupMenu (popup, TPM_RIGHTALIGN, p.x, p.y, 0, dlg, NULL);
2148     DestroyMenu (hm);
2149     DestroyMenu (popup);
2150     }
2151     break;
2152    
2153     case WM_COMMAND:
2154     switch (LOWORD (wparam)) {
2155     case IDOK:
2156     cmd = lookup_cmd (dlg);
2157     if (cmd == LB_ERR) {
2158     msg_box (dlg, _("Please select a command."), _("Key Edit"), MB_INFO);
2159     return FALSE;
2160     }
2161     if (k->is_v3 && is_cmd_openpgp (cmd)) {
2162     msg_box (dlg, _("This command cannot be used with PGP 2 (v3) keys.\n"),
2163     _("Key Edit"), MB_ERR);
2164     return FALSE;
2165     }
2166     switch (cmd) {
2167     case CMD_SHOWPREF: do_editkey_showpref (k, dlg, lvuid); break;
2168     case CMD_DELKEY: do_editkey_delkey (k, dlg, lvsub); break;
2169     case CMD_ADDKEY: keyedit_add_subkey (k, dlg, lvsub); break;
2170     case CMD_EXPIRE: do_editkey_expire (k, dlg, lvsub); break;
2171     case CMD_REVKEY: do_editkey_revoke (k, dlg, lvsub); break;
2172     case CMD_SETPREF:/*do_editkey_setpref (k, dlg, lvuid);*/ break;
2173     case CMD_ADDUID: keyedit_add_userid( k, dlg, lvuid ); break;
2174     case CMD_ADDREVOKER: keyedit_add_revoker( k, dlg ); break;
2175     case CMD_ADDPHOTO: keyedit_add_photo( k, dlg ); break;
2176     case CMD_REVUID: do_editkey_revuid( k, dlg, lvuid ); break;
2177     case CMD_DELUID: do_editkey_deluid( k, dlg, lvuid ); break;
2178     case CMD_PASSWD: keyedit_change_passwd (k, dlg); break;
2179     case CMD_PRIMARY: do_editkey_primary (k, dlg, lvuid); break;
2180     case CMD_ENABLE: do_editkey_enable_disable (k, dlg, lvsub, 1); break;
2181     case CMD_DISABLE: do_editkey_enable_disable (k, dlg, lvsub, 0); break;
2182     case CMD_CHECK: do_editkey_check (k, dlg); break;
2183     case CMD_TRUST: keyedit_change_ownertrust (k, dlg); break;
2184     case CMD_SIGN:
2185     case CMD_LSIGN: do_editkey_sign_userid (k, dlg,
2186     lvuid, cmd);
2187     break;
2188     case CMD_CLEAN: do_editkey_clean (k, dlg); break;
2189     case CMD_MINIMIZE: do_editkey_minimize (k, dlg); break;
2190     }
2191     break;
2192    
2193     case IDCANCEL:
2194     EndDialog (dlg, FALSE);
2195     break;
2196    
2197     case IDC_KEYEDIT_HELP:
2198     do_show_help (dlg);
2199     break;
2200    
2201     case IDC_KEYEDIT_REVOKE:
2202     gen_desig_revoke_cert (k, dlg);
2203     break;
2204    
2205     case ID_KEYEDIT_UID_PRIM:
2206     do_editkey_primary (k, dlg, lvuid);
2207     break;
2208    
2209     case ID_KEYEDIT_UID_DEL:
2210     do_editkey_deluid (k, dlg, lvuid);
2211     break;
2212    
2213     case ID_KEYEDIT_UID_REV:
2214     do_editkey_revuid (k, dlg, lvuid);
2215     break;
2216     }
2217     break;
2218     }
2219     return FALSE;
2220     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26