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

Contents of /trunk/Src/wptKeyEditDlgs.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 121 - (show annotations)
Mon Dec 12 11:19:56 2005 UTC (19 years, 2 months ago) by twoaday
File size: 50075 byte(s)
2005-12-11  Timo Schulz  <ts@g10code.com>
 
        * wptW32API.cpp (get_file_version): New.
        * wptGPGUtil.cpp (create_process): Always hide window.
        * wptClipEditDlg.cpp (clipedit_dlg_proc): Use 'Close'
        instead of 'Exit'.
        * wptKeyManager.cpp (km_http_import): New filename
        generation code.
        (km_send_to_mail_recipient): Cleanups.
        * wptKeyEditDlg.cpp (showpref_dlg_proc): Localize dialog.
        * wptKeyManagerDlg.cpp (update_ui_items): Handle the case
        when multiple keys are selected.
        (popup_multiple): New.
        * WinPT.cpp (WinMain): Check that the PTD.dll and WinPT.exe
        file versions are equal. Rewrote --keymanager code.
         
Removed temporary w32gpgme dirctory, all code is now in Src.
Changed configure files.


1 /* wptKeyEditDlgs.cpp - GPG key edit dialogs
2 * Copyright (C) 2002-2005 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with WinPT; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <windows.h>
26 #include <oleauto.h>
27 #include <commctrl.h>
28 #include <time.h>
29
30 #include "resource.h"
31
32 #include "wptTypes.h"
33 #include "wptW32API.h"
34 #include "wptVersion.h"
35 #include "wptGPG.h"
36 #include "wptCommonCtl.h"
37 #include "wptContext.h"
38 #include "wptDlgs.h"
39 #include "wptNLS.h"
40 #include "wptUTF8.h"
41 #include "wptErrors.h"
42 #include "wptKeylist.h"
43 #include "wptKeyManager.h"
44 #include "wptRegistry.h"
45 #include "wptKeyEdit.h"
46
47 /* All edit key commands. */
48 enum keyedit_commands {
49 CMD_ADDKEY = 0,
50 CMD_ADDUID,
51 CMD_ADDPHOTO,
52 CMD_ADDREVOKER,
53 /*CMD_FPR,*/
54 CMD_DELUID,
55 CMD_DELKEY,
56 CMD_DELPHOTO,
57 /*CMD_DELSIG,*/
58 CMD_EXPIRE,
59 /*CMD_PREF,*/
60 CMD_SHOWPREF,
61 /*CMD_SETPREF,*/
62 /*CMD_UPDPREF,*/
63 CMD_PASSWD,
64 CMD_PRIMARY,
65 CMD_TRUST,
66 /*CMD_REVSIG,*/
67 CMD_REVUID,
68 CMD_REVKEY,
69 CMD_DISABLE,
70 CMD_ENABLE,
71 /*CMD_SHOWPHOTO,*/
72 };
73
74
75 /* Symbolic ids for the subkey columns. */
76 enum subk_col_t {
77 SUBK_COL_DESC = 0,
78 SUBK_COL_KEYID = 1,
79 SUBK_COL_CREATION = 2,
80 SUBK_COL_EXPIRES = 3,
81 SUBK_COL_STATUS = 4,
82 SUBK_COL_C_FLAG = 5,
83 SUBK_COL_S_FLAG = 6,
84 SUBK_COL_E_FLAG = 7,
85 SUBK_COL_A_FLAG = 8
86 };
87
88 /* Symbolic ids for the userid columns. */
89 enum uid_col_t {
90 UID_COL_VALID = 0,
91 UID_COL_NAME = 1,
92 UID_COL_EMAIL = 2,
93 UID_COL_CREATION = 3
94 };
95
96 struct keyedit_callback_s {
97 const char *keyid;
98 const char *pass;
99 listview_ctrl_t lv;
100 void *opaque;
101 unsigned int finished:1;
102 };
103 typedef struct keyedit_callback_s KEYEDIT_CB;
104
105 struct keygen_callback_s {
106 int bits;
107 int algo;
108 u32 expire;
109 char *fpr;
110 };
111 typedef struct keygen_callback_s KEYGEN_CB;
112
113
114 static subclass_s keyedit_subkey_proc;
115 static subclass_s keyedit_uid_proc;
116
117 int keygen_check_date (SYSTEMTIME *st);
118 void get_userid_preflist (char **r_prefs, int * r_flags);
119 char* get_subkey_fingerprint (const char *keyid);
120
121
122 /* Associate each key with a combo box entry.
123 Skip the key in @k. */
124 static void
125 do_init_keylist (HWND dlg, winpt_key_t k)
126 {
127 gpg_keycache_t pub;
128 gpgme_key_t key;
129 const char * s, * kid;
130 char * u;
131 int i, n;
132
133 pub = keycache_get_ctx (1);
134 if (!pub)
135 BUG (0);
136
137 gpg_keycache_rewind (pub);
138 while( !gpg_keycache_next_key( pub, 0, &key ) ) {
139 if (key->expired || key->revoked ||
140 key->disabled || key->invalid)
141 continue;
142
143 s = key->uids->uid;
144 kid = key->subkeys->keyid;
145 if (!s || !strcmp (kid+8, k->keyid+2))
146 continue;
147 u = utf8_to_wincp (s, strlen (s));
148 SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_ADDSTRING,
149 0, (WPARAM)(char *)u);
150 free (u);
151 }
152 gpg_keycache_rewind (pub);
153 n = SendDlgItemMessage( dlg, IDC_ADDREV_KEYLIST, CB_GETCOUNT, 0, 0 );
154 for (i = 0; i < n; i++) {
155 gpg_keycache_next_key (pub, 0, &key);
156 SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETITEMDATA,
157 (WPARAM)(int)i, (LPARAM)key);
158 }
159 SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETCURSEL, 0, 0);
160 }
161
162
163 /* Add a new user-id to the list view @lv. */
164 static void
165 do_add_new_userid (listview_ctrl_t lv,
166 const char * name, const char *email, const char * comment)
167 {
168 char * p;
169 size_t n;
170
171 n = strlen (name) + strlen (email) + 16;
172 if (comment)
173 n += strlen (comment);
174 p = new char[n+1];
175 if (!p)
176 BUG( NULL );
177 if (comment)
178 sprintf (p, "%s (%s)", name, comment);
179 else
180 sprintf (p, "%s", name);
181
182 listview_add_item (lv, "");
183 listview_add_sub_item (lv, 0, 0, _("Ultimate" ));
184 listview_add_sub_item (lv, 0, 1, p);
185 listview_add_sub_item (lv, 0, 2, email && *email? email : "");
186 listview_add_sub_item (lv, 0, 3, get_key_created (time (NULL)));
187 free_if_alloc (p);
188 } /* do_add_new_userid */
189
190
191 static void
192 do_add_new_subkey (listview_ctrl_t lv, KEYGEN_CB *keygen, unsigned int flags)
193 {
194 char info[128], keyid[32];
195 const char * expdate, * s;
196 int n;
197
198 expdate = keygen->expire? get_key_expire_date (keygen->expire) : _("Never");
199 _snprintf (info, sizeof info-1, "%d-bit %s",
200 keygen->bits,
201 get_key_pubalgo ((gpgme_pubkey_algo_t)keygen->algo));
202 _snprintf (keyid, sizeof keyid-1, "0x%s", keygen->fpr+32);
203 n = listview_count_items (lv, 0);
204 listview_add_item_pos (lv, n);
205 listview_add_sub_item (lv, n, 0, info);
206 listview_add_sub_item (lv, n, 1, keyid);
207 listview_add_sub_item (lv, n, 2, get_key_created (time (NULL)));
208 listview_add_sub_item (lv, n, 3, expdate);
209 if (flags & KM_FLAG_REVOKED) s = _("Revoked");
210 else if (flags & KM_FLAG_EXPIRED) s = _("Expired");
211 else s = _("OK");
212 listview_add_sub_item (lv, n, 4, s);
213 } /* do_add_new_subkey */
214
215
216 /* Try to find the GPG edit key index which belongs to the user ID
217 given by @name. If @r_inf != NULL, the info context will be returned.
218 Return value: index of the user ID or -1 on error. */
219 static int
220 do_find_userid (const char *keyid, const char *name, gpg_uid_info_t *r_inf)
221 {
222 GpgKeyEdit *ke;
223 gpgme_error_t err;
224 gpg_uid_info_t inf, ui;
225 int pos = -1;
226
227 ke = new GpgKeyEdit (keyid);
228 if (!ke)
229 BUG (NULL);
230 err = ke->getUseridInfo (&inf);
231 delete ke;
232 if (err) {
233 log_box (_("user ID"), MB_ERR,
234 _("Could not get key information for: \"%s\":\n%s"),
235 name, gpgme_strerror (err));
236 return -1;
237 }
238
239 for (ui = inf; ui; ui = ui->next) {
240 if (!strcmp (ui->email, name)) {
241 pos = ui->index;
242 break;
243 }
244 }
245 if (r_inf)
246 *r_inf = inf;
247 else
248 gpg_uid_info_release (inf);
249 return pos;
250 }
251
252
253 /* Dialog box procedure to add a photo. */
254 BOOL CALLBACK
255 keyedit_addphoto_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
256 {
257 static winpt_key_t k;
258 GpgKeyEdit *ke;
259 gpgme_error_t ec;
260 const char * s;
261 char pwd[128], file[128];
262 int id;
263
264 switch( msg ) {
265 case WM_INITDIALOG:
266 k = (winpt_key_t)lparam;
267 if (!k)
268 BUG (NULL);
269 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 a good size to use."));
270 SetDlgItemText (dlg, IDC_ADDPHOTO_FILEINF, _("Pick an image to use for your photo ID.\nThe image must be a JPEG file."));
271 SetDlgItemText (dlg, IDC_ADDPHOTO_PWDINF, _("Passphrase"));
272 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
273 SetWindowText (dlg, _("Add Photo ID"));
274 SetForegroundWindow (dlg);
275 break;
276
277 case WM_DESTROY:
278 break;
279
280 case WM_SYSCOMMAND:
281 if( LOWORD (wparam) == SC_CLOSE )
282 EndDialog( dlg, TRUE );
283 break;
284
285 case WM_COMMAND:
286 switch( LOWORD( wparam ) ) {
287
288 case IDC_ADDPHOTO_SELFILE:
289 s = get_fileopen_dlg( dlg, _("Select Image File"), _("JPEG Files (*.jpg, *.jpeg)\0*.jpg;*.jpeg\0\0"), NULL );
290 if( s && *s )
291 SetDlgItemText( dlg, IDC_ADDPHOTO_FILE, s );
292 break;
293
294 case IDOK:
295 if( !GetDlgItemText( dlg, IDC_ADDPHOTO_FILE, file, sizeof file-1 ) ){
296 msg_box( dlg, _("Please enter a file name."), _("Add Photo"), MB_ERR );
297 return FALSE;
298 }
299 if( get_file_size( file ) == 0 || get_file_size( file ) > 6144 ) {
300 id = msg_box( dlg, _("The JPEG is really large.\n"
301 "Are you sure you want to use it?"),
302 _("Add Photo"), MB_YESNO|MB_INFO );
303 if( id == IDNO )
304 return TRUE;
305 }
306 if( k->is_protected ) {
307 if( !GetDlgItemText( dlg, IDC_ADDPHOTO_PASS, pwd, sizeof pwd-1 ) ) {
308 msg_box( dlg, _("Please enter a passphrase."), _("Add Photo"), MB_ERR );
309 return FALSE;
310 }
311 }
312 ke = new GpgKeyEdit (k->keyid);
313 if (!ke)
314 BUG (NULL);
315
316 if (k->is_protected)
317 ke->setPassphrase (pwd);
318 ec = ke->addPhotoid (file);
319 delete ke;
320 memset (pwd, 0, sizeof pwd);
321 if (ec) {
322 msg_box (dlg, gpgme_strerror (ec), _("Add Photo"), MB_ERR );
323 return FALSE;
324 }
325 else {
326 k->update = 1;
327 msg_box (dlg, _("Photo successfully added."), _("GnuPG Status"), MB_OK);
328 }
329 EndDialog (dlg, TRUE);
330 break;
331
332 case IDCANCEL:
333 EndDialog (dlg, FALSE);
334 break;
335 }
336 break;
337 }
338 return FALSE;
339 }
340
341
342 /* Dialog box procedure to add a designated revoker. */
343 BOOL CALLBACK
344 keyedit_addrevoker_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
345 {
346 static winpt_key_t k;
347 static gpgme_key_t seckey;
348 GpgKeyEdit *ke;
349 gpgme_error_t err;
350 char uid[128], pwd[128];
351
352
353 switch( msg ) {
354 case WM_INITDIALOG:
355 k = (winpt_key_t)lparam;
356 if( !k )
357 BUG( NULL );
358 if( get_seckey( k->keyid, &seckey ) )
359 BUG( NULL );
360 if (!k->is_protected)
361 EnableWindow (GetDlgItem (dlg, IDC_ADDREV_PASS), FALSE);
362 do_init_keylist (dlg, k);
363 SetDlgItemText (dlg, IDC_ADDREV_INF, _("Appointing a key as designated revoker cannot be undone."));
364 SetDlgItemText (dlg, IDC_ADDREV_KEYINF, _("Public key"));
365 SetDlgItemText (dlg, IDC_ADDREV_PWDINF, _("Passphrase"));
366 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
367 SetWindowText (dlg, _("Add Revoker"));
368 SetForegroundWindow (dlg);
369 break;
370
371 case WM_DESTROY:
372 break;
373
374 case WM_SYSCOMMAND:
375 if( LOWORD (wparam) == SC_CLOSE )
376 EndDialog( dlg, TRUE );
377 break;
378
379 case WM_COMMAND:
380 switch( LOWORD( wparam ) ) {
381 case IDOK:
382 if( !GetDlgItemText( dlg, IDC_ADDREV_KEYLIST, uid, sizeof uid-1 ) ) {
383 msg_box( dlg, _("Please select a user ID."), _("Add Revoker"), MB_ERR );
384 return FALSE;
385 }
386
387 if( k->is_protected ) {
388 if( !GetDlgItemText( dlg, IDC_ADDREV_PASS, pwd, sizeof pwd-1 ) ) {
389 msg_box( dlg, _("Please enter the passphrase."), _("Add Revoker"), MB_ERR );
390 return FALSE;
391 }
392 }
393 ke = new GpgKeyEdit (k->keyid);
394 if (k->is_protected)
395 ke->setPassphrase (pwd);
396 err = ke->addDesignatedRevoker (uid);
397 delete ke;
398 memset (pwd, 0, sizeof pwd);
399 if (err) {
400 msg_box (dlg, gpgme_strerror (err), _("Add Revoker"), MB_ERR);
401 return TRUE;
402 }
403 else {
404 k->update = 1;
405 msg_box (dlg, _("Revoker successfully addded."), _("GnuPG Status"), MB_OK);
406 }
407 EndDialog( dlg, TRUE );
408 break;
409
410 case IDCANCEL:
411 EndDialog( dlg, FALSE );
412 break;
413 }
414 break;
415 }
416 return FALSE;
417 }
418
419
420 /* Dialog box procedure to add a new user-ID. */
421 BOOL CALLBACK
422 keyedit_adduid_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
423 {
424 static KEYEDIT_CB *ctx;
425 gpgme_error_t err;
426 GpgKeyEdit *ke;
427 char *utf8_name = NULL;
428 char name[128], email[128], comment[128];
429 int rc;
430
431 switch ( msg ) {
432 case WM_INITDIALOG:
433 ctx = (KEYEDIT_CB *)lparam;
434 if( !ctx )
435 dlg_fatal_error(dlg, "Could not get dialog param!");
436
437 SetWindowText (dlg, _("Add new User ID"));
438 SetDlgItemText (dlg, IDC_ADDUID_INFNAME, _("&Name"));
439 SetDlgItemText (dlg, IDC_ADDUID_INFEMAIL, _("&Email"));
440 SetDlgItemText (dlg, IDC_ADDUID_INFCOMMENT, _("&Comment"));
441 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
442 SetForegroundWindow (dlg);
443 return FALSE;
444
445 case WM_SYSCOMMAND:
446 if (LOWORD (wparam) == SC_CLOSE) {
447 EndDialog(dlg, TRUE);
448 }
449 return FALSE;
450
451 case WM_COMMAND:
452 switch ( LOWORD( wparam ) ) {
453 case IDOK:
454 rc = GetDlgItemText( dlg, IDC_ADDUID_NAME, name, sizeof name-1 );
455 if (!rc || rc < 5) {
456 msg_box( dlg, _("Please enter a name (min. 5 chars.)"), _("UserID"), MB_ERR );
457 return FALSE;
458 }
459 if (strchr (name, '@')) {
460 msg_box( dlg, _("Please enter the email address in the email field and not in the name field"), _("UserID"), MB_INFO );
461 return FALSE;
462 }
463
464 if( !GetDlgItemText( dlg, IDC_ADDUID_EMAIL, email, sizeof email -1 ) ) {
465 msg_box( dlg, _("Please enter an email address."), _("UserID"), MB_ERR );
466 return FALSE;
467 }
468 if( !strchr( email, '@' ) || strchr (email, ' ')) {
469 msg_box( dlg, _("Invalid email address."), _("UserID"), MB_ERR );
470 return FALSE;
471 }
472
473 rc = GetDlgItemText( dlg, IDC_ADDUID_COMMENT, comment, sizeof comment -1 );
474
475 /* XXX: something is wrong with the encoding :-( */
476 utf8_name = wincp_to_utf8 (name, strlen (name));
477
478 ke = new GpgKeyEdit (ctx->keyid);
479 if (!ke)
480 BUG (NULL);
481 if (ctx->pass)
482 ke->setPassphrase (ctx->pass);
483 err = ke->addUserid (utf8_name? utf8_name : name,
484 rc > 0? comment : NULL, email);
485 if (err)
486 msg_box (dlg, gpgme_strerror (err), _("UserID"), MB_ERR);
487 else {
488 msg_box (dlg, _("user ID successfully added."), _("GnuPG Status"), MB_OK);
489 ctx->finished = 1;
490 }
491 delete ke;
492 free (utf8_name);
493 if (!err && ctx->lv)
494 do_add_new_userid (ctx->lv, name, email, rc?comment : NULL);
495 EndDialog (dlg, TRUE);
496 return TRUE;
497
498 case IDCANCEL:
499 EndDialog (dlg, FALSE);
500 return FALSE;
501 }
502 break;
503 }
504
505 return FALSE;
506 }
507
508
509 static int
510 diff_time (HWND dt, SYSTEMTIME *in_exp)
511 {
512 SYSTEMTIME exp, now;
513 double e=0, n=0;
514
515 if (in_exp)
516 memcpy (&exp, in_exp, sizeof (SYSTEMTIME));
517 else
518 DateTime_GetSystemtime (dt, &exp);
519 GetSystemTime (&now);
520 SystemTimeToVariantTime (&exp, &e);
521 SystemTimeToVariantTime (&now, &n);
522 if (n > e)
523 return 0;
524 return (int)(e-n);
525 }
526
527
528 static void
529 init_keysize_box (HWND dlg, int ctlid)
530 {
531 const char *sizelist[] = {
532 "1024", "1536", "2048", "2560", "3072", "3854", "4096", NULL
533 };
534 int i;
535 for (i=0; sizelist[i] != NULL; i++)
536 SendDlgItemMessage (dlg, ctlid, CB_ADDSTRING, 0, (LPARAM)(char*)sizelist[i]);
537 SendDlgItemMessage (dlg, ctlid, CB_SETCURSEL, (WPARAM)2, 0);
538 }
539
540 static int
541 get_keysize_from_box (HWND dlg, int ctlid)
542 {
543 int pos;
544 char buf[32];
545
546 pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0);
547 if (pos == CB_ERR)
548 return -1;
549 SendDlgItemMessage (dlg, ctlid, CB_GETLBTEXT, pos, (LPARAM)(char*)buf);
550 return atol (buf);
551 }
552
553
554 BOOL CALLBACK
555 keyedit_addsubkey_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
556 {
557 static KEYEDIT_CB *ctx;
558 static KEYGEN_CB *keygen;
559 GpgKeyEdit *ke;
560 gpgme_error_t err;
561 HWND lb;
562 int index, size, valid;
563
564 switch (msg) {
565 case WM_INITDIALOG:
566 ctx = (KEYEDIT_CB *)lparam;
567 if (!ctx)
568 dlg_fatal_error (dlg, "Could not get dialog param!");
569 keygen = (KEYGEN_CB *)ctx->opaque;
570
571 SetWindowText (dlg, _("Add new Subkey"));
572 SetDlgItemText (dlg, IDC_ADDSUBKEY_INFALGO, _("Key type"));
573 SetDlgItemText (dlg, IDC_ADDSUBKEY_INFSIZE, _("Size in bits"));
574 SetDlgItemText (dlg, IDC_ADDSUBKEY_INFVALID, _("Key expiration"));
575 SetDlgItemText (dlg, IDC_ADDSUBKEY_EXPIRE, _("&Never"));
576 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
577
578 lb = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
579 listbox_add_string (lb, "DSA (sign only)");
580 listbox_add_string (lb, "ElGamal (encrypt only)");
581 listbox_add_string (lb, "RSA (sign only)");
582 listbox_add_string (lb, "RSA (encrypt only)");
583 CheckDlgButton (dlg, IDC_ADDSUBKEY_EXPIRE, BST_CHECKED);
584 EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
585 init_keysize_box (dlg, IDC_ADDSUBKEY_SIZE);
586 SetForegroundWindow (dlg);
587 return FALSE;
588
589 case WM_SYSCOMMAND:
590 if( LOWORD (wparam) == SC_CLOSE ) {
591 EndDialog( dlg, TRUE );
592 }
593 return FALSE;
594
595 case WM_COMMAND:
596 if (HIWORD (wparam) == BN_CLICKED && LOWORD (wparam) == IDC_ADDSUBKEY_EXPIRE) {
597 if (IsDlgButtonChecked (dlg, IDC_ADDSUBKEY_EXPIRE))
598 EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
599 else
600 EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), TRUE);
601 }
602 if (HIWORD (wparam) == LBN_SELCHANGE && LOWORD (wparam) == IDC_ADDSUBKEY_ALGO) {
603 index = SendMessage ((HWND)lparam, LB_GETCURSEL, 0, 0);
604 if (index == 0)
605 SendDlgItemMessage (dlg, IDC_ADDSUBKEY_SIZE, CB_SETCURSEL, 0, 0);
606 }
607
608 switch ( LOWORD(wparam) ) {
609 case IDOK:
610 lb = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
611 switch (listbox_get_cursel (lb)) {
612 case 0: index = 2; break;
613 case 1: index = 4; break;
614 case 2: index = 5; break;
615 case 3: index = 6; break;
616 default:
617 msg_box( dlg, _("Please select one entry."), _("Add Subkey"), MB_ERR );
618 return FALSE;
619 }
620 size = get_keysize_from_box (dlg, IDC_ADDSUBKEY_SIZE);
621 if (index == 2 && size != 1024) {
622 msg_box( dlg,_("DSS uses a fixed keysize of 1024. Size changed."), _("Add Subkey"), MB_INFO );
623 size = 1024;
624 }
625 valid = diff_time (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), NULL);
626
627 keygen->bits = size;
628 switch (index) {
629 case 2: keygen->algo = GPGME_PK_DSA; break;
630 case 4: keygen->algo = GPGME_PK_ELG_E; break;
631 case 5: keygen->algo = GPGME_PK_RSA_S; break;
632 case 6: keygen->algo = GPGME_PK_RSA_E; break;
633 }
634 if (valid > 0)
635 keygen->expire = time (NULL) + valid*24*60*60;
636
637 ke = new GpgKeyEdit (ctx->keyid);
638 if (!ke)
639 BUG (NULL);
640 ke->setCallback (keygen_cb, NULL);
641 if (ctx->pass)
642 ke->setPassphrase (ctx->pass);
643 keygen_cb_dlg_create ();
644
645 err = ke->addSubkey ((gpgme_pubkey_algo_t)index, size, valid);
646 keygen->fpr = get_subkey_fingerprint (ctx->keyid);
647 keygen_cb_dlg_destroy ();
648 keygen_cb (NULL, NULL, 0, 0, 0); /* flush */
649 if (err)
650 msg_box (dlg, gpgme_strerror (err), _("Add Subkey"), MB_ERR);
651 else {
652 msg_box (dlg, _("Subkey successfully added."), _("GnuPG Status"), MB_OK);
653 if (ctx->lv)
654 do_add_new_subkey (ctx->lv, keygen, /*XXXk->flags*/0);
655 ctx->finished = 1;
656 }
657 delete ke;
658 EndDialog (dlg, TRUE);
659 return TRUE;
660
661 case IDCANCEL:
662 EndDialog( dlg, FALSE );
663 return FALSE;
664 }
665 break;
666 }
667
668 return FALSE;
669 } /* keyedit_addsubkey_dlg_proc */
670
671
672 BOOL
673 keyedit_add_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
674 {
675 KEYEDIT_CB cb;
676 char *pass = NULL;
677 int cancel = 0;
678
679 if (!k->key_pair) {
680 msg_box( dlg, _("There is no secret key available!"), _("Add user ID"), MB_ERR );
681 return FALSE;
682 }
683
684 if (k->is_protected) {
685 pass = request_passphrase( _("Key Edit"), 1, &cancel );
686 if (cancel)
687 return FALSE;
688 }
689
690 memset (&cb, 0, sizeof cb);
691 cb.pass = k->is_protected? pass : NULL;
692 cb.lv = lv;
693 cb.keyid = k->keyid;
694 dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDUID,
695 dlg, keyedit_adduid_dlg_proc,
696 (LPARAM)&cb, _("Add user ID"),
697 IDS_WINPT_KEYEDIT_ADDUID);
698
699 if (cb.finished)
700 k->update = 1;
701
702 sfree_if_alloc (pass);
703 return TRUE;
704 }
705
706
707 char*
708 get_subkey_fingerprint (const char *keyid)
709 {
710 gpgme_error_t err;
711 gpgme_key_t key, main;
712 gpgme_ctx_t ctx;
713 gpgme_subkey_t last_sk, k, new_sk;
714 int n;
715
716 err = gpgme_new (&ctx);
717 if (err)
718 return NULL;
719 err = gpgme_get_key (ctx, keyid, &key, 0);
720 if (err)
721 return NULL;
722 /* XXX: this is very slow and complicated */
723
724 n = count_subkeys (key);
725 last_sk = get_nth_key (key, n-1);
726 new_sk = (gpgme_subkey_t)calloc (1, sizeof *new_sk);
727 if (!new_sk)
728 BUG (NULL);
729 memcpy (new_sk, last_sk, sizeof *last_sk);
730 new_sk->fpr = strdup (last_sk->fpr);
731 new_sk->keyid = strdup (last_sk->keyid);
732
733 get_pubkey (keyid, &main);
734 for (k=main->subkeys; k->next; k=k->next)
735 ;
736 k->next = new_sk;
737
738 gpgme_key_release (key);
739 return new_sk->fpr;
740 }
741
742
743 BOOL
744 keyedit_add_subkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
745 {
746 KEYEDIT_CB cb;
747 KEYGEN_CB keygen;
748 char *pass = NULL;
749 int cancel = 0;
750
751 if (!k->key_pair) {
752 msg_box (dlg, _("There is no secret key available!"), _("Add Subkey"), MB_ERR);
753 return FALSE;
754 }
755 if (k->is_protected) {
756 pass = request_passphrase (_("Key Edit"), 1, &cancel);
757 if (cancel)
758 return FALSE;
759 }
760
761 memset (&keygen, 0, sizeof (keygen));
762 memset (&cb, 0, sizeof (cb));
763 cb.keyid = k->keyid;
764 cb.pass = k->is_protected? pass : NULL;
765 cb.opaque = &keygen;
766 dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDSUBKEY,
767 dlg, keyedit_addsubkey_dlg_proc,
768 (LPARAM)&cb, _("Add new Subkey"),
769 IDS_WINPT_KEYEDIT_ADDSUBKEY);
770 if (cb.finished)
771 k->update = 1;
772
773 sfree_if_alloc (pass);
774 return cb.finished? TRUE: FALSE;
775 }
776
777
778 BOOL
779 keyedit_set_pref_keyserver (winpt_key_t k, HWND dlg)
780 {
781 GpgKeyEdit *ke;
782 gpgme_error_t err;
783 struct URL_ctx_s *url;
784 char *pass;
785
786 url = (struct URL_ctx_s *)get_keyserver_URL_dlg (dlg);
787 if (url->cancel == 1) {
788 delete url;
789 return FALSE;
790 }
791
792 pass = request_passphrase (_("Key Edit"), 1, &url->cancel);
793 if (url->cancel) {
794 delete url;
795 return FALSE;
796 }
797
798 ke = new GpgKeyEdit (k->keyid);
799 if (!ke)
800 BUG (NULL);
801 ke->setPassphrase (pass);
802 err = ke->setPreferredKeyserver (0 /* XXX */, url->url);
803 if (!err)
804 msg_box (dlg, _("Preferred keyserver successfully set."), _("Key Edit"), MB_OK);
805
806 sfree_if_alloc (pass);
807 delete ke;
808 delete url;
809 return err == 0? 0 : WPTERR_GENERAL;
810 }
811
812
813 /* Add a photo-ID to the key specified in @k. @dlg is the handle of
814 the calling dialog. */
815 BOOL
816 keyedit_add_photo (winpt_key_t k, HWND dlg)
817 {
818 if (!k->key_pair) {
819 msg_box (dlg, _("There is no secret key available!"), _("Add Photo"), MB_ERR);
820 return FALSE;
821 }
822 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDPHOTO, dlg,
823 keyedit_addphoto_dlg_proc, (LPARAM)k);
824 return TRUE;
825 }
826
827
828 BOOL
829 keyedit_add_revoker (winpt_key_t k, HWND dlg)
830 {
831 if( !k->key_pair ) {
832 msg_box( dlg, _("There is no secret key available!"), _("Add Revoker"), MB_ERR );
833 return FALSE;
834 }
835 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDREV, dlg,
836 keyedit_addrevoker_dlg_proc, (LPARAM)k);
837 return TRUE;
838 } /* keyedit_add_revoker */
839
840
841 static int
842 is_idea_protect_algo (const char * keyid)
843 {
844 winpt_key_s k;
845 const unsigned char *sym_prefs;
846 size_t n;
847
848 memset (&k, 0, sizeof (k));
849 if (winpt_get_pubkey (keyid, &k))
850 BUG (NULL);
851 sym_prefs = k.ext->sym_prefs;
852 if (!sym_prefs)
853 return 1; /* assume that only v3 keys have no symmetric cipher preferences
854 and thus IDEA is explicit. */
855 for (n = 0; sym_prefs[n]; n++)
856 ;
857 if ((n == 0 || n == 1) && *sym_prefs == 0x01)
858 return 1;
859 return 0;
860 } /* is_idea_protect_algo */
861
862
863 BOOL
864 keyedit_change_passwd( winpt_key_t k, HWND dlg )
865 {
866 GpgKeyEdit *ke;
867 gpgme_error_t ec;
868 char *old_pass = NULL, *new_pass = NULL;
869 int cancel = 0;
870
871 if( !k->key_pair ) {
872 msg_box( dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR );
873 return FALSE;
874 }
875
876 if( !idea_available && is_idea_protect_algo( k->keyid ) ) {
877 msg_box( dlg, _("Cannot change passphrase because the key\n"
878 "is protected with the IDEA encryption algorithm."),
879 _("Key Edit"), MB_ERR );
880 return FALSE;
881 }
882
883 if( k->is_protected ) {
884 old_pass = request_passphrase( _("Current (old) Passphrase"), 1, &cancel );
885 if( cancel )
886 return FALSE;
887 }
888 new_pass = request_passphrase( _("New Passphrase" ), 1, &cancel );
889 if( cancel ) {
890 free_if_alloc( old_pass );
891 return FALSE;
892 }
893
894 if( is_8bit_string( new_pass ) ) {
895 msg_box( dlg, _("The passphrase contains 8-bit characters.\n"
896 "It is not suggested to use charset specific characters."),
897 _("Key Edit"), MB_ERR );
898 free_if_alloc( old_pass );
899 free_if_alloc( new_pass );
900 return FALSE;
901 }
902
903 ke = new GpgKeyEdit (k->keyid);
904 if (!ke)
905 BUG (NULL);
906
907 ke->setPassphrase (k->is_protected? old_pass : NULL);
908 ec = ke->changePassphrase (new_pass, 0);
909 if( ec )
910 msg_box (dlg, gpgme_strerror (ec), _("Change Passwd"), MB_ERR);
911 else
912 msg_box (dlg, _("Passphrase successfully changed."), _("GnuPG status"), MB_OK);
913 sfree_if_alloc (old_pass);
914 sfree_if_alloc (new_pass);
915 delete ke;
916 return TRUE;
917 }
918
919
920 listview_ctrl_t
921 subkey_list_init( HWND dlg, winpt_key_t k )
922 {
923 LV_ITEM lvi;
924 gpgme_key_t key;
925 gpgme_subkey_t sub;
926 struct listview_column_s cols[] = {
927 {0, 80, (char *)_("Description")},
928 {1, 78, (char *)_("Key ID")},
929 {2, 66, (char *)_("Creation")},
930 {3, 66, (char *)_("Expires")},
931 {4, 64, (char *)_("Status")},
932 {5, 16, "C"/*ertify*/},
933 {6, 16, "S"/*ign*/},
934 {7, 16, "E"/*ncrypt*/},
935 {8, 16, "A"/*uth*/},
936 {0, 0, 0}
937 };
938 listview_ctrl_t lv;
939 char buf[256], tmp[128];
940 const char *t;
941 int nkeys = 0, rc = 0, i, bits;
942
943 if( get_pubkey( k->keyid, &key ) ) {
944 msg_box( dlg, _("Could not find key."), _("Key Edit"), MB_ERR );
945 return NULL;
946 }
947 nkeys = count_subkeys (key);
948 if( !nkeys ) {
949 msg_box( dlg, _("No subkey(s) found."), _("Key Edit"), MB_ERR );
950 return NULL;
951 }
952
953 rc = listview_new( &lv );
954 if( rc )
955 BUG( dlg );
956
957 lv->ctrl = GetDlgItem( dlg, IDC_KEYEDIT_KEYLIST );
958 for( i = 0; cols[i].fieldname != NULL; i++ )
959 listview_add_column( lv, &cols[i] );
960
961 for( i = 0; i < nkeys; i++ ) {
962 listview_add_item( lv, "" );
963 listview_add_sub_item( lv, 0, 1, "" );
964 memset( &lvi, 0, sizeof lvi );
965 lvi.mask = LVIF_PARAM;
966 lvi.lParam = (LPARAM )key;
967 if( ListView_SetItem( lv->ctrl, &lvi ) == FALSE )
968 return NULL;
969 }
970
971 listview_set_ext_style( lv );
972 for( i = 0, sub = key->subkeys; i < nkeys; i++, sub = sub->next ) {
973 memset( buf, 0, sizeof buf );
974
975 bits = sub->length;
976 _snprintf( tmp, sizeof tmp-1, "%d-bit ", bits );
977 strcat( buf, tmp );
978
979 _snprintf( tmp, sizeof tmp-1, "%s", get_key_pubalgo (sub->pubkey_algo));
980 strcat( buf, tmp );
981
982 listview_add_sub_item( lv, i, 0, buf );
983 t = sub->keyid;
984 if( !t )
985 t = "DEADBEEFDEADBEEF";
986 _snprintf( tmp, sizeof tmp-1, "0x%s", t+8 );
987 listview_add_sub_item( lv, i, 1, tmp );
988
989 t = get_key_created (sub->timestamp);
990 if( !t )
991 t = "????" "-??" "-??";
992 listview_add_sub_item( lv, i, 2, t );
993
994 if( sub->expires ) {
995 t = get_key_created (sub->expires);
996 listview_add_sub_item( lv, i, 3, t );
997 }
998 else
999 listview_add_sub_item( lv, i, 3, _("Never") );
1000
1001 if( sub->expired )
1002 t = _("Expired");
1003 else if( sub->revoked )
1004 t = _("Revoked");
1005 else
1006 t = _("OK");
1007 listview_add_sub_item( lv, i, 4, t );
1008
1009 if (sub->can_certify) t = "*"; else t = "";
1010 listview_add_sub_item (lv, i, 5, t);
1011 if (sub->can_sign) t = "*"; else t = "";
1012 listview_add_sub_item( lv, i, 6, t );
1013 if (sub->can_encrypt) t = "*"; else t = "";
1014 listview_add_sub_item( lv, i, 7, t );
1015 if (sub->can_authenticate) t = "*"; else t = "";
1016 listview_add_sub_item (lv, i, 8, t);
1017 }
1018 return lv;
1019 } /* subkey_list_init */
1020
1021
1022 static listview_ctrl_t
1023 userid_list_init (HWND dlg, winpt_key_t k)
1024 {
1025 listview_ctrl_t lv = NULL;
1026 gpgme_key_t key;
1027 gpgme_key_sig_t ks;
1028 gpgme_user_id_t u;
1029 int nuids = 0, rc, j, u_attr;
1030 struct listview_column_s cols[] = {
1031 {0, 72, (char *)_("Validity")},
1032 {1, 150, (char *)_("Name")},
1033 {2, 110, (char *)_("Email")},
1034 {3, 76, (char *)_("Creation")},
1035 {0, 0, 0}
1036 };
1037 const char *attr;
1038
1039 if (get_pubkey( k->keyid, &key)) {
1040 msg_box( dlg, _("Could not find key."), _("Key Edit"), MB_ERR );
1041 return NULL;
1042 }
1043
1044 nuids = count_userids (key);
1045 if (!nuids) {
1046 msg_box (dlg, _("No user ID(s) found."), _("Key Edit"), MB_ERR);
1047 return NULL;
1048 }
1049
1050 rc = listview_new (&lv);
1051 if( rc )
1052 BUG( dlg );
1053 lv->ctrl = GetDlgItem( dlg, IDC_KEYEDIT_UIDLIST );
1054 for( j = 0; cols[j].fieldname != NULL; j++ )
1055 listview_add_column( lv, &cols[j] );
1056
1057 for( j = 0; j < nuids; j++ ) {
1058 listview_add_item( lv, " " );
1059 listview_add_sub_item( lv, 0, 1, " " );
1060 }
1061
1062 listview_set_ext_style (lv);
1063 for (j = 0, u=key->uids; j < nuids; u=u->next, j++) {
1064 if (u->revoked)
1065 attr = _("Revoked");
1066 else {
1067 u_attr = (int)u->validity;
1068 attr = get_key_trust2 (NULL, u_attr, 0, 0);
1069 }
1070 listview_add_sub_item( lv, j, 0, (char *)attr );
1071
1072 /* XXX: add comment if available */
1073 attr = u->name;
1074 if (attr) {
1075 char * uid = utf8_to_wincp (attr, strlen (attr));
1076 if (uid) {
1077 listview_add_sub_item( lv, j, 1, uid );
1078 free( uid );
1079 }
1080 }
1081 else
1082 listview_add_sub_item( lv, j, 1, _("Invalid user ID") );
1083 attr = u->email;
1084 if (attr)
1085 listview_add_sub_item (lv, j, 2, attr);
1086
1087 ks = get_selfsig (u, k->keyid+2, 1);
1088 if (ks)
1089 listview_add_sub_item (lv, j, 3, get_key_created (ks->timestamp));
1090 }
1091 if( !k->key_pair ) {
1092 CheckDlgButton( dlg, IDC_KEYUID_ADD, BST_INDETERMINATE );
1093 CheckDlgButton( dlg, IDC_KEYUID_REVOKE, BST_INDETERMINATE );
1094 }
1095 return lv;
1096 } /* userid_list_init */
1097
1098
1099 static void
1100 do_init_cmdlist( HWND dlg )
1101 {
1102 const char *cmdlist[] = {
1103 "ADDKEY",
1104 "ADDUID",
1105 "ADDPHOTO",
1106 "ADDREVOKER",
1107 /*"FPR",*/
1108 "DELUID",
1109 "DELKEY",
1110 "DELPHOTO",
1111 /*"DELSIG",*/
1112 "EXPIRE",
1113 /*"PREF",*/
1114 "SHOWPREF",
1115 /*"SETPREF",*/
1116 "PASSWD",
1117 "PRIMARY",
1118 "TRUST",
1119 /*"REVSIG",*/
1120 "REVUID",
1121 "REVKEY",
1122 "DISABLE",
1123 "ENABLE",
1124 "SHOWPHOTO",
1125 NULL
1126 };
1127 const char * s;
1128 int i = 0;
1129
1130 for( i = 0; (s=cmdlist[i]); i++ ) {
1131 SendDlgItemMessage( dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1132 (LPARAM)(char *)s );
1133 }
1134 SendDlgItemMessage( dlg, IDC_KEYEDIT_CMD, CB_SETCURSEL, 0, 0 );
1135 } /* do_init_cmdlist */
1136
1137
1138 static int
1139 is_cmd_openpgp( int cmdid )
1140 {
1141 switch( cmdid ) {
1142 case CMD_ADDKEY:
1143 case CMD_ADDPHOTO:
1144 case CMD_ADDREVOKER:
1145 case CMD_DELPHOTO:
1146 /*case CMD_SHOWPHOTO:*/
1147 /*case CMD_SETPREF:*/
1148 return 1;
1149 }
1150 return 0;
1151 } /* is_cmd_openpgp */
1152
1153
1154 static void
1155 do_show_help( HWND dlg )
1156 {
1157 char helptext[2048];
1158
1159 _snprintf( helptext, sizeof helptext-1,
1160 _(/*"FPR \t\tshow fingerprint\r\n"*/
1161 "ADDUID \t\tadd a user ID\r\n"
1162 "ADDPHOTO \t\tadd a photo ID\r\n"
1163 "DELUID \t\tdelete a user ID\r\n"
1164 "ADDKEY \t\tadd a secondard key\r\n"
1165 "DELKEY \t\tdelete a secondary key\r\n"
1166 "ADDREVOKER\t\tadd a revocation key\r\n"
1167 /*"DELSIG \t\tdelete signatures\r\n"*/
1168 "EXPIRE \t\tchange the expire date\r\n"
1169 /*"PREF \t\tlist preferences (expert)\r\n"
1170 "SHOWPREF \t\tlist preferences (verbose)\r\n"
1171 "SETPREF \t\tset preference list\r\n"*/
1172 "UPDPREF \t\tupdated preferences\r\n"
1173 "PASSWD \t\tchange the passphrase\r\n"
1174 "PRIMARY \t\tflag user ID as primary\r\n"
1175 "TRUST \t\tchange the ownertrust\r\n"
1176 /*"REVSIG \t\trevoke signatures\r\n"*/
1177 "REVUID \t\trevoke a user ID\r\n"
1178 "REVKEY \t\trevoke a secondary key\r\n"
1179 "DISABLE \t\tdisable a key\r\n"
1180 "ENABLE \t\tenable a key\r\n"
1181 /*"SHOWPHOTO \t\tshow photo ID\r\n"*/) );
1182 msg_box( dlg, helptext, _("Key Edit Help"), MB_OK );
1183 } /* do_show_help */
1184
1185
1186 static int
1187 do_editkey_delkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1188 {
1189 gpgme_error_t err;
1190 GpgKeyEdit *ke;
1191 int j, id;
1192 char tmp[64];
1193
1194 if (!k->key_pair)
1195 return FALSE; /* XXX: shall we allow to modify non-secret keys?? */
1196
1197 if( listview_count_items( lv, 0 ) == 1 ) {
1198 msg_box( dlg, _("Primary key can not be deleted!"), _("Key Edit"), MB_ERR);
1199 return FALSE;
1200 }
1201 if( (j = listview_get_curr_pos( lv )) == -1 ) {
1202 msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1203 return FALSE;
1204 }
1205 if( j == 0 ) {
1206 msg_box( dlg, _("Primary subkey can not be deleted!"), _("Key Edit"), MB_ERR );
1207 return FALSE;
1208 }
1209
1210 listview_get_item_text( lv, j, 0, tmp, sizeof tmp -1 );
1211 id = log_box( _("Key Edit"), MB_YESNO|MB_ICONWARNING,
1212 _("\"Subkey %s.\"\n\n"
1213 "Anything encrypted to the selected subkey will no longer\n"
1214 "be able to be decrypted.\n\n"
1215 "Do you really want to delete this subkey?"), tmp );
1216 if( id == IDNO )
1217 return FALSE;
1218
1219 ke = new GpgKeyEdit (k->keyid);
1220 if (!ke)
1221 BUG (NULL);
1222 err = ke->delKey (j);
1223 if (err)
1224 msg_box (dlg, gpgme_strerror (err), _("Delete Subkey"), MB_ERR);
1225 else {
1226 listview_del_item (lv, j);
1227 k->update = 1;
1228 status_box (dlg, _("Subkey successfully deleted."), _("GnuPG status"));
1229 }
1230 delete ke;
1231 return err? FALSE : TRUE;
1232 } /* do_editkey_delkey */
1233
1234
1235 /* Set the expiration date for the selected key in list view @lv.
1236 Return value: TRUE on success. */
1237 static int
1238 do_editkey_expire (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1239 {
1240 gpgme_error_t err;
1241 GpgKeyEdit *ke;
1242 date_s udd = {0};
1243 char buf[256], * pass = NULL;
1244 int j, cancel = 0;
1245
1246 if (!k->key_pair) {
1247 msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1248 return FALSE;
1249 }
1250 if ((j = listview_get_curr_pos (lv)) == -1) {
1251 msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1252 return FALSE;
1253 }
1254
1255 /* If a key already expired, it is possible the user wants to
1256 set a new expiration date.. */
1257 listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, sizeof buf -1);
1258 if (!strcmp (buf, _("Expired"))) {
1259 cancel = msg_box (dlg, _("Key already expired.\n\n"
1260 "Do you want to change the expiration date?"),
1261 _("Key Edit"), MB_QUEST_ASK);
1262 if (cancel == IDNO)
1263 return FALSE;
1264 cancel = 0;
1265 }
1266
1267 memset (&udd, 0, sizeof udd);
1268 udd.text = _("Key Expiration Date");
1269 dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_DATE, dlg,
1270 date_dlg_proc, (LPARAM)&udd,
1271 _("Key Expiration Date"), IDS_WINPT_DATE);
1272 if (udd.cancel == 1)
1273 return FALSE;
1274 if (!keygen_check_date (&udd.st)) {
1275 msg_box (dlg, _("The date you have chosen lies in the past."),
1276 _("Key Edit"), MB_ERR);
1277 return FALSE;
1278 }
1279 if( k->is_protected ) {
1280 pass = request_passphrase (_("Key Edit"), 1, &cancel);
1281 if (cancel)
1282 return FALSE;
1283 }
1284
1285 ke = new GpgKeyEdit (k->keyid);
1286 if (!ke)
1287 BUG (NULL);
1288 if (k->is_protected)
1289 ke->setPassphrase (pass);
1290 err = ke->setKeyExpireDate (j, diff_time (NULL, &udd.st), true);
1291 if (err)
1292 msg_box (dlg, gpgme_strerror (err), _("Expire Subkey"), MB_ERR);
1293 else {
1294 _snprintf (buf, sizeof buf - 1, "%04d-%02d-%02d",
1295 udd.st.wYear, udd.st.wMonth, udd.st.wDay);
1296 listview_add_sub_item (lv, j, SUBK_COL_EXPIRES, buf);
1297 k->update = 1;
1298 msg_box (dlg, _("Subkey expire date successfully set."),
1299 _("GnuPG status"), MB_OK);
1300 }
1301 sfree_if_alloc (pass);
1302 delete ke;
1303 return TRUE;
1304 }
1305
1306
1307 /* Revoke the selected key in the list view @lv. @k contains
1308 control information about the global key.
1309 Return value: TRUE on success. */
1310 static int
1311 do_editkey_revoke (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1312 {
1313 gpgme_error_t err;
1314 GpgKeyEdit *ke;
1315 char buf[256];
1316 char *pass = NULL;
1317 int j, cancel = 0;
1318
1319 if (!k->key_pair) {
1320 msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1321 return FALSE;
1322 }
1323
1324 if ((j = listview_get_curr_pos (lv)) == -1) {
1325 msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1326 return FALSE;
1327 }
1328 else if (listview_count_items (lv, 0) == 1) {
1329 msg_box( dlg, _("No subkeys were found, if you want to revoke the\n"
1330 "whole key, please use the Key Manager command directly.\n\n"
1331 "This command is only available to revoke single subkeys"),
1332 _("Key Edit"), MB_INFO );
1333 return FALSE;
1334 }
1335
1336 listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, sizeof (buf)-1);
1337 if (!strcmp (buf, _("Revoked"))) {
1338 msg_box (dlg, _("Key already revoked."), _("Key Edit"), MB_ERR);
1339 return FALSE;
1340 }
1341
1342 if (k->is_protected) {
1343 pass = request_passphrase (_("Key Edit"), 1, &cancel);
1344 if (cancel)
1345 return FALSE;
1346 }
1347
1348 ke = new GpgKeyEdit (k->keyid);
1349 if (!ke)
1350 BUG (NULL);
1351 if (k->is_protected)
1352 ke->setPassphrase (pass);
1353 err = ke->revokeSubkey (j, 0, NULL);
1354 if (err)
1355 msg_box( dlg, gpgme_strerror (err), _("Revoke Subkey"), MB_ERR);
1356 else {
1357 listview_add_sub_item (lv, j, SUBK_COL_STATUS, _("Revoked"));
1358 k->update = 1;
1359 msg_box( dlg, _("Subkey successfully revoked."), _("GnuPG Status"), MB_OK );
1360 }
1361 sfree_if_alloc (pass);
1362 delete ke;
1363 return TRUE;
1364 }
1365
1366
1367 /* Revoked the selected userid in list view @lv.
1368 Return value: TRUE on success. */
1369 int
1370 do_editkey_revuid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1371 {
1372 gpgme_error_t err;
1373 GpgKeyEdit *ke;
1374 char buf[256], t[512];
1375 char *pass=NULL;
1376 int cancel = 0, id = 0, j;
1377
1378 if (!k->key_pair) {
1379 msg_box( dlg, _("There is no secret key available!"), _("Revoke user ID"), MB_ERR );
1380 return FALSE;
1381 }
1382
1383 if( listview_count_items( lv, 0 ) == 1 ) {
1384 msg_box( dlg, _("Key has only one user ID."), _("Key Edit"), MB_ERR );
1385 return FALSE;
1386 }
1387
1388 if( (j = listview_get_curr_pos( lv )) == -1 ) {
1389 msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
1390 return FALSE;
1391 }
1392
1393 listview_get_item_text( lv, j, 0, buf, sizeof buf - 1 );
1394 if( strstr( buf, _("Revoked") ) ) {
1395 msg_box( dlg, _("This user ID has been already revoked."), _("Key Edit"), MB_INFO );
1396 return FALSE;
1397 }
1398
1399 listview_get_item_text (lv, j, 1, buf, sizeof buf -1);
1400 _snprintf( t, sizeof t -1, _("user ID \"%s\".\n\n"
1401 "Do you really want to revoke this user ID?"), buf );
1402 if( msg_box( dlg, t, _("Key Edit"), MB_WARN_ASK) == IDNO )
1403 return FALSE;
1404 if( k->is_protected ) {
1405 pass = request_passphrase (_("Key Edit"), 1, &cancel);
1406 if (cancel)
1407 return FALSE;
1408 }
1409 listview_get_item_text (lv, j, 2, buf, sizeof (buf)-1);
1410 id = do_find_userid (k->keyid, buf, NULL);
1411 if (id == -1)
1412 BUG (NULL);
1413
1414 ke = new GpgKeyEdit (k->keyid);
1415 if (!ke)
1416 BUG (NULL);
1417 if (k->is_protected)
1418 ke->setPassphrase (pass);
1419 err = ke->revokeUserid (id);
1420 if (err)
1421 msg_box (dlg, gpgme_strerror (err), _("Revoke Signature"), MB_ERR);
1422 else {
1423 listview_add_sub_item (lv, j, 0, _("Revoked"));
1424 k->update = 1;
1425 status_box (dlg, _("User ID successfully revoked"), _("GnuPG Status"));
1426 }
1427 sfree_if_alloc (pass);
1428 delete ke;
1429 return err? FALSE : TRUE;
1430 }
1431
1432
1433 static int
1434 do_editkey_setpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1435 {
1436 gpgme_error_t rc;
1437 GpgKeyEdit *ke;
1438 char buf[256], * pass = NULL, * prefs;
1439 int j, id, cancel=0, flags=0;
1440
1441 if ((j = listview_get_curr_pos (lv)) == -1) {
1442 msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1443 return FALSE;
1444 }
1445 listview_get_item_text (lv, j, 2, buf, sizeof buf-1);
1446 id = do_find_userid (k->keyid, buf, NULL);
1447 if (id == -1)
1448 BUG (dlg);
1449 if (k->is_protected) {
1450 pass = request_passphrase (_("Key Edit"), 1, &cancel);
1451 if (cancel)
1452 return FALSE;
1453 }
1454
1455 ke = new GpgKeyEdit (k->keyid);
1456 if (!ke)
1457 BUG (NULL);
1458 if (k->is_protected)
1459 ke->setPassphrase (pass);
1460
1461 get_userid_preflist (&prefs, &flags);
1462
1463 rc = ke->setUseridPreferences (id, prefs);
1464 /* XXX */
1465
1466 sfree_if_alloc (pass);
1467 free_if_alloc (prefs);
1468 delete ke;
1469 return 0;
1470 }
1471
1472
1473 static int
1474 do_editkey_primary (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1475 {
1476 gpgme_error_t err;
1477 GpgKeyEdit *ke;
1478 int j, id, cancel=0;
1479 char buf[256], * pass = NULL;
1480
1481 if (listview_count_items (lv, 0) == 1)
1482 return TRUE;
1483 if ((j = listview_get_curr_pos (lv)) == -1) {
1484 msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
1485 return FALSE;
1486 }
1487 listview_get_item_text (lv, j, 2, buf, sizeof buf-1);
1488 id = do_find_userid (k->keyid, buf, NULL);
1489 if (id == -1)
1490 BUG (dlg);
1491 if (k->is_protected) {
1492 pass = request_passphrase (_("Key Edit"), 1, &cancel);
1493 if( cancel )
1494 return FALSE;
1495 }
1496
1497 ke = new GpgKeyEdit (k->keyid);
1498 if (k->is_protected)
1499 ke->setPassphrase (pass);
1500 err = ke->setPrimaryUserid (id);
1501 if (err)
1502 msg_box (dlg, gpgme_strerror (err), _("Primary"), MB_ERR);
1503 else {
1504 k->update = 1;
1505 status_box (dlg, _("User ID successfully flagged"), _("GnuPG Status"));
1506 }
1507
1508 sfree_if_alloc (pass);
1509 delete ke;
1510 return err? FALSE : TRUE;
1511 }
1512
1513
1514 static int
1515 parse_preflist (HWND dlg, const char *list)
1516 {
1517 char *p, buf[128] = {0}, *pbuf = buf;
1518 const char *ciphers[11] = {0, "IDEA", "3DES", "CAST5", "BLOWFISH", 0, 0, "AES", "AES192", "AES256", "TWOFISH"};
1519 const char *hash[11] = {0, "MD5", "SHA1", "RMD160", 0, 0, 0, 0, "SHA256", "SHA384", "SHA512"};
1520 const char *compress[4] = {0, "ZIP", "ZLIB", "BZIP2"};
1521 int n=0;
1522
1523 strncpy (buf, list, 127);
1524 p = strtok (pbuf, " ");
1525 while (p != NULL) {
1526 int algid = atol (p+1);
1527 n++;
1528 switch (*p) {
1529 case 'S':
1530 SendDlgItemMessage (dlg, IDC_SHOWPREF_CIPHERS, LB_ADDSTRING, 0, (LPARAM)(const char*)ciphers[algid % 11]);
1531 break;
1532
1533 case 'H':
1534 SendDlgItemMessage (dlg, IDC_SHOWPREF_HASH, LB_ADDSTRING, 0, (LPARAM)(const char*)hash[algid % 10]);
1535 break;
1536
1537 case 'Z':
1538 SendDlgItemMessage (dlg, IDC_SHOWPREF_ZIP, LB_ADDSTRING, 0, (LPARAM)(const char*)compress[algid % 4]);
1539 break;
1540
1541 default:
1542 n--;
1543 }
1544 p = strtok (NULL, " ");
1545 }
1546 return n;
1547 }
1548
1549
1550 /* Dialog box procedure to show the key preferences. */
1551 BOOL CALLBACK
1552 showpref_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1553 {
1554 static keyedit_callback_s *cb = NULL;
1555 gpg_uid_info_t inf=NULL;
1556 char buf[128];
1557 int pos;
1558
1559 switch (msg) {
1560 case WM_INITDIALOG:
1561 cb = (keyedit_callback_s *)lparam;
1562 if (cb == NULL)
1563 BUG (dlg);
1564 pos = listview_get_curr_pos (cb->lv);
1565 listview_get_item_text (cb->lv, pos, 2, buf, DIM (buf)-1);
1566 SetDlgItemText (dlg, IDC_SHOWPREF_INFO, buf);
1567 pos = do_find_userid (((winpt_key_t)cb->opaque)->keyid, buf, &inf);
1568 if (inf) {
1569 const char *prefs = inf->prefs;
1570 if (prefs && *prefs) {
1571 if (parse_preflist (dlg, prefs) <= 0)
1572 pos = -1;
1573 }
1574 else
1575 pos = -1;
1576 gpg_uid_info_release (inf);
1577 if (pos == -1) {
1578 msg_box (dlg, _("No preferences available."), _("Key Edit"), MB_ERR);
1579 EndDialog (dlg, TRUE);
1580 }
1581 if (inf->flags.mdc)
1582 CheckDlgButton (dlg, IDC_SHOWPREF_MDC, BST_CHECKED);
1583 }
1584 SetWindowText (dlg, _("Key Preferences"));
1585 SetDlgItemText (dlg, IDC_SHOWPREF_MDC, _("MDC feature"));
1586 SetDlgItemText (dlg, IDC_SHOWPREF_PREFINF, _("Preferences"));
1587 SetForegroundWindow (dlg);
1588 break;
1589
1590 case WM_COMMAND:
1591 switch (LOWORD (wparam)) {
1592 case IDOK:
1593 EndDialog (dlg, TRUE);
1594 break;
1595 }
1596 break;
1597 }
1598 return FALSE;
1599 }
1600
1601
1602 static int
1603 do_editkey_showpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1604 {
1605 struct keyedit_callback_s cb;
1606
1607 if (k->is_v3)
1608 return TRUE;
1609
1610 if (listview_get_curr_pos (lv) == -1) {
1611 msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1612 return FALSE;
1613 }
1614
1615 memset (&cb, 0, sizeof (cb));
1616 cb.lv = lv;
1617 cb.opaque = k;
1618 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_SHOWPREF, dlg,
1619 showpref_dlg_proc, (LPARAM)&cb);
1620 return TRUE;
1621 }
1622
1623
1624 static int
1625 do_editkey_deluid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1626 {
1627 gpgme_error_t err;
1628 GpgKeyEdit *ke;
1629 char buf[256], t[512];
1630 int j, id = 0;
1631
1632 if (!k->key_pair)
1633 return FALSE; /* XXX: see do_editkey_delsubkey */
1634
1635 if( listview_count_items( lv, 0 ) == 1 ) {
1636 msg_box( dlg, _("Primary user ID can not be deleted!"), _("Key Edit"), MB_ERR );
1637 return FALSE;
1638 }
1639 if( (j = listview_get_curr_pos( lv )) == -1 ) {
1640 msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
1641 return FALSE;
1642 }
1643
1644 /* XXX: add a hint that also all signatures will be deleted? */
1645 listview_get_item_text( lv, j, 1, buf, DIM(buf) -1 );
1646 _snprintf( t, DIM (t)-1, _("user ID \"%s\".\n\n"
1647 "Do you really want to delete this user ID?"),
1648 buf);
1649 if( msg_box( dlg, t, _("Key Edit"), MB_YESNO|MB_ICONWARNING ) == IDNO )
1650 return FALSE;
1651
1652 listview_get_item_text (lv, j, 2, buf, DIM (buf)-1);
1653 id = do_find_userid (k->keyid, buf, NULL);
1654 if (id == -1)
1655 BUG (dlg);
1656
1657 ke = new GpgKeyEdit (k->keyid);
1658 if (!ke)
1659 BUG (NULL);
1660
1661 err = ke->delUserid (id);
1662 if( err )
1663 msg_box( dlg, gpgme_strerror (err), _("Delete user ID"), MB_ERR );
1664 else {
1665 listview_del_item( lv, j );
1666 k->update = 1;
1667 status_box( dlg, _("User ID successfully deleted"), _("GnuPG Status") );
1668 }
1669 delete ke;
1670 return err? FALSE : TRUE;
1671 } /* do_editkey_deluid */
1672
1673
1674
1675 static BOOL CALLBACK
1676 subkey_subclass_proc( HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam )
1677 {
1678 switch( msg ) {
1679 case WM_KEYUP:
1680 int virt_key = (int)wparam;
1681 switch( virt_key ) {
1682 case VK_DELETE:
1683 SendDlgItemMessage( keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1684 CB_SETCURSEL, CMD_DELKEY, 0 );
1685 send_cmd_id( keyedit_subkey_proc.dlg, IDOK );
1686 break;
1687
1688 case VK_INSERT:
1689 SendDlgItemMessage( keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1690 CB_SETCURSEL, CMD_ADDKEY, 0 );
1691 send_cmd_id( keyedit_subkey_proc.dlg, IDOK );
1692 break;
1693 }
1694 }
1695 return CallWindowProc( keyedit_subkey_proc.old, dlg, msg, wparam, lparam );
1696 } /* subkey_subclass_proc */
1697
1698
1699 static BOOL CALLBACK
1700 uid_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1701 {
1702 switch( msg ) {
1703 case WM_KEYUP:
1704 int virt_key = (int)wparam;
1705 switch (virt_key) {
1706 case VK_DELETE:
1707 SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1708 CB_SETCURSEL, CMD_DELUID, 0);
1709 send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1710 break;
1711
1712 case VK_INSERT:
1713 SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1714 CB_SETCURSEL, CMD_ADDUID, 0);
1715 send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1716 break;
1717 }
1718 }
1719 return CallWindowProc( keyedit_uid_proc.old, dlg, msg, wparam, lparam );
1720 } /* uid_subclass_proc */
1721
1722
1723 BOOL CALLBACK
1724 keyedit_main_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1725 {
1726 static winpt_key_t k;
1727 static listview_ctrl_t lvsub = NULL, lvuid = NULL;
1728 int cmd, idxsub = 0;
1729 HWND item;
1730
1731 switch( msg ) {
1732 case WM_INITDIALOG:
1733 k = (winpt_key_t)lparam;
1734 if (!k)
1735 BUG (NULL);
1736 do_init_cmdlist (dlg);
1737 lvsub = subkey_list_init (dlg, k);
1738 if( !lvsub )
1739 BUG( NULL );
1740 lvuid = userid_list_init (dlg, k);
1741 if( !lvuid )
1742 BUG( NULL );
1743 item = GetDlgItem( dlg, IDC_KEYEDIT_KEYLIST );
1744 keyedit_subkey_proc.dlg = dlg;
1745 keyedit_subkey_proc.current = (WNDPROC)subkey_subclass_proc;
1746 keyedit_subkey_proc.old = (WNDPROC)GetWindowLong( item, GWL_WNDPROC );
1747 if( keyedit_subkey_proc.old ) {
1748 if( !SetWindowLong( item, GWL_WNDPROC, (LONG)keyedit_subkey_proc.current ) ) {
1749 msg_box( dlg, _("Could not set subkey window procedure."), _("Key Edit"), MB_ERR );
1750 BUG( NULL );
1751 }
1752 }
1753 item = GetDlgItem( dlg, IDC_KEYEDIT_UIDLIST );
1754 keyedit_uid_proc.dlg = dlg;
1755 keyedit_uid_proc.current = (WNDPROC)uid_subclass_proc;
1756 keyedit_uid_proc.old = (WNDPROC)GetWindowLong( item, GWL_WNDPROC );
1757 if( keyedit_uid_proc.old ) {
1758 if( !SetWindowLong( item, GWL_WNDPROC, (LONG)keyedit_uid_proc.current ) ) {
1759 msg_box( dlg, _("Could not set user ID window procedure."), _("Key Edit"), MB_ERR );
1760 BUG( NULL );
1761 }
1762 }
1763 if (!k->key_pair) {
1764 EnableWindow (GetDlgItem (dlg, IDC_KEYEDIT_CMD), FALSE);
1765 EnableWindow (GetDlgItem (dlg, IDOK), FALSE);
1766 }
1767 SetDlgItemText (dlg, IDC_KEYEDIT_CMDINF, _("Command>"));
1768 SetDlgItemText (dlg, IDCANCEL, _("&Close"));
1769 SetDlgItemText (dlg, IDC_KEYEDIT_HELP, _("&Help"));
1770 SetWindowText (dlg, _("Key Edit"));
1771
1772 SetForegroundWindow( dlg );
1773 center_window( dlg, NULL );
1774 return TRUE;
1775
1776 case WM_DESTROY:
1777 if( lvsub ) {
1778 listview_release( lvsub );
1779 lvsub = NULL;
1780 }
1781 if( lvuid ) {
1782 listview_release( lvuid );
1783 lvuid = NULL;
1784 }
1785 break;
1786
1787 case WM_NOTIFY:
1788 NMHDR * notify;
1789 notify = (NMHDR *)lparam;
1790 if (notify && notify->code == NM_DBLCLK &&
1791 notify->idFrom == IDC_KEYEDIT_UIDLIST)
1792 do_editkey_showpref (k, dlg, lvuid);
1793 break;
1794
1795 case WM_COMMAND:
1796 switch( LOWORD( wparam ) ) {
1797 case IDOK:
1798 cmd = SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_GETCURSEL, 0, 0);
1799 if (cmd == LB_ERR) {
1800 msg_box( dlg, _("Please select a command."), _("Key Edit"), MB_INFO );
1801 return FALSE;
1802 }
1803 idxsub = listview_get_curr_pos (lvsub);
1804 if (k->is_v3 && is_cmd_openpgp (cmd)) {
1805 msg_box (dlg, _("This command cannot be used with PGP 2 (v3) keys.\n"),
1806 _("Key Edit"), MB_ERR);
1807 return FALSE;
1808 }
1809 switch (cmd) {
1810 case CMD_SHOWPREF: do_editkey_showpref (k, dlg, lvuid); break;
1811 case CMD_DELKEY: do_editkey_delkey (k, dlg, lvsub); break;
1812 case CMD_ADDKEY: keyedit_add_subkey (k, dlg, lvsub); break;
1813 case CMD_EXPIRE: do_editkey_expire (k, dlg, lvsub); break;
1814 case CMD_REVKEY: do_editkey_revoke (k, dlg, lvsub); break;
1815 /*case CMD_SETPREF:do_editkey_setpref( k, dlg, lvuid ); break;*/
1816 case CMD_ADDUID: keyedit_add_userid( k, dlg, lvuid ); break;
1817 case CMD_ADDREVOKER: keyedit_add_revoker( k, dlg ); break;
1818 case CMD_ADDPHOTO: keyedit_add_photo( k, dlg ); break;
1819 case CMD_REVUID: do_editkey_revuid( k, dlg, lvuid ); break;
1820 case CMD_DELUID: do_editkey_deluid( k, dlg, lvuid ); break;
1821 case CMD_PASSWD: keyedit_change_passwd( k, dlg ); break;
1822 case CMD_PRIMARY: do_editkey_primary( k, dlg, lvuid ); break;
1823 case CMD_ENABLE: km_enable_disable_key( lvsub, dlg, idxsub, 1 ); break;
1824 case CMD_DISABLE: km_enable_disable_key( lvsub, dlg, idxsub, 0 ); break;
1825 }
1826 break;
1827
1828 case IDCANCEL:
1829 EndDialog (dlg, FALSE);
1830 break;
1831
1832 case IDC_KEYEDIT_HELP:
1833 do_show_help (dlg);
1834 break;
1835 }
1836 break;
1837 }
1838 return FALSE;
1839 } /* keyedit_main_dlg_proc */

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26