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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26