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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26