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

Annotation of /trunk/Src/wptKeyEditDlgs.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26