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

Annotation of /trunk/Src/wptKeyEditDlgs.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 88 - (hide annotations)
Mon Nov 21 12:06:59 2005 UTC (19 years, 3 months ago) by twoaday
File size: 49658 byte(s)
2005-11-21  Timo Schulz  <ts@g10code.com>
 
        * WinPT.cpp (WinMain): Implement --stop switch.
        * wptClipEditDlg.cpp (clip_edit_dlg_proc): Localize
        missing string.
        * wptPreferencesDlg.cpp (prefs_dlg_proc): Likewise.
        * wptKeygenDlg.cpp (keygen_dlg_proc): Verify valid context
        first. Thanks to Ralf.
        * wptFileManagerDlg.cpp (update_ui_items): New.
        * wptFileManager.cpp (fm_set_status): New sigmode param.
        Changed all callers.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26