/[winpt]/trunk/Src/wptKeyManager.cpp
ViewVC logotype

Diff of /trunk/Src/wptKeyManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 33 by twoaday, Tue Oct 25 07:46:20 2005 UTC revision 129 by twoaday, Fri Dec 30 13:56:10 2005 UTC
# Line 1  Line 1 
 /* wptKeyManager.cpp - Handy functions for the Key Manager dialog  
  *      Copyright (C) 2001-2005 Timo Schulz  
  *      Copyright (C) 2005 g10 Code GmbH  
  *  
  * 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 <stdio.h>  
   
 #include "gpgme.h"  
 #include "../resource.h"  
 #include "wptTypes.h"  
 #include "wptW32API.h"  
 #include "wptVersion.h"  
 #include "wptCommonCtl.h"  
 #include "wptNLS.h"  
 #include "wptErrors.h"  
 #include "wptContext.h"  
 #include "wptGPG.h"  
 #include "wptKeylist.h"  
 #include "wptFileManager.h"  
 #include "wptDlgs.h"  
 #include "wptKeyserver.h"  
 #include "wptKeyManager.h"  
 #include "wptKeylist.h"  
 #include "wptHTTP.h"  
 #include "wptKeyEdit.h"  
 #include "wptImport.h"  
   
   
 /* Return a user friendly key representation in @buf of  
    the key given by @keyid. */  
 static void  
 key_get_clip_info (const char *keyid, char *buf, size_t buflen)  
 {  
     gpgme_key_t pk;  
   
     if (get_pubkey (keyid, &pk))  
         BUG (NULL);  
     _snprintf (buf, buflen-1,  
                "pub %04d%s/%s %s %s\r\n"  
                "    Primary key fingerprint: %s\r\n",  
                pk->subkeys->length,  
                get_key_pubalgo (pk->subkeys->pubkey_algo),  
                pk->subkeys->keyid+8,  
                get_key_created (pk->subkeys->timestamp),  
                pk->uids->uid,  
                get_key_fpr (pk));  
 }  
   
   
 #if 0  
 /* Quoted the user-id given by @uid. If @uid is already  
    quoted @uid is returned without any modifications.  
    Return value: quoted @uid. */  
 char*  
 km_quote_uid (const char *uid)  
 {      
     char *q;  
   
     if (*uid == '"' && uid[strlen (uid)-1] == '"')  
         return m_strdup (uid);  
     q = new char[strlen (uid) + 4];  
     if (!q)  
         BUG (NULL);  
     _snprintf (q, strlen (uid) + 3, "\"%s\"", uid);  
     return q;  
 }  
 #endif  
   
   
 /* Check if list view @lv contains a secret key at position @pos.  
    If utrust is valid, set it to 1 if the key is valid -1 otherwise.  
    Return value: 1 normal key, 2 smart card key. */  
 int  
 km_check_for_seckey (listview_ctrl_t lv, int pos, int *utrust)  
 {  
     char t[32], t2[64];  
     int type = 0;  
       
     if (utrust)  
         *utrust = 0;  
     listview_get_item_text (lv, pos, 5, t, DIM (t)-1);  
     listview_get_item_text (lv, pos, 2, t2, DIM (t2)-1);  
     if (!strcmp (t2, "pub/sec"))  
         type = 1;  
     else if (!strcmp (t2, "pub/crd"))  
         type = 2;  
     if ((strstr (t, "Expired") || strstr (t, "Revoked")) && utrust)  
         *utrust = -1;  
     else if (stristr (t, "Ultimate") && utrust)  
         *utrust = 1;  
     return type;  
 }  
   
   
 /* Check if the key at position @pos is protected with a passwd. */  
 int  
 km_check_if_protected (listview_ctrl_t lv, int pos)  
 {  
     gpgme_key_t key;  
     winpt_key_s k;  
   
     key = (gpgme_key_t)listview_get_item2 (lv, pos);  
     if (!key)  
         return 1; /* assume yes */  
     winpt_get_pubkey (key->subkeys->keyid, &k);  
     return k.is_protected;  
 }  
   
   
 int  
 km_check_key_status (listview_ctrl_t lv, int pos)  
 {  
     int flags = km_get_key_status (lv, pos);  
       
     if (flags & KM_FLAG_EXPIRED) {  
         msg_box (lv->ctrl, _("This key has expired!\n"    
                              "Key check failed."), _("Key Manager"), MB_ERR);  
         return -1;  
     }  
     else if (flags & KM_FLAG_REVOKED) {  
         msg_box (lv->ctrl, _("This key has been revoked by its owner!\n"  
                              "Key check failed."), _("Key Manager"), MB_ERR);  
         return -1;  
     }  
   
     return 0;  
 } /* km_check_key_status */  
   
   
 int  
 km_get_key_status (listview_ctrl_t lv, int pos)  
 {  
     gpgme_key_t key;  
     int flags = 0;  
   
     if (pos == -1)  
         return 0;  
     key = (gpgme_key_t)listview_get_item2 (lv, pos);  
     if (key == NULL)  
         return 0;  
   
     if (key->expired)  
         flags |= KM_FLAG_EXPIRED;  
     if (key->revoked)  
         flags |= KM_FLAG_REVOKED;  
     if (key->disabled)  
         flags |= KM_FLAG_DISABLED;  
     return flags;  
 } /* km_get_key_status */  
   
   
 /* Interface to enable or disable a key (@enable = 1 then enable).  
    The key is retrieved from a list control @lv at the pos @pos. */  
 int  
 km_enable_disable_key (listview_ctrl_t lv, HWND dlg, int pos, int enable)  
 {  
     GpgKeyEdit *ke;  
     gpgme_error_t err;  
     char keyid[32];  
   
     listview_get_item_text (lv, pos, 1, keyid, DIM (keyid)-1);  
   
     ke = new GpgKeyEdit (keyid);  
     if (!ke)  
         BUG (NULL);  
   
     err = enable? ke->enable () : ke->disable ();  
     if (!err) {  
         show_msg (dlg, 1500, _("Key status changed."));  
         keycache_set_reload (1); /* XXX: set update flag */  
     }  
     else  
         msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);  
     delete ke;  
     return err? WPTERR_GENERAL : 0;  
 }  
   
   
   
 /* Create a string that contain all keyids from  
    the key list @rset separated by a space. */  
 char*  
 gpg_keylist_to_pattern (gpgme_key_t *rset, int n)  
 {  
     char *p;  
     int i;  
   
     if (!n)  
         return NULL;  
     p = (char *)calloc (1, n*(16+1)+n+2);  
     if (!p)  
         BUG (NULL);  
     for (i=0; i < n; i++) {  
         strcat (p, rset[i]->subkeys->keyid);  
         strcat (p, " ");  
     }  
     return p;  
 }  
   
   
 /* Export the keys given in @rset to the clipboard.  
    Return value: 0 on success. */  
 static gpgme_error_t  
 gpg_clip_export (gpgme_key_t *rset, int n)  
 {  
     gpgme_error_t err = 0;  
     gpgme_ctx_t ctx = NULL;  
     gpgme_data_t keydata = NULL;  
     char *patt=NULL;  
       
     err = gpgme_new (&ctx);  
     if (err)  
         return err;  
     gpgme_set_armor (ctx, 1);            
     err = gpgme_data_new (&keydata);  
     if (err)  
         goto leave;  
   
     patt = gpg_keylist_to_pattern (rset, n);  
     if (!patt) {  
         err = gpg_error (GPG_ERR_ENOMEM);  
         goto leave;  
     }  
   
     err = gpgme_op_export (ctx, patt, 0, keydata);  
     if (err)  
         goto leave;  
   
     gpg_data_release_and_set_clipboard (keydata, 1);  
   
 leave:  
     if (patt)  
         free (patt);  
     gpgme_release (ctx);  
     return err;  
 }  
   
   
 /* Export the selected keys in @lv to the clipboard. */  
 int  
 km_clip_export (HWND dlg, listview_ctrl_t lv)  
 {  
     gpgme_error_t err;  
     gpgme_key_t *rset;  
     char buf[256];  
     int n=0;  
     int rc=0;  
       
     rset = keylist_enum_recipients (lv, KEYLIST_LIST, &n);  
     if (!n) {  
         msg_box (dlg, _("No key was selected for export."), _("Key Manager"), MB_ERR);  
         rc = WPTERR_GENERAL;  
         goto leave;  
     }  
       
     err = gpg_clip_export (rset, n);  
     if (err) {  
         msg_box( dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);  
         rc = WPTERR_GENERAL;  
         goto leave;  
     }  
     if (n == 1) {  
         key_get_clip_info (rset[0]->subkeys->keyid, buf, sizeof (buf)-1);  
         set_clip_text2 (NULL, buf, strlen (buf), 0);  
     }  
   
     show_msg (dlg, 1500, _("GnuPG Status: Finished"));  
       
 leave:  
     free (rset);  
     return rc;  
 } /* km_clip_export */  
   
   
 /* Export the selected secret key from @lv into @fname.  
    It is only allowed to export a single secret key. */  
 int  
 km_privkey_export (HWND dlg, listview_ctrl_t lv, const char *fname)  
 {  
     gpgme_key_t *rset;  
     gpgme_error_t err;  
     int n = 0;  
   
     rset = keylist_enum_recipients (lv, KEYLIST_LIST, &n);  
     if (!n) {  
         msg_box (dlg, _("No key was selected for export."),  
                  _("Key Manager"), MB_ERR);  
         return WPTERR_GENERAL;  
     }  
     if (n > 1) {  
         msg_box (dlg, _("Only one secret key can be exported."),  
                  _("Key Manager"), MB_ERR);  
         free (rset);  
         return 0; /* we checked this before, so we just quit */  
     }  
   
     err = gpg_export_seckey (rset[0]->subkeys->keyid, fname);  
     if (err)  
         msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);  
     else  
         log_box (_("Key Manager"), MB_OK,  
                  _("Secret key successfully saved in '%s'."), fname);  
   
     free (rset);  
     return err? WPTERR_GENERAL : 0;  
 }  
   
   
 int  
 km_file_export (HWND dlg, listview_ctrl_t lv, const char * fname)  
 {  
     gpgme_key_t *rset;  
     gpgme_data_t keydata;        
     gpgme_error_t err;  
     gpgme_ctx_t ctx;  
     char *patt;  
     int n;  
   
     rset = keylist_enum_recipients (lv, KEYLIST_LIST, &n);  
     if (!n) {  
         msg_box (dlg, _("No key was selected for export."),  
                  _("Key Manager"), MB_ERR);  
         return WPTERR_GENERAL;  
     }  
       
     err = gpgme_data_new (&keydata);  
     if (err)  
         BUG (NULL);  
     err = gpgme_new (&ctx);  
     if (err)  
         BUG (NULL);  
     gpgme_set_armor (ctx, 1);  
   
     /*gpgme_set_comment (ctx, "Generated by WinPT "PGM_VERSION);*/  
     patt = gpg_keylist_to_pattern (rset, n);  
       
     err = gpgme_op_export( ctx, patt, 0, keydata);  
     if( err ) {  
         msg_box( dlg, gpgme_strerror( err ), _("Key Manager"), MB_ERR );  
         goto leave;  
     }  
           
     log_box( _("Key Manager"), MB_OK,  
              _("Key(s) successfully saved in '%s'."), fname );  
       
 leave:  
     err = gpg_data_release_and_set_file( keydata, fname );  
     if (err)  
         log_box (_("Key Manager"), MB_OK,  
                  _("Could not save data to '%s'."), fname);  
     gpgme_release (ctx);  
     free (patt);  
     return (int)err;  
 } /* km_file_export */  
   
   
 static int  
 extract_dash_escaped_key (void)  
 {  
     gpgme_data_t inp, plain;  
     gpgme_error_t err;  
   
     err = gpg_data_new_from_clipboard (&inp, 0);  
     if (err) {  
         msg_box (NULL, gpgme_strerror( err ), _("Key Manager"), MB_ERR);  
         return -1;  
     }  
     gpg_data_extract_plaintext (inp, &plain);  
     gpg_data_release_and_set_clipboard (plain, 0);  
     gpgme_data_release (inp);  
   
     return 0;  
 } /* extract_dash_escaped_key */  
   
   
 /* Import keys from the clipboard. */  
 int  
 km_clip_import (HWND dlg)  
 {  
     gpgme_error_t err;  
     int pgptype;  
     int id;  
     int has_data = 0;  
       
     if (!gpg_clip_istext_avail (&has_data) && !has_data) {  
         msg_box( dlg, winpt_strerror (WPTERR_CLIP_ISEMPTY), _("Key Manager"), MB_ERR);  
         return WPTERR_CLIP_ISEMPTY;  
     }  
     err = gpg_clip_is_secured (&pgptype, &has_data);  
     if (err)  
         msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);  
     if (!has_data) {  
         msg_box (dlg, _("No valid OpenPGP data found."), _("Key Manager"), MB_ERR);  
         return WPTERR_GENERAL;  
     }  
     if (!(pgptype & PGP_PUBKEY) && !(pgptype & PGP_SECKEY)) {  
         msg_box (dlg, _("No valid OpenPGP keys found."), _("Key Manager"), MB_ERR);  
         return WPTERR_GENERAL;  
     }  
     if (pgptype & PGP_DASH_ESCAPED) {  
         id = msg_box (dlg, _("The key you want to import is dash escacped.\n"  
                              "Do you want to extract the key?"),  
                       _("Key Manager"), MB_YESNO);  
         if (id == IDYES)  
             extract_dash_escaped_key ();  
         else  
             msg_box (dlg, _("Cannot import dash escaped OpenPGP keys."),  
                      _("Key Manager"), MB_INFO);  
     }  
   
     dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,  
                       clip_import_dlg_proc, NULL,  
                       _("Key Import"), IDS_WINPT_IMPORT);  
   
     return 0;  
 }  
   
   
 /* Import a key from the http URL @url. */  
 int  
 km_http_import (HWND dlg, const char *url)  
 {  
     http_hd_t hd;  
     FILE *fp;  
     char *p;  
     char tmpfile[500];  
     int statcode;  
     int rc = 0;  
   
     if (strncmp (url, "http://", 7)) {  
         log_box (_("Key Import HTTP"), MB_ERR, _("Invalid HTTP URL: %s"), url);  
         return WPTERR_GENERAL;  
     }  
   
     GetTempPath (sizeof (tmpfile)-128, tmpfile);  
     p = make_filename (tmpfile, "winpt_file_http", "tmp");  
     if (!p)  
         BUG (0);  
     fp = fopen (p, "wb");  
     if (!fp) {  
         free_if_alloc (p);  
         log_box (_("Key Import HTTP"), MB_ERR, "%s: %s", p, winpt_strerror (WPTERR_FILE_CREAT));  
         return WPTERR_FILE_CREAT;  
     }  
   
     /* parse URL */  
     rc = http_send_request2 (url, &hd);  
     if (!rc)  
         rc = http_parse_response (hd, &statcode);  
     if (!rc)  
         rc = http_parse_data (hd, fp);  
     http_hd_free (hd);  
     fclose (fp);  
     if (rc) {    
         msg_box (dlg, winpt_strerror (rc), _("Key Import HTTP"), MB_ERR);  
         rc = WPTERR_GENERAL;  
     }  
     km_file_import (dlg, p);  
     unlink (p);  
     free_if_alloc (p);  
     return rc;  
 }  
   
   
 /* Import a key from the given file @fname.  
    On success an import statistics dialog is shown. */  
 int  
 km_file_import (HWND dlg, const char *fname)  
 {  
     gpgme_data_t keydata = NULL;  
     gpgme_ctx_t ctx;  
     gpgme_error_t err;      
     fm_state_s fm_stat;  
     gpgme_import_result_t res;  
       
     memset (&fm_stat, 0, sizeof (fm_stat));  
     fm_stat.opaque = m_strdup (fname);  
       
     dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,  
                       file_import_dlg_proc, (LPARAM)&fm_stat,  
                       _("File Import"), IDS_WINPT_IMPORT);  
     if (fm_stat.cancel == 1 ) {  
         free_if_alloc (fm_stat.opaque);  
         return WPTERR_GENERAL;  
     }  
       
     err = gpgme_new (&ctx);  
     if (err)  
         BUG (NULL);  
     err = gpgme_data_new_from_file (&keydata, fname, 1);  
     if (err) {  
         msg_box (dlg, _("Could not read key-data from file."),  
                  _("Key Manager"), MB_ERR);  
         goto leave;  
     }  
       
     err = gpgme_op_import (ctx, keydata);  
     if (err) {  
         msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);  
         goto leave;  
     }      
   
     res = gpgme_op_import_result (ctx);  
     if (res->new_revocations == 0 && fm_stat.import.revcert == 1)  
         res->new_revocations = 1;  
     if (res->secret_imported == 0 && fm_stat.import.has_seckey == 1)  
         res->secret_imported = 1;  
   
     print_import_status (res);  
     if (res->no_user_id > 0) {  
         msg_box (dlg, _("Key without a self signature was dectected!\n"  
                         "(This key is NOT usable for encryption, etc)\n"  
                         "\n"      
                         "Cannot import these key(s)!"), _("Import"), MB_INFO);  
     }  
   
 leave:  
     gpgme_data_release (keydata);  
     gpgme_release (ctx);  
     free_if_alloc (fm_stat.opaque);  
     return (int)err;  
 }  
   
   
 /* Mark the keys in @rset as deleted in the keycache. */  
 static void  
 delete_keys_from_cache (gpgme_key_t *rset, size_t n)  
 {  
     gpg_keycache_t pub = keycache_get_ctx (1);  
     int i=0;  
   
     while (n-- > 0)  
         gpg_keycache_delete_key (pub, rset[i++]->subkeys->keyid);  
 }  
   
   
 /* Delete all selected keys from the list view @lv. */  
 int  
 km_delete_keys (listview_ctrl_t lv, HWND dlg)  
 {  
     gpgme_error_t err;  
     gpgme_ctx_t ctx;  
     gpgme_key_t *rset, k;  
     char keyid[32], uid[256], date[64], keylen[64];      
     int with_seckey=0, seckey_type=0, confirm=0;  
     int i, rc, n, k_pos=0;  
       
     if (listview_get_curr_pos (lv) == -1) {  
         msg_box (dlg, _("Please select a key."), _("Key Manager"), MB_ERR);  
         return WPTERR_GENERAL;  
     }  
           
     if (listview_count_items (lv, 1) > 8) {  
         i = msg_box (NULL, _("Do you really want to confirm each key?"),  
                      _("Delete Confirmation"), MB_YESNOCANCEL|MB_ICONQUESTION);  
         if (i == IDCANCEL)  
             return 0;  
         if (i != IDNO)  
             confirm = 1;  
     }  
     else  
         confirm = 1;  
   
     n = listview_count_items (lv, 0);  
     rset = (gpgme_key_t *)calloc (n+1, sizeof (gpgme_key_t));  
     if (!rset)  
         BUG (NULL);  
     for( i = 0; i < n; i++ ) {  
         if( listview_get_item_state( lv, i ) ) {  
             listview_get_item_text( lv, i, 0, uid, sizeof uid - 1 );  
             listview_get_item_text( lv, i, 1, keyid, sizeof keyid - 1 );  
             listview_get_item_text( lv, i, 3, keylen, sizeof keylen - 1 );  
             listview_get_item_text( lv, i, 7, date, sizeof date - 1 );  
             seckey_type = km_check_for_seckey (lv, i, NULL);  
             if (confirm && !seckey_type) {  
                 rc = log_box( _("Key Manager"), MB_YESNO|MB_ICONWARNING,  
                               _("Do you really want to delete this key?\n\n"  
                                 "pub %s %s %s\n"  
                                 "  \"%s\""), keylen, keyid, date, uid );  
                 if (rc == IDYES) {  
                     get_pubkey (keyid, &k);  
                     rset[k_pos++] = k;  
                 }  
                 with_seckey = 0;  
             }  
             else if (confirm) {  
                 rc = log_box( _("Key Manager"), MB_YESNO|MB_ICONWARNING,                  
                               _("Do you really want to delete this KEY PAIR?\n\n"  
                                 "Please remember that you are not able to decrypt\n"  
                                 "messages you stored with this key any longer.\n"  
                                 "\n"  
                                 "pub/sec %s %s %s\n"  
                                 "  \"%s\""), keylen, keyid, date, uid );  
                 if( rc == IDYES ) {  
                     if (seckey_type == 2)  
                         msg_box( dlg, _("The actual secret key is stored on a smartcard.\n"  
                                         "Only the public key and the secret key \n"  
                                         "placeholder will be deleted.\n"), _("Key Manager"), MB_OK );  
                     get_pubkey (keyid, &k);  
                     rset[k_pos++] = k;  
                 }  
                 with_seckey = 1;  
             }  
             else {  
                 with_seckey = 1;  
                 get_pubkey (keyid, &k);  
                 rset[k_pos++] = k;  
             }  
         }  
     }  
       
     if (k_pos == 0) {  
         free (rset);  
         return 0;  
     }  
   
     err = gpgme_new (&ctx);  
     if (err)  
         BUG (NULL);  
     n=k_pos;  
     for (i=0; i < k_pos; i++) {  
         err = gpgme_op_delete (ctx, rset[i], with_seckey);  
         if (err)  
             msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);  
         else  
             n--;  
     }  
     if (n == 0)  
         show_msg (dlg, 1500, _("GnuPG Status: Finished"));  
     gpgme_release (ctx);  
     listview_del_items (lv);  
     delete_keys_from_cache (rset, k_pos);  
     free (rset);  
   
     return (int)err;  
 }  
   
   
 int  
 km_send_to_keyserver (listview_ctrl_t lv, HWND dlg, const char * host, u16 port)  
 {  
     char keyid[32];  
     const char *t;  
     int id;  
       
     id = listview_get_curr_pos( lv );  
     if( id == -1 ) {  
         msg_box( dlg, _("Please select a key."), _("Key Manager"), MB_ERR );  
         return WPTERR_GENERAL;  
     }  
   
     listview_get_item_text( lv, id, 1, keyid, sizeof keyid - 1 );  
     id = log_box (_("Key Manager"), MB_YESNO,  
                   _("Do you really want to send '%s' to keyserver %s?"),  
                     keyid, host);  
     if (id == IDYES) {  
         t = keyid;  
         if (!strncmp (keyid, "0x", 2))  
             t += 2;  
         hkp_send_key (dlg, host, port, t);  
     }  
   
     return 0;  
 } /* km_send_to_keyserver */  
   
   
 int  
 km_send_to_mail_recipient( listview_ctrl_t lv, HWND dlg )  
 {  
 #if 0 /*FIXME*/  
     gpgme_key_t key;  
     gpgme_ctx_t ctx=NULL;  
     gpgme_recipients_t rset=NULL;  
     gpgme_error_t rc;  
     const char * s;  
     char keyid[32], tmp[192+256], * p =NULL;  
     int pos;  
   
     if( listview_count_items( lv, 1 ) > 1 ) {  
         msg_box( dlg, _("Please only select one key."), _("Key Manager"), MB_INFO|MB_OK );  
         return WPTERR_GENERAL;  
     }  
     pos = listview_get_curr_pos( lv );  
     if( pos == -1 ) {  
         msg_box( dlg, _("Please select a key."), _("Key Manager"), MB_ERR );  
         return WPTERR_GENERAL;  
     }  
     listview_get_item_text( lv, pos, 1, keyid, sizeof keyid-1 );  
     if( get_pubkey( keyid, &key ) )  
         BUG( NULL );  
     s = key->uids->name;  
     GetTempPath (sizeof tmp-1, tmp);  
     strncat (tmp, s, sizeof tmp-200);  
     strncat (tmp, ".asc", sizeof tmp-200);  
     p = fm_quote_file (tmp);  
   
     rc = gpgme_recipients_new( &rset );  
     if( !rc )  
         rc = gpgme_recipients_add_name( rset, keyid );  
     if( !rc )  
         rc = gpgme_new( &ctx );  
     if( !rc ) {  
         gpgme_set_armor (ctx, 1);  
         rc = gpgme_op_file_export( ctx, rset, p );  
     }  
     if( rc )  
         msg_box( dlg, gpgme_strerror( rc ), _("Key Manager"), MB_ERR );  
     else  
         mapi_send_pubkey (keyid, tmp);  
     free_if_alloc( p );  
     gpgme_recipients_release( rset );  
     gpgme_release( ctx );      
     return rc;  
 #endif  
     return 0;  
 }  
   
   
 static void  
 km_refresh_one_key (listview_ctrl_t lv, HWND dlg, int pos)  
 {  
     int idx;  
     char keyid[32];  
     const char *t;  
   
     if (pos != 0)  
         idx = pos;  
     else  
         idx = listview_get_curr_pos (lv);  
     if (idx != -1)  
     {  
         listview_get_item_text (lv, idx, 1, keyid, sizeof keyid - 1);  
         t = keyid;  
         if (!strncmp (keyid, "0x", 2))  
             t += 2;  
         hkp_recv_key (dlg, default_keyserver, default_keyserver_port, t, 0, KM_KS_REFRESH);  
     }  
 }  
   
   
 void  
 km_refresh_from_keyserver (listview_ctrl_t lv, HWND dlg)  
 {  
     int idx, id, i;  
       
     if (kserver_check_inet_connection ())  
     {  
         msg_box (dlg, _("Could not connect to keyserver, abort procedure."),  
                  _("Key Manager"), MB_ERR);  
         return;  
     }  
     idx = listview_count_items (lv, 0);  
     if (listview_count_items (lv, 1) == idx) {  
         id = msg_box (dlg, _("Do you really want to refresh all keys in the keyring?"), _("Key Manager"), MB_YESNO);  
         if (id == IDNO)  
             return;  
         for (i = 0; i < idx; i++)  
             km_refresh_one_key (lv, dlg, i);  
     }  
     else if (idx == 1)  
         km_refresh_one_key (lv, dlg, 0);  
     else {  
         for (i=0; i < listview_count_items (lv, 0); i++) {  
             if (listview_get_item_state (lv, i))  
                 km_refresh_one_key (lv, dlg, i);  
         }  
     }  
 } /* km_refresh_from_keyserver */  
   
   
 void  
 km_set_clip_info (const char *uid)  
 {      
     char buf[256];  
       
     key_get_clip_info (uid, buf, 255);      
     set_clip_text (NULL, buf, strlen (buf));  
 } /* km_set_clip_info */  
   
   
   
 /* Return TRUE if the key in the list @lv at pos @pos is an  
    old version 3 key. */  
 int  
 km_key_is_v3 (listview_ctrl_t lv, int pos)  
 {  
     gpgme_key_t pk;  
     char keyid[32];  
   
     listview_get_item_text (lv, pos, 1, keyid, sizeof keyid-1);  
     if (get_pubkey (keyid, &pk))  
         BUG (NULL);  
     if (strlen (pk->subkeys->fpr) == 32 &&  
         pk->subkeys->pubkey_algo == GPGME_PK_RSA)  
         return -1;  
     return 0;  
 }  
   
   
 /* Update the default key entry in the status bar for dialog @dlg. */  
 void  
 km_update_default_key_str (HWND dlg)  
 {  
     char *keyid, defkeyinf[512];  
     const char *fmt;  
       
     /* XXX: also show the name? */  
     keyid = get_gnupg_default_key ();  
     if (!keyid)  
         BUG (0);  
     if( (keyid[0] >= 'A' && keyid[0] <= 'Z') || (keyid[0] >= 'a' && keyid[0] <= 'z')  
         || (keyid[0] == '0' && keyid[1] == 'x') )  
         fmt = _("Default Key: %s");  
     else  
         fmt = _("Default Key: 0x%s");  
     _snprintf (defkeyinf, sizeof defkeyinf - 1, fmt, keyid);  
     SendMessage (dlg, SB_SETTEXT, 0, (LPARAM)defkeyinf);  
     free_if_alloc (keyid);  
 }  
   
   
 /* Count all keys and show from @lv results in the status bar @sb. */  
 void  
 km_complete_status_bar (HWND sb, listview_ctrl_t lv)  
 {  
     char txt_sec[128], txt_pub[128];  
     int nkeys = 0, nsec = 0, i;  
   
     nkeys = listview_count_items (lv, 0);  
     for (i = 0; i < nkeys; i++) {  
         if (km_check_for_seckey (lv, i, NULL))  
             nsec++;  
     }  
     _snprintf (txt_sec, sizeof (txt_sec)-1, _("%d secret keys"), nsec);  
     _snprintf (txt_pub, sizeof (txt_pub)-1, _("%d keys"), nkeys);  
     SendMessage (sb, SB_SETTEXT, 1, (LPARAM)txt_sec);  
     SendMessage (sb, SB_SETTEXT, 2, (LPARAM)txt_pub);  
 }  
   
   
 /* Set trust of selected key in @lv (at @pos) to ultimate. */  
 int  
 km_set_implicit_trust (HWND dlg, listview_ctrl_t lv, int pos)  
 {  
     GpgKeyEdit *ke;  
     gpgme_error_t err;      
     char keyid[32];  
   
     listview_get_item_text (lv, pos, 1, keyid, 31);  
   
     ke = new GpgKeyEdit (keyid);  
     if (!ke)  
         BUG (0);  
   
     err = ke->setTrust (GPGME_VALIDITY_ULTIMATE);  
     if (err)  
         msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);  
     else  
         show_msg (dlg, 1500, _("GnuPG Status: Finished"));  
   
     delete ke;  
     return (int)err;  
 }  
   
   
 void  
 km_find_key (HWND dlg, listview_ctrl_t lv)  
 {  
     int oldpos = listview_get_curr_pos (lv);  
     int n;  
     char *name = get_input_dialog (dlg, _("Search"), _("Search for:"));  
     if (name == NULL)  
         return;  
     if (oldpos < 0)  
         oldpos = 0;  
     n = listview_find (lv, name);  
     if (n != -1) {  
         listview_select_one (lv, n);  
         listview_scroll (lv, oldpos, n);  
     }  
     else {  
         const char *s = _("String pattern \"%s\" not found.");  
         char *p = new char[strlen (s) + strlen (name) + 2];  
         if (!p)  
             BUG (0);  
         sprintf (p, s, name);  
         msg_box (dlg, p, _("Key Manager"), MB_INFO);  
         free_if_alloc (p);  
     }  
     free_if_alloc (name);  
 }  
   
   
   
 void  
 km_dump_key (gpgme_key_t key)  
 {  
 #if _DEBUG  
     log_box ("DEBUG", MB_OK,  
              "%d %d %s %d\n%s", key->subkeys->length,  
              key->subkeys->pubkey_algo,  
              key->subkeys->keyid,  
              key->subkeys->timestamp,  
              key->uids->uid);  
 #endif  
 }  
   
 #if 0  
 gpg_optfile_t  
 km_groupdb_open (void)  
 {        
     gpg_optfile_t opt;  
     char * optfile;  
     int err = 0;  
       
     optfile = get_gnupg_cfgfile();  
     if( !optfile )  
         BUG( NULL );  
     if( parse_gpg_options( optfile, &opt ) )  
         err = 1;  
     free_if_alloc( optfile );  
     return err? NULL : opt;  
 } /* km_groupdb_open */  
   
   
 int  
 km_groupdb_expand_recipients( const char *name, gpgme_recipients_t rset )  
 {    
     gpg_keycache_t kc;  
     gpgme_key_t pk;  
     gpg_optfile_t opt;  
     gpg_group_t grp;      
     gpg_member_t mbr;  
     int no_trust = 0, n;  
   
     kc = keycache_get_ctx( 1 );  
     if( !kc )  
         BUG( NULL );  
   
     opt = km_groupdb_open( );  
     if( !opt )  
         return WPTERR_FILE_OPEN;  
       
     grp = find_group( opt, name );  
     if( !grp )  
         return WPTERR_GENERAL;  
       
     /* we are paranoid and check that all group members exist in the  
        key cache. there is no need that it is really the real key, but  
        an entry should be available. the rest is up to GPG. */  
     for( mbr = grp->list; mbr; mbr = mbr->next ) {  
         if( gpgme_keycache_find_key( kc, mbr->name, 0, &pk ) )  
             BUG( NULL );  
         n = count_userids (pk);  
         while( n-- ) {  
             gpgme_user_id_t u = get_nth_userid (pk, n);  
             const char * s =  u->uid;  
             if( s && stristr( s, mbr->name )  
                 && u->validity < 3 )  
                 no_trust++;  
         }  
     }  
   
     gpgme_recipients_add_name( rset, name );  
     release_gpg_options( opt );  
       
     return no_trust;  
 } /* km_groupdb_expand_recipients */  
   
   
 static HTREEITEM  
 km_tv_insert_item( HWND tree, HTREEITEM parent, const char *text )  
 {  
     TVINSERTSTRUCT tvis;  
     HTREEITEM node;  
       
     memset( &tvis, 0, sizeof tvis );  
     tvis.hParent = parent;  
     tvis.hInsertAfter = TVI_LAST;  
     tvis.item.mask = TVIF_TEXT;  
     tvis.item.pszText = (char *)text;  
     node = TreeView_InsertItem( tree, &tvis );  
     return node;  
 } /* km_tv_insert_item */  
   
   
 int  
 km_groups_new( km_group_t *r_gc, HWND ctrl )  
 {  
     km_group_t gc;  
       
     gc = new km_group_s;  
     if (!gc)  
         BUG (NULL);  
     gc->tree = ctrl;  
     gc->gh = km_groupdb_open ();  
     *r_gc = gc;  
     return 0;  
 } /* km_groups_new */  
   
   
 void  
 km_groups_sync( km_group_t gc )  
 {  
     char * optfile;  
   
     optfile = get_gnupg_cfgfile ();  
     if( !optfile )  
         BUG( NULL );  
     commit_gpg_options( optfile, gc->gh );  
     free_if_alloc( optfile );  
     gc->need_sync = 0;  
 } /* km_groups_sync */  
   
   
 void  
 km_groups_release (km_group_t gc)  
 {  
     if( gc ) {  
         /* xxx: this reset the default key (sync=1) */  
         gc->need_sync=0;  
         if (gc->need_sync)  
             km_groups_sync (gc);  
         if (gc->gh)  
             release_gpg_options( gc->gh );  
         gc->gh = NULL;  
         gc->tree = NULL;  
         delete gc;  
     }      
 } /* km_groups_release */  
   
   
 int  
 km_groups_load( km_group_t gc )  
 {      
     HTREEITEM n;  
     gpg_group_t grp, g;  
     gpg_member_t mbr;  
     u32 gid = 0;  
       
     if( !gc->gh )  
         return 0;  
     grp = gc->gh->grp;  
     if( !grp )  
         return 0; /* no groups */  
           
     for( g = grp; g; g = g->next ) {  
         n = km_tv_insert_item( gc->tree, NULL, g->name );  
         for( mbr = g->list; mbr; mbr = mbr->next ) {  
             if( mbr->used && mbr->name )  
                 km_tv_insert_item( gc->tree, n, mbr->name );  
         }  
     }  
     DragAcceptFiles( gc->tree, TRUE );  
     gc->need_sync = 0;  
     return 0;  
 } /* km_groups_load */  
   
   
 int  
 km_groups_add( km_group_t gc, listview_ctrl_t lv, int km_index )  
 {  
     TVITEM tvi;  
     char uid[128], valid[64], text[128];  
     int i_valid;  
       
     memset( &tvi, 0, sizeof tvi );  
     tvi.hItem = TreeView_GetSelection( gc->tree );  
     tvi.pszText = text;  
     tvi.cchTextMax = sizeof text -1;  
     tvi.mask = TVIF_TEXT;  
     TreeView_GetItem( gc->tree, &tvi );  
       
       
     listview_get_item_text( lv, km_index, 0, uid, sizeof uid -1 );  
     listview_get_item_text( lv, km_index, 5, valid, sizeof valid -1 );  
       
     if( strstr( valid, "Ultimate" ) )  
         i_valid = 5;      
     else if( !strstr( valid, "Full" ) )  
         i_valid = 4;  
     else if( !strstr( valid, "Marginal" ) )  
         i_valid = 3;  
     else  
         i_valid = 0;  
       
     /* we can't add the full name. one way would be to use the first  
        text until a space appears.  
     group_add_entry(&gc->gh, gid, i_valid, uid);  
     treeview_add_item(gc->tree, tvi.hItem, uid);  
     */  
     gc->need_sync = 1;  
       
     return 0;  
 } /* km_groups_add */  
   
   
 static int  
 km_groups_del_main( km_group_t gc )  
 {  
     TVITEM tvi;  
     char text[128];  
     int id;  
       
     memset( &tvi, 0, sizeof tvi );  
     tvi.hItem = TreeView_GetSelection( gc->tree );  
     tvi.pszText = text;  
     tvi.cchTextMax = sizeof text -1;  
     tvi.mask = TVIF_TEXT;  
     TreeView_GetItem( gc->tree, &tvi );  
                               
     id = log_box( _("Key Manager"), MB_INFO_ASK,  
                    _("Do you really want to delete this group?\n\n%s"), text);  
     if( id == IDNO )  
         return 0;  
     delete_group( gc->gh, text );      
     TreeView_DeleteItem( gc->tree, &tvi );  
     gc->need_sync = 1;  
       
     return 0;  
 } /* km_groups_del */  
   
   
 static int  
 km_groups_del_entry( km_group_t gc )  
 {  
     TVITEM tvi;  
     HTREEITEM root;  
     int id;  
     char text[128], info[256];  
     gpg_group_t  grp = NULL;  
       
     memset( &tvi, 0, sizeof tvi );  
     tvi.hItem = TreeView_GetSelection( gc->tree );  
     tvi.pszText = text;  
     tvi.cchTextMax = sizeof text-1;  
     tvi.mask = TVIF_TEXT;  
     TreeView_GetItem( gc->tree, &tvi );  
       
     _snprintf( info, sizeof info -1,  
               _("Do you really want to delete this entry?\n\n%s"), text );  
       
     id = msg_box( gc->tree, info, _("Key Manager"), MB_INFO_ASK );  
     if( id == IDNO )  
         return 0;  
   
     root = TreeView_GetParent( gc->tree, tvi.hItem );  
     if( root ) {  
     }  
       
     delete_member( gc->gh, /*fixme*/NULL, text );  
     TreeView_DeleteItem( gc->tree, &tvi );  
     gc->need_sync = 1;  
     return 0;  
 } /* km_groups_del_entry */  
   
   
 int  
 km_groups_del( km_group_t gc )  
 {  
     if ( TreeView_GetParent( gc->tree, TreeView_GetSelection( gc->tree ) ) )  
         return km_groups_del_entry( gc );  
     else  
         return km_groups_del_main( gc );  
 } /* km_groups_del */  
 #endif  
1    /* wptKeyManager.cpp - Handy functions for the Key Manager dialog
2     *      Copyright (C) 2001-2005 Timo Schulz
3     *      Copyright (C) 2005 g10 Code GmbH
4     *
5     * This file is part of WinPT.
6     *
7     * WinPT is free software; you can redistribute it and/or
8     * modify it under the terms of the GNU General Public License
9     * as published by the Free Software Foundation; either version 2
10     * of the License, or (at your option) any later version.
11     *  
12     * WinPT is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     * General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with WinPT; if not, write to the Free Software Foundation,
19     * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22    #ifdef HAVE_CONFIG_H
23    #include <config.h>
24    #endif
25    
26    #include <windows.h>
27    #include <commctrl.h>
28    #include <stdio.h>
29    
30    #include "gpgme.h"
31    #include "resource.h"
32    #include "wptTypes.h"
33    #include "wptW32API.h"
34    #include "wptVersion.h"
35    #include "wptCommonCtl.h"
36    #include "wptNLS.h"
37    #include "wptErrors.h"
38    #include "wptContext.h"
39    #include "wptGPG.h"
40    #include "wptKeylist.h"
41    #include "wptFileManager.h"
42    #include "wptDlgs.h"
43    #include "wptKeyserver.h"
44    #include "wptKeyManager.h"
45    #include "wptKeylist.h"
46    #include "wptHTTP.h"
47    #include "wptKeyEdit.h"
48    #include "wptImport.h"
49    #include "wptCrypto.h"
50    #include "wptUTF8.h"
51    
52    
53    /* Return a user friendly key representation in @buf of
54       the key given by @keyid. */
55    static void
56    key_get_clip_info (const char *keyid, char *buf, size_t buflen)
57    {
58        gpgme_key_t pk;
59        char *uid;
60    
61        if (get_pubkey (keyid, &pk))
62            BUG (NULL);
63        uid = utf8_to_wincp2 (pk->uids->uid);
64        _snprintf (buf, buflen-1,
65                   "pub %04d%s/%s %s %s\r\n"
66                   "    Primary key fingerprint: %s\r\n",
67                   pk->subkeys->length,
68                   get_key_pubalgo2 (pk->subkeys->pubkey_algo),
69                   pk->subkeys->keyid+8,
70                   get_key_created (pk->subkeys->timestamp),
71                   uid,
72                   get_key_fpr (pk));
73        safe_free (uid);
74    }
75    
76    
77    /* Return a general description of the key @key. */
78    static char*
79    key_get_info (gpgme_key_t pk, int is_sec)
80    {
81        const char *fmt = "%s %04d%s/0x%s %s\n  \"%s\"";
82        char *p, *uid;
83        int n;
84    
85        n = strlen (fmt) + 8 + 2 + 16 + 12 + strlen (pk->uids->uid) + 32;
86        p = new char[n+1];
87        if (!p)
88            BUG (NULL);
89        uid = utf8_to_wincp2 (pk->uids->uid);
90        _snprintf (p, n, fmt, is_sec? "sec" : "pub",
91                   pk->subkeys->length,
92                   get_key_pubalgo2 (pk->subkeys->pubkey_algo),
93                   pk->subkeys->keyid+8, get_key_created (pk->subkeys->timestamp),
94                   uid);
95        safe_free (uid);
96        return p;
97    }
98    
99    
100    #if 0
101    /* Quoted the user-id given by @uid. If @uid is already
102       quoted @uid is returned without any modifications.
103       Return value: quoted @uid. */
104    char*
105    km_quote_uid (const char *uid)
106    {    
107        char *q;
108    
109        if (*uid == '"' && uid[strlen (uid)-1] == '"')
110            return m_strdup (uid);
111        q = new char[strlen (uid) + 4];
112        if (!q)
113            BUG (NULL);
114        _snprintf (q, strlen (uid) + 3, "\"%s\"", uid);
115        return q;
116    }
117    #endif
118    
119    
120    /* Check if list view @lv contains a secret key at position @pos.
121       If utrust is valid, set it to 1 if the key is valid -1 otherwise.
122       Return value: 1 normal key, 2 smart card key. */
123    int
124    km_check_for_seckey (listview_ctrl_t lv, int pos, int *utrust)
125    {
126        gpgme_key_t key;
127        winpt_key_s sk;
128        int type = 0;
129        
130        key = (gpgme_key_t)listview_get_item2 (lv, pos);
131        if (!key)
132            BUG (NULL);
133        if (utrust)
134            *utrust = 0;
135        memset (&sk, 0, sizeof (sk));
136        if (!winpt_get_seckey (key->subkeys->keyid+8, &sk))
137            type = 1;
138        if (sk.ext && sk.ext->gloflags.divert_to_card)
139            type = 2;
140        if (utrust && (key->expired || key->revoked))
141            *utrust = -1;
142        else if (utrust && key->owner_trust == GPGME_VALIDITY_ULTIMATE)
143            *utrust = 1;
144        return type;
145    }
146    
147    
148    /* Check if the key at position @pos is protected with a passwd. */
149    int
150    km_check_if_protected (listview_ctrl_t lv, int pos)
151    {
152        gpgme_key_t key;
153        winpt_key_s k;
154    
155        key = (gpgme_key_t)listview_get_item2 (lv, pos);
156        if (!key)
157            return 1; /* assume yes */
158        winpt_get_pubkey (key->subkeys->keyid, &k);
159        return k.is_protected;
160    }
161    
162    
163    /* Check if the key has a good status.
164       Return value: 0 on success. */
165    int
166    km_check_key_status (listview_ctrl_t lv, int pos)
167    {
168        int flags = km_get_key_status (lv, pos);
169        
170        if (flags & KM_FLAG_EXPIRED) {
171            msg_box (lv->ctrl, _("This key has expired!\n"  
172                                 "Key check failed."), _("Key Manager"), MB_ERR);
173            return -1;
174        }
175        else if (flags & KM_FLAG_REVOKED) {
176            msg_box (lv->ctrl, _("This key has been revoked by its owner!\n"
177                                 "Key check failed."), _("Key Manager"), MB_ERR);
178            return -1;
179        }
180    
181        return 0;
182    }
183    
184    
185    /* Return all key flags ORed. */
186    int
187    km_get_key_status (listview_ctrl_t lv, int pos)
188    {
189        gpgme_key_t key;
190        int flags = 0;
191    
192        if (pos == -1)
193            return 0;
194        key = (gpgme_key_t)listview_get_item2 (lv, pos);
195        if (key == NULL)
196            return 0;
197    
198        if (key->expired)
199            flags |= KM_FLAG_EXPIRED;
200        if (key->revoked)
201            flags |= KM_FLAG_REVOKED;
202        if (key->disabled)
203            flags |= KM_FLAG_DISABLED;
204        return flags;
205    }
206    
207    
208    /* Interface to enable or disable a key (@enable = 1 then enable).
209       The key is retrieved from a list control @lv at the pos @pos. */
210    int
211    km_enable_disable_key (listview_ctrl_t lv, HWND dlg, int pos, int enable)
212    {
213        gpgme_error_t err;
214        gpgme_key_t key;
215        GpgKeyEdit *ke;
216    
217        key = (gpgme_key_t)listview_get_item2 (lv, pos);
218        if (!key)
219            BUG (NULL);
220        ke = new GpgKeyEdit (key->subkeys->keyid);
221        if (!ke)
222            BUG (NULL);
223    
224        err = enable? ke->enable () : ke->disable ();
225        if (!err)
226            show_msg (dlg, 1500, _("Key status changed."));
227        else
228            msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
229        delete ke;
230        return err? WPTERR_GENERAL : 0;
231    }
232    
233    
234    
235    /* Create a string that contain all keyids from
236       the key list @rset separated by a space. */
237    char*
238    gpg_keylist_to_pattern (gpgme_key_t *rset, int n)
239    {
240        char *p;
241        int i;
242    
243        if (!n)
244            return NULL;
245        p = (char *)calloc (1, n*(16+1)+n+2);
246        if (!p)
247            BUG (NULL);
248        for (i=0; i < n; i++) {
249            strcat (p, rset[i]->subkeys->keyid);
250            strcat (p, " ");
251        }
252        return p;
253    }
254    
255    
256    /* Export the keys given in @rset to the clipboard.
257       Return value: 0 on success. */
258    static gpgme_error_t
259    gpg_clip_export (gpgme_key_t *rset, int n)
260    {
261        gpgme_error_t err = 0;
262        gpgme_ctx_t ctx = NULL;
263        gpgme_data_t keydata = NULL;
264        char *patt=NULL;
265        
266        err = gpgme_new (&ctx);
267        if (err)
268            return err;
269        gpgme_set_armor (ctx, 1);          
270        err = gpgme_data_new (&keydata);
271        if (err)
272            goto leave;
273    
274        patt = gpg_keylist_to_pattern (rset, n);
275        if (!patt) {
276            err = gpg_error (GPG_ERR_ENOMEM);
277            goto leave;
278        }
279    
280        err = gpgme_op_export (ctx, patt, 0, keydata);
281        if (err)
282            goto leave;
283    
284        gpg_data_release_and_set_clipboard (keydata, 1);
285    
286    leave:
287        if (patt)
288            free (patt);
289        gpgme_release (ctx);
290        return err;
291    }
292    
293    
294    /* Export the selected keys in @lv to the clipboard. */
295    int
296    km_clip_export (HWND dlg, listview_ctrl_t lv)
297    {
298        gpgme_error_t err;
299        gpgme_key_t *rset;
300        char buf[256];
301        int n=0;
302        int rc=0;
303        
304        rset = keylist_enum_recipients (lv, KEYLIST_LIST, &n);
305        if (!n) {
306            msg_box (dlg, _("No key was selected for export."),
307                     _("Key Manager"), MB_ERR);
308            rc = WPTERR_GENERAL;
309            goto leave;
310        }
311        
312        err = gpg_clip_export (rset, n);
313        if (err) {
314            msg_box( dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
315            rc = WPTERR_GENERAL;
316            goto leave;
317        }
318        if (n == 1) {
319            key_get_clip_info (rset[0]->subkeys->keyid, buf, sizeof (buf)-1);
320            set_clip_text2 (NULL, buf, strlen (buf), 0);
321        }
322    
323        show_msg (dlg, 1500, _("GnuPG Status: Finished"));
324        
325    leave:
326        free (rset);
327        return rc;
328    }
329    
330    
331    /* Export the selected secret key from @lv into @fname.
332       It is only allowed to export a single secret key. */
333    int
334    km_privkey_export (HWND dlg, listview_ctrl_t lv, const char *fname)
335    {
336        gpgme_key_t *rset;
337        gpgme_error_t err;
338        int n = 0;
339    
340        rset = keylist_enum_recipients (lv, KEYLIST_LIST, &n);
341        if (!n) {
342            msg_box (dlg, _("No key was selected for export."),
343                     _("Key Manager"), MB_ERR);
344            return WPTERR_GENERAL;
345        }
346        if (n > 1) {
347            msg_box (dlg, _("Only one secret key can be exported."),
348                     _("Key Manager"), MB_ERR);
349            free (rset);
350            return 0; /* we checked this before, so we just quit */
351        }
352    
353        err = gpg_export_seckey (rset[0]->subkeys->keyid, fname);
354        if (err)
355            msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
356        else
357            log_box (_("Key Manager"), MB_OK,
358                     _("Secret key successfully saved in '%s'."), fname);
359    
360        free (rset);
361        return err? WPTERR_GENERAL : 0;
362    }
363    
364    
365    /* Export the selected recipients from @lv into the file @fname. */
366    int
367    km_file_export (HWND dlg, listview_ctrl_t lv, const char *fname)
368    {
369        gpgme_key_t *rset;
370        gpgme_data_t keydata;      
371        gpgme_error_t err;
372        gpgme_ctx_t ctx;
373        char *patt;
374        int n;
375    
376        rset = keylist_enum_recipients (lv, KEYLIST_LIST, &n);
377        if (!n) {
378            msg_box (dlg, _("No key was selected for export."),
379                     _("Key Manager"), MB_ERR);
380            return WPTERR_GENERAL;
381        }
382        
383        err = gpgme_data_new (&keydata);
384        if (err)
385            BUG (NULL);
386        err = gpgme_new (&ctx);
387        if (err)
388            BUG (NULL);
389        gpgme_set_armor (ctx, 1);
390    
391        /*gpgme_set_comment (ctx, "Generated by WinPT "PGM_VERSION);*/
392        patt = gpg_keylist_to_pattern (rset, n);
393        
394        err = gpgme_op_export (ctx, patt, 0, keydata);
395        if( err ) {
396            msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
397            goto leave;
398        }
399    
400        log_box (_("Key Manager"), MB_OK,
401                 _("Key(s) successfully saved in '%s'."), fname);
402        
403    leave:
404        err = gpg_data_release_and_set_file (keydata, fname);
405        if (err)
406            log_box (_("Key Manager"), MB_OK,
407                     _("Could not save data to '%s'."), fname);
408        gpgme_release (ctx);
409        free (patt);
410        return (int)err;
411    }
412    
413    
414    /* Read a dash escaped key from the clipboard
415       unescape it and write it back. */
416    static int
417    extract_dash_escaped_key (void)
418    {
419        gpgme_data_t inp, plain;
420        gpgme_error_t err;
421    
422        err = gpg_data_new_from_clipboard (&inp, 0);
423        if (err) {
424            msg_box (NULL, gpgme_strerror (err), _("Key Manager"), MB_ERR);
425            return -1;
426        }
427        gpg_data_extract_plaintext (inp, &plain);
428        gpg_data_release_and_set_clipboard (plain, 0);
429        gpgme_data_release (inp);
430    
431        return 0;
432    }
433    
434    
435    /* Import keys from the clipboard. */
436    int
437    km_clip_import (HWND dlg)
438    {
439        gpgme_error_t err;
440        int pgptype;
441        int id;
442        int has_data = 0;
443        
444        if (!gpg_clip_istext_avail (&has_data) && !has_data) {
445            msg_box (dlg, winpt_strerror (WPTERR_CLIP_ISEMPTY),
446                     _("Key Manager"), MB_ERR);
447            return WPTERR_CLIP_ISEMPTY;
448        }
449        err = gpg_clip_is_secured (&pgptype, &has_data);
450        if (err)
451            msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
452        if (!has_data) {
453            msg_box (dlg, _("No valid OpenPGP data found."),
454                     _("Key Manager"), MB_ERR);
455            return WPTERR_GENERAL;
456        }
457        if (!(pgptype & PGP_PUBKEY) && !(pgptype & PGP_SECKEY)) {
458            msg_box (dlg, _("No valid OpenPGP keys found."),
459                     _("Key Manager"), MB_ERR);
460            return WPTERR_GENERAL;
461        }
462        if (pgptype & PGP_DASH_ESCAPED) {
463            id = msg_box (dlg, _("The key you want to import is dash escacped.\n"
464                                 "Do you want to extract the key?"),
465                          _("Key Manager"), MB_YESNO);
466            if (id == IDYES)
467                extract_dash_escaped_key ();
468            else
469                msg_box (dlg, _("Cannot import dash escaped OpenPGP keys."),
470                         _("Key Manager"), MB_INFO);
471        }
472    
473        dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,
474                          clip_import_dlg_proc, 0,
475                          _("Key Import"), IDS_WINPT_IMPORT);
476    
477        return 0;
478    }
479    
480    
481    /* Import a key from the http URL @url. */
482    int
483    km_http_import (HWND dlg, const char *url)
484    {
485        http_hd_t hd;
486        FILE *fp;
487        char *p;
488        char tmpfile[500];
489        int statcode;
490        int rc = 0;
491    
492        if (strncmp (url, "http://", 7)) {
493            log_box (_("Key Import HTTP"), MB_ERR, _("Invalid HTTP URL: %s"), url);
494            return WPTERR_GENERAL;
495        }
496    
497        GetTempPath (sizeof (tmpfile)-128, tmpfile);
498        p = make_filename (tmpfile, "winpt_file_http", "tmp");
499        if (!p)
500            BUG (0);
501        fp = fopen (p, "wb");
502        if (!fp) {
503            free_if_alloc (p);
504            log_box (_("Key Import HTTP"), MB_ERR, "%s: %s", p,
505                     winpt_strerror (WPTERR_FILE_CREAT));
506            return WPTERR_FILE_CREAT;
507        }
508    
509        /* parse URL */
510        rc = http_send_request2 (url, &hd);
511        if (!rc)
512            rc = http_parse_response (hd, &statcode);
513        if (!rc)
514            rc = http_parse_data (hd, fp);
515        http_hd_free (hd);
516        fclose (fp);
517        if (rc) {  
518            msg_box (dlg, winpt_strerror (rc), _("Key Import HTTP"), MB_ERR);
519            rc = WPTERR_GENERAL;
520        }
521        km_file_import (dlg, p);
522        remove (p);
523        free_if_alloc (p);
524        return rc;
525    }
526    
527    
528    /* Import a key from the given file @fname.
529       On success an import statistics dialog is shown. */
530    int
531    km_file_import (HWND dlg, const char *fname)
532    {
533        gpgme_data_t keydata = NULL;
534        gpgme_ctx_t ctx;
535        gpgme_error_t err;    
536        fm_state_s fm_stat;
537        gpgme_import_result_t res;
538        
539        memset (&fm_stat, 0, sizeof (fm_stat));
540        fm_stat.opaque = m_strdup (fname);
541        
542        dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,
543                          file_import_dlg_proc, (LPARAM)&fm_stat,
544                          _("File Import"), IDS_WINPT_IMPORT);
545        if (fm_stat.cancel == 1) {
546            free_if_alloc (fm_stat.opaque);
547            return WPTERR_GENERAL;
548        }
549        
550        err = gpgme_new (&ctx);
551        if (err)
552            BUG (NULL);
553        err = gpgme_data_new_from_file (&keydata, fname, 1);
554        if (err) {
555            msg_box (dlg, _("Could not read key-data from file."),
556                     _("Key Manager"), MB_ERR);
557            goto leave;
558        }
559        
560        SetCursor (LoadCursor (NULL, IDC_WAIT));
561        err = gpgme_op_import (ctx, keydata);
562        SetCursor (LoadCursor (NULL, IDC_ARROW));
563        if (err) {
564            msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
565            goto leave;
566        }    
567    
568        res = gpgme_op_import_result (ctx);
569        if (res->new_revocations == 0 && fm_stat.import.revcert == 1)
570            res->new_revocations = 1;
571        if (res->secret_imported == 0 && fm_stat.import.has_seckey == 1)
572            res->secret_imported = 1;
573    
574        /* XXX: if we import a key pair but the secret key comes first,
575                no_{valid}_user_id is 1 even so the public key, which comes
576                later is valid and self-signed. */
577        print_import_status (res);
578        if (res->no_user_id > 0) {
579            msg_box (dlg, _("Key without a self signature was dectected!\n"
580                            "(This key is NOT usable for encryption, etc)\n"
581                            "\n"    
582                            "Cannot import these key(s)!"), _("Import"), MB_INFO);
583        }
584    
585    leave:
586        gpgme_data_release (keydata);
587        gpgme_release (ctx);
588        free_if_alloc (fm_stat.opaque);
589        return (int)err;
590    }
591    
592    
593    /* Mark the keys in @rset as deleted in the keycache. */
594    static void
595    delete_keys_from_cache (gpgme_key_t *rset, size_t n)
596    {
597        gpg_keycache_t pub = keycache_get_ctx (1);
598        int i=0;
599    
600        while (n-- > 0)
601            gpg_keycache_delete_key (pub, rset[i++]->subkeys->keyid);
602    }
603    
604    
605    /* Delete all selected keys from the list view @lv. */
606    int
607    km_delete_keys (listview_ctrl_t lv, HWND dlg)
608    {
609        gpgme_error_t err;
610        gpgme_ctx_t ctx;
611        gpgme_key_t *rset;
612        gpgme_key_t key;
613        char keyid[32];
614        char *p;
615        int with_seckey=0, seckey_type=0, confirm=0;
616        int i, rc, n, k_pos=0;
617        
618        if (listview_get_curr_pos (lv) == -1) {
619            msg_box (dlg, _("Please select a key."), _("Key Manager"), MB_ERR);
620            return -1;
621        }
622            
623        if (listview_count_items (lv, 1) > 8) {
624            i = msg_box (NULL, _("Do you really want to confirm each key?"),
625                         _("Delete Confirmation"), MB_YESNOCANCEL|MB_ICONQUESTION);
626            if (i == IDCANCEL)
627                return 0;
628            if (i != IDNO)
629                confirm = 1;
630        }
631        else
632            confirm = 1;
633    
634        n = listview_count_items (lv, 0);
635        rset = (gpgme_key_t *)calloc (n+1, sizeof (gpgme_key_t));
636        if (!rset)
637            BUG (NULL);
638        for (i = 0; i < n; i++) {
639            if (listview_get_item_state(lv, i)) {
640                key = (gpgme_key_t)listview_get_item2 (lv, i);
641                if (!key)
642                    BUG (NULL);
643                seckey_type = km_check_for_seckey (lv, i, NULL);
644                if (confirm && !seckey_type) {
645                    p = key_get_info (key, 0);
646                    rc = log_box( _("Key Manager"), MB_YESNO|MB_ICONWARNING,
647                                  _("Do you really want to delete this key?\n\n"
648                                    "%s"), p);
649                    if (rc == IDYES)
650                        rset[k_pos++] = key;
651                    with_seckey = 0;
652                    free_if_alloc (p);
653                }
654                else if (confirm) {
655                    p = key_get_info (key, 1);
656                    rc = log_box (_("Key Manager"), MB_YESNO|MB_ICONWARNING,                
657                                  _("Do you really want to delete this KEY PAIR?\n\n"
658                                    "Please remember that you are not able to decrypt\n"
659                                    "messages you stored with this key any longer.\n"
660                                    "\n"
661                                    "%s"), p);
662                    if( rc == IDYES ) {
663                        if (seckey_type == 2)
664                            msg_box (dlg, _("The actual secret key is stored on a smartcard.\n"
665                                            "Only the public key and the secret key \n"
666                                            "placeholder will be deleted.\n"),
667                                            _("Key Manager"), MB_OK);
668                        rset[k_pos++] = key;
669                    }
670                    with_seckey = 1;
671                    free_if_alloc (p);
672                }
673                else {
674                    with_seckey = 1;
675                    get_pubkey (keyid, &key);
676                    rset[k_pos++] = key;
677                }
678            }
679        }
680        
681        if (k_pos == 0) {
682            free (rset);
683            return 0;
684        }
685    
686        err = gpgme_new (&ctx);
687        if (err)
688            BUG (NULL);
689        n = k_pos;
690        for (i=0; i < k_pos; i++) {
691            err = gpgme_op_delete (ctx, rset[i], with_seckey);
692            if (err)
693                msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
694            else
695                n--;
696        }
697        if (n == 0)
698            show_msg (dlg, 1500, _("GnuPG Status: Finished"));      
699        gpgme_release (ctx);
700        listview_del_items (lv);
701        delete_keys_from_cache (rset, k_pos);
702        free (rset);
703    
704        return (int)err;
705    }
706    
707    
708    /* Send the select key in @lv to the keyserver @host:@port. */
709    int
710    km_send_to_keyserver (listview_ctrl_t lv, HWND dlg, const char *host, u16 port)
711    {
712        gpgme_key_t key;
713        int id;
714        
715        id = listview_get_curr_pos (lv);
716        if (id == -1) {
717            msg_box( dlg, _("Please select a key."), _("Key Manager"), MB_ERR );
718            return WPTERR_GENERAL;
719        }
720    
721        key = (gpgme_key_t)listview_get_item2 (lv, id);
722        if (!key)
723            BUG (NULL);
724        id = log_box (_("Key Manager"), MB_YESNO,
725                      _("Do you really want to send '%s' to keyserver %s?"),
726                        key->subkeys->keyid+8, host);
727        if (id == IDYES)
728            hkp_send_key (dlg, host, port, key->subkeys->keyid+8);
729    
730        return 0;
731    }
732    
733    
734    /* Send the selected key in @lv via MAPI to a mail recipient. */
735    int
736    km_send_to_mail_recipient (listview_ctrl_t lv, HWND dlg)
737    {
738        gpgme_key_t key;
739        gpgme_ctx_t ctx=NULL;
740        gpgme_data_t out;
741        gpgme_error_t rc;
742        char tmp[128];
743        char *fname;
744        char *name;
745        int pos;
746    
747        if (listview_count_items (lv, 1) > 1) {
748            msg_box (dlg, _("Please only select one key."),
749                     _("Key Manager"), MB_INFO|MB_OK);
750            return WPTERR_GENERAL;
751        }
752        pos = listview_get_curr_pos (lv);
753        if (pos == -1) {
754            msg_box (dlg, _("Please select a key."), _("Key Manager"), MB_ERR);
755            return WPTERR_GENERAL;
756        }
757        key = (gpgme_key_t)listview_get_item2 (lv, pos);
758        if (!key)
759            BUG (NULL);
760    
761        GetTempPath (sizeof (tmp)-1, tmp);
762        if (tmp[strlen (tmp)-1] == '\\')
763            tmp[strlen (tmp)-1] = 0;
764        name = utf8_to_wincp2 (key->uids->name);
765        fname = make_filename (tmp, name, "asc");
766        for (pos=0; pos < (int)strlen (fname); pos++) {
767            if (fname[pos] == ' ')
768                fname[pos] = '_';
769        }
770    
771        rc = gpgme_new (&ctx);
772        if (rc)
773            BUG (NULL);
774        rc = gpgme_data_new (&out);
775        if (rc)
776            BUG (NULL);
777    
778        gpgme_set_armor (ctx, 1);
779        rc = gpgme_op_export (ctx, key->subkeys->keyid, 0, out);
780        if (rc)
781            msg_box (dlg, gpgme_strerror (rc), _("Key Manager"), MB_ERR);
782        else
783            mapi_send_pubkey (key->subkeys->keyid+8, fname);
784    
785        gpg_data_release_and_set_file (out, fname);
786        gpgme_release (ctx);
787        safe_free (name);
788        free_if_alloc (fname);
789        return rc;
790    }
791    
792    
793    static void
794    km_refresh_one_key (listview_ctrl_t lv, HWND dlg, int pos)
795    {
796        gpgme_key_t key;
797        int idx;
798    
799        if (pos != 0)
800            idx = pos;
801        else
802            idx = listview_get_curr_pos (lv);
803        if (idx != -1) {
804            key = (gpgme_key_t)listview_get_item2 (lv, idx);
805            hkp_recv_key (dlg, default_keyserver, default_keyserver_port,
806                          key->subkeys->keyid+8, 0, KM_KS_REFRESH);
807        }
808    }
809    
810    
811    /* Refresh all keys from the default keyserver. */
812    void
813    km_refresh_from_keyserver (listview_ctrl_t lv, HWND dlg)
814    {
815        int idx, id, i;
816        
817        if (kserver_check_inet_connection ()) {
818            msg_box (dlg, _("Could not connect to keyserver, abort procedure."),
819                     _("Key Manager"), MB_ERR);
820            return;
821        }
822        idx = listview_count_items (lv, 0);
823        if (listview_count_items (lv, 1) == idx) {
824            id = msg_box (dlg, _("Do you really want to refresh all keys in the keyring?"),
825                          _("Key Manager"), MB_YESNO);
826            if (id == IDNO)
827                return;
828            for (i = 0; i < idx; i++)
829                km_refresh_one_key (lv, dlg, i);
830        }
831        else if (idx == 1)
832            km_refresh_one_key (lv, dlg, 0);
833        else {
834            for (i=0; i < listview_count_items (lv, 0); i++) {
835                if (listview_get_item_state (lv, i))
836                    km_refresh_one_key (lv, dlg, i);
837            }
838        }
839    }
840    
841    
842    void
843    km_set_clip_info (const char *uid)
844    {    
845        char buf[256];
846        
847        key_get_clip_info (uid, buf, sizeof (buf)-1);
848        set_clip_text (NULL, buf, strlen (buf));
849    }
850    
851    
852    
853    /* Return TRUE if the key in the list @lv at pos @pos is an
854       old version 3 key. */
855    int
856    km_key_is_v3 (listview_ctrl_t lv, int pos)
857    {
858        gpgme_key_t pk;
859    
860        pk = (gpgme_key_t)listview_get_item2 (lv, pos);
861        if (!pk)
862            BUG (NULL);
863        if (strlen (pk->subkeys->fpr) == 32 &&
864            pk->subkeys->pubkey_algo == GPGME_PK_RSA)
865            return -1;
866        return 0;
867    }
868    
869    
870    /* Set trust of selected key in @lv (at @pos) to ultimate. */
871    int
872    km_set_implicit_trust (HWND dlg, listview_ctrl_t lv, int pos)
873    {
874        gpgme_error_t err;
875        gpgme_key_t key;
876        GpgKeyEdit *ke;
877    
878        key = (gpgme_key_t)listview_get_item2 (lv, pos);
879        if (!key)
880            BUG (NULL);
881        ke = new GpgKeyEdit (key->subkeys->keyid);
882        if (!ke)
883            BUG (0);
884    
885        err = ke->setTrust (GPGME_VALIDITY_ULTIMATE);
886        if (err)
887            msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
888        else
889            show_msg (dlg, 1500, _("GnuPG Status: Finished"));
890    
891        delete ke;
892        return (int)err;
893    }
894    
895    
896    void
897    km_find_key (HWND dlg, listview_ctrl_t lv)
898    {
899        int oldpos = listview_get_curr_pos (lv);
900        int n;
901        char *name = get_input_dialog (dlg, _("Search"), _("Search for:"));
902        if (name == NULL)
903            return;
904        if (oldpos < 0)
905            oldpos = 0;
906        n = listview_find (lv, name);
907        if (n != -1) {
908            listview_select_one (lv, n);
909            listview_scroll (lv, oldpos, n);
910        }
911        else {
912            const char *s = _("String pattern \"%s\" not found.");
913            char *p = new char[strlen (s) + strlen (name) + 2];
914            if (!p)
915                BUG (0);
916            sprintf (p, s, name);
917            msg_box (dlg, p, _("Key Manager"), MB_INFO);
918            free_if_alloc (p);
919        }
920        free_if_alloc (name);
921    }
922    
923    
924    /* Return a user-friendly name for a key derrived from
925       name. If @is_secret is 1, a secret key name will be generated. */
926    char*
927    km_gen_export_filename (const char *keyid, int is_secret)
928    {
929        gpgme_key_t key;
930        char *p, *uid;
931    
932        if (get_pubkey (keyid, &key))
933            return m_strdup (keyid);
934        uid = utf8_to_wincp2 (key->uids->name);
935        if (!uid)
936            return m_strdup (keyid);
937        p = new char[strlen (uid) + 8 + 16];
938        if (!p)
939            BUG (0);
940        sprintf (p, "%s%s.asc", uid, is_secret? "_sec" : "");
941        for (size_t i=0; i < strlen (p); i++) {
942            if (p[i] == ' ' || p[i] == ':' || p[i] == '?' || p[i] == '|')
943                p[i] = '_';
944        }
945        safe_free (uid);
946        return p;
947    }

Legend:
Removed from v.33  
changed lines
  Added in v.129

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26