/[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 150 by twoaday, Wed Jan 18 11:52:45 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;  
     }  
       
     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-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)
431    {
432        gpgme_error_t err;
433        int pgptype;
434        int id;
435        int 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_GENERAL;
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_GENERAL;
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        has_data = dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,
467                                     clip_import_dlg_proc, 0,
468                                     _("Key Import"), IDS_WINPT_IMPORT);
469        if (!has_data)
470            return WPTERR_GENERAL;
471        return 0;
472    }
473    
474    
475    /* Import a key from the http URL @url. */
476    int
477    km_http_import (HWND dlg, const char *url)
478    {
479        http_hd_t hd;
480        FILE *fp;
481        char *p;
482        char tmpfile[500];
483        int statcode;
484        int rc = 0;
485    
486        if (strncmp (url, "http://", 7)) {
487            log_box (_("Key Import HTTP"), MB_ERR, _("Invalid HTTP URL: %s"), url);
488            return WPTERR_GENERAL;
489        }
490    
491        GetTempPath (sizeof (tmpfile)-128, tmpfile);
492        p = make_filename (tmpfile, "winpt_file_http", "tmp");
493        if (!p)
494            BUG (0);
495        fp = fopen (p, "wb");
496        if (!fp) {
497            free_if_alloc (p);
498            log_box (_("Key Import HTTP"), MB_ERR, "%s: %s", p,
499                     winpt_strerror (WPTERR_FILE_CREAT));
500            return WPTERR_FILE_CREAT;
501        }
502    
503        /* parse URL */
504        rc = http_send_request2 (url, &hd);
505        if (!rc)
506            rc = http_parse_response (hd, &statcode);
507        if (!rc)
508            rc = http_parse_data (hd, fp);
509        http_hd_free (hd);
510        fclose (fp);
511        if (rc) {  
512            msg_box (dlg, winpt_strerror (rc), _("Key Import HTTP"), MB_ERR);
513            rc = WPTERR_GENERAL;
514        }
515        km_file_import (dlg, p);
516        remove (p);
517        free_if_alloc (p);
518        return rc;
519    }
520    
521    
522    /* Import a key from the given file @fname.
523       On success an import statistics dialog is shown. */
524    int
525    km_file_import (HWND dlg, const char *fname)
526    {
527        gpgme_data_t keydata = NULL;
528        gpgme_ctx_t ctx;
529        gpgme_error_t err;    
530        fm_state_s fm_stat;
531        gpgme_import_result_t res;
532        int no_data = 0;
533        
534        memset (&fm_stat, 0, sizeof (fm_stat));
535        fm_stat.opaque = m_strdup (fname);
536        
537        dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,
538                          file_import_dlg_proc, (LPARAM)&fm_stat,
539                          _("File Import"), IDS_WINPT_IMPORT);
540        if (fm_stat.cancel == 1) {
541            free_if_alloc (fm_stat.opaque);
542            return WPTERR_GENERAL;
543        }
544        
545        err = gpgme_new (&ctx);
546        if (err)
547            BUG (NULL);
548        err = gpgme_data_new_from_file (&keydata, fname, 1);
549        if (err) {
550            msg_box (dlg, _("Could not read key-data from file."),
551                     _("Key Manager"), MB_ERR);
552            goto leave;
553        }
554        
555        op_begin ();
556        err = gpgme_op_import (ctx, keydata);
557        op_end ();
558        if (err) {
559            msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
560            goto leave;
561        }    
562    
563        res = gpgme_op_import_result (ctx);
564        if (res->unchanged == res->considered)
565            no_data = 1;
566        if (res->new_revocations == 0 && fm_stat.import.revcert == 1)
567            res->new_revocations = 1;
568        if (res->secret_imported == 0 && fm_stat.import.has_seckey == 1)
569            res->secret_imported = 1;
570    
571        /* XXX: if we import a key pair but the secret key comes first,
572                no_{valid}_user_id is 1 even so the public key, which comes
573                later is valid and self-signed. */
574        print_import_status (res);
575        if (res->no_user_id > 0) {
576            msg_box (dlg, _("Key without a self signature was dectected!\n"
577                            "(This key is NOT usable for encryption, etc)\n"
578                            "\n"    
579                            "Cannot import these key(s)!"), _("Import"), MB_INFO);
580        }
581    
582    leave:
583        gpgme_data_release (keydata);
584        gpgme_release (ctx);
585        free_if_alloc (fm_stat.opaque);
586        if (no_data)
587            return WPTERR_GENERAL;
588        return (int)err;
589    }
590    
591    
592    /* Mark the keys in @rset as deleted in the keycache. */
593    static void
594    delete_keys_from_cache (gpgme_key_t *rset, size_t n)
595    {
596        gpg_keycache_t pub = keycache_get_ctx (1);
597        int i=0;
598    
599        while (n-- > 0)
600            gpg_keycache_delete_key (pub, rset[i++]->subkeys->keyid);
601    }
602    
603    
604    /* Delete all selected keys from the list view @lv. */
605    int
606    km_delete_keys (listview_ctrl_t lv, HWND dlg)
607    {
608        gpgme_error_t err;
609        gpgme_ctx_t ctx;
610        gpgme_key_t *rset;
611        gpgme_key_t key;
612        char *p;
613        int with_seckey=0, seckey_type=0, confirm=0;
614        int i, rc, n, k_pos=0;
615        
616        if (listview_get_curr_pos (lv) == -1) {
617            msg_box (dlg, _("Please select a key."), _("Key Manager"), MB_ERR);
618            return -1;
619        }
620            
621        if (listview_count_items (lv, 1) > 8) {
622            i = msg_box (NULL, _("Do you really want to confirm each key?"),
623                         _("Delete Confirmation"), MB_YESNOCANCEL|MB_ICONQUESTION);
624            if (i == IDCANCEL)
625                return 0;
626            if (i != IDNO)
627                confirm = 1;
628        }
629        else
630            confirm = 1;
631    
632        /* n = total amount of keys, i is the selected amount. */
633        n = listview_count_items (lv, 0);
634        i = listview_count_items (lv, 1);
635        rset = (gpgme_key_t *)calloc (i+1, sizeof (gpgme_key_t));
636        if (!rset)
637            BUG (NULL);
638        for (i = 0; i < n; i++) {
639            if (listview_get_item_state(lv, i)) {
640                key = (gpgme_key_t)listview_get_item2 (lv, i);
641                if (!key)
642                    BUG (NULL);
643                seckey_type = km_check_for_seckey (lv, i, NULL);
644                if (confirm && !seckey_type) {
645                    p = km_key_get_info (key, 0);
646                    rc = log_box (_("Key Manager"), MB_YESNO|MB_ICONWARNING,
647                                  _("Do you really want to delete this key?\n\n"
648                                    "%s"), p);
649                    if (rc == IDYES)
650                        rset[k_pos++] = key;
651                    with_seckey = 0;
652                    free_if_alloc (p);
653                }
654                else if (confirm) {
655                    p = km_key_get_info (key, 1);
656                    rc = log_box (_("Key Manager"), MB_YESNO|MB_ICONWARNING,                
657                                  _("Do you really want to delete this KEY PAIR?\n\n"
658                                    "Please remember that you are not able to decrypt\n"
659                                    "messages you stored with this key any longer.\n"
660                                    "\n"
661                                    "%s"), p);
662                    if (rc == IDYES) {
663                        if (seckey_type == 2)
664                            msg_box (dlg, _("The actual secret key is stored on a smartcard.\n"
665                                            "Only the public key and the secret key \n"
666                                            "placeholder will be deleted.\n"),
667                                            _("Key Manager"), MB_OK);
668                        rset[k_pos++] = key;
669                    }
670                    with_seckey = 1;
671                    free_if_alloc (p);
672                }
673                else {
674                    with_seckey = 1;
675                    rset[k_pos++] = key;
676                }
677            }
678        }
679        
680        if (k_pos == 0) {
681            free (rset);
682            return 0;
683        }
684    
685        err = gpgme_new (&ctx);
686        if (err)
687            BUG (NULL);
688        n = k_pos;
689        op_begin ();
690        for (i=0; i < k_pos; i++) {
691            err = gpgme_op_delete (ctx, rset[i], with_seckey);
692            if (err)
693                msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
694            else
695                n--;
696        }
697        op_end ();
698        if (n == 0)
699            show_msg (dlg, 1500, _("GnuPG Status: Finished"));      
700        gpgme_release (ctx);
701        listview_del_sel_items (lv);
702        delete_keys_from_cache (rset, k_pos);
703        free (rset);
704    
705        return (int)err;
706    }
707    
708    
709    /* Send the select key in @lv to the keyserver @host:@port. */
710    int
711    km_send_to_keyserver (listview_ctrl_t lv, HWND dlg, const char *host, u16 port)
712    {
713        gpgme_key_t key;
714        int id;
715        
716        id = listview_get_curr_pos (lv);
717        if (id == -1) {
718            msg_box( dlg, _("Please select a key."), _("Key Manager"), MB_ERR );
719            return WPTERR_GENERAL;
720        }
721    
722        key = (gpgme_key_t)listview_get_item2 (lv, id);
723        if (!key)
724            BUG (NULL);
725        id = log_box (_("Key Manager"), MB_YESNO,
726                      _("Do you really want to send '%s' to keyserver %s?"),
727                        key->subkeys->keyid+8, host);
728        if (id == IDYES)
729            hkp_send_key (dlg, host, port, key->subkeys->keyid+8);
730    
731        return 0;
732    }
733    
734    
735    /* Send the selected key in @lv via MAPI to a mail recipient. */
736    int
737    km_send_to_mail_recipient (listview_ctrl_t lv, HWND dlg)
738    {
739        gpgme_key_t key;
740        gpgme_ctx_t ctx=NULL;
741        gpgme_data_t out;
742        gpgme_error_t rc;
743        char tmp[128];
744        char *fname;
745        char *name;
746        int pos;
747    
748        if (listview_count_items (lv, 1) > 1) {
749            msg_box (dlg, _("Please only select one key."),
750                     _("Key Manager"), MB_INFO|MB_OK);
751            return WPTERR_GENERAL;
752        }
753        pos = listview_get_curr_pos (lv);
754        if (pos == -1) {
755            msg_box (dlg, _("Please select a key."), _("Key Manager"), MB_ERR);
756            return WPTERR_GENERAL;
757        }
758        key = (gpgme_key_t)listview_get_item2 (lv, pos);
759        if (!key)
760            BUG (NULL);
761    
762        GetTempPath (sizeof (tmp)-1, tmp);
763        if (tmp[strlen (tmp)-1] == '\\')
764            tmp[strlen (tmp)-1] = 0;
765        name = utf8_to_wincp2 (key->uids->name);
766        fname = make_filename (tmp, name, "asc");
767        for (pos=0; pos < (int)strlen (fname); pos++) {
768            if (fname[pos] == ' ')
769                fname[pos] = '_';
770        }
771    
772        rc = gpgme_new (&ctx);
773        if (rc)
774            BUG (NULL);
775        rc = gpgme_data_new (&out);
776        if (rc)
777            BUG (NULL);
778    
779        gpgme_set_armor (ctx, 1);
780        rc = gpgme_op_export (ctx, key->subkeys->keyid, 0, out);
781        if (rc) {
782            gpgme_data_release (out);
783            msg_box (dlg, gpgme_strerror (rc), _("Key Manager"), MB_ERR);
784        }
785        else {
786            gpg_data_release_and_set_file (out, fname);
787            mapi_send_pubkey (key->subkeys->keyid+8, fname);
788        }
789    
790        gpgme_release (ctx);
791        safe_free (name);
792        free_if_alloc (fname);
793        return rc;
794    }
795    
796    
797    static void
798    km_refresh_one_key (listview_ctrl_t lv, HWND dlg, int pos, int flags)
799    {
800        gpgme_key_t key;
801        int idx;
802    
803        if (pos != 0)
804            idx = pos;
805        else
806            idx = listview_get_curr_pos (lv);
807        if (idx != -1) {
808            key = (gpgme_key_t)listview_get_item2 (lv, idx);
809            if (!key)
810                BUG (0);
811            hkp_recv_key (dlg, default_keyserver, default_keyserver_port,
812                          key->subkeys->keyid+8, 0, flags);
813        }
814    }
815    
816    
817    /* Refresh the selected keys from the default keyserver. */
818    void
819    km_refresh_from_keyserver (listview_ctrl_t lv, HWND dlg)
820    {
821        int cnt, id, i;
822        
823        if (kserver_check_inet_connection ()) {
824            msg_box (dlg, _("Could not connect to keyserver, abort procedure."),
825                     _("Key Manager"), MB_ERR);
826            return;
827        }
828    
829        cnt = listview_count_items (lv, 0);
830        if (listview_count_items (lv, 1) == cnt) {
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        }
836        if (listview_count_items (lv, 1) == 1)
837            km_refresh_one_key (lv, dlg, listview_get_curr_pos (lv), 0);
838        else {
839            for (i=0; i < cnt; i++) {
840                if (listview_get_item_state (lv, i))
841                    km_refresh_one_key (lv, dlg, i, KM_KS_REFRESH);
842            }
843        }
844    }
845    
846    
847    void
848    km_set_clip_info (const char *uid)
849    {    
850        char buf[256];
851        
852        key_get_clip_info (uid, buf, sizeof (buf)-1);
853        set_clip_text (NULL, buf, strlen (buf));
854    }
855    
856    
857    
858    /* Return TRUE if the key in the list @lv at pos @pos is an
859       old version 3 key. */
860    int
861    km_key_is_v3 (listview_ctrl_t lv, int pos)
862    {
863        gpgme_key_t pk;
864    
865        pk = (gpgme_key_t)listview_get_item2 (lv, pos);
866        if (!pk)
867            BUG (NULL);
868        if (strlen (pk->subkeys->fpr) == 32 &&
869            pk->subkeys->pubkey_algo == GPGME_PK_RSA)
870            return -1;
871        return 0;
872    }
873    
874    
875    /* Set trust of selected key in @lv (at @pos) to ultimate. */
876    int
877    km_set_implicit_trust (HWND dlg, listview_ctrl_t lv, int pos)
878    {
879        gpgme_error_t err;
880        gpgme_key_t key;
881        GpgKeyEdit *ke;
882    
883        key = (gpgme_key_t)listview_get_item2 (lv, pos);
884        if (!key)
885            BUG (NULL);
886        ke = new GpgKeyEdit (key->subkeys->keyid);
887        if (!ke)
888            BUG (0);
889    
890        err = ke->setTrust (GPGME_VALIDITY_ULTIMATE);
891        if (err)
892            msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);
893        else
894            show_msg (dlg, 1500, _("GnuPG Status: Finished"));
895    
896        delete ke;
897        return (int)err;
898    }
899    
900    
901    void
902    km_find_key (HWND dlg, listview_ctrl_t lv)
903    {
904        int oldpos = listview_get_curr_pos (lv);
905        int n;
906        char *name = get_input_dialog (dlg, _("Search"), _("Search for:"));
907        if (name == NULL)
908            return;
909        if (oldpos < 0)
910            oldpos = 0;
911        n = listview_find (lv, name);
912        if (n != -1) {
913            listview_select_one (lv, n);
914            listview_scroll (lv, oldpos, n);
915        }
916        else {
917            const char *s = _("String pattern \"%s\" not found.");
918            char *p = new char[strlen (s) + strlen (name) + 2];
919            if (!p)
920                BUG (0);
921            sprintf (p, s, name);
922            msg_box (dlg, p, _("Key Manager"), MB_INFO);
923            free_if_alloc (p);
924        }
925        free_if_alloc (name);
926    }
927    
928    
929    /* Return a user-friendly name for a key derrived from
930       name. If @is_secret is 1, a secret key name will be generated. */
931    char*
932    km_gen_export_filename (const char *keyid, int is_secret)
933    {
934        gpgme_key_t key;
935        char *p, *uid;
936    
937        if (get_pubkey (keyid, &key))
938            return m_strdup (keyid);
939        uid = utf8_to_wincp2 (key->uids->name);
940        if (!uid)
941            return m_strdup (keyid);
942        p = new char[strlen (uid) + 8 + 16];
943        if (!p)
944            BUG (0);
945        sprintf (p, "%s%s.asc", uid, is_secret? "_sec" : "");
946        for (size_t i=0; i < strlen (p); i++) {
947            if (p[i] == ' ' || p[i] == ':' || p[i] == '?' || p[i] == '|')
948                p[i] = '_';
949        }
950        safe_free (uid);
951        return p;
952    }

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26