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

Diff of /trunk/Src/wptKeyEditDlgs.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.22  
changed lines
  Added in v.48

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26