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

Legend:
Removed from v.19  
changed lines
  Added in v.181

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26