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

Legend:
Removed from v.2  
changed lines
  Added in v.314

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26