/[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 20 by twoaday, Wed Jul 27 11:17:22 2005 UTC revision 211 by twoaday, Sun May 7 12:36:48 2006 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 */  
   
   
 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;  
     int index, size, valid;  
     HWND lb;  
       
     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") );  
         SetDlgItemText( dlg, IDC_ADDSUBKEY_INFVALID,  
                         _("Valid for 'n' days. 0 means forever") );  
 #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)" );  
         SetDlgItemInt( dlg, IDC_ADDSUBKEY_VALID, 0, FALSE );  
         SetDlgItemInt( dlg, IDC_ADDSUBKEY_SIZE, DFAULT_KEYSIZE, FALSE );  
         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:  
             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;  
             }  
             if (gpgver[0] == 1 && gpgver[1] == 2) { /* GPG 1.2.x kludge */  
                 if (listbox_get_cursel (lb) > 1)  
                     index++;  
             }  
             size = GetDlgItemInt( dlg, IDC_ADDSUBKEY_SIZE, NULL, TRUE );  
             if( !size ) {  
                 msg_box( dlg, _("Please enter the keysize."), _("Add Subkey"), MB_ERR );  
                 return FALSE;  
             }  
             else if (index == 2 && size != 1024) {  
                 msg_box( dlg,_("DSS uses a fixed keysize of 1024. Size changed."), _("Add Subkey"), MB_INFO );  
                 size = 1024;  
             }  
             else if (size > 4096) {  
                 int id;  
                 msg_box (dlg, _("Chosen size must be between 1024 and 4096."), _("Add Subkey"), MB_ERR);  
                 id = msg_box (dlg, _("Do you really need such a large key?"), _("Add Subkey"), MB_QUEST_ASK);  
                 if (id == IDNO)  
                     size = DFAULT_KEYSIZE;  
                 else  
                     size = 4096;  
                 SetDlgItemInt (dlg, IDC_ADDSUBKEY_SIZE, size, TRUE);  
             }  
             else if (size < 1024) {  
                 msg_box( dlg, _("Keys with a size of less then 1024 are considered insecure.\n"  
                                 "Size changed to 1024!"), _("Add Subkey"), MB_INFO );  
                 size = 1024;  
             }  
             valid = GetDlgItemInt (dlg, IDC_ADDSUBKEY_VALID, NULL, TRUE);  
             if (valid < 0) {  
                 msg_box( dlg, _("Please enter the days the key is valid."), _("Add Subkey"), MB_ERR );  
                 return FALSE;  
             }  
             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)  
                 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_UPDPREF:  
         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( (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:  
             if (k->update)  
                 keycache_update (0, k->keyid);  
             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-2006 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    #ifdef HAVE_CONFIG_H
21    #include <config.h>
22    #endif
23    
24    #include <windows.h>
25    #include <commctrl.h>
26    #include <time.h>
27    #include <assert.h>
28    
29    #include "resource.h"
30    #include "wptTypes.h"
31    #include "wptW32API.h"
32    #include "wptVersion.h"
33    #include "wptGPG.h"
34    #include "wptCommonCtl.h"
35    #include "wptContext.h"
36    #include "wptDlgs.h"
37    #include "wptNLS.h"
38    #include "wptUTF8.h"
39    #include "wptErrors.h"
40    #include "wptKeylist.h"
41    #include "wptKeyManager.h"
42    #include "wptRegistry.h"
43    #include "wptKeyEdit.h"
44    
45    /* All edit key commands. */
46    enum keyedit_commands {    
47        CMD_ADDKEY = 0,
48        CMD_ADDUID,
49        CMD_ADDPHOTO,
50        CMD_ADDREVOKER,
51        CMD_DELUID,
52        CMD_DELKEY,
53        CMD_EXPIRE,
54        CMD_SHOWPREF,
55        //CMD_SETPREF,
56        CMD_PASSWD,
57        CMD_PRIMARY,
58        CMD_TRUST,
59        CMD_REVUID,
60        CMD_REVKEY,
61        CMD_DISABLE,
62        CMD_ENABLE,    
63        CMD_SIGN,
64        CMD_LSIGN,
65        CMD_CHECK,
66        CMD_CLEAN,
67        CMD_MINIMIZE
68    };
69    
70    struct cmdlist_s {
71        const char   *name;
72        unsigned int  need_pair:1;
73        int       id;
74    } cmdlist[] = {
75        {"ADDKEY", 1, CMD_ADDKEY},
76        {"ADDUID", 1, CMD_ADDUID},
77        {"ADDPHOTO", 1, CMD_ADDPHOTO},
78        {"ADDREVOKER", 1, CMD_ADDREVOKER},
79        {"DELUID", 1, CMD_DELUID},
80        {"DELKEY", 1, CMD_DELKEY},
81        {"EXPIRE", 1, CMD_EXPIRE},
82        {"SHOWPREF", 0, CMD_SHOWPREF},
83        /*{"SETPREF", 1, CMD_SETPREF},*/
84        {"PASSWD", 1, CMD_PASSWD},
85        {"PRIMARY", 1, CMD_PRIMARY},
86        {"TRUST", 0, CMD_TRUST},
87        {"REVUID", 1, CMD_REVUID},
88        {"REVKEY", 1, CMD_REVKEY},
89        {"DISABLE", 0, CMD_DISABLE},
90        {"ENABLE", 0, CMD_ENABLE},
91        {"SIGN", 0, CMD_SIGN},
92        {"LSIGN", 0, CMD_LSIGN},
93        {"CHECK", 0, CMD_CHECK},
94        {"CLEAN", 0, CMD_CLEAN},
95        {"MINIMIZE", 0, CMD_MINIMIZE},
96        {NULL, 0}  
97    };
98    
99    
100    /* Symbolic ids for the subkey columns. */
101    enum subk_col_t {
102        SUBK_COL_DESC       = 0,
103        SUBK_COL_KEYID      = 1,    
104        SUBK_COL_CREATION   = 2,    
105        SUBK_COL_EXPIRES    = 3,
106        SUBK_COL_STATUS     = 4,
107        SUBK_COL_C_FLAG     = 5,
108        SUBK_COL_S_FLAG     = 6,
109        SUBK_COL_E_FLAG     = 7,
110        SUBK_COL_A_FLAG     = 8
111    };
112    
113    /* Symbolic ids for the userid columns. */
114    enum uid_col_t {
115        UID_COL_VALID       = 0,
116        UID_COL_NAME        = 1,
117        UID_COL_EMAIL       = 2,
118        UID_COL_CREATION    = 3
119    };
120    
121    /* Key edit callback context. */
122    struct keyedit_cb_s {
123        const char     *keyid;
124        const char     *pass;
125        listview_ctrl_t lv;
126        int             lv_pos;
127        void           *opaque;
128        unsigned int    finished:1;
129        unsigned int    is_protected:1;
130    };
131    typedef struct keyedit_cb_s *keyedit_cb_t;
132    
133    
134    /* Key generation callback context. */
135    struct keygen_cb_s {
136        int   bits;
137        int   algo;
138        u32   expire;
139        char *fpr;
140        char *name;
141        char *comment;
142        char *email;
143    };
144    typedef struct keygen_cb_s *keygen_cb_t;
145    
146    /* Subclass context for the subkey list. */
147    static subclass_s keyedit_subkey_proc;
148    
149    /* Subclass context for the user-id list. */
150    static subclass_s keyedit_uid_proc;
151    
152    int keygen_check_date (SYSTEMTIME *st);
153    void get_userid_preflist (char **r_prefs, int * r_flags);
154    char* get_subkey_keyid (const char *keyid);
155    
156    void ComboBox_AddString_utf8 (HWND cb, const char *txt);
157    
158    static GpgKeyEdit*
159    create_GpgKeyEdit (const char *keyid)
160    {
161        GpgKeyEdit *ke;
162    
163        ke = new GpgKeyEdit (keyid);
164        if (!ke)
165            BUG (NULL);
166        return ke;
167    }
168    
169    
170    /* Associate each key with a combo box entry.
171       Skip the key in @k. */
172    static void
173    do_init_keylist (HWND dlg, const char *keyid)
174    {
175        gpg_keycache_t pub;
176        gpgme_key_t key;
177        const char *s, *kid;
178        int i, n;
179    
180        pub = keycache_get_ctx (1);
181        if (!pub)
182            BUG (0);
183    
184        gpg_keycache_rewind (pub);
185        while( !gpg_keycache_next_key (pub, 0, &key)) {
186            if (key->expired || key->revoked ||
187                key->disabled || key->invalid)
188                continue;
189            s = key->uids->uid;
190            kid = key->subkeys->keyid;
191            if (!s || !strcmp (kid+8, keyid))
192                continue;
193            ComboBox_AddString_utf8 (GetDlgItem (dlg, IDC_ADDREV_KEYLIST), s);
194        }
195        gpg_keycache_rewind (pub);
196        n = SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_GETCOUNT, 0, 0);
197        for (i = 0; i < n; i++) {
198            gpg_keycache_next_key (pub, 0, &key);
199            SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETITEMDATA,
200                                (WPARAM)(int)i, (LPARAM)key);
201        }
202        SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETCURSEL, 0, 0);
203    }
204    
205    
206    /* Add a new user-id to the list view @lv. */
207    static void
208    do_add_new_userid (listview_ctrl_t lv,
209                       const char *utf8_name, const char *email,
210                       const char *utf8_comment)
211    {
212        char *p;
213        size_t n;
214        
215        n = strlen (utf8_name) + strlen (email) + 16;
216        if (utf8_comment)
217            n += strlen (utf8_comment);
218        p = new char[n+1];
219        if (!p)
220            BUG (NULL);
221        if (utf8_comment) {
222            sprintf (p, "%s (%s)", utf8_name, utf8_comment);
223        }
224        else
225            sprintf (p, "%s", utf8_name);
226    
227        listview_add_item (lv, "");
228        listview_add_sub_item (lv, 0, 0, _("Ultimate" ));
229        listview_add_sub_item (lv, 0, 1, p);
230        listview_add_sub_item (lv, 0, 2, email && *email? email : "");
231        listview_add_sub_item (lv, 0, 3, get_key_created (time (NULL)));
232        free_if_alloc (p);
233    }
234    
235    
236    static void
237    do_add_new_subkey (listview_ctrl_t lv, keygen_cb_t keygen, unsigned int flags)
238    {
239        char info[128], keyid[32];
240        const char *expdate, *s;
241        int n;
242        
243        expdate = keygen->expire? get_key_expire_date (keygen->expire) : _("Never");
244        _snprintf (info, sizeof info-1, "%d-bit %s",
245                   keygen->bits,
246                   get_key_pubalgo ((gpgme_pubkey_algo_t)keygen->algo));
247        _snprintf (keyid, sizeof keyid-1, "0x%s", keygen->fpr+8);
248        s = get_key_created (time (NULL));
249        n = listview_count_items (lv, 0);
250        listview_add_item_pos (lv, n);
251        listview_add_sub_item (lv, n, SUBK_COL_DESC, info);
252        listview_add_sub_item (lv, n, SUBK_COL_KEYID, keyid);
253        listview_add_sub_item (lv, n, SUBK_COL_CREATION, s);
254        listview_add_sub_item (lv, n, SUBK_COL_EXPIRES, expdate);
255        if (flags & KM_FLAG_REVOKED)
256            s = _("Revoked");      
257        else if (flags & KM_FLAG_EXPIRED)
258            s = _("Expired");
259        else
260            s = _("OK");
261        listview_add_sub_item (lv, n, SUBK_COL_STATUS, s);
262    }
263    
264    
265    /* Try to find the GPG edit key index which belongs to the user ID
266       given by the email address @email, @name is used as a fallback.
267       If @r_inf != NULL, the info context will be returned.
268       Return value: index of the user ID or -1 on error. */
269    static int
270    do_find_userid (const char *keyid, const char *email,
271                    const char *name, gpg_uid_info_t *r_inf)
272    {
273        GpgKeyEdit *ke;
274        gpgme_error_t err;
275        gpg_uid_info_t inf, ui;
276        int pos = -1;
277    
278        ke = create_GpgKeyEdit (keyid);
279        err = ke->getUseridInfo (&inf);
280        delete ke;
281        if (err) {
282            log_box (_("user ID"), MB_ERR,
283                    _("Could not get key information for: \"%s\":\n%s"),
284                    name, gpgme_strerror (err));
285            return -1;
286        }
287    
288        for (ui = inf; ui; ui = ui->next) {
289            if (name && email && ui->email && ui->name) {
290                if (!strcmp (ui->email, email) &&
291                    !strncmp (ui->name, name, strlen (name))) {
292                    pos = ui->index;
293                    break;
294                }
295                continue;
296            }
297            if (email && ui->email) {
298                if (!strcmp (ui->email, email)) {
299                    pos = ui->index;
300                    break;
301                }
302                /* The email address is more unique, use the name just
303                   as the fallbck when no email address is available. */
304                continue;
305            }
306            if (ui->name && name && !strcmp (ui->name, name)) {
307                pos = ui->index;
308                break;
309            }
310        }
311        if (r_inf)
312            *r_inf = inf;
313        else
314            gpg_uid_info_release (inf);
315        return pos;
316    }
317    
318    
319    /* Return true if @fname is a JPEG file. */
320    bool
321    is_jpg_file (const char *fname)
322    {
323        FILE *fp;
324        BYTE buf[10];
325        int n;
326    
327        fp = fopen (fname, "rb");
328        if (!fp)
329            return false;
330        n = fread (buf, 1, 10, fp);
331        fclose (fp);
332        if (n < 10)
333            return false;
334        return buf[6] == 'J' && buf[7] == 'F' &&
335               buf[8] == 'I' && buf[9] == 'F';
336    }
337    
338    
339    /* Dialog box procedure to add a photo. */
340    BOOL CALLBACK
341    keyedit_addphoto_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
342    {
343        static keyedit_cb_t cb;
344        GpgKeyEdit *ke;
345        gpgme_error_t err;
346        const char *s;    
347        char file[128];
348        int id;
349    
350        switch( msg ) {
351        case WM_INITDIALOG:
352            cb = (keyedit_cb_t)lparam;
353            if (!cb)
354                BUG (NULL);
355            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."));
356            SetDlgItemText (dlg, IDC_ADDPHOTO_FILEINF, _("Pick an image to use for your photo ID.\nThe image must be a JPEG file."));
357            SetDlgItemText (dlg, IDC_ADDPHOTO_PWDINF, _("Passphrase"));
358            SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
359            SetWindowText (dlg, _("Add Photo ID"));
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 IDC_ADDPHOTO_SELFILE:
374                s = get_fileopen_dlg (dlg, _("Select Image File"),
375                                      "JPEG Files (*.jpg, *.jpeg)\0*.jpg;*.jpeg\0\0",
376                                      NULL);
377                if (s && !is_jpg_file (s)) {
378                    log_box (_("Add Photo"), MB_ERR,
379                             _("'%s' is not a valid JPEG file."), s);
380                    return FALSE;
381                }
382                if (s && *s)
383                    SetDlgItemText (dlg, IDC_ADDPHOTO_FILE, s);
384                break;
385    
386            case IDOK:
387                if (!GetDlgItemText (dlg, IDC_ADDPHOTO_FILE, file, sizeof (file)-1)){
388                    msg_box( dlg, _("Please enter a file name."), _("Add Photo"), MB_ERR);
389                    return FALSE;
390                }
391                if (get_file_size (file) == 0 || get_file_size (file) > 6144 ) {
392                    id = msg_box (dlg, _("The JPEG is really large.\n"
393                                         "Are you sure you want to use it?"),
394                                         _("Add Photo"), MB_YESNO|MB_INFO);
395                    if (id == IDNO)
396                        return TRUE;
397                }
398                ke = create_GpgKeyEdit (cb->keyid);
399                if (cb->pass)
400                    ke->setPassphrase (cb->pass);
401                else
402                    ke->setNoPassphrase (true);
403                err = ke->addPhotoid (file);
404                delete ke;
405                if (err) {
406                    msg_box (dlg, gpgme_strerror (err), _("Add Photo"), MB_ERR);
407                    return FALSE;
408                }
409                else {
410                    cb->finished = 1;
411                    msg_box (dlg, _("Photo successfully added."),
412                             _("GnuPG Status"), MB_OK);
413                }
414                EndDialog (dlg, TRUE);
415                break;
416    
417            case IDCANCEL:
418                EndDialog (dlg, FALSE);
419                break;
420            }
421            break;
422        }
423        return FALSE;
424    }
425    
426    
427    /* Dialog box procedure to add a designated revoker. */
428    BOOL CALLBACK
429    keyedit_addrevoker_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
430    {
431        static keyedit_cb_t cb;
432        gpgme_error_t err;
433        GpgKeyEdit *ke;
434        char *uid=NULL;
435    
436        switch (msg) {
437        case WM_INITDIALOG:
438            cb = (keyedit_cb_t)lparam;
439            if (!cb)
440                BUG (NULL);
441            do_init_keylist (dlg, cb->keyid);
442            SetDlgItemText (dlg, IDC_ADDREV_INF,
443                            _("Appointing a key as designated revoker cannot be undone."));
444            SetDlgItemText (dlg, IDC_ADDREV_KEYINF, _("Public key"));
445            SetDlgItemText (dlg, IDC_ADDREV_PWDINF, _("Passphrase"));
446            SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
447            SetWindowText (dlg, _("Add Revoker"));
448            SetForegroundWindow (dlg);
449            break;
450    
451        case WM_SYSCOMMAND:
452            if (LOWORD (wparam) == SC_CLOSE)
453                EndDialog (dlg, FALSE);
454            break;
455    
456        case WM_COMMAND:
457            switch (LOWORD (wparam)) {
458            case IDOK:
459                if (!GetDlgItemText_utf8 (dlg, IDC_ADDREV_KEYLIST, &uid)) {
460                    msg_box (dlg, _("Please select a user ID."), _("Add Revoker"), MB_ERR);
461                    return FALSE;
462                }
463            
464                ke = create_GpgKeyEdit (cb->keyid);
465                if (cb->pass)
466                    ke->setPassphrase (cb->pass);
467                else
468                    ke->setNoPassphrase (true);
469                err = ke->addDesignatedRevoker (uid);
470                delete ke;
471                safe_free (uid);
472                if (err) {
473                    msg_box (dlg, gpgme_strerror (err), _("Add Revoker"), MB_ERR);
474                    return TRUE;
475                }
476                else {
477                    cb->finished = 1;
478                    msg_box (dlg, _("Revoker successfully addded."),
479                             _("GnuPG Status"), MB_OK);
480                }
481                EndDialog (dlg, TRUE);
482                break;
483    
484            case IDCANCEL:
485                EndDialog (dlg, FALSE);
486                break;
487            }
488            break;
489        }
490        return FALSE;
491    }
492    
493    
494    /* Dialog box procedure to add a new user-ID. */
495    BOOL CALLBACK
496    keyedit_adduid_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
497    {
498        static keyedit_cb_t ctx;
499        keygen_cb_t keygen;
500        gpgme_error_t err;
501        GpgKeyEdit *ke;
502        char *utf8_name = NULL;
503        char *utf8_comment = NULL;
504        char email[128];
505        int rc;
506        
507        switch (msg) {
508        case WM_INITDIALOG:
509            ctx = (keyedit_cb_t)lparam;
510            if (!ctx)
511                dlg_fatal_error(dlg, "Could not get dialog param!");
512            SetWindowText (dlg, _("Add new User ID"));
513            SetDlgItemText (dlg, IDC_ADDUID_INFNAME, _("&Name"));
514            SetDlgItemText (dlg, IDC_ADDUID_INFEMAIL, _("&Email"));
515            SetDlgItemText (dlg, IDC_ADDUID_INFCOMMENT, _("&Comment"));
516            SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
517            SetForegroundWindow (dlg);
518            return FALSE;
519            
520        case WM_SYSCOMMAND:
521            if (LOWORD (wparam) == SC_CLOSE)
522                EndDialog(dlg, TRUE);
523            return FALSE;
524            
525        case WM_COMMAND:
526            switch ( LOWORD( wparam ) )  {
527            case IDOK:
528                keygen = (keygen_cb_t)ctx->opaque;
529                rc = GetDlgItemText_utf8 (dlg, IDC_ADDUID_NAME, &utf8_name);
530                if (!rc || rc < 5) {
531                    msg_box (dlg, _("Please enter a name (min. 5 chars.)"),
532                             _("UserID"), MB_ERR);
533                    free_if_alloc (utf8_name);
534                    return FALSE;
535                }
536                if (strchr (utf8_name, '@')) {
537                    msg_box (dlg, _("Please enter the email address in the email field and not in the name field"),
538                             _("UserID"), MB_INFO);
539                    return FALSE;
540                }
541    
542                if( !GetDlgItemText (dlg, IDC_ADDUID_EMAIL, email, sizeof (email) -1)) {
543                    msg_box( dlg, _("Please enter an email address."), _("UserID"), MB_ERR );
544                    return FALSE;
545                }
546                if (check_email_address (email)) {
547                    msg_box (dlg, _("Invalid email address."), _("UserID"), MB_ERR);
548                    return FALSE;
549                }
550                
551                rc = GetDlgItemText_utf8 (dlg, IDC_ADDUID_COMMENT, &utf8_comment);
552    
553                ke = create_GpgKeyEdit (ctx->keyid);
554                if (ctx->is_protected)
555                    ke->setPassphrase (ctx->pass);
556                else
557                    ke->setNoPassphrase (true);
558                err = ke->addUserid (utf8_name, utf8_comment, email);
559                if (err)
560                    msg_box (dlg, gpgme_strerror (err), _("UserID"), MB_ERR);
561                else {
562                    msg_box (dlg, _("user ID successfully added."), _("GnuPG Status"), MB_OK);
563                    ctx->finished = 1;
564                    keygen->name = utf8_name;
565                    keygen->comment = utf8_comment;
566                    keygen->email = m_strdup (email);
567                }
568                delete ke;
569                EndDialog (dlg, TRUE);
570                return TRUE;
571                
572            case IDCANCEL:
573                EndDialog (dlg, FALSE);
574                return FALSE;
575            }
576            break;
577        }
578        
579        return FALSE;
580    }
581    
582    
583    static void
584    init_keysize_box (HWND dlg, int ctlid)
585    {
586        const char *sizelist[] = {
587            "1024", "1536",
588            "2048", "3072",
589            "4096", NULL
590        };
591        int i;
592    
593        for (i=0; sizelist[i] != NULL; i++)
594            SendDlgItemMessage (dlg, ctlid, CB_ADDSTRING, 0,
595                                (LPARAM)(char*)sizelist[i]);
596        SendDlgItemMessage (dlg, ctlid, CB_SETCURSEL, (WPARAM)2, 0);
597    }
598    
599    
600    static int
601    get_keysize_from_box (HWND dlg, int ctlid)
602    {
603        int pos;
604        char buf[32];
605    
606        pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0);
607        if (pos == CB_ERR)
608            return -1;
609        SendDlgItemMessage (dlg, ctlid, CB_GETLBTEXT, pos, (LPARAM)(char*)buf);
610        return atoi (buf);
611    }
612    
613    
614    /* Create a time_t from a system time @st. */
615    time_t
616    w32_mktime (SYSTEMTIME *st)
617    {
618        struct tm tm;
619    
620        memset (&tm, 0, sizeof (tm));
621        tm.tm_year = st->wYear-1900;
622        tm.tm_mday = st->wDay+1;
623        tm.tm_mon = st->wMonth-1;
624        return mktime (&tm);
625    }
626    
627    
628    /* Dialog procedure for adding a new secondary key. */
629    BOOL CALLBACK
630    keyedit_addsubkey_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
631    {
632        static keyedit_cb_t ctx;
633        keygen_cb_t keygen;
634        GpgKeyEdit *ke;
635        gpgme_error_t err;
636        SYSTEMTIME st;
637        HWND hwnd;
638        int index, size, valid;
639        
640        switch (msg) {
641        case WM_INITDIALOG:
642            ctx = (keyedit_cb_t)lparam;
643            if (!ctx)
644                dlg_fatal_error (dlg, "Could not get dialog param!");
645    
646            SetWindowText (dlg, _("Add new Subkey"));
647            SetDlgItemText (dlg, IDC_ADDSUBKEY_INFALGO, _("Key type"));
648            SetDlgItemText (dlg, IDC_ADDSUBKEY_INFSIZE, _("Size in bits"));
649            SetDlgItemText (dlg, IDC_ADDSUBKEY_INFVALID, _("Key expiration"));
650            SetDlgItemText (dlg, IDC_ADDSUBKEY_EXPIRE, _("&Never"));
651            SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
652    
653            hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
654            listbox_add_string (hwnd, "DSA (sign only)");
655            listbox_add_string (hwnd, "ElGamal (encrypt only)");
656            listbox_add_string (hwnd, "RSA (sign only)");
657            listbox_add_string (hwnd, "RSA (encrypt only)");
658            CheckDlgButton (dlg, IDC_ADDSUBKEY_EXPIRE, BST_CHECKED);
659            EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
660            init_keysize_box (dlg, IDC_ADDSUBKEY_SIZE);
661            SetForegroundWindow (dlg);
662            return FALSE;
663            
664        case WM_SYSCOMMAND:
665            if (LOWORD (wparam) == SC_CLOSE)
666                EndDialog (dlg, TRUE);
667            return FALSE;
668            
669        case WM_COMMAND:
670            if (HIWORD (wparam) == BN_CLICKED &&
671                LOWORD (wparam) == IDC_ADDSUBKEY_EXPIRE) {
672                if (IsDlgButtonChecked (dlg, IDC_ADDSUBKEY_EXPIRE))
673                    EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
674                else
675                    EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), TRUE);
676            }
677            if (HIWORD (wparam) == LBN_SELCHANGE &&
678                LOWORD (wparam) == IDC_ADDSUBKEY_ALGO) {
679                index = SendMessage ((HWND)lparam, LB_GETCURSEL, 0, 0);
680                if (index == 0)
681                    SendDlgItemMessage (dlg, IDC_ADDSUBKEY_SIZE, CB_SETCURSEL, 0, 0);
682            }
683    
684            switch (LOWORD (wparam)) {
685            case IDOK:
686                keygen = (keygen_cb_t)ctx->opaque;
687                assert (keygen);
688                hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
689                switch (listbox_get_cursel (hwnd)) {
690                case 0: index = 2; break;
691                case 1: index = 4; break;
692                case 2: index = 5; break;
693                case 3: index = 6; break;
694                default:
695                    msg_box (dlg, _("Please select one entry."),
696                             _("Add Subkey"), MB_ERR);
697                    return FALSE;
698                }
699                size = get_keysize_from_box (dlg, IDC_ADDSUBKEY_SIZE);
700                if (index == 2 && size != 1024) {
701                    msg_box (dlg,_("DSS uses a fixed keysize of 1024. Size changed."),
702                             _("Add Subkey"), MB_INFO);
703                    size = 1024;
704                }
705    
706                hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE);
707                DateTime_GetSystemtime (hwnd, &st);
708                valid = w32_mktime (&st) - time (NULL);
709                valid /= 86400;
710    
711                keygen->bits = size;
712                switch (index) {
713                case 2: keygen->algo = GPGME_PK_DSA; break;
714                case 4: keygen->algo = GPGME_PK_ELG_E; break;
715                case 5: keygen->algo = GPGME_PK_RSA_S; break;
716                case 6: keygen->algo = GPGME_PK_RSA_E; break;
717                }
718                if (valid > 0)
719                    keygen->expire = time (NULL) + valid*24*60*60;
720    
721                ke = create_GpgKeyEdit (ctx->keyid);
722                ke->setCallback (keygen_cb, NULL);
723                if (ctx->is_protected)
724                    ke->setPassphrase (ctx->pass);
725                else
726                    ke->setNoPassphrase (true);
727                keygen_cb_dlg_create ();
728    
729                err = ke->addSubkey ((gpgme_pubkey_algo_t)index, size, valid);
730                keygen->fpr = get_subkey_keyid (ctx->keyid);
731                keygen_cb_dlg_destroy (1);
732                if (err)
733                    msg_box (dlg, gpgme_strerror (err), _("Add Subkey"), MB_ERR);
734                else {
735                    msg_box (dlg, _("Subkey successfully added."),
736                             _("GnuPG Status"), MB_OK);
737                    ctx->finished = 1;
738                }
739                delete ke;
740                EndDialog (dlg, TRUE);
741                return TRUE;
742                
743            case IDCANCEL:
744                EndDialog (dlg, FALSE);
745                return FALSE;
746            }
747            break;
748        }
749        
750        return FALSE;
751    }
752    
753    
754    BOOL
755    keyedit_add_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
756    {
757        keyedit_cb_s cb;
758        keygen_cb_s keygen;
759        char *pass = NULL;
760        int cancel = 0;
761    
762        if (!k->key_pair) {
763            msg_box (dlg, _("There is no secret key available!"),
764                     _("Add user ID"), MB_ERR);
765            return FALSE;
766        }
767    
768        if (k->is_protected) {
769            pass = request_passphrase (_("Key Edit"), 1, &cancel);
770            if (cancel)
771                return FALSE;
772        }
773    
774        memset (&keygen, 0, sizeof (keygen));
775        memset (&cb, 0, sizeof cb);
776        cb.opaque = &keygen;
777        cb.is_protected = k->is_protected;
778        cb.pass = pass;
779        cb.keyid = k->keyid;
780        dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDUID,
781                          dlg, keyedit_adduid_dlg_proc,        
782                          (LPARAM)&cb, _("Add user ID"),
783                          IDS_WINPT_KEYEDIT_ADDUID);
784        if (lv != NULL && cb.finished)
785            do_add_new_userid (lv, keygen.name, keygen.email, keygen.comment);
786        if (cb.finished)
787            k->update = 1;
788    
789        free_if_alloc (keygen.name);
790        free_if_alloc (keygen.email);
791        free_if_alloc (keygen.comment);
792        sfree_if_alloc (pass);
793        return TRUE;
794    }
795    
796    
797    /* Return the keyID of the last subkey. */
798    char*
799    get_subkey_keyid (const char *keyid)
800    {
801        gpgme_error_t err;
802        gpgme_key_t key;
803        gpgme_ctx_t ctx;
804        gpgme_subkey_t subk;
805        char *kid = NULL;
806    
807        err = gpgme_new (&ctx);
808        if (err)
809            return NULL;
810        err = gpgme_get_key (ctx, keyid, &key, 0);
811        gpgme_release (ctx);
812        if (err)
813            return NULL;
814        subk = get_nth_key (key, count_subkeys (key));
815        if (subk != NULL)
816            kid = strdup (subk->keyid);
817        gpgme_key_release (key);
818        return kid;
819    }
820    
821    
822    BOOL
823    keyedit_add_subkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
824    {
825        keyedit_cb_s cb;
826        keygen_cb_s keygen;
827        char *pass = NULL;
828        int cancel = 0;
829    
830        if (!k->key_pair) {
831            msg_box (dlg, _("There is no secret key available!"),
832                     _("Add Subkey"), MB_ERR);
833            return FALSE;
834        }
835        if (k->is_protected) {
836            pass = request_passphrase (_("Key Edit"), 1, &cancel);
837            if (cancel)
838                return FALSE;
839        }
840    
841        memset (&keygen, 0, sizeof (keygen));
842        memset (&cb, 0, sizeof (cb));
843        cb.keyid = k->keyid;
844        cb.is_protected = k->is_protected;
845        cb.pass = pass;
846        cb.opaque = &keygen;
847        dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDSUBKEY,    
848                          dlg, keyedit_addsubkey_dlg_proc,
849                          (LPARAM)&cb, _("Add new Subkey"),
850                          IDS_WINPT_KEYEDIT_ADDSUBKEY);
851        if (lv != NULL && cb.finished)
852            do_add_new_subkey (lv, &keygen, 0);
853        if (cb.finished)
854            k->update = 1;
855    
856        safe_free (keygen.fpr);
857        sfree_if_alloc (pass);
858        return cb.finished? TRUE: FALSE;
859    }
860    
861    
862    BOOL
863    keyedit_set_pref_keyserver (winpt_key_t k, HWND dlg)
864    {
865        GpgKeyEdit *ke;
866        gpgme_error_t err;
867        struct URL_ctx_s *url;
868        char *pass = NULL;
869    
870        url = (struct URL_ctx_s *)get_keyserver_URL_dlg (dlg);
871        if (url->cancel == 1) {
872            delete url;
873            return FALSE;
874        }
875    
876        pass = request_passphrase (_("Key Edit"), 1, &url->cancel);
877        if (url->cancel) {
878            delete url;
879            return FALSE;
880        }
881    
882        ke = create_GpgKeyEdit (k->keyid);
883        if (k->is_protected)
884            ke->setPassphrase (pass);
885        else
886            ke->setNoPassphrase (true);
887        err = ke->setPreferredKeyserver (-1, url->url);
888        if (!err)
889            msg_box (dlg, _("Preferred keyserver successfully set."), _("Key Edit"), MB_OK);
890        else
891            msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
892    
893        sfree_if_alloc (pass);
894        delete ke;
895        delete url;
896        return err == 0? 0 : WPTERR_GENERAL;
897    }
898    
899    
900    /* Add a photo-ID to the key specified in @k. @dlg is the handle of
901       the calling dialog. */
902    BOOL
903    keyedit_add_photo (winpt_key_t k, HWND dlg)
904    {
905        keyedit_cb_s cb;
906        char *pass = NULL;
907        int cancel;
908        
909        if (!k->key_pair) {
910            msg_box (dlg, _("There is no secret key available!"),
911                     _("Add Photo"), MB_ERR);
912            return FALSE;
913        }
914    
915        memset (&cb, 0, sizeof (cb));
916        if (k->is_protected) {
917            pass = request_passphrase (_("Key Edit"), 1, &cancel);
918            if (cancel)
919                return FALSE;
920        }
921        cb.pass = pass;
922        cb.keyid = k->keyid;
923    
924        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDPHOTO, dlg,
925                        keyedit_addphoto_dlg_proc, (LPARAM)&cb);
926    
927        if (cb.finished)
928            k->update = 1;
929        sfree_if_alloc (pass);    
930        return TRUE;
931    }
932    
933    
934    BOOL
935    keyedit_add_revoker (winpt_key_t k, HWND dlg)
936    {
937        keyedit_cb_s cb;
938        char *pass = NULL;
939        int cancel;
940    
941        if (!k->key_pair) {
942            msg_box (dlg, _("There is no secret key available!"), _("Add Revoker"), MB_ERR);
943            return FALSE;
944        }
945    
946        if (k->is_protected) {
947            pass = request_passphrase (_("Key Edit"), 1, &cancel);
948            if (cancel)
949                return FALSE;
950        }
951    
952        memset (&cb, 0, sizeof (cb));
953        cb.is_protected = k->is_protected;
954        cb.keyid = k->keyid;
955        cb.pass = pass;
956        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDREV, dlg,
957                        keyedit_addrevoker_dlg_proc, (LPARAM)&cb);
958    
959        if (cb.finished)
960            k->update = 1;
961        sfree_if_alloc (pass);
962        return TRUE;
963    }
964    
965    
966    /* Change ownertrust of the given key @key.
967       Return TRUE if the ownertrust was changed. */
968    BOOL
969    keyedit_change_ownertrust (winpt_key_t key, HWND dlg)
970    {
971        int rc;
972    
973        rc = dialog_box_param (glob_hinst,
974                                 (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,
975                                 dlg, keyedit_ownertrust_dlg_proc,
976                                 (LPARAM)key, _("Change Ownertrust"),
977                                 IDS_WINPT_KEYEDIT_OWNERTRUST);
978        if (rc == TRUE) {
979            msg_box (dlg, _("Key status changed."), _("Key Edit"), MB_OK);
980            key->update = 1;
981        }
982        return rc;
983    }
984    
985    
986    /* Check if the given key is supposed to have IDEA
987       for secret key protection. */
988    static int
989    is_idea_protect_algo (const char *keyid)
990    {
991        winpt_key_s k;
992        const unsigned char *sym_prefs;
993        size_t n;
994    
995        memset (&k, 0, sizeof (k));
996        if (winpt_get_pubkey (keyid, &k))
997            BUG (0);
998        sym_prefs = k.ext->sym_prefs;
999        if (!k.is_v3)
1000            return 0;
1001        if (!sym_prefs)
1002            return 1; /* assume that only v3 keys have no symmetric cipher preferences
1003                         and thus IDEA is explicit. */
1004        for (n = 0; sym_prefs[n]; n++)
1005            ;
1006        if ((n == 0 || n == 1) && *sym_prefs == 0x01)
1007            return 1;
1008        return 0;
1009    }
1010    
1011    
1012    BOOL
1013    keyedit_change_passwd (winpt_key_t k, HWND dlg)
1014    {
1015        gpgme_error_t err;
1016        GpgKeyEdit *ke;
1017        char *old_pass = NULL;
1018        char *new_pass = NULL;
1019        int cancel = 0;
1020    
1021        if (!k->key_pair) {
1022            msg_box (dlg, _("There is no secret key available!"),
1023                     _("Key Edit"), MB_ERR);
1024            return FALSE;
1025        }
1026    
1027        if (!idea_available && is_idea_protect_algo (k->keyid)) {
1028            msg_box (dlg, _("Cannot change passphrase because the key\n"
1029                            "is protected with the IDEA encryption algorithm."),
1030                            _("Key Edit"), MB_ERR);
1031            return FALSE;
1032        }
1033    
1034        if (k->is_protected) {
1035            old_pass = request_passphrase (_("Current (old) Passphrase"), 1, &cancel);
1036            if (cancel)
1037                return FALSE;
1038        }
1039        new_pass = request_passphrase2 (_("New Passphrase" ), 1, &cancel);
1040        if (cancel) {
1041            free_if_alloc (old_pass);
1042            return FALSE;
1043        }
1044    
1045        if (is_8bit_string (new_pass)) {
1046            msg_box (dlg, _("The passphrase contains 8-bit characters.\n"
1047                             "It is not suggested to use charset specific characters."),
1048                             _("Key Edit"), MB_ERR);
1049            free_if_alloc (old_pass);
1050            free_if_alloc (new_pass);
1051            return FALSE;
1052        }
1053    
1054        ke = create_GpgKeyEdit (k->keyid);
1055        ke->setPassphrase (k->is_protected? old_pass : NULL);
1056        err = ke->changePassphrase (new_pass, 0);
1057        if (err)
1058            msg_box (dlg, gpgme_strerror (err), _("Change Passwd"), MB_ERR);
1059        else
1060            msg_box (dlg, _("Passphrase successfully changed."),  _("GnuPG status"), MB_OK);
1061        sfree_if_alloc (old_pass);
1062        sfree_if_alloc (new_pass);
1063        delete ke;
1064        return TRUE;
1065    }
1066    
1067    
1068    /* Initialize sub key list from key @k and return
1069       the new listview control. */
1070    listview_ctrl_t
1071    subkey_list_init (HWND dlg, winpt_key_t k)
1072    {
1073        LV_ITEM lvi;
1074        gpgme_subkey_t sub;
1075        struct listview_column_s cols[] = {
1076            {0, 80, (char *)_("Description")},
1077            {1, 78, (char *)_("Key ID")},
1078            {2, 66, (char *)_("Creation")},
1079            {3, 66, (char *)_("Expires")},
1080            {4, 64, (char *)_("Status")},
1081            {5, 16,  "C"/*ertify*/},
1082            {6, 16,  "S"/*ign*/},
1083            {7, 16,  "E"/*ncrypt*/},
1084            {8, 16,  "A"/*uth*/},
1085            {0, 0, 0}
1086        };
1087        listview_ctrl_t lv;
1088        char buf[256], tmp[128];
1089        const char *t;
1090        int nkeys = 0, i, bits;
1091    
1092        nkeys = count_subkeys (k->ctx);
1093        if( !nkeys ) {
1094            msg_box (dlg, _("No subkey(s) found."), _("Key Edit"), MB_ERR);
1095            return NULL;
1096        }
1097            
1098        listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
1099        for (i = 0; cols[i].fieldname != NULL; i++)
1100            listview_add_column (lv, &cols[i]);
1101            
1102        for( i = 0; i < nkeys; i++ ) {
1103            listview_add_item( lv, "" );
1104            listview_add_sub_item( lv, 0, 1, "" );
1105            memset( &lvi, 0, sizeof lvi );
1106            lvi.mask = LVIF_PARAM;  
1107            lvi.lParam = (LPARAM)k->ctx;
1108            if( ListView_SetItem( lv->ctrl, &lvi ) == FALSE )
1109                return NULL;
1110        }
1111            
1112        listview_set_ext_style( lv );
1113        for( i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next ) {
1114            memset( buf, 0, sizeof buf );
1115    
1116            bits = sub->length;
1117            _snprintf( tmp, sizeof tmp-1, "%d-bit ", bits );
1118            strcat( buf, tmp );
1119    
1120            _snprintf( tmp, sizeof tmp-1, "%s", get_key_pubalgo (sub->pubkey_algo));
1121            strcat( buf, tmp );
1122            
1123            listview_add_sub_item( lv, i, 0, buf );
1124            t = sub->keyid;
1125            if( !t )
1126                t = "DEADBEEFDEADBEEF";
1127            _snprintf( tmp, sizeof tmp-1, "0x%s", t+8 );
1128            listview_add_sub_item( lv, i, 1, tmp );
1129    
1130            t = get_key_created (sub->timestamp);
1131            if( !t )
1132                t = "????" "-??" "-??";
1133            listview_add_sub_item( lv, i, 2, t );
1134    
1135            if( sub->expires ) {
1136                t = get_key_created (sub->expires);
1137                listview_add_sub_item( lv, i, 3, t );
1138            }
1139            else
1140                listview_add_sub_item( lv, i, 3, _("Never") );
1141    
1142            if( sub->expired )
1143                t = _("Expired");
1144            else if( sub->revoked )
1145                t = _("Revoked");
1146            else
1147                t = _("OK");
1148            listview_add_sub_item( lv, i, 4, t );
1149    
1150            if (sub->can_certify) t = "*"; else t = "";
1151            listview_add_sub_item (lv, i, 5, t);
1152            if (sub->can_sign) t = "*"; else t = "";
1153            listview_add_sub_item( lv, i, 6, t );
1154            if (sub->can_encrypt) t = "*"; else t = "";
1155            listview_add_sub_item( lv, i, 7, t );
1156            if (sub->can_authenticate) t = "*"; else t = "";
1157            listview_add_sub_item (lv, i, 8, t);
1158        }
1159        return lv;
1160    }
1161    
1162    
1163    static listview_ctrl_t
1164    userid_list_init (HWND dlg, winpt_key_t k)
1165    {
1166        listview_ctrl_t lv = NULL;
1167        gpgme_key_sig_t ks;
1168        struct native_uid_s *u;
1169        int nuids = 0, j, u_attr;
1170        struct listview_column_s cols[] = {
1171            {0,  72, (char *)_("Validity")},
1172            {1, 150, (char *)_("Name")},
1173            {2, 110, (char *)_("Email")},
1174            {3,  76, (char *)_("Creation")},
1175            {0, 0, 0}
1176        };    
1177        const char *attr;
1178        
1179        nuids = count_userids (k->ctx);
1180        if (!nuids) {
1181            msg_box (dlg, _("No user ID(s) found."), _("Key Edit"), MB_ERR);
1182            return NULL;
1183        }
1184            
1185        listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST));
1186        for( j = 0; cols[j].fieldname != NULL; j++ )
1187            listview_add_column (lv, &cols[j]);
1188            
1189        for (j = 0; j < nuids; j++) {
1190            listview_add_item (lv, " ");
1191            listview_add_sub_item (lv, 0, 1, " " );        
1192        }
1193    
1194        listview_set_ext_style (lv);
1195        for (j = 0, u=k->ext->uids; j < nuids; u=u->next, j++) {
1196            if (u->revoked)
1197                attr = _("Revoked");
1198            else {
1199                u_attr = (int)u->validity;
1200                attr = get_key_trust2 (NULL, u_attr, 0, 0);
1201            }
1202            listview_add_sub_item (lv, j, UID_COL_VALID, (char *)attr);
1203            /* XXX: add comment if available */
1204            listview_add_sub_item (lv, j, UID_COL_NAME,
1205                                   u->name? u->name : _("Invalid user ID"));
1206            if (u->email)
1207                listview_add_sub_item (lv, j, UID_COL_EMAIL, u->email);
1208    
1209            ks = get_selfsig (u->signatures, k->keyid, 1);
1210            if (ks)
1211                listview_add_sub_item (lv, j, UID_COL_CREATION,
1212                                       get_key_created (ks->timestamp));
1213        }
1214        if( !k->key_pair ) {
1215            CheckDlgButton (dlg, IDC_KEYUID_ADD, BST_INDETERMINATE);
1216            CheckDlgButton (dlg, IDC_KEYUID_REVOKE, BST_INDETERMINATE);
1217        }
1218        return lv;
1219    }
1220    
1221    
1222    static void
1223    do_init_cmdlist (HWND dlg, int is_keypair)
1224    {    
1225        const char *s;
1226        int i = 0;
1227    
1228        for (i = 0; (s=cmdlist[i].name); i++) {
1229            if (is_keypair)
1230                SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1231                                    (LPARAM)(char *)s);
1232            else if (!cmdlist[i].need_pair)
1233                SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1234                                    (LPARAM)(char *)s);
1235        }
1236        SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_SETCURSEL, 0, 0);
1237    }
1238    
1239    
1240    /* Return 1 if the requested command is RFC2440. */
1241    static int
1242    is_cmd_openpgp (int cmdid)
1243    {
1244        switch (cmdid) {
1245        case CMD_ADDKEY:
1246        case CMD_ADDPHOTO:
1247        case CMD_ADDREVOKER:
1248        //case CMD_SETPREF:
1249            return 1;
1250        }
1251        return 0;
1252    }
1253    
1254    
1255    /* Display a message box with a short description of the commands. */
1256    static void
1257    do_show_help (HWND dlg)
1258    {
1259        char helptext[2048];
1260    
1261        _snprintf (helptext, sizeof (helptext)-1,
1262            _(
1263             "ADDUID   \t\tadd a user ID\r\n"
1264             "ADDPHOTO  \t\tadd a photo ID\r\n"
1265             "DELUID    \t\tdelete a user ID\r\n"
1266             "ADDKEY    \t\tadd a secondard key\r\n"
1267             "DELKEY    \t\tdelete a secondary key\r\n"
1268             "ADDREVOKER\t\tadd a revocation key\r\n"
1269             "EXPIRE    \t\tchange the expire date\r\n"
1270             "SHOWPREF  \t\tlist preferences (verbose)\r\n"
1271             "SETPREF   \t\tset preference list\r\n"
1272             "UPDPREF   \t\tupdated preferences\r\n"
1273             "PASSWD    \t\tchange the passphrase\r\n"
1274             "PRIMARY   \t\tflag user ID as primary\r\n"
1275             "TRUST     \t\tchange the ownertrust\r\n"
1276             "REVUID    \t\trevoke a user ID\r\n"
1277             "REVKEY    \t\trevoke a secondary key\r\n"
1278             "DISABLE   \t\tdisable a key\r\n"
1279             "ENABLE    \t\tenable a key\r\n"
1280             "SIGN      \t\tsign a user-id (exportable)\r\n"
1281             "LSIGN     \t\tsign a user-id (non-exportable)\r\n"
1282             "CLEAN     \t\tremove unusable signatures from key\r\n"
1283             "MINIMIZE  \t\tremove all signatures from key\r\n"
1284             ));
1285        msg_box (dlg, helptext, _("Key Edit Help"), MB_OK);
1286    }
1287    
1288    
1289    static int
1290    do_editkey_delkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1291    {
1292        gpgme_error_t err;
1293        GpgKeyEdit *ke;
1294        int j, id;
1295        char tmp[64];
1296    
1297        if (!k->key_pair)
1298            return FALSE; /* XXX: shall we allow to modify non-secret keys?? */
1299    
1300        if( listview_count_items( lv, 0 ) == 1 ) {
1301            msg_box( dlg, _("Primary key can not be deleted!"), _("Key Edit"), MB_ERR);
1302            return FALSE;
1303        }
1304        if( (j = listview_get_curr_pos( lv )) == -1 ) {
1305            msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1306            return FALSE;
1307        }
1308        if( j == 0 ) {
1309            msg_box( dlg, _("Primary subkey can not be deleted!"), _("Key Edit"), MB_ERR );
1310            return FALSE;
1311        }
1312        
1313        /* XXX: change the warning to make clear that verification won't work
1314                any longer if this is a sign-only key. */
1315        listview_get_item_text (lv, j, 0, tmp, sizeof (tmp) -1);
1316        id = log_box (_("Key Edit"), MB_YESNO|MB_ICONWARNING,
1317                        _("\"Subkey %s.\"\n\n"
1318                          "Anything encrypted to the selected subkey will no longer\n"
1319                          "be able to be decrypted.\n\n"
1320                          "Do you really want to delete this subkey?"), tmp);
1321        if (id == IDNO)
1322            return FALSE;
1323    
1324        ke = new GpgKeyEdit (k->keyid);
1325        if (!ke)
1326            BUG (NULL);
1327        err = ke->delKey (j);
1328        if (err)
1329            msg_box (dlg, gpgme_strerror (err), _("Delete Subkey"), MB_ERR);
1330        else {
1331            listview_del_item (lv, j);
1332            k->update = 1;
1333            status_box (dlg, _("Subkey successfully deleted."), _("GnuPG status"));
1334        }
1335        delete ke;
1336        return err? FALSE : TRUE;
1337    }
1338    
1339    
1340    /* Set the expiration date for the selected key in list view @lv.
1341       Return value: TRUE on success. */
1342    static int
1343    do_editkey_expire (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1344    {
1345        gpgme_error_t err;
1346        GpgKeyEdit *ke;
1347        date_s udd = {0};
1348        char buf[256], * pass = NULL;
1349        int j, cancel = 0;
1350    
1351        if (!k->key_pair) {
1352            msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1353            return FALSE;
1354        }
1355        if ((j = listview_get_curr_pos (lv)) == -1) {
1356            msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1357            return FALSE;
1358        }
1359    
1360        /* If a key already expired, it is possible the user wants to
1361           set a new expiration date.. */  
1362        listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, sizeof buf -1);
1363        if (!strcmp (buf, _("Expired"))) {
1364            cancel = msg_box (dlg, _("Key already expired.\n\n"
1365                              "Do you want to change the expiration date?"),
1366                              _("Key Edit"), MB_QUEST_ASK);
1367            if (cancel == IDNO)
1368                return FALSE;
1369            cancel = 0;
1370        }
1371    
1372        memset (&udd, 0, sizeof udd);
1373        udd.text = _("Key Expiration Date");
1374        dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_DATE, dlg,    
1375                          date_dlg_proc, (LPARAM)&udd,
1376                          _("Key Expiration Date"), IDS_WINPT_DATE);
1377        if (udd.cancel == 1)
1378            return FALSE;
1379        if (!keygen_check_date (&udd.st)) {
1380            msg_box (dlg, _("The date you have chosen lies in the past."),
1381                     _("Key Edit"), MB_ERR);
1382            return FALSE;
1383        }
1384        if( k->is_protected ) {
1385            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1386            if (cancel)
1387                return FALSE;
1388        }
1389    
1390        ke = new GpgKeyEdit (k->keyid);
1391        if (!ke)
1392            BUG (NULL);
1393        if (k->is_protected)
1394            ke->setPassphrase (pass);
1395        else
1396            ke->setNoPassphrase (true);
1397        err = ke->setKeyExpireDate (j, w32_mktime (&udd.st), false);
1398        if (err)
1399            msg_box (dlg, gpgme_strerror (err), _("Expire Subkey"), MB_ERR);
1400        else {
1401            _snprintf (buf, sizeof buf - 1, "%04d-%02d-%02d",      
1402                       udd.st.wYear, udd.st.wMonth, udd.st.wDay);
1403            listview_add_sub_item (lv, j, SUBK_COL_EXPIRES, buf);
1404            k->update = 1;
1405            msg_box (dlg, _("Subkey expire date successfully set."),
1406                     _("GnuPG status"), MB_OK);
1407        }
1408        sfree_if_alloc (pass);
1409        delete ke;
1410        return TRUE;
1411    }
1412    
1413    
1414    /* Revoke the selected key in the list view @lv. @k contains
1415       control information about the global key.
1416       Return value: TRUE on success. */
1417    static int
1418    do_editkey_revoke (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1419    {
1420        gpgme_error_t err;
1421        GpgKeyEdit *ke;
1422        char buf[256];
1423        char *pass = NULL;
1424        int j, cancel = 0;
1425    
1426        if (!k->key_pair) {
1427            msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1428            return FALSE;
1429        }
1430    
1431        if ((j = listview_get_curr_pos (lv)) == -1) {
1432            msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1433            return FALSE;
1434        }
1435        else if (listview_count_items (lv, 0) == 1) {
1436            msg_box( dlg, _("No subkeys were found, if you want to revoke the\n"
1437                            "whole key, please use the Key Manager command directly.\n\n"
1438                            "This command is only available to revoke single subkeys"),
1439                     _("Key Edit"), MB_INFO );
1440            return FALSE;
1441        }
1442                
1443        listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, sizeof (buf)-1);
1444        if (!strcmp (buf, _("Revoked"))) {
1445            msg_box (dlg, _("Key already revoked."), _("Key Edit"), MB_ERR);
1446            return FALSE;
1447        }
1448        
1449        if (k->is_protected) {
1450            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1451            if (cancel)
1452                return FALSE;          
1453        }
1454    
1455        ke = new GpgKeyEdit (k->keyid);
1456        if (!ke)
1457            BUG (NULL);
1458        if (k->is_protected)
1459            ke->setPassphrase (pass);
1460        else
1461            ke->setNoPassphrase (true);
1462        err = ke->revokeSubkey (j, 0, NULL);
1463        if (err)
1464            msg_box( dlg, gpgme_strerror (err), _("Revoke Subkey"), MB_ERR);
1465        else {
1466            listview_add_sub_item (lv, j, SUBK_COL_STATUS, _("Revoked"));
1467            k->update = 1;
1468            msg_box( dlg, _("Subkey successfully revoked."), _("GnuPG Status"), MB_OK );
1469        }
1470        sfree_if_alloc (pass);
1471        delete ke;
1472        return TRUE;
1473    }
1474    
1475    
1476    /* Revoked the selected userid in list view @lv.
1477       Return value: TRUE on success. */
1478    int
1479    do_editkey_revuid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1480    {
1481        gpgme_error_t err;
1482        GpgKeyEdit *ke;
1483        char buf[128], email[128];
1484        char inf[512];
1485        char *pass = NULL;
1486        int cancel = 0, id = 0, j;
1487    
1488        if (!k->key_pair) {
1489            msg_box (dlg, _("There is no secret key available!"),
1490                     _("Revoke user ID"), MB_ERR);
1491            return FALSE;
1492        }
1493    
1494        if (listview_count_items (lv, 0) == 1) {
1495            msg_box (dlg, _("Key has only one user ID."), _("Key Edit"), MB_ERR);  
1496            return FALSE;
1497        }
1498    
1499        if( (j = listview_get_curr_pos( lv )) == -1 ) {
1500            msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );  
1501            return FALSE;  
1502        }
1503                
1504        listview_get_item_text( lv, j, UID_COL_VALID, buf, sizeof buf - 1);
1505        if (strstr (buf, _("Revoked"))) {
1506            msg_box (dlg, _("This user ID has been already revoked."),
1507                     _("Key Edit"), MB_INFO);
1508            return FALSE;
1509        }
1510                
1511        listview_get_item_text (lv, j, UID_COL_NAME, buf, sizeof buf -1);
1512        _snprintf (inf, sizeof (inf) -1, _("user ID \"%s\".\n\n"
1513                   "Do you really want to revoke this user ID?"), buf);
1514        if (msg_box (dlg, inf, _("Key Edit"), MB_WARN_ASK) == IDNO)
1515            return FALSE;
1516        if (k->is_protected) {
1517            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1518            if (cancel)
1519                return FALSE;          
1520        }
1521        listview_get_item_text (lv, j, UID_COL_EMAIL, email, sizeof (email)-1);
1522        listview_get_item_text (lv, j, UID_COL_NAME, buf, sizeof (buf)-1);
1523        id = do_find_userid (k->keyid, email, buf, NULL);
1524        if (id == -1)
1525            BUG (NULL);
1526    
1527        ke = new GpgKeyEdit (k->keyid);
1528        if (!ke)
1529            BUG (NULL);
1530        if (k->is_protected)
1531            ke->setPassphrase (pass);
1532        else
1533            ke->setNoPassphrase (true);
1534        err = ke->revokeUserid (id);
1535        if (err)
1536            msg_box (dlg, gpgme_strerror (err), _("Revoke User ID"), MB_ERR);
1537        else {
1538            listview_add_sub_item (lv, j, 0, _("Revoked"));
1539            k->update = 1;
1540            status_box (dlg, _("User ID successfully revoked"), _("GnuPG Status"));
1541        }
1542        sfree_if_alloc (pass);
1543        delete ke;
1544        return err? FALSE : TRUE;
1545    }
1546    
1547    
1548    static int
1549    do_editkey_setpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1550    {
1551        gpgme_error_t rc;
1552        GpgKeyEdit *ke;
1553        char buf[256], * pass = NULL, * prefs;
1554        int j, id, cancel=0, flags=0;
1555    
1556        if ((j = listview_get_curr_pos (lv)) == -1) {
1557            msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1558            return FALSE;
1559        }
1560        listview_get_item_text (lv, j, 2, buf, sizeof buf-1);
1561        id = do_find_userid (k->keyid, buf, NULL, NULL);
1562        if (id == -1)
1563            BUG (dlg);
1564        if (k->is_protected) {
1565            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1566            if (cancel)
1567                return FALSE;
1568        }
1569    
1570        ke = new GpgKeyEdit (k->keyid);
1571        if (!ke)
1572            BUG (NULL);
1573        if (k->is_protected)
1574            ke->setPassphrase (pass);
1575        else
1576            ke->setNoPassphrase (true);
1577    
1578        get_userid_preflist (&prefs, &flags);
1579    
1580        rc = ke->setUseridPreferences (id, prefs);
1581        if (rc)
1582            msg_box (dlg, _("Could not set user ID preferences"), _("Key Edit"), MB_ERR);
1583    
1584        sfree_if_alloc (pass);
1585        free_if_alloc (prefs);
1586        delete ke;
1587        return 0;
1588    }
1589    
1590    
1591    static int
1592    do_editkey_primary (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1593    {
1594        gpgme_error_t err;
1595        GpgKeyEdit *ke;
1596        int j, id, cancel=0;
1597        char buf[256], *pass = NULL;
1598    
1599        if (listview_count_items (lv, 0) == 1)
1600            return TRUE;
1601        if ((j = listview_get_curr_pos (lv)) == -1) {
1602            msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
1603            return FALSE;
1604        }
1605        listview_get_item_text (lv, j, 2, buf, sizeof buf-1);
1606        id = do_find_userid (k->keyid, buf, NULL, NULL);
1607        if (id == -1)
1608            BUG (0);
1609        if (k->is_protected) {
1610            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1611            if (cancel)
1612                return FALSE;
1613        }
1614    
1615        ke = new GpgKeyEdit (k->keyid);
1616        if (k->is_protected)
1617            ke->setPassphrase (pass);
1618        else
1619            ke->setNoPassphrase (true);
1620        err = ke->setPrimaryUserid (id);
1621        if (err)
1622            msg_box (dlg, gpgme_strerror (err), _("Primary"), MB_ERR);
1623        else {
1624            k->update = 1;
1625            status_box (dlg, _("User ID successfully flagged"), _("GnuPG Status"));
1626        }
1627    
1628        sfree_if_alloc (pass);
1629        delete ke;
1630        return err? FALSE : TRUE;
1631    }
1632    
1633    
1634    
1635    #define CIPHER  11
1636    #define HASH    11
1637    #define COMPR    4
1638    
1639    static int
1640    parse_preflist (HWND dlg, const char *list)
1641    {
1642        char buf[128] = {0};
1643        char *p, *pbuf = buf;
1644        const char *ciphers[CIPHER] = {"", "IDEA", "3DES",
1645                                       "CAST5", "BLOWFISH", "", "",
1646                                       "AES", "AES192", "AES256", "TWOFISH"};
1647        const char *hash[HASH] = {"", "MD5", "SHA1", "RMD160", "",
1648                                  "", "", "", "SHA256", "SHA384", "SHA512"};
1649        const char *compress[COMPR] = {"", "ZIP", "ZLIB", "BZIP2"};
1650        int n=0;
1651    
1652        strncpy (buf, list, 127);
1653        p = strtok (pbuf, " ");
1654        while (p != NULL) {
1655            int algid = atol (p+1);
1656            n++;
1657            switch (*p) {
1658            case 'S':
1659                SendDlgItemMessage (dlg, IDC_SHOWPREF_CIPHERS, LB_ADDSTRING, 0,
1660                                    (LPARAM)(const char*)ciphers[algid % CIPHER]);
1661                break;
1662    
1663            case 'H':
1664                SendDlgItemMessage (dlg, IDC_SHOWPREF_HASH, LB_ADDSTRING, 0,
1665                                    (LPARAM)(const char*)hash[algid % HASH]);
1666                break;
1667    
1668            case 'Z':
1669                SendDlgItemMessage (dlg, IDC_SHOWPREF_ZIP, LB_ADDSTRING, 0,
1670                                    (LPARAM)(const char*)compress[algid % COMPR]);
1671                break;
1672    
1673            default:
1674                n--;
1675            }
1676            p = strtok (NULL, " ");
1677        }
1678        return n;
1679    }
1680    
1681    
1682    /* Dialog box procedure to show the key preferences. */
1683    BOOL CALLBACK
1684    showpref_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1685    {
1686        static keyedit_cb_t cb = NULL;
1687        gpg_uid_info_t inf=NULL, u;
1688        gpgme_key_t key;
1689        char buf[128];
1690        int pos;
1691    
1692        switch (msg) {
1693        case WM_INITDIALOG:
1694            cb = (keyedit_cb_t)lparam;
1695            if (!cb)
1696                BUG (NULL);
1697            key = (gpgme_key_t)cb->opaque;
1698            listview_get_item_text (cb->lv, cb->lv_pos,
1699                                    UID_COL_EMAIL, buf, sizeof (buf)-1);
1700            pos = do_find_userid (cb->keyid, buf, NULL, &inf);
1701            if (pos < 0 || !inf) {
1702                gpg_uid_info_release (inf);
1703                EndDialog (dlg, FALSE);
1704                break;
1705            }
1706            for (u=inf; u; u = u->next) {
1707                if (u->index == pos && u->prefs && *u->prefs) {
1708                    _snprintf (buf, sizeof (buf)-1, "%s", u->name);
1709                    SetDlgItemText (dlg, IDC_SHOWPREF_INFO, buf);
1710                    if (parse_preflist (dlg, u->prefs) <= 0)
1711                        pos = -1;
1712                    if (u->flags.mdc)
1713                        CheckDlgButton (dlg, IDC_SHOWPREF_MDC, BST_CHECKED);
1714                    break;
1715                }
1716            }
1717            gpg_uid_info_release (inf);
1718            if (pos == -1) {        
1719                msg_box (dlg, _("No preferences available."), _("Key Edit"), MB_ERR);
1720                EndDialog (dlg, FALSE);
1721                break;
1722            }
1723            SetDlgItemText (dlg, IDC_SHOWPREF_MDC, _("MDC feature"));
1724            SetDlgItemText (dlg, IDC_SHOWPREF_PREFINF, _("Preferences"));
1725            SetDlgItemText (dlg, IDC_SHOWPREF_UIDHINT, _("user ID:"));
1726            SetWindowText (dlg, _("Key Preferences"));
1727            SetForegroundWindow (dlg);
1728            break;
1729    
1730        case WM_COMMAND:
1731            switch (LOWORD (wparam)) {
1732            case IDOK:
1733                EndDialog (dlg, TRUE);
1734                break;
1735    
1736            case IDCANCEL:
1737                EndDialog (dlg, FALSE);
1738                break;
1739            }
1740            break;
1741        }
1742        return FALSE;
1743    }
1744    
1745    
1746    static int
1747    do_editkey_showpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1748    {
1749        struct keyedit_cb_s cb;
1750        char status[32];
1751    
1752        if (k->is_v3)
1753            return TRUE;
1754    
1755        if (listview_get_curr_pos (lv) == -1) {
1756            msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1757            return FALSE;
1758        }
1759        memset (&cb, 0, sizeof (cb));
1760        cb.opaque = k->ctx;
1761        cb.keyid = k->keyid;
1762        cb.lv = lv;
1763        cb.lv_pos = listview_get_curr_pos (lv);
1764    
1765        listview_get_item_text (lv, cb.lv_pos, UID_COL_VALID,
1766                                status, sizeof (status)-1);
1767        if (!strcmp (status, _("Revoked")))
1768            return TRUE;
1769        
1770        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_SHOWPREF, dlg,
1771                        showpref_dlg_proc, (LPARAM)&cb);
1772        return TRUE;
1773    }
1774    
1775    
1776    static int
1777    do_editkey_deluid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1778    {
1779        gpgme_error_t err;
1780        GpgKeyEdit *ke;
1781        char email[128], name[128];
1782        char inf[384];
1783        int j, id = 0;
1784    
1785        if (!k->key_pair)
1786            return FALSE; /* XXX: see do_editkey_delsubkey */
1787    
1788        if (listview_count_items (lv, 0) == 1) {
1789            msg_box (dlg, _("Primary user ID can not be deleted!"),
1790                     _("Key Edit"), MB_ERR);
1791            return FALSE;
1792        }
1793        if ((j = listview_get_curr_pos (lv)) == -1) {
1794            msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1795            return FALSE;
1796        }
1797        
1798        /* XXX: add a hint that also all signatures will be deleted? */
1799        listview_get_item_text (lv, j, UID_COL_NAME, name, DIM(name) -1);
1800        _snprintf (inf, DIM (inf)-1, _("user ID \"%s\".\n\n"
1801                                       "All signatures on this user ID will be also deleted."
1802                                       "\n\n"
1803                                       "Do you really want to delete this user ID?"),
1804                                   name);
1805        if (msg_box (dlg, inf, _("Key Edit"), MB_YESNO|MB_ICONWARNING) == IDNO)
1806            return FALSE;
1807        
1808        listview_get_item_text (lv, j, UID_COL_EMAIL, email, DIM (email)-1);
1809        listview_get_item_text (lv, j, UID_COL_NAME, name, DIM (name)-1);
1810        id = do_find_userid (k->keyid, email, name, NULL);
1811        if (id == -1)
1812            BUG (dlg);
1813    
1814        ke = new GpgKeyEdit (k->keyid);
1815        if (!ke)
1816            BUG (NULL);
1817    
1818        err = ke->delUserid (id);
1819        if (err)
1820            msg_box (dlg, gpgme_strerror (err), _("Delete user ID"), MB_ERR);
1821        else {
1822            listview_del_item (lv, j);
1823            k->update = 1;
1824            status_box (dlg, _("User ID successfully deleted"), _("GnuPG Status"));
1825        }
1826        delete ke;
1827        return err? FALSE : TRUE;
1828    }
1829    
1830    
1831    /* Subclass routine for the subkey listview control to allow shortcuts. */
1832    static BOOL CALLBACK
1833    subkey_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1834    {
1835        int virt_key = 0;
1836        winpt_key_t key;
1837    
1838        switch (msg) {
1839        case WM_KEYUP:
1840            virt_key = (int)wparam;
1841            key = (winpt_key_t)keyedit_subkey_proc.opaque;
1842            if (!key || !key->key_pair)
1843                break;
1844    
1845            switch (virt_key) {
1846            case VK_DELETE:
1847                SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1848                                    CB_SETCURSEL, CMD_DELKEY, 0);
1849                send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
1850                break;
1851    
1852            case VK_INSERT:
1853                SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1854                                    CB_SETCURSEL, CMD_ADDKEY, 0);
1855                send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
1856                break;
1857            }
1858        }
1859        return CallWindowProc (keyedit_subkey_proc.old, dlg, msg, wparam, lparam);
1860    }
1861    
1862    
1863    static BOOL CALLBACK
1864    uid_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1865    {
1866        int virt_key = 0;
1867        winpt_key_t key;
1868    
1869        switch (msg) {
1870        case WM_KEYUP:
1871            virt_key = (int)wparam;
1872            key = (winpt_key_t)keyedit_uid_proc.opaque;
1873            if (!key || !key->key_pair)
1874                break;
1875    
1876            switch (virt_key) {
1877            case VK_DELETE:
1878                SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1879                                    CB_SETCURSEL, CMD_DELUID, 0);
1880                send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1881                break;
1882    
1883            case VK_INSERT:
1884                SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1885                                    CB_SETCURSEL, CMD_ADDUID, 0);
1886                send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1887                break;
1888            }
1889        }
1890        return CallWindowProc (keyedit_uid_proc.old, dlg, msg, wparam, lparam);
1891    }
1892    
1893    
1894    /* Enable the key @k when @enable is 1, disable it otherwise. */
1895    static void
1896    do_editkey_enable_disable (winpt_key_t k, HWND dlg,
1897                               listview_ctrl_t lv, int enable)
1898    {
1899        km_enable_disable_key (lv, dlg, 0, enable);
1900        k->update = 1;
1901    }
1902    
1903    
1904    /* Return default secret key. */
1905    static gpgme_key_t
1906    get_default_key (void)
1907    {
1908        gpgme_key_t def_sk;
1909        char *keyid = get_gnupg_default_key ();
1910    
1911        get_seckey (keyid, &def_sk);
1912        free_if_alloc (keyid);
1913        return def_sk;
1914    }
1915    
1916    
1917    
1918    static void
1919    do_editkey_minimize (winpt_key_t k, HWND dlg)
1920    {
1921        gpgme_error_t err;
1922        GpgKeyEdit *ke;
1923    
1924        ke = create_GpgKeyEdit (k->keyid);
1925        err = ke->minimizeKey ();
1926        if (err)
1927            msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
1928        else {
1929            msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
1930            k->update = 1;
1931        }
1932        delete ke;
1933    }
1934    
1935    
1936    static void
1937    do_editkey_clean (winpt_key_t k, HWND dlg)
1938    {
1939        gpgme_error_t err;
1940        GpgKeyEdit *ke;
1941        
1942        ke = create_GpgKeyEdit (k->keyid);
1943        err = ke->cleanKey ();
1944        if (err)
1945            msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);  
1946        else {
1947            msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
1948            k->update = 1;
1949        }
1950        delete ke;
1951    }
1952    
1953    
1954    /* Start the dialog to list and display the status of all
1955       signatures for this key. */
1956    static void
1957    do_editkey_check (winpt_key_t k, HWND dlg)
1958    {
1959        if (!k->ctx)
1960            get_pubkey (k->keyid, &k->ctx);
1961        if (!k->uid && k->ctx)
1962            k->uid = k->ctx->uids->uid;
1963        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYSIG_TREE, dlg,
1964                        sigtree_dlg_proc, (LPARAM)k);
1965    }
1966    
1967    
1968    static int
1969    do_editkey_sign_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv, int mode)
1970    {
1971        gpgme_error_t err;
1972        GpgKeyEdit *ke;
1973        char *pass = NULL;
1974        char email[64], name[128];
1975        int uid_index;
1976        int cancel = 0;
1977    
1978        uid_index = listview_get_curr_pos (lv);
1979        if (uid_index == -1) {
1980            msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1981            return FALSE;
1982        }
1983        if (mode == CMD_SIGN) {
1984            cancel = msg_box (dlg, _("Do you really want to make this sig exportable?"),
1985                              _("Key Edit"), MB_QUEST_ASK);
1986            if (cancel == IDNO)
1987                return FALSE;
1988        }
1989    
1990        listview_get_item_text (lv, uid_index, UID_COL_EMAIL, email, sizeof (email)-1);
1991        listview_get_item_text (lv, uid_index, UID_COL_NAME, name, sizeof (name)-1);
1992        uid_index = do_find_userid (k->keyid, email, name, NULL);
1993        if (k->is_protected) {
1994            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1995            if (cancel)
1996                return FALSE;
1997        }
1998        ke = create_GpgKeyEdit (k->keyid);
1999        if (k->is_protected)
2000            ke->setPassphrase (pass);
2001        else
2002            ke->setNoPassphrase (true);
2003        ke->setLocalUser (get_default_key ());
2004        err = ke->signUserid (uid_index,
2005                              mode == CMD_SIGN? GPG_EDITKEY_SIGN : GPG_EDITKEY_LSIGN,
2006                              0, NULL);
2007        if (!err) {
2008            msg_box (dlg, _("Key successfully signed."), _("Key Edit"), MB_OK);
2009            k->update = 1;
2010        }
2011        else
2012            msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
2013        delete ke;
2014        sfree_if_alloc (pass);
2015        return !err? TRUE : FALSE;
2016    }
2017    
2018    
2019    static int
2020    lookup_cmd (HWND dlg)
2021    {
2022        char buf[64];
2023        int i;
2024    
2025        i = SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_GETCURSEL, 0, 0);
2026        if (i == LB_ERR)
2027            return LB_ERR;
2028        GetDlgItemText (dlg, IDC_KEYEDIT_CMD, buf, sizeof (buf)-1);
2029        for (i=0; cmdlist[i].name != NULL; i++) {
2030            if (!strcmp (buf, cmdlist[i].name))
2031                return cmdlist[i].id;
2032        }
2033        return LB_ERR;
2034    }
2035    
2036    
2037    
2038    gpgme_error_t key_get_revokers (winpt_key_t key, int reload,
2039                                    gpg_desig_rev_t *r_rev);
2040    
2041    /* Check if the key supports designated revokers and if
2042        secret keys exist to generate such a revoke cert. */
2043    static bool
2044    check_desig_rev (winpt_key_t key)
2045    {
2046        gpg_desig_rev_t rev, u;
2047        struct winpt_key_s sk;
2048    
2049        if (!key->ext->gloflags.has_desig_rev)
2050            return false;
2051        key_get_revokers (key, 0, &rev);
2052        for (u = rev; u; u = u->next) {
2053            memset (&sk, 0, sizeof (sk));
2054            if (!winpt_get_seckey (u->fpr+32, &sk))
2055                return true;
2056        }
2057        return false;
2058    }
2059    
2060    
2061    /* Use the gpg --desig-revoker command to create a revocation
2062       cert for a key that lists our key as a designated revoker. */
2063    static void
2064    gen_desig_revoke_cert (winpt_key_t key, HWND dlg)
2065    {
2066        const char *warn;
2067        char *inf, *p;
2068        int id;
2069    
2070        inf = km_key_get_info (key, 0);
2071        warn = _("Your keys is listed as a designated revoker for the key\n\n"
2072                 "%s\n\n"
2073                 "Are you sure you want to create a revocation certificate\n"
2074                 "which allow to revoke the key listed above?");
2075        p = new char[strlen (inf)+1+strlen (warn)+1];
2076        sprintf (p, warn, inf);
2077        free_if_alloc (inf);
2078    
2079        id = msg_box (dlg, p, _("Key Edit"), MB_YESNO|MB_ICONWARNING);
2080        free_if_alloc (p);
2081        if (id == IDNO)
2082            return;
2083    
2084        key->internal = 1;
2085        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKE, dlg,
2086                        key_revoke_dlg_proc, (LPARAM)key);
2087    }
2088    
2089    
2090    /* Dialog box procedure for the edit key dialog. */
2091    BOOL CALLBACK
2092    keyedit_main_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
2093    {
2094        static winpt_key_t k;
2095        static listview_ctrl_t lvsub = NULL, lvuid = NULL;
2096        int cmd;
2097        HWND item;
2098    
2099        switch (msg) {
2100        case WM_INITDIALOG:
2101            k = (winpt_key_t)lparam;
2102            if (!k)
2103                BUG (NULL);
2104            do_init_cmdlist (dlg, k->key_pair);
2105            lvsub = subkey_list_init (dlg, k);
2106            if (!lvsub)
2107                BUG (0);
2108            lvuid = userid_list_init (dlg, k);
2109            if (!lvuid)
2110                BUG (0);
2111            item = GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST);
2112            keyedit_subkey_proc.opaque = (void*)k;
2113            keyedit_subkey_proc.dlg = dlg;
2114            keyedit_subkey_proc.current = (WNDPROC)subkey_subclass_proc;
2115            keyedit_subkey_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
2116            if (keyedit_subkey_proc.old) {
2117                if( !SetWindowLong (item, GWL_WNDPROC,
2118                                    (LONG)keyedit_subkey_proc.current)) {
2119                    msg_box (dlg, _("Could not set subkey window procedure."),
2120                             _("Key Edit"), MB_ERR);
2121                    BUG (0);
2122                }
2123            }
2124            item = GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST);
2125            keyedit_uid_proc.opaque = (void*)k;
2126            keyedit_uid_proc.dlg = dlg;
2127            keyedit_uid_proc.current = (WNDPROC)uid_subclass_proc;
2128            keyedit_uid_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
2129            if (keyedit_uid_proc.old) {
2130                if (!SetWindowLong (item, GWL_WNDPROC,
2131                                    (LONG)keyedit_uid_proc.current)) {
2132                    msg_box (dlg, _("Could not set user ID window procedure."),
2133                             _("Key Edit"), MB_ERR);
2134                    BUG (0);
2135                }
2136            }
2137            if (k->ctx->revoked) {
2138                EnableWindow (GetDlgItem (dlg, IDC_KEYEDIT_CMD), FALSE);
2139                EnableWindow (GetDlgItem (dlg, IDOK), FALSE);
2140            }
2141            SetDlgItemText (dlg, IDC_KEYEDIT_CMDINF, _("Command>"));
2142            SetDlgItemText (dlg, IDCANCEL, _("&Close"));
2143            SetDlgItemText (dlg, IDC_KEYEDIT_HELP, _("&Help"));
2144            SetDlgItemText (dlg, IDC_KEYEDIT_REVOKE, _("&Revoke..."));
2145            if (!check_desig_rev (k))
2146                ShowWindow (GetDlgItem (dlg, IDC_KEYEDIT_REVOKE), SW_HIDE);
2147            SetWindowText (dlg, _("Key Edit"));
2148            SetForegroundWindow (dlg);
2149            center_window (dlg, NULL);
2150            return TRUE;
2151    
2152        case WM_DESTROY:
2153            if (lvsub) {
2154                listview_release (lvsub);
2155                lvsub = NULL;
2156            }
2157            if (lvuid) {
2158                listview_release (lvuid);
2159                lvuid = NULL;
2160            }
2161            break;
2162    
2163        case WM_NOTIFY:
2164            NMHDR * notify;
2165            notify = (NMHDR *)lparam;
2166            if (notify && notify->code == NM_DBLCLK &&
2167                notify->idFrom == IDC_KEYEDIT_UIDLIST)
2168                do_editkey_showpref (k, dlg, lvuid);
2169            break;
2170    
2171        case WM_COMMAND:
2172            switch( LOWORD( wparam ) ) {
2173            case IDOK:
2174                cmd = lookup_cmd (dlg);
2175                if (cmd == LB_ERR) {
2176                    msg_box( dlg, _("Please select a command."), _("Key Edit"), MB_INFO );
2177                    return FALSE;
2178                }
2179                if (k->is_v3 && is_cmd_openpgp (cmd)) {
2180                    msg_box (dlg, _("This command cannot be used with PGP 2 (v3) keys.\n"),
2181                                    _("Key Edit"), MB_ERR);
2182                    return FALSE;
2183                }
2184                switch (cmd) {
2185                case CMD_SHOWPREF: do_editkey_showpref (k, dlg, lvuid); break;
2186                case CMD_DELKEY: do_editkey_delkey (k, dlg, lvsub); break;
2187                case CMD_ADDKEY: keyedit_add_subkey (k, dlg, lvsub); break;
2188                case CMD_EXPIRE: do_editkey_expire (k, dlg, lvsub); break;
2189                case CMD_REVKEY: do_editkey_revoke (k, dlg, lvsub); break;
2190                /*case CMD_SETPREF:do_editkey_setpref( k, dlg, lvuid ); break;*/
2191                case CMD_ADDUID: keyedit_add_userid( k, dlg, lvuid ); break;
2192                case CMD_ADDREVOKER: keyedit_add_revoker( k, dlg ); break;
2193                case CMD_ADDPHOTO: keyedit_add_photo( k, dlg ); break;
2194                case CMD_REVUID: do_editkey_revuid( k, dlg, lvuid ); break;
2195                case CMD_DELUID: do_editkey_deluid( k, dlg, lvuid ); break;
2196                case CMD_PASSWD: keyedit_change_passwd( k, dlg ); break;
2197                case CMD_PRIMARY: do_editkey_primary( k, dlg, lvuid ); break;
2198                case CMD_ENABLE: do_editkey_enable_disable (k, dlg, lvsub, 1); break;
2199                case CMD_DISABLE: do_editkey_enable_disable (k, dlg, lvsub, 0); break;
2200                case CMD_CHECK: do_editkey_check (k, dlg); break;
2201                case CMD_TRUST: keyedit_change_ownertrust (k, dlg); break;
2202                case CMD_SIGN:
2203                case CMD_LSIGN: do_editkey_sign_userid (k, dlg,
2204                                                        lvuid, cmd);
2205                                break;
2206                case CMD_CLEAN: do_editkey_clean (k, dlg);
2207                case CMD_MINIMIZE: do_editkey_minimize (k, dlg);
2208                }
2209                break;
2210                
2211            case IDCANCEL:
2212                EndDialog (dlg, FALSE);
2213                break;
2214    
2215            case IDC_KEYEDIT_HELP:
2216                do_show_help (dlg);
2217                break;
2218    
2219            case IDC_KEYEDIT_REVOKE:
2220                gen_desig_revoke_cert (k, dlg);
2221                break;
2222            }
2223            break;
2224        }
2225        return FALSE;
2226    }

Legend:
Removed from v.20  
changed lines
  Added in v.211

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26