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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26