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

Legend:
Removed from v.34  
changed lines
  Added in v.164

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26