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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26