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

Legend:
Removed from v.25  
changed lines
  Added in v.190

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26