/[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 187 by twoaday, Wed Mar 22 11:04:20 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 (!strchr (email, '@' ) || strchr (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    
886        sfree_if_alloc (pass);
887        delete ke;
888        delete url;
889        return err == 0? 0 : WPTERR_GENERAL;
890    }
891    
892    
893    /* Add a photo-ID to the key specified in @k. @dlg is the handle of
894       the calling dialog. */
895    BOOL
896    keyedit_add_photo (winpt_key_t k, HWND dlg)
897    {
898        if (!k->key_pair) {
899            msg_box (dlg, _("There is no secret key available!"),
900                     _("Add Photo"), MB_ERR);
901            return FALSE;
902        }
903        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDPHOTO, dlg,
904                        keyedit_addphoto_dlg_proc, (LPARAM)k);
905        return TRUE;
906    }
907    
908    
909    BOOL
910    keyedit_add_revoker (winpt_key_t k, HWND dlg)
911    {
912        if (!k->key_pair) {
913            msg_box (dlg, _("There is no secret key available!"), _("Add Revoker"), MB_ERR);
914            return FALSE;
915        }
916        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDREV, dlg,
917                        keyedit_addrevoker_dlg_proc, (LPARAM)k);
918        return TRUE;
919    }
920    
921    
922    /* Change ownertrust of the given key @key.
923       Return TRUE if the ownertrust was changed. */
924    BOOL
925    keyedit_change_ownertrust (winpt_key_t key, HWND dlg)
926    {
927        int rc;
928    
929        rc = dialog_box_param (glob_hinst,
930                                 (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,
931                                 dlg, keyedit_ownertrust_dlg_proc,
932                                 (LPARAM)key, _("Change Ownertrust"),
933                                 IDS_WINPT_KEYEDIT_OWNERTRUST);
934        if (rc == TRUE) {
935            msg_box (dlg, _("Key status changed."), _("Key Edit"), MB_OK);
936            key->update = 1;
937        }
938        return rc;
939    }
940    
941    
942    /* Check if the given key is supposed to have IDEA
943       for secret key protection. */
944    static int
945    is_idea_protect_algo (const char *keyid)
946    {
947        winpt_key_s k;
948        const unsigned char *sym_prefs;
949        size_t n;
950    
951        memset (&k, 0, sizeof (k));
952        if (winpt_get_pubkey (keyid, &k))
953            BUG (0);
954        sym_prefs = k.ext->sym_prefs;
955        if (!k.is_v3)
956            return 0;
957        if (!sym_prefs)
958            return 1; /* assume that only v3 keys have no symmetric cipher preferences
959                         and thus IDEA is explicit. */
960        for (n = 0; sym_prefs[n]; n++)
961            ;
962        if ((n == 0 || n == 1) && *sym_prefs == 0x01)
963            return 1;
964        return 0;
965    }
966    
967    
968    BOOL
969    keyedit_change_passwd (winpt_key_t k, HWND dlg)
970    {
971        gpgme_error_t ec;
972        GpgKeyEdit *ke;
973        char *old_pass = NULL;
974        char *new_pass = NULL;
975        int cancel = 0;
976    
977        if (!k->key_pair) {
978            msg_box (dlg, _("There is no secret key available!"),
979                     _("Key Edit"), MB_ERR);
980            return FALSE;
981        }
982    
983        if (!idea_available && is_idea_protect_algo (k->keyid)) {
984            msg_box (dlg, _("Cannot change passphrase because the key\n"
985                            "is protected with the IDEA encryption algorithm."),
986                            _("Key Edit"), MB_ERR);
987            return FALSE;
988        }
989    
990        if (k->is_protected) {
991            old_pass = request_passphrase (_("Current (old) Passphrase"), 1, &cancel);
992            if (cancel)
993                return FALSE;
994        }
995        new_pass = request_passphrase2 (_("New Passphrase" ), 1, &cancel);
996        if (cancel) {
997            free_if_alloc (old_pass);
998            return FALSE;
999        }
1000    
1001        if (is_8bit_string (new_pass)) {
1002            msg_box (dlg, _("The passphrase contains 8-bit characters.\n"
1003                             "It is not suggested to use charset specific characters."),
1004                             _("Key Edit"), MB_ERR);
1005            free_if_alloc (old_pass);
1006            free_if_alloc (new_pass);
1007            return FALSE;
1008        }
1009    
1010        ke = new GpgKeyEdit (k->keyid);
1011        if (!ke)
1012            BUG (NULL);
1013    
1014        ke->setPassphrase (k->is_protected? old_pass : NULL);
1015        ec = ke->changePassphrase (new_pass, 0);
1016        if( ec )
1017            msg_box (dlg, gpgme_strerror (ec), _("Change Passwd"), MB_ERR);
1018        else
1019            msg_box (dlg, _("Passphrase successfully changed."),  _("GnuPG status"), MB_OK);
1020        sfree_if_alloc (old_pass);
1021        sfree_if_alloc (new_pass);
1022        delete ke;
1023        return TRUE;
1024    }
1025    
1026    
1027    /* Initialize sub key list from key @k and return
1028       the new listview control. */
1029    listview_ctrl_t
1030    subkey_list_init (HWND dlg, winpt_key_t k)
1031    {
1032        LV_ITEM lvi;
1033        gpgme_key_t key;
1034        gpgme_subkey_t sub;
1035        struct listview_column_s cols[] = {
1036            {0, 80, (char *)_("Description")},
1037            {1, 78, (char *)_("Key ID")},
1038            {2, 66, (char *)_("Creation")},
1039            {3, 66, (char *)_("Expires")},
1040            {4, 64, (char *)_("Status")},
1041            {5, 16,  "C"/*ertify*/},
1042            {6, 16,  "S"/*ign*/},
1043            {7, 16,  "E"/*ncrypt*/},
1044            {8, 16,  "A"/*uth*/},
1045            {0, 0, 0}
1046        };
1047        listview_ctrl_t lv;
1048        char buf[256], tmp[128];
1049        const char *t;
1050        int nkeys = 0, rc = 0, i, bits;    
1051    
1052        if( get_pubkey( k->keyid, &key ) ) {
1053            msg_box( dlg, _("Could not find key."), _("Key Edit"), MB_ERR );
1054            return NULL;
1055        }
1056        if (!k->ctx)
1057            k->ctx = key;
1058        nkeys = count_subkeys (key);
1059        if( !nkeys ) {
1060            msg_box (dlg, _("No subkey(s) found."), _("Key Edit"), MB_ERR);
1061            return NULL;
1062        }
1063            
1064        rc  = listview_new( &lv );
1065        if( rc )
1066            BUG( dlg );
1067            
1068        lv->ctrl = GetDlgItem( dlg, IDC_KEYEDIT_KEYLIST );
1069        for( i = 0; cols[i].fieldname != NULL; i++ )    
1070            listview_add_column( lv, &cols[i] );
1071            
1072        for( i = 0; i < nkeys; i++ ) {
1073            listview_add_item( lv, "" );
1074            listview_add_sub_item( lv, 0, 1, "" );
1075            memset( &lvi, 0, sizeof lvi );
1076            lvi.mask = LVIF_PARAM;  
1077            lvi.lParam = (LPARAM)key;
1078            if( ListView_SetItem( lv->ctrl, &lvi ) == FALSE )
1079                return NULL;
1080        }
1081            
1082        listview_set_ext_style( lv );
1083        for( i = 0, sub = key->subkeys; i < nkeys; i++, sub = sub->next ) {
1084            memset( buf, 0, sizeof buf );
1085    
1086            bits = sub->length;
1087            _snprintf( tmp, sizeof tmp-1, "%d-bit ", bits );
1088            strcat( buf, tmp );
1089    
1090            _snprintf( tmp, sizeof tmp-1, "%s", get_key_pubalgo (sub->pubkey_algo));
1091            strcat( buf, tmp );
1092            
1093            listview_add_sub_item( lv, i, 0, buf );
1094            t = sub->keyid;
1095            if( !t )
1096                t = "DEADBEEFDEADBEEF";
1097            _snprintf( tmp, sizeof tmp-1, "0x%s", t+8 );
1098            listview_add_sub_item( lv, i, 1, tmp );
1099    
1100            t = get_key_created (sub->timestamp);
1101            if( !t )
1102                t = "????" "-??" "-??";
1103            listview_add_sub_item( lv, i, 2, t );
1104    
1105            if( sub->expires ) {
1106                t = get_key_created (sub->expires);
1107                listview_add_sub_item( lv, i, 3, t );
1108            }
1109            else
1110                listview_add_sub_item( lv, i, 3, _("Never") );
1111    
1112            if( sub->expired )
1113                t = _("Expired");
1114            else if( sub->revoked )
1115                t = _("Revoked");
1116            else
1117                t = _("OK");
1118            listview_add_sub_item( lv, i, 4, t );
1119    
1120            if (sub->can_certify) t = "*"; else t = "";
1121            listview_add_sub_item (lv, i, 5, t);
1122            if (sub->can_sign) t = "*"; else t = "";
1123            listview_add_sub_item( lv, i, 6, t );
1124            if (sub->can_encrypt) t = "*"; else t = "";
1125            listview_add_sub_item( lv, i, 7, t );
1126            if (sub->can_authenticate) t = "*"; else t = "";
1127            listview_add_sub_item (lv, i, 8, t);
1128        }
1129        return lv;
1130    } /* subkey_list_init */
1131    
1132    
1133    static listview_ctrl_t
1134    userid_list_init (HWND dlg, winpt_key_t k)
1135    {
1136        listview_ctrl_t lv = NULL;
1137        gpgme_key_t key;
1138        gpgme_key_sig_t ks;
1139        gpgme_user_id_t u;
1140        int nuids = 0, rc, j, u_attr;
1141        struct listview_column_s cols[] = {
1142            {0,  72, (char *)_("Validity")},
1143            {1, 150, (char *)_("Name")},
1144            {2, 110, (char *)_("Email")},
1145            {3,  76, (char *)_("Creation")},
1146            {0, 0, 0}
1147        };    
1148        const char *attr;
1149    
1150        if (get_pubkey (k->keyid, &key)) {
1151            msg_box (dlg, _("Could not find key."), _("Key Edit"), MB_ERR);
1152            return NULL;
1153        }
1154        
1155        nuids = count_userids (key);
1156        if (!nuids) {
1157            msg_box (dlg, _("No user ID(s) found."), _("Key Edit"), MB_ERR);
1158            return NULL;
1159        }
1160            
1161        rc = listview_new (&lv);
1162        if (rc)
1163            BUG (dlg);
1164        lv->ctrl = GetDlgItem( dlg, IDC_KEYEDIT_UIDLIST );
1165        for( j = 0; cols[j].fieldname != NULL; j++ )
1166            listview_add_column( lv, &cols[j] );
1167            
1168        for( j = 0; j < nuids; j++ ) {          
1169            listview_add_item( lv, " " );
1170            listview_add_sub_item( lv, 0, 1, " " );        
1171        }
1172    
1173        listview_set_ext_style (lv);
1174        for (j = 0, u=key->uids; j < nuids; u=u->next, j++) {
1175            if (u->revoked)
1176                attr = _("Revoked");
1177            else {
1178                u_attr = (int)u->validity;
1179                attr = get_key_trust2 (NULL, u_attr, 0, 0);
1180            }
1181            listview_add_sub_item( lv, j, 0, (char *)attr );        
1182    
1183            /* XXX: add comment if available */
1184            attr = u->name;
1185            if (attr) {
1186                char *uid = utf8_to_native (attr);
1187                if (uid) {
1188                    listview_add_sub_item (lv, j, 1, uid);
1189                    free (uid);
1190                }
1191            }
1192            else
1193                listview_add_sub_item (lv, j, 1, _("Invalid user ID"));
1194            attr = u->email;
1195            if (attr)
1196                listview_add_sub_item (lv, j, 2, attr);
1197    
1198            ks = get_selfsig (u, k->keyid, 1);
1199            if (ks)
1200                listview_add_sub_item (lv, j, 3, get_key_created (ks->timestamp));
1201        }
1202        if( !k->key_pair ) {
1203            CheckDlgButton( dlg, IDC_KEYUID_ADD, BST_INDETERMINATE );
1204            CheckDlgButton( dlg, IDC_KEYUID_REVOKE, BST_INDETERMINATE );    
1205        }
1206        return lv;
1207    } /* userid_list_init */
1208    
1209    
1210    static void
1211    do_init_cmdlist (HWND dlg, int is_keypair)
1212    {    
1213        const char *s;
1214        int i = 0;
1215    
1216        for (i = 0; (s=cmdlist[i].name); i++) {
1217            if (is_keypair)
1218                SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1219                                    (LPARAM)(char *)s);
1220            else if (!cmdlist[i].need_pair)
1221                SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
1222                                    (LPARAM)(char *)s);
1223        }
1224        SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_SETCURSEL, 0, 0);
1225    }
1226    
1227    
1228    /* Return 1 if the requested command is RFC2440. */
1229    static int
1230    is_cmd_openpgp (int cmdid)
1231    {
1232        switch (cmdid) {
1233        case CMD_ADDKEY:
1234        case CMD_ADDPHOTO:
1235        case CMD_ADDREVOKER:
1236        //case CMD_SETPREF:
1237            return 1;
1238        }
1239        return 0;
1240    }
1241    
1242    
1243    /* Display a message box with a short description of the commands. */
1244    static void
1245    do_show_help (HWND dlg)
1246    {
1247        char helptext[2048];
1248    
1249        _snprintf (helptext, sizeof (helptext)-1,
1250            _(
1251             "ADDUID   \t\tadd a user ID\r\n"
1252             "ADDPHOTO  \t\tadd a photo ID\r\n"
1253             "DELUID    \t\tdelete a user ID\r\n"
1254             "ADDKEY    \t\tadd a secondard key\r\n"
1255             "DELKEY    \t\tdelete a secondary key\r\n"
1256             "ADDREVOKER\t\tadd a revocation key\r\n"
1257             "EXPIRE    \t\tchange the expire date\r\n"
1258             "SHOWPREF  \t\tlist preferences (verbose)\r\n"
1259             "SETPREF   \t\tset preference list\r\n"
1260             "UPDPREF   \t\tupdated preferences\r\n"
1261             "PASSWD    \t\tchange the passphrase\r\n"
1262             "PRIMARY   \t\tflag user ID as primary\r\n"
1263             "TRUST     \t\tchange the ownertrust\r\n"
1264             "REVUID    \t\trevoke a user ID\r\n"
1265             "REVKEY    \t\trevoke a secondary key\r\n"
1266             "DISABLE   \t\tdisable a key\r\n"
1267             "ENABLE    \t\tenable a key\r\n"
1268             "SIGN      \t\tsign a user-id (exportable)\r\n"
1269             "LSIGN     \t\tsign a user-id (non-exportable)\r\n"));
1270        msg_box (dlg, helptext, _("Key Edit Help"), MB_OK);
1271    }
1272    
1273    
1274    static int
1275    do_editkey_delkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1276    {
1277        gpgme_error_t err;
1278        GpgKeyEdit *ke;
1279        int j, id;
1280        char tmp[64];
1281    
1282        if (!k->key_pair)
1283            return FALSE; /* XXX: shall we allow to modify non-secret keys?? */
1284    
1285        if( listview_count_items( lv, 0 ) == 1 ) {
1286            msg_box( dlg, _("Primary key can not be deleted!"), _("Key Edit"), MB_ERR);
1287            return FALSE;
1288        }
1289        if( (j = listview_get_curr_pos( lv )) == -1 ) {
1290            msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1291            return FALSE;
1292        }
1293        if( j == 0 ) {
1294            msg_box( dlg, _("Primary subkey can not be deleted!"), _("Key Edit"), MB_ERR );
1295            return FALSE;
1296        }
1297        
1298        listview_get_item_text( lv, j, 0, tmp, sizeof tmp -1 );
1299        id = log_box( _("Key Edit"), MB_YESNO|MB_ICONWARNING,
1300                        _("\"Subkey %s.\"\n\n"
1301                          "Anything encrypted to the selected subkey will no longer\n"
1302                          "be able to be decrypted.\n\n"
1303                          "Do you really want to delete this subkey?"), tmp );
1304        if( id == IDNO )
1305            return FALSE;
1306    
1307        ke = new GpgKeyEdit (k->keyid);
1308        if (!ke)
1309            BUG (NULL);
1310        err = ke->delKey (j);
1311        if (err)
1312            msg_box (dlg, gpgme_strerror (err), _("Delete Subkey"), MB_ERR);
1313        else {
1314            listview_del_item (lv, j);
1315            k->update = 1;
1316            status_box (dlg, _("Subkey successfully deleted."), _("GnuPG status"));
1317        }
1318        delete ke;
1319        return err? FALSE : TRUE;
1320    } /* do_editkey_delkey */
1321    
1322    
1323    
1324    /* Set the expiration date for the selected key in list view @lv.
1325       Return value: TRUE on success. */
1326    static int
1327    do_editkey_expire (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1328    {
1329        gpgme_error_t err;
1330        GpgKeyEdit *ke;
1331        date_s udd = {0};
1332        char buf[256], * pass = NULL;
1333        int j, cancel = 0;
1334    
1335        if (!k->key_pair) {
1336            msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1337            return FALSE;
1338        }
1339        if ((j = listview_get_curr_pos (lv)) == -1) {
1340            msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1341            return FALSE;
1342        }
1343    
1344        /* If a key already expired, it is possible the user wants to
1345           set a new expiration date.. */  
1346        listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, sizeof buf -1);
1347        if (!strcmp (buf, _("Expired"))) {
1348            cancel = msg_box (dlg, _("Key already expired.\n\n"
1349                              "Do you want to change the expiration date?"),
1350                              _("Key Edit"), MB_QUEST_ASK);
1351            if (cancel == IDNO)
1352                return FALSE;
1353            cancel = 0;
1354        }
1355    
1356        memset (&udd, 0, sizeof udd);
1357        udd.text = _("Key Expiration Date");
1358        dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_DATE, dlg,    
1359                          date_dlg_proc, (LPARAM)&udd,
1360                          _("Key Expiration Date"), IDS_WINPT_DATE);
1361        if (udd.cancel == 1)
1362            return FALSE;
1363        if (!keygen_check_date (&udd.st)) {
1364            msg_box (dlg, _("The date you have chosen lies in the past."),
1365                     _("Key Edit"), MB_ERR);
1366            return FALSE;
1367        }
1368        if( k->is_protected ) {
1369            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1370            if (cancel)
1371                return FALSE;
1372        }
1373    
1374        ke = new GpgKeyEdit (k->keyid);
1375        if (!ke)
1376            BUG (NULL);
1377        if (k->is_protected)
1378            ke->setPassphrase (pass);
1379        else
1380            ke->setNoPassphrase (true);
1381        err = ke->setKeyExpireDate (j, w32_mktime (&udd.st), false);
1382        if (err)
1383            msg_box (dlg, gpgme_strerror (err), _("Expire Subkey"), MB_ERR);
1384        else {
1385            _snprintf (buf, sizeof buf - 1, "%04d-%02d-%02d",      
1386                       udd.st.wYear, udd.st.wMonth, udd.st.wDay);
1387            listview_add_sub_item (lv, j, SUBK_COL_EXPIRES, buf);
1388            k->update = 1;
1389            msg_box (dlg, _("Subkey expire date successfully set."),
1390                     _("GnuPG status"), MB_OK);
1391        }
1392        sfree_if_alloc (pass);
1393        delete ke;
1394        return TRUE;
1395    }
1396    
1397    
1398    /* Revoke the selected key in the list view @lv. @k contains
1399       control information about the global key.
1400       Return value: TRUE on success. */
1401    static int
1402    do_editkey_revoke (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1403    {
1404        gpgme_error_t err;
1405        GpgKeyEdit *ke;
1406        char buf[256];
1407        char *pass = NULL;
1408        int j, cancel = 0;
1409    
1410        if (!k->key_pair) {
1411            msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
1412            return FALSE;
1413        }
1414    
1415        if ((j = listview_get_curr_pos (lv)) == -1) {
1416            msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
1417            return FALSE;
1418        }
1419        else if (listview_count_items (lv, 0) == 1) {
1420            msg_box( dlg, _("No subkeys were found, if you want to revoke the\n"
1421                            "whole key, please use the Key Manager command directly.\n\n"
1422                            "This command is only available to revoke single subkeys"),
1423                     _("Key Edit"), MB_INFO );
1424            return FALSE;
1425        }
1426                
1427        listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, sizeof (buf)-1);
1428        if (!strcmp (buf, _("Revoked"))) {
1429            msg_box (dlg, _("Key already revoked."), _("Key Edit"), MB_ERR);
1430            return FALSE;
1431        }
1432        
1433        if (k->is_protected) {
1434            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1435            if (cancel)
1436                return FALSE;          
1437        }
1438    
1439        ke = new GpgKeyEdit (k->keyid);
1440        if (!ke)
1441            BUG (NULL);
1442        if (k->is_protected)
1443            ke->setPassphrase (pass);
1444        else
1445            ke->setNoPassphrase (true);
1446        err = ke->revokeSubkey (j, 0, NULL);
1447        if (err)
1448            msg_box( dlg, gpgme_strerror (err), _("Revoke Subkey"), MB_ERR);
1449        else {
1450            listview_add_sub_item (lv, j, SUBK_COL_STATUS, _("Revoked"));
1451            k->update = 1;
1452            msg_box( dlg, _("Subkey successfully revoked."), _("GnuPG Status"), MB_OK );
1453        }
1454        sfree_if_alloc (pass);
1455        delete ke;
1456        return TRUE;
1457    }
1458    
1459    
1460    /* Revoked the selected userid in list view @lv.
1461       Return value: TRUE on success. */
1462    int
1463    do_editkey_revuid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1464    {
1465        gpgme_error_t err;
1466        GpgKeyEdit *ke;
1467        char buf[128], email[128];
1468        char inf[512];
1469        char *pass = NULL;
1470        int cancel = 0, id = 0, j;
1471    
1472        if (!k->key_pair) {
1473            msg_box (dlg, _("There is no secret key available!"),
1474                     _("Revoke user ID"), MB_ERR);
1475            return FALSE;
1476        }
1477    
1478        if (listview_count_items (lv, 0) == 1) {
1479            msg_box (dlg, _("Key has only one user ID."), _("Key Edit"), MB_ERR);  
1480            return FALSE;
1481        }
1482    
1483        if( (j = listview_get_curr_pos( lv )) == -1 ) {
1484            msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );  
1485            return FALSE;  
1486        }
1487                
1488        listview_get_item_text( lv, j, UID_COL_VALID, buf, sizeof buf - 1);
1489        if (strstr (buf, _("Revoked"))) {
1490            msg_box (dlg, _("This user ID has been already revoked."),
1491                     _("Key Edit"), MB_INFO);
1492            return FALSE;
1493        }
1494                
1495        listview_get_item_text (lv, j, UID_COL_NAME, buf, sizeof buf -1);
1496        _snprintf (inf, sizeof (inf) -1, _("user ID \"%s\".\n\n"
1497                   "Do you really want to revoke this user ID?"), buf);
1498        if (msg_box (dlg, inf, _("Key Edit"), MB_WARN_ASK) == IDNO)
1499            return FALSE;
1500        if (k->is_protected) {
1501            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1502            if (cancel)
1503                return FALSE;          
1504        }
1505        listview_get_item_text (lv, j, UID_COL_EMAIL, email, sizeof (email)-1);
1506        listview_get_item_text (lv, j, UID_COL_NAME, buf, sizeof (buf)-1);
1507        id = do_find_userid (k->keyid, email, buf, NULL);
1508        if (id == -1)
1509            BUG (NULL);
1510    
1511        ke = new GpgKeyEdit (k->keyid);
1512        if (!ke)
1513            BUG (NULL);
1514        if (k->is_protected)
1515            ke->setPassphrase (pass);
1516        else
1517            ke->setNoPassphrase (true);
1518        err = ke->revokeUserid (id);
1519        if (err)
1520            msg_box (dlg, gpgme_strerror (err), _("Revoke User ID"), MB_ERR);
1521        else {
1522            listview_add_sub_item (lv, j, 0, _("Revoked"));
1523            k->update = 1;
1524            status_box (dlg, _("User ID successfully revoked"), _("GnuPG Status"));
1525        }
1526        sfree_if_alloc (pass);
1527        delete ke;
1528        return err? FALSE : TRUE;
1529    }
1530    
1531    
1532    static int
1533    do_editkey_setpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1534    {
1535        gpgme_error_t rc;
1536        GpgKeyEdit *ke;
1537        char buf[256], * pass = NULL, * prefs;
1538        int j, id, cancel=0, flags=0;
1539    
1540        if ((j = listview_get_curr_pos (lv)) == -1) {
1541            msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1542            return FALSE;
1543        }
1544        listview_get_item_text (lv, j, 2, buf, sizeof buf-1);
1545        id = do_find_userid (k->keyid, buf, NULL, NULL);
1546        if (id == -1)
1547            BUG (dlg);
1548        if (k->is_protected) {
1549            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1550            if (cancel)
1551                return FALSE;
1552        }
1553    
1554        ke = new GpgKeyEdit (k->keyid);
1555        if (!ke)
1556            BUG (NULL);
1557        if (k->is_protected)
1558            ke->setPassphrase (pass);
1559        else
1560            ke->setNoPassphrase (true);
1561    
1562        get_userid_preflist (&prefs, &flags);
1563    
1564        rc = ke->setUseridPreferences (id, prefs);
1565        if (rc)
1566            msg_box (dlg, _("Could not set user ID preferences"), _("Key Edit"), MB_ERR);
1567    
1568        sfree_if_alloc (pass);
1569        free_if_alloc (prefs);
1570        delete ke;
1571        return 0;
1572    }
1573    
1574    
1575    static int
1576    do_editkey_primary (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1577    {
1578        gpgme_error_t err;
1579        GpgKeyEdit *ke;
1580        int j, id, cancel=0;
1581        char buf[256], * pass = NULL;
1582    
1583        if (listview_count_items (lv, 0) == 1)
1584            return TRUE;
1585        if ((j = listview_get_curr_pos (lv)) == -1) {
1586            msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
1587            return FALSE;
1588        }
1589        listview_get_item_text (lv, j, 2, buf, sizeof buf-1);
1590        id = do_find_userid (k->keyid, buf, NULL, NULL);
1591        if (id == -1)
1592            BUG (dlg);
1593        if (k->is_protected) {
1594            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1595            if (cancel)
1596                return FALSE;
1597        }
1598    
1599        ke = new GpgKeyEdit (k->keyid);
1600        if (k->is_protected)
1601            ke->setPassphrase (pass);
1602        else
1603            ke->setNoPassphrase (true);
1604        err = ke->setPrimaryUserid (id);
1605        if (err)
1606            msg_box (dlg, gpgme_strerror (err), _("Primary"), MB_ERR);
1607        else {
1608            k->update = 1;
1609            status_box (dlg, _("User ID successfully flagged"), _("GnuPG Status"));
1610        }
1611    
1612        sfree_if_alloc (pass);
1613        delete ke;
1614        return err? FALSE : TRUE;
1615    }
1616    
1617    
1618    
1619    #define CIPHER  11
1620    #define HASH    11
1621    #define COMPR    4
1622    
1623    static int
1624    parse_preflist (HWND dlg, const char *list)
1625    {
1626        char buf[128] = {0};
1627        char *p, *pbuf = buf;
1628        const char *ciphers[CIPHER] = {"", "IDEA", "3DES",
1629                                       "CAST5", "BLOWFISH", "", "",
1630                                       "AES", "AES192", "AES256", "TWOFISH"};
1631        const char *hash[HASH] = {"", "MD5", "SHA1", "RMD160", "",
1632                                  "", "", "", "SHA256", "SHA384", "SHA512"};
1633        const char *compress[COMPR] = {"", "ZIP", "ZLIB", "BZIP2"};
1634        int n=0;
1635    
1636        strncpy (buf, list, 127);
1637        p = strtok (pbuf, " ");
1638        while (p != NULL) {
1639            int algid = atol (p+1);
1640            n++;
1641            switch (*p) {
1642            case 'S':
1643                SendDlgItemMessage (dlg, IDC_SHOWPREF_CIPHERS, LB_ADDSTRING, 0,
1644                                    (LPARAM)(const char*)ciphers[algid % CIPHER]);
1645                break;
1646    
1647            case 'H':
1648                SendDlgItemMessage (dlg, IDC_SHOWPREF_HASH, LB_ADDSTRING, 0,
1649                                    (LPARAM)(const char*)hash[algid % HASH]);
1650                break;
1651    
1652            case 'Z':
1653                SendDlgItemMessage (dlg, IDC_SHOWPREF_ZIP, LB_ADDSTRING, 0,
1654                                    (LPARAM)(const char*)compress[algid % COMPR]);
1655                break;
1656    
1657            default:
1658                n--;
1659            }
1660            p = strtok (NULL, " ");
1661        }
1662        return n;
1663    }
1664    
1665    
1666    /* Dialog box procedure to show the key preferences. */
1667    BOOL CALLBACK
1668    showpref_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1669    {
1670        static keyedit_cb_t cb = NULL;
1671        gpg_uid_info_t inf=NULL;
1672        char buf[128];
1673        int pos;
1674    
1675        switch (msg) {
1676        case WM_INITDIALOG:
1677            cb = (keyedit_cb_t)lparam;
1678            if (cb == NULL)
1679                BUG (dlg);
1680            pos = listview_get_curr_pos (cb->lv);
1681            listview_get_item_text (cb->lv, pos, 2, buf, DIM (buf)-1);
1682            SetDlgItemText (dlg, IDC_SHOWPREF_INFO, buf);
1683            pos = do_find_userid (((winpt_key_t)cb->opaque)->keyid,
1684                                  buf, NULL, &inf);
1685            if (inf) {
1686                const char *prefs = inf->prefs;
1687                if (prefs && *prefs) {
1688                    if (parse_preflist (dlg, prefs) <= 0)
1689                        pos = -1;
1690                }
1691                else
1692                    pos = -1;
1693                gpg_uid_info_release (inf);
1694                if (pos == -1) {
1695                    msg_box (dlg, _("No preferences available."), _("Key Edit"), MB_ERR);
1696                    EndDialog (dlg, TRUE);
1697                }
1698                if (inf->flags.mdc)
1699                    CheckDlgButton (dlg, IDC_SHOWPREF_MDC, BST_CHECKED);
1700            }
1701            SetDlgItemText (dlg, IDC_SHOWPREF_MDC, _("MDC feature"));
1702            SetDlgItemText (dlg, IDC_SHOWPREF_PREFINF, _("Preferences"));
1703            SetWindowText (dlg, _("Key Preferences"));
1704            SetForegroundWindow (dlg);
1705            break;
1706    
1707        case WM_COMMAND:
1708            switch (LOWORD (wparam)) {
1709            case IDOK:
1710                EndDialog (dlg, TRUE);
1711                break;
1712            }
1713            break;
1714        }
1715        return FALSE;
1716    }
1717    
1718    
1719    static int
1720    do_editkey_showpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1721    {
1722        struct keyedit_cb_s cb;
1723    
1724        if (k->is_v3)
1725            return TRUE;
1726    
1727        if (listview_get_curr_pos (lv) == -1) {
1728            msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1729            return FALSE;
1730        }
1731    
1732        memset (&cb, 0, sizeof (cb));
1733        cb.lv = lv;
1734        cb.opaque = k;
1735        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_SHOWPREF, dlg,
1736                        showpref_dlg_proc, (LPARAM)&cb);
1737        return TRUE;
1738    }
1739    
1740    
1741    static int
1742    do_editkey_deluid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
1743    {
1744        gpgme_error_t err;
1745        GpgKeyEdit *ke;
1746        char email[128], name[128];
1747        char inf[384];
1748        int j, id = 0;
1749    
1750        if (!k->key_pair)
1751            return FALSE; /* XXX: see do_editkey_delsubkey */
1752    
1753        if (listview_count_items (lv, 0) == 1) {
1754            msg_box (dlg, _("Primary user ID can not be deleted!"),
1755                     _("Key Edit"), MB_ERR);
1756            return FALSE;
1757        }
1758        if ((j = listview_get_curr_pos (lv)) == -1) {
1759            msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1760            return FALSE;
1761        }
1762        
1763        /* XXX: add a hint that also all signatures will be deleted? */
1764        listview_get_item_text (lv, j, UID_COL_NAME, name, DIM(name) -1);
1765        _snprintf (inf, DIM (inf)-1, _("user ID \"%s\".\n\n"
1766                                       "Do you really want to delete this user ID?"),
1767                                   name);
1768        if (msg_box (dlg, inf, _("Key Edit"), MB_YESNO|MB_ICONWARNING) == IDNO)
1769            return FALSE;
1770        
1771        listview_get_item_text (lv, j, UID_COL_EMAIL, email, DIM (email)-1);
1772        listview_get_item_text (lv, j, UID_COL_NAME, name, DIM (name)-1);
1773        id = do_find_userid (k->keyid, email, name, NULL);
1774        if (id == -1)
1775            BUG (dlg);
1776    
1777        ke = new GpgKeyEdit (k->keyid);
1778        if (!ke)
1779            BUG (NULL);
1780    
1781        err = ke->delUserid (id);
1782        if (err)
1783            msg_box (dlg, gpgme_strerror (err), _("Delete user ID"), MB_ERR);
1784        else {
1785            listview_del_item (lv, j);
1786            k->update = 1;
1787            status_box (dlg, _("User ID successfully deleted"), _("GnuPG Status"));
1788        }
1789        delete ke;
1790        return err? FALSE : TRUE;
1791    } /* do_editkey_deluid */
1792    
1793    
1794    
1795    static BOOL CALLBACK
1796    subkey_subclass_proc( HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam )
1797    {
1798        switch( msg ) {
1799        case WM_KEYUP:
1800            int virt_key = (int)wparam;
1801            switch( virt_key ) {        
1802            case VK_DELETE:
1803                SendDlgItemMessage( keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1804                                    CB_SETCURSEL, CMD_DELKEY, 0 );
1805                send_cmd_id( keyedit_subkey_proc.dlg, IDOK );
1806                break;
1807    
1808            case VK_INSERT:
1809                SendDlgItemMessage( keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD,
1810                                    CB_SETCURSEL, CMD_ADDKEY, 0 );
1811                send_cmd_id( keyedit_subkey_proc.dlg, IDOK );
1812                break;
1813            }
1814        }
1815        return CallWindowProc( keyedit_subkey_proc.old, dlg, msg, wparam, lparam );
1816    } /* subkey_subclass_proc */
1817    
1818    
1819    static BOOL CALLBACK
1820    uid_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1821    {
1822        switch( msg ) {
1823        case WM_KEYUP:
1824            int virt_key = (int)wparam;
1825            switch (virt_key) {
1826            case VK_DELETE:
1827                SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1828                                    CB_SETCURSEL, CMD_DELUID, 0);
1829                send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1830                break;
1831    
1832            case VK_INSERT:
1833                SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
1834                                    CB_SETCURSEL, CMD_ADDUID, 0);
1835                send_cmd_id (keyedit_uid_proc.dlg, IDOK);
1836                break;
1837            }
1838        }
1839        return CallWindowProc( keyedit_uid_proc.old, dlg, msg, wparam, lparam );
1840    } /* uid_subclass_proc */
1841    
1842    
1843    static void
1844    do_editkey_enable_disable (winpt_key_t k, HWND dlg, listview_ctrl_t lv, int enable)
1845    {
1846        km_enable_disable_key (lv, dlg, 0, enable);
1847        k->update = 1;
1848    }
1849    
1850    
1851    /* Return default secret key. */
1852    static gpgme_key_t
1853    get_default_key (void)
1854    {
1855        gpgme_key_t def_sk;
1856        char *keyid = get_gnupg_default_key ();
1857    
1858        get_seckey (keyid, &def_sk);
1859        free_if_alloc (keyid);
1860        return def_sk;
1861    }
1862    
1863    
1864    static void
1865    do_editkey_check (winpt_key_t k, HWND dlg)
1866    {
1867        if (!k->ctx)
1868            get_pubkey (k->keyid, &k->ctx);
1869        if (!k->uid && k->ctx)
1870            k->uid = k->ctx->uids->uid;
1871        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYSIG_TREE, dlg,
1872                        sigtree_dlg_proc, (LPARAM)k);
1873    }
1874    
1875    
1876    static int
1877    do_editkey_sign_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv, int mode)
1878    {
1879        gpgme_error_t err;
1880        GpgKeyEdit *ke;
1881        char *pass = NULL;
1882        char email[64], name[128];
1883        int uid_index;
1884        int cancel = 0;
1885    
1886        uid_index = listview_get_curr_pos (lv);
1887        if (uid_index == -1) {
1888            msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
1889            return FALSE;
1890        }
1891        if (mode == CMD_SIGN) {
1892            cancel = msg_box (dlg, _("Do you really want to make this sig exportable?"),
1893                              _("Key Edit"), MB_QUEST_ASK);
1894            if (cancel == IDNO)
1895                return FALSE;
1896        }
1897    
1898        listview_get_item_text (lv, uid_index, UID_COL_EMAIL, email, sizeof (email)-1);
1899        listview_get_item_text (lv, uid_index, UID_COL_NAME, name, sizeof (name)-1);
1900        uid_index = do_find_userid (k->keyid, email, name, NULL);
1901        if (k->is_protected) {
1902            pass = request_passphrase (_("Key Edit"), 1, &cancel);
1903            if (cancel)
1904                return FALSE;
1905        }
1906        ke = new GpgKeyEdit (k->keyid);
1907        if (k->is_protected)
1908            ke->setPassphrase (pass);
1909        else
1910            ke->setNoPassphrase (true);
1911        ke->setLocalUser (get_default_key ());
1912        err = ke->signUserid (uid_index,
1913                              mode == CMD_SIGN? GPG_EDITKEY_SIGN : GPG_EDITKEY_LSIGN,
1914                              0, NULL);
1915        if (!err) {
1916            msg_box (dlg, _("Key successfully signed."), _("Key Edit"), MB_OK);
1917            k->update = 1;
1918        }
1919        else
1920            msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
1921        delete ke;
1922        sfree_if_alloc (pass);
1923        return !err? TRUE : FALSE;
1924    }
1925    
1926    
1927    static int
1928    lookup_cmd (HWND dlg)
1929    {
1930        char buf[64];
1931        int i;
1932    
1933        i = SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_GETCURSEL, 0, 0);
1934        if (i == LB_ERR)
1935            return LB_ERR;
1936        GetDlgItemText (dlg, IDC_KEYEDIT_CMD, buf, sizeof (buf)-1);
1937        for (i=0; cmdlist[i].name != NULL; i++) {
1938            if (!strcmp (buf, cmdlist[i].name))
1939                return cmdlist[i].id;
1940        }
1941        return LB_ERR;
1942    }
1943    
1944    /* Dialog box procedure for the edit key dialog. */
1945    BOOL CALLBACK
1946    keyedit_main_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
1947    {
1948        static winpt_key_t k;
1949        static listview_ctrl_t lvsub = NULL, lvuid = NULL;
1950        int cmd;
1951        HWND item;
1952    
1953        switch( msg ) {
1954        case WM_INITDIALOG:
1955            k = (winpt_key_t)lparam;
1956            if (!k)
1957                BUG (NULL);
1958            do_init_cmdlist (dlg, k->key_pair);
1959            lvsub = subkey_list_init (dlg, k);
1960            if( !lvsub )
1961                BUG( NULL );
1962            lvuid = userid_list_init (dlg, k);
1963            if( !lvuid )
1964                BUG( NULL );
1965            item = GetDlgItem( dlg, IDC_KEYEDIT_KEYLIST );
1966            keyedit_subkey_proc.dlg = dlg;
1967            keyedit_subkey_proc.current = (WNDPROC)subkey_subclass_proc;
1968            keyedit_subkey_proc.old = (WNDPROC)GetWindowLong( item, GWL_WNDPROC );
1969            if( keyedit_subkey_proc.old ) {
1970                if( !SetWindowLong( item, GWL_WNDPROC, (LONG)keyedit_subkey_proc.current ) ) {
1971                    msg_box( dlg, _("Could not set subkey window procedure."), _("Key Edit"), MB_ERR );
1972                    BUG( NULL );
1973                }
1974            }
1975            item = GetDlgItem( dlg, IDC_KEYEDIT_UIDLIST );
1976            keyedit_uid_proc.dlg = dlg;
1977            keyedit_uid_proc.current = (WNDPROC)uid_subclass_proc;
1978            keyedit_uid_proc.old = (WNDPROC)GetWindowLong( item, GWL_WNDPROC );
1979            if( keyedit_uid_proc.old ) {
1980                if( !SetWindowLong( item, GWL_WNDPROC, (LONG)keyedit_uid_proc.current ) ) {
1981                    msg_box( dlg, _("Could not set user ID window procedure."), _("Key Edit"), MB_ERR );
1982                    BUG( NULL );
1983                }
1984            }
1985            if (k->ctx->revoked) {
1986                EnableWindow (GetDlgItem (dlg, IDC_KEYEDIT_CMD), FALSE);
1987                EnableWindow (GetDlgItem (dlg, IDOK), FALSE);
1988            }
1989            SetDlgItemText (dlg, IDC_KEYEDIT_CMDINF, _("Command>"));
1990            SetDlgItemText (dlg, IDCANCEL, _("&Close"));
1991            SetDlgItemText (dlg, IDC_KEYEDIT_HELP, _("&Help"));
1992            SetWindowText (dlg, _("Key Edit"));
1993            SetForegroundWindow (dlg);
1994            center_window (dlg, NULL);
1995            return TRUE;
1996    
1997        case WM_DESTROY:
1998            if( lvsub ) {
1999                listview_release( lvsub );
2000                lvsub = NULL;
2001            }
2002            if( lvuid ) {
2003                listview_release( lvuid );
2004                lvuid = NULL;
2005            }
2006            break;
2007    
2008        case WM_NOTIFY:
2009            NMHDR * notify;
2010            notify = (NMHDR *)lparam;
2011            if (notify && notify->code == NM_DBLCLK &&
2012                notify->idFrom == IDC_KEYEDIT_UIDLIST)
2013                do_editkey_showpref (k, dlg, lvuid);
2014            break;
2015    
2016        case WM_COMMAND:
2017            switch( LOWORD( wparam ) ) {
2018            case IDOK:
2019                cmd = lookup_cmd (dlg);
2020                if (cmd == LB_ERR) {
2021                    msg_box( dlg, _("Please select a command."), _("Key Edit"), MB_INFO );
2022                    return FALSE;
2023                }
2024                if (k->is_v3 && is_cmd_openpgp (cmd)) {
2025                    msg_box (dlg, _("This command cannot be used with PGP 2 (v3) keys.\n"),
2026                                    _("Key Edit"), MB_ERR);
2027                    return FALSE;
2028                }
2029                switch (cmd) {
2030                case CMD_SHOWPREF: do_editkey_showpref (k, dlg, lvuid); break;
2031                case CMD_DELKEY: do_editkey_delkey (k, dlg, lvsub); break;
2032                case CMD_ADDKEY: keyedit_add_subkey (k, dlg, lvsub); break;
2033                case CMD_EXPIRE: do_editkey_expire (k, dlg, lvsub); break;
2034                case CMD_REVKEY: do_editkey_revoke (k, dlg, lvsub); break;
2035                /*case CMD_SETPREF:do_editkey_setpref( k, dlg, lvuid ); break;*/
2036                case CMD_ADDUID: keyedit_add_userid( k, dlg, lvuid ); break;
2037                case CMD_ADDREVOKER: keyedit_add_revoker( k, dlg ); break;
2038                case CMD_ADDPHOTO: keyedit_add_photo( k, dlg ); break;
2039                case CMD_REVUID: do_editkey_revuid( k, dlg, lvuid ); break;
2040                case CMD_DELUID: do_editkey_deluid( k, dlg, lvuid ); break;
2041                case CMD_PASSWD: keyedit_change_passwd( k, dlg ); break;
2042                case CMD_PRIMARY: do_editkey_primary( k, dlg, lvuid ); break;
2043                case CMD_ENABLE: do_editkey_enable_disable (k, dlg, lvsub, 1); break;
2044                case CMD_DISABLE: do_editkey_enable_disable (k, dlg, lvsub, 0); break;
2045                case CMD_CHECK: do_editkey_check (k, dlg); break;
2046                case CMD_TRUST: keyedit_change_ownertrust (k, dlg); break;
2047                case CMD_SIGN:
2048                case CMD_LSIGN: do_editkey_sign_userid (k, dlg,
2049                                                        lvuid, cmd);
2050                                break;
2051                }
2052                break;
2053    
2054            case IDCANCEL:
2055                EndDialog (dlg, FALSE);
2056                break;
2057    
2058            case IDC_KEYEDIT_HELP:
2059                do_show_help (dlg);
2060                break;
2061            }
2062            break;
2063        }
2064        return FALSE;
2065    }
2066    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26