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

Diff of /trunk/Src/wptKeylist.cpp

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

revision 2 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 197 by twoaday, Mon Apr 10 07:38:06 2006 UTC
# Line 1  Line 1 
 /* wptKeylist.cpp - Keylist element  
  *      Copyright (C) 2001-2004 Timo Schulz  
  *      Copyright (C) 2004 Andreas Jobs  
  *  
  * 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 <time.h>  
   
 #include "wptCommonCtl.h"  
 #include "wptTypes.h"  
 #include "wptGPG.h"  
 #include "wptKeylist.h"  
 #include "wptKeyManager.h"  
 #include "wptW32API.h"  
 #include "wptNLS.h"  
 #include "wptErrors.h"  
 #include "wptUTF8.h"  
 #include "wptRegistry.h"  
   
 static struct listview_column_s klist_enc[] = {  
     {0, 242, (char *)_("User ID")},  
     {1, 80, (char *)_("Key ID")},  
     {3, 46, (char *)_("Size")},  
     {4, 50, (char *)_("Cipher")},  
     {5, 70, (char *)_("Validity")},  
     {0, 0, NULL}  
 };  
 #define KLIST_ENC_ITEMS (DIM(klist_enc) -1)  
   
 static struct listview_column_s klist[] = {  
     {0, 242, (char *)_("User ID")},  
     {1, 78, (char *)_("Key ID")},  
     {2, 52, (char *)_("Type")},      
     {3, 68, (char *)_("Size")},  
     {4, 66, (char *)_("Cipher")},  
     {5, 70, (char *)_("Validity")},  
     {6, 40, (char *)_("Trust")},  
     {7, 72, (char *) _("Creation")},  
     {0, 0, NULL}  
 };  
 #define KLIST_ITEMS (DIM(klist) - 1)  
   
 struct key_array_s {  
     char keyid[32];  
     int checked;  
 };  
   
 static int keylist_add_key( listview_ctrl_t lv, int mode, gpgme_key_t key );  
 static int find_secret_key( gpgme_key_t key );  
   
   
 static key_array_s*  
 key_array_new( size_t items )  
 {  
     key_array_s *ka;  
     size_t j;  
       
     if( items == 0 )  
         return NULL;  
     ka = new key_array_s[items + 1];  
     if( ka == NULL )  
         return NULL;      
     for ( j = 0; j < items; j++ )  
         ka[j].checked = 0;  
     return ka;  
 } /* key_array_new */  
   
   
 static void  
 key_array_release( key_array_s *ka )  
 {  
     free_if_alloc( ka );  
 } /* key_array_release */  
   
   
 static int  
 key_array_search( key_array_s *ka, size_t items, const char *keyid )  
 {  
     size_t j;  
       
     /* fixme: we need a faster search method */  
     for( j = 0; j < items; j++ ) {  
         if( !strcmp( keyid, ka[j].keyid ) )  
             return 1;    
     }  
       
     return 0;  
 } /* key_array_search */  
   
   
 const char*  
 get_key_algo( gpgme_key_t key, int keyidx )  
 {  
     static char algo_id[128];  
     int n, algo_main, algo_sub;  
       
     if( keyidx > 0 ) {  
         algo_main = gpgme_key_get_ulong_attr( key, GPGME_ATTR_ALGO, NULL, keyidx-1 );  
         _snprintf( algo_id, sizeof algo_id-1, "%s",  
             gpgme_key_expand_attr( GPGME_ATTR_ALGO, algo_main ) );  
         return algo_id;  
     }  
     algo_main = gpgme_key_get_ulong_attr( key, GPGME_ATTR_ALGO, NULL, 0 );  
     n = gpgme_key_count_items( key, GPGME_ATTR_KEYID );  
     if( n > 1 ) {  
         algo_sub = gpgme_key_get_ulong_attr( key, GPGME_ATTR_ALGO, NULL, n-1 );  
         _snprintf( algo_id, sizeof algo_id - 1, "%s/%s",  
             gpgme_key_expand_attr( GPGME_ATTR_ALGO, algo_main ),  
             gpgme_key_expand_attr( GPGME_ATTR_ALGO, algo_sub ) );  
         return algo_id;  
     }  
     return gpgme_key_expand_attr( GPGME_ATTR_ALGO, algo_main );  
 } /* get_key_algo */  
   
   
 const char*  
 get_key_created( long timestamp )  
 {  
     static char timebuf[128];  
     struct tm *warp;  
   
     if( timestamp == 0 || timestamp == -1 )  
         return "????-??-??";  
     warp = localtime( &timestamp );  
     _snprintf( timebuf, sizeof timebuf - 1, "%04d-%02d-%02d",  
                 warp->tm_year + 1900, warp->tm_mon + 1, warp->tm_mday );  
     return timebuf;  
 } /* get_key_created */  
   
   
 const char*  
 get_key_expire_date( long timestamp )  
 {  
     static char timebuf[64];  
     struct tm *warp;  
   
     if( !timestamp )  
         return _("Never");  
     warp = localtime( &timestamp );  
     _snprintf( timebuf, sizeof timebuf -1, "%04d-%02d-%02d",  
                 warp->tm_year + 1900, warp->tm_mon + 1, warp->tm_mday );  
     return timebuf;  
 } /* get_key_expire_date */  
   
   
 const char *  
 get_key_type( gpgme_key_t key )  
 {  
     int valid = gpgme_key_get_ulong_attr( key, GPGME_ATTR_VALIDITY, NULL, 0 );  
     if( find_secret_key( key ) || valid == GPGME_VALIDITY_ULTIMATE )      
         return _("Key Pair");  
     return _("Public Key");  
 } /* get_key_type */  
   
   
 const char *  
 get_key_size( gpgme_key_t key, int keyidx )  
 {  
     static char size_id[64];  
     int n, size_main, size_sub;  
       
     if( keyidx > 0 ) {  
         size_main = gpgme_key_get_ulong_attr( key, GPGME_ATTR_LEN, NULL, keyidx-1 );  
         _snprintf( size_id, sizeof size_id-1, "%d", size_main );  
         return size_id;  
     }  
     size_main = gpgme_key_get_ulong_attr( key, GPGME_ATTR_LEN, NULL, 0 );  
     n = gpgme_key_count_items( key, GPGME_ATTR_KEYID );  
     if( n > 1 ) {      
         size_sub = gpgme_key_get_ulong_attr( key, GPGME_ATTR_LEN, NULL, n-1 );  
         _snprintf( size_id, sizeof size_id - 1, "%d/%d", size_main, size_sub );  
         return size_id;  
     }  
     _snprintf( size_id, sizeof size_id - 1, "%d", size_main );  
     return size_id;  
 } /* get_key_size */  
   
   
 const char *  
 get_key_fpr( gpgme_key_t key )  
 {  
     static char fpr_md[64];  
     const char * fpr;  
     char t[16];  
     size_t i;  
       
     memset( fpr_md, 0, sizeof fpr_md );  
     fpr = gpgme_key_get_string_attr( key, GPGME_ATTR_FPR, NULL, 0 );  
     for( i = 0; i < strlen( fpr ) / 4; i++ ) {  
         sprintf( t, "%c%c%c%c ", fpr[4*i], fpr[4*i+1], fpr[4*i+2], fpr[4*i+3] );  
         strcat( fpr_md, t );  
     }  
     return fpr_md;  
 } /* get_key_fpr */  
   
   
   
 static const char *  
 get_key_trust2 (gpgme_key_t key, int val, int uididx, int listmode)  
 {  
     if (key)  
         val = gpgme_key_get_ulong_attr (key, GPGME_ATTR_OTRUST, NULL, uididx);  
     switch (val) {  
     case GPGME_TRUST_UNKNOWN:  
     case GPGME_TRUST_DONTKNOW:      
         return "None";  
     case GPGME_TRUST_NEVER:      
         return "Never";  
     case GPGME_TRUST_MARGINAL:  
         return "Marginal";  
     case GPGME_TRUST_FULLY:  
     case GPGME_TRUST_ULTIMATE:  
         return "Full";  
     }  
     return "";  
 }  
   
   
 const char *  
 get_key_trust (gpgme_key_t key, int uididx, int listmode)  
 {  
     return get_key_trust2 (key, 0, uididx, listmode);  
 }  
   
   
 const char *  
 get_key_trust_str (int val)  
 {  
     return get_key_trust2 (NULL, val, 0, 0);  
 }  
   
   
 char*  
 get_key_status( gpgme_key_t key, int uididx, int listmode )  
 {  
     char fmt[128], * p;  
     const char * attr;  
     int i = 0;  
     u32 key_attr =0;  
   
     if( uididx < 0 || gpgme_key_count_items( key, GPGME_ATTR_USERID ) > uididx )  
         uididx = 0;  
     memset( fmt, 0, sizeof fmt );  
     if( listmode ) {  
         fmt[i++] = '[';  
         if( gpgme_key_get_ulong_attr( key, GPGME_ATTR_KEY_REVOKED, NULL, 0 ) )  
             fmt[i++] = 'R';      
         if( gpgme_key_get_ulong_attr( key, GPGME_ATTR_KEY_EXPIRED, NULL, 0 ) )  
             fmt[i++] = 'E';      
         if( gpgme_key_get_ulong_attr( key, GPGME_ATTR_KEY_DISABLED, NULL, 0 ) )  
             fmt[i++] = 'D';  
         fmt[i++] = ']';  
         fmt[i++] = ' ';  
     }  
     key_attr = gpgme_key_get_ulong_attr( key, GPGME_ATTR_VALIDITY, NULL, uididx );  
     attr = gpgme_key_expand_attr( GPGME_ATTR_VALIDITY, key_attr );  
     p = new char[strlen( fmt ) + 1 + strlen( attr ) + 2];  
     sprintf( p, "%s%s", fmt, attr );  
     return p;  
 } /* get_key_status */  
   
   
 static inline int  
 int_cmp( int a, int b )  
 {  
     if( a == b ) return 0;        
     else if( a > b ) return 1;  
     else return -1;  
     return 0;  
 }  
   
   
 static int CALLBACK  
 keylist_cmp_cb (LPARAM first, LPARAM second, LPARAM sortby)  
 {  
     static char tmpa[128], tmpb[128];      
     gpgme_key_t a, b;      
     const char *aa = NULL, *bb = NULL;  
     long ta, tb;  
     int na = 0, nb = 0;  
     int cmpresult = 0;  
       
     a = (gpgme_key_t)first;  
     b = (gpgme_key_t)second;      
       
     switch( sortby & ~KEYLIST_SORT_DESC ) {  
     case GPGME_ATTR_USERID:  
         aa = gpgme_key_get_string_attr( a, GPGME_ATTR_USERID, NULL, 0 );  
         bb = gpgme_key_get_string_attr( b, GPGME_ATTR_USERID, NULL, 0 );  
         cmpresult = strcmpi( aa? aa : "", bb? bb : "" );  
         break;  
           
     case GPGME_ATTR_KEYID:  
         aa = gpgme_key_get_string_attr( a, GPGME_ATTR_KEYID, NULL, 0) + 8;  
         bb = gpgme_key_get_string_attr( b, GPGME_ATTR_KEYID, NULL, 0) + 8;  
         cmpresult = strcmpi( aa? aa : "", bb? bb : "" );  
         break;  
   
     case GPGME_ATTR_VALIDITY:  
         na = gpgme_key_get_ulong_attr( a, GPGME_ATTR_VALIDITY, NULL, 0 );  
         nb = gpgme_key_get_ulong_attr( b, GPGME_ATTR_VALIDITY, NULL, 0 );        
         cmpresult = int_cmp( na, nb );  
         break;  
   
     case GPGME_ATTR_OTRUST:  
         na = gpgme_key_get_ulong_attr (a, GPGME_ATTR_OTRUST, NULL, 0);  
         nb = gpgme_key_get_ulong_attr (b, GPGME_ATTR_OTRUST, NULL, 0);  
         cmpresult = int_cmp (na, nb);  
         break;  
   
     case GPGME_ATTR_IS_SECRET:    
         aa = gpgme_key_get_string_attr( a, GPGME_ATTR_KEYID, NULL, 0 );  
         bb = gpgme_key_get_string_attr( b, GPGME_ATTR_KEYID, NULL, 0 );  
         get_seckey( aa, &a );  
         get_seckey( bb, &b );  
         if( a )  
             na = gpgme_key_get_ulong_attr( a, GPGME_ATTR_IS_SECRET, NULL, 0 );  
         if( b )  
             nb = gpgme_key_get_ulong_attr( b, GPGME_ATTR_IS_SECRET, NULL, 0 );  
         cmpresult = int_cmp( na, nb );  
         break;  
   
     case GPGME_ATTR_LEN:  
         na = gpgme_key_get_ulong_attr( a, GPGME_ATTR_LEN, NULL, 0 );  
         nb = gpgme_key_get_ulong_attr( b, GPGME_ATTR_LEN, NULL, 0 );  
         cmpresult = int_cmp( na, nb );  
         break;  
   
     case GPGME_ATTR_CREATED:  
         ta = gpgme_key_get_ulong_attr( a, GPGME_ATTR_CREATED, NULL, 0 );  
         tb = gpgme_key_get_ulong_attr( b, GPGME_ATTR_CREATED, NULL, 0 );  
         strcpy( tmpa, get_key_created( ta ) ); aa = tmpa;  
         strcpy( tmpb, get_key_created( tb ) ); bb = tmpb;  
         cmpresult = strcmpi( aa? aa : "", bb? bb : "" );  
         break;  
   
     case GPGME_ATTR_ALGO:  
         aa = gpgme_key_get_string_attr (a, GPGME_ATTR_ALGO, NULL, 0);  
         bb = gpgme_key_get_string_attr (b, GPGME_ATTR_ALGO, NULL, 0);  
         cmpresult = strcmpi (aa? aa : "", bb? bb : "");  
         break;  
           
     default:  
         aa = gpgme_key_get_string_attr( a, GPGME_ATTR_USERID, NULL, 0 );  
         bb = gpgme_key_get_string_attr( b, GPGME_ATTR_USERID, NULL, 0 );  
         cmpresult = strcmpi( aa? aa : "", bb? bb : "" );  
         break;  
     }  
     if (sortby & KEYLIST_SORT_DESC)  
         return (~cmpresult + 1);  
     else  
         return cmpresult;  
 } /* keylist_cmp_cb */  
   
   
 static const char*  
 calc_validity( gpg_group_t grp )  
 {  
     int level = 0, valid;  
     gpg_member_t mbr;  
     gpgme_key_t key;  
   
     for( mbr = grp->list; mbr; mbr = mbr->next ) {  
         if( get_pubkey( mbr->name, &key ) )  
             continue;  
         valid = gpgme_key_get_ulong_attr( key, GPGME_ATTR_KEY_VALIDITY, NULL, 0 );  
         switch( valid ) {        
         case GPGME_VALIDITY_MARGINAL:  
         case GPGME_VALIDITY_NEVER:  
         case GPGME_VALIDITY_UNDEFINED:  
             return gpgme_key_expand_attr( GPGME_ATTR_VALIDITY, valid );  
         }  
     }  
     return gpgme_key_expand_attr( GPGME_ATTR_VALIDITY, GPGME_VALIDITY_FULL );  
 } /* calc_validity */  
   
   
 int  
 keylist_add_groups( listview_ctrl_t lv )  
 {  
     gpg_optfile_t gh;  
     gpg_group_t grp;  
     const char *valid;  
   
     gh = km_groupdb_open( );      
     if( !gh )    
         return WPTERR_FILE_OPEN;  
   
     for( grp = gh->grp; grp; grp = grp->next ) {  
         valid = calc_validity( grp );  
         listview_add_item( lv, " " );    
         listview_add_sub_item( lv, 0, 0, grp->name );    
         listview_add_sub_item( lv, 0, 1, "gpg_group_t" );        
         listview_add_sub_item( lv, 0, 2, "" );    
         listview_add_sub_item( lv, 0, 3, "Unknown" );  
         listview_add_sub_item( lv, 0, 4, valid?valid : "Unknown" );  
     }  
     return 0;  
 } /* keylist_add_groups */  
   
   
 static int  
 keylist_build( listview_ctrl_t *r_lv, HWND ctrl, int mode )  
 {  
     listview_ctrl_t lv;  
     listview_column_t col;  
     int j, n = 0;  
     int kl_nolist = 0, rc = 0;  
       
     rc = listview_new( &lv );  
     if( rc )  
         return rc;  
       
     lv->ctrl = ctrl;  
     if( (mode & KEYLIST_ENCRYPT) || (mode & KEYLIST_ENCRYPT_MIN) ) {  
         col = klist_enc;  
         n = KLIST_ENC_ITEMS;  
     }    
     else if( (mode & KEYLIST_SIGN) ) {  
         col = klist_enc;  
         n = KLIST_ENC_ITEMS - 1;  
     }  
     else {  
         col = klist;  
         n = KLIST_ITEMS;  
     }  
       
     for( j = 0; j < n; j++ )      
         listview_add_column( lv, &col[j] );      
     listview_set_ext_style( lv );  
     *r_lv = lv;  
       
     return 0;  
 } /* keylist_build */  
   
   
 static void  
 keylist_load_keycache( listview_ctrl_t lv, int mode, gpgme_keycache_t pubkc,  
                        gpgme_keycache_t seckc )  
 {  
     gpgme_error_t err = GPGME_No_Error;  
     gpgme_key_t key, skey;  
     const char * keyid;  
   
     if( pubkc && seckc ) {  
         gpgme_keycache_rewind( pubkc );  
         while( !gpgme_keycache_next_key( pubkc, 0, &key ) ) {  
             keyid = gpgme_key_get_string_attr( key, GPGME_ATTR_KEYID, NULL, 0 );  
             if( keyid && !gpgme_keycache_find_key( seckc, keyid, 0, &skey ) )  
                 keylist_add_key( lv, mode, key );              
         }        
     }  
     else if( pubkc ) {  
         gpgme_keycache_rewind( pubkc );  
         while( !err ) {      
             err = gpgme_keycache_next_key( pubkc, 0, &key );  
             if( !err )  
                 keylist_add_key( lv, mode, key );  
         }  
     }  
 } /* keylist_load_keycache */  
   
   
 listview_ctrl_t  
 keylist_load( HWND ctrl, gpgme_keycache_t pubkc, gpgme_keycache_t seckc,  
               int mode, int sortby )  
 {      
     listview_ctrl_t lv;  
     int rc = 0;  
   
     rc = keylist_build( &lv, ctrl, mode );  
     if( rc )  
         return NULL;              
     keylist_load_keycache( lv, mode, pubkc, seckc );  
     keylist_sort( lv, sortby );  
     if( (mode & KEYLIST_ENCRYPT) || (mode & KEYLIST_ENCRYPT_MIN) )  
         keylist_add_groups( lv );  
     return lv;  
 } /* keylist_load */  
   
   
 int  
 keylist_reload( listview_ctrl_t lv, gpgme_keycache_t pubkc, int mode, int sortby )  
 {  
     listview_del_all( lv );  
     keylist_load_keycache( lv, mode, pubkc, NULL );  
     keylist_sort( lv, sortby );  
     return 0;  
 } /* keylist_reload */  
   
   
 void  
 keylist_delete( listview_ctrl_t lv )  
 {  
     if( lv ) {  
         listview_release( lv );  
     }  
 } /* keylist_delete */  
   
   
 static int  
 find_secret_key( gpgme_key_t key )  
 {  
     const char * keyid;  
     gpgme_key_t skey;    
   
     keyid = gpgme_key_get_string_attr( key, GPGME_ATTR_KEYID, NULL, 0 );  
     if( !keyid )  
         return 0;  
     get_seckey( keyid, &skey );  
     return skey? 1 : 0;  
 } /* find_secret_key */  
   
   
 static int  
 do_addkey( listview_ctrl_t lv, gpgme_key_t key, int uididx, int keyidx, int list )  
 {      
     LV_ITEM lvi;  
     gpgme_key_t seckey;  
     char fmt[128];  
     const char *attr;  
     u32 key_attr;  
     int idx = 0;  
   
     /* we check the pubkey algorithm here to make sure that no ElGamal  
        sign+encrypt key is used in _any_ mode */  
     if( list != 1 && gpgme_key_get_ulong_attr( key, GPGME_ATTR_ALGO, NULL, 0 )  
                  == GPGME_PK_ELG_ES )  
         return 0;  
           
     if( listview_add_item( lv, " " ) )    
         return WPTERR_GENERAL;  
           
     attr = gpgme_key_get_string_attr( key, GPGME_ATTR_USERID, NULL, 0 );  
     memset( &lvi, 0, sizeof lvi );  
     lvi.mask = LVIF_TEXT | LVIF_PARAM;  
     lvi.pszText = (char *)attr;  
     lvi.lParam = (LPARAM )key;  
     if( ListView_SetItem( lv->ctrl, &lvi ) == FALSE )    
         return WPTERR_GENERAL;  
           
     if( uididx == -1 ) {  
         /* request the primary user-id of the key. */  
         attr = gpgme_key_get_string_attr( key, GPGME_ATTR_USERID, NULL, 0 );  
         uididx = 0;  
     }  
     else {  
         if( gpgme_key_get_ulong_attr( key, GPGME_ATTR_UID_REVOKED, NULL, uididx ) || uididx < 0 )  
             uididx = 0; /* fixme: this happen sometimes but it's illegal! (<0) */  
         attr = gpgme_key_get_string_attr( key, GPGME_ATTR_USERID, NULL, uididx );  
     }  
     if( attr == NULL || strlen( attr ) < 5 ) { /* normal userids are >= 5 chars */  
         attr = _("Invalid User ID");  
         listview_add_sub_item( lv, 0, idx++, attr );  
     }    
     else {  
         char * uid = utf8_to_wincp (attr, strlen (attr));  
         if( uid ) {        
             listview_add_sub_item( lv, 0, idx++, uid );  
             free( uid );  
         }  
     }  
     attr = gpgme_key_get_string_attr( key, GPGME_ATTR_KEYID, NULL, keyidx );  
     if( attr ) {  
         _snprintf( fmt, sizeof fmt -1, "0x%s", attr + 8 );  
         listview_add_sub_item( lv, 0, idx++, fmt );  
     }  
           
     if( list > 0 ) {  
         attr = find_secret_key( key )? "pub/sec" : "pub";  
         if( strchr( attr, '/' ) ) {  
             const char * kid;  
             kid = gpgme_key_get_string_attr( key, GPGME_ATTR_KEYID, NULL, 0 );  
             get_seckey( kid, &seckey );  
             if( gpgme_key_get_ulong_attr( seckey, GPGME_ATTR_DIVERT_CARD, NULL, 0 ) )  
                 attr = "pub/crd";  
         }  
         listview_add_sub_item( lv, 0, idx++, attr );  
     }  
     if( lv->cols >= 2 ) {  
         attr = get_key_size( key, list==-1? keyidx+1 : 0 );  
         if( attr )  
             listview_add_sub_item( lv, 0, idx++, attr );          
     }  
     if( lv->cols >= 3 ) {  
         attr = get_key_algo( key, list==-1? keyidx+1 : 0 );  
         if( attr )  
             listview_add_sub_item( lv, 0, idx++, attr );  
     }  
     if( lv->cols >= 4 ) {  
         char * status = get_key_status( key, uididx, list>0? 1 : 0 );  
         if( !status )  
             return WPTERR_GENERAL;  
         listview_add_sub_item( lv, 0, idx++, status );  
         free_if_alloc( status );  
     }  
     if (lv->cols >= 5) {  
         const char * s = get_key_trust (key, uididx, list>0? 1 : 0);  
         listview_add_sub_item (lv, 0, idx++, s);  
     }  
     if( lv->cols >= 6 ) {  
         key_attr = gpgme_key_get_ulong_attr( key, GPGME_ATTR_CREATED, NULL, keyidx );  
         if( key_attr ) {  
             attr = gpgme_key_expand_attr( GPGME_ATTR_CREATED, key_attr );  
             listview_add_sub_item( lv, 0, idx++, attr );  
         }        
     }  
   
     return 0;  
 } /* do_addkey */  
   
   
 static int  
 keylist_add_key (listview_ctrl_t lv, int mode, gpgme_key_t key)  
 {  
     int uids, rc = 0, i, n = 0;  
           
     for ( i = 0; i < gpgme_key_count_items( key, GPGME_ATTR_KEYID ); i++ ) {  
         if( gpgme_key_get_ulong_attr( key, GPGME_ATTR_KEY_INVALID, NULL, i ) )    
             continue; /* Don't use invalid keys */  
                   
         if( mode & KEYLIST_ALL ) {  
             uids = gpgme_key_count_items( key, GPGME_ATTR_USERID );  
             rc = do_addkey( lv, key, uids, i, 0 );  
             if( rc )  
                 return rc;  
         }  
         else if( mode & KEYLIST_LIST )        
             return do_addkey( lv, key, -1, i, 1 );  
         else if (mode & KEYLIST_ENCRYPT)  
         {  
             if (gpgme_key_get_cability (key, GPGME_ATTR_CAN_ENCRYPT, i)  
                 && gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_USABLE, NULL, i))  
             {  
                 if (mode & KEYLIST_FLAG_FILE ) {  
                     rc = do_addkey( lv, key, -1, i, -1 );  
                     if( rc )  
                         return rc;  
                 }  
                 else {  
                     for( uids = 0;  uids < gpgme_key_count_items( key, GPGME_ATTR_USERID ); uids++ ) {  
                         rc = do_addkey( lv, key, uids, i, -1 );  
                         if( rc )  
                             return rc;  
                     }  
                 }  
             }  
         }  
         else if (mode & KEYLIST_ENCRYPT_MIN)  
         {  
             if( gpgme_key_get_cability (key, GPGME_ATTR_CAN_ENCRYPT, i)  
                 && gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_USABLE, NULL, i))  
             {  
                 rc = do_addkey (lv, key, -1, i, -1);  
                 return rc;  
             }  
         }        
         else if( mode & KEYLIST_SIGN ) {  
             if ( gpgme_key_get_cability( key, GPGME_ATTR_CAN_SIGN, i )  
                 && find_secret_key( key )  
                 && gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_USABLE, NULL, i))  
             {  
                 rc = do_addkey (lv, key, -1, i, -1);  
                 if( rc )  
                     return rc;    
             }  
         }        
     }  
   
     return rc;    
 } /* keylist_add_key */  
   
   
 int  
 keylist_sort (listview_ctrl_t lv, int sortby)  
 {        
     return listview_sort_items( lv, sortby, keylist_cmp_cb );  
 } /* keylist_sort */  
   
   
 static int  
 key_check_validity (const char *validity)  
 {      
     if (strstr (validity, "Unknown")  
         || strstr (validity, "Undefined")  
         || strstr (validity, "Never"))  
         return 0;    
     return 1;  
 } /* key_check_validity */  
   
   
 gpgme_recipients_t  
 keylist_get_recipients (listview_ctrl_t lv, int *r_force_trust, int *r_count)  
 {  
     int count = 0, force_trust = 0;  
     int n, j, ka_pos = 0, rc = 0;  
     char keyid[32], valid[32], id[100];  
     key_array_s *ka = NULL;  
     gpgme_error_t err;  
     gpgme_recipients_t rset;  
   
     err = gpgme_recipients_new( &rset );  
     if( err )  
         BUG( NULL );  
       
     n = listview_count_items( lv, 0 );  
     ka = key_array_new( n );  
     if ( !ka )  
         BUG( NULL );  
           
     for( j = 0; j < n; j++ ) {  
         if( listview_get_item_state( lv, j ) || n == 1 ) {  
             listview_get_item_text( lv, j, 1, keyid, sizeof keyid - 1 );                          
             listview_get_item_text( lv, j, 4, valid, sizeof valid -1 );  
             listview_get_item_text( lv, j, 0, id, sizeof id-1 );  
             if( !strncmp( keyid, "gpg_group_t", 5 ) ) {  
                 listview_get_item_text( lv, j, 0, id, sizeof id -1 );  
                 rc = km_groupdb_expand_recipients( id, rset );  
                 if( rc )  
                     force_trust++;  
             }  
             else if( !key_check_validity( valid )  
                     && !key_array_search( ka, ka_pos, keyid ) ) {  
                 char *warn = new char[512+strlen (id) + 1];  
                 if (!warn)  
                     BUG (0);  
                 sprintf (warn,  
                     _("It is NOT certain that the key belongs to the person\n"  
                       "named in the user ID.  If you *really* know what you are\n"  
                       "doing, you may answer the next question with yes\n"  
                       "\n"  
                       "Use \"%s\" anyway?"), id);  
                 if( reg_prefs.always_trust )  
                     rc = IDYES;  
                 else  
                     rc = msg_box (NULL, warn, _("Recipients"), MB_ERR_ASK);  
                 if (rc == IDYES)  
                 {  
                     gpgme_recipients_add_name_with_validity (rset, keyid, GPGME_VALIDITY_FULL);  
                     force_trust++;  
                     ka[ka_pos].checked = 1;  
                     strcpy (ka[ka_pos++].keyid, keyid);  
                 }  
                 free_if_alloc (warn);  
             }  
             else {  
                 listview_get_item_text( lv, j, 1, keyid, sizeof keyid -1 );  
                 gpgme_recipients_add_name( rset, keyid );  
                 count++;          
             }  
         }  
     }  
     key_array_release( ka );  
     if( r_force_trust )  
         *r_force_trust = force_trust;  
     if( r_count )  
         *r_count = count;  
     return rset;  
 } /* keylist_get_recipients */  
   
   
 static int  
 keylist_get_keyflags (const char *buf, size_t buflen)  
 {  
     int c = 0, flags = 0;  
   
     if( *buf != '[' )  
         return KEYFLAG_NONE;  
     while (buf && c != ']')  
     {  
         c = *buf++;  
         if (c == 'R')  
             flags |= KEYFLAG_REVOKED;  
         if (c == 'E')  
             flags |= KEYFLAG_EXPIRED;  
         if (c == 'D')  
             flags |= KEYFLAG_DISABLED;  
     }  
   
     return flags;  
 } /* keylist_get_keyflags */  
   
   
 gpgme_recipients_t  
 keylist_enum_recipients (listview_ctrl_t lv,  int listype)  
 {  
     gpgme_recipients_t rset;  
     int i, n, id;  
     char keyid[32], t[128], t2[128];  
   
     if( gpgme_recipients_new( &rset ) )  
         BUG( NULL );  
   
     n = listview_count_items( lv, 0 );  
     for( i = 0; i < n; i++ ) {  
         if( !listview_get_item_state( lv, i ) )  
             continue;  
         listview_get_item_text( lv, i, 1, keyid, sizeof keyid - 1 );  
         switch( listype ) {  
         case KEYLIST_LIST:  
             listview_get_item_text( lv, i, 5, t, sizeof t - 1 );  
             if( keylist_get_keyflags( t, strlen( t ) ) & KEYFLAG_REVOKED ) {  
                 _snprintf( t2, sizeof t2 -1,  
                             _("KeyID %s.\nDo you really want to export a revoked key?"), keyid );  
                 id = msg_box( lv->ctrl, t2, _("Recipients"), MB_INFO|MB_YESNO );  
                 if( id == IDNO )  
                     continue;            
             }  
             break;  
         }  
         gpgme_recipients_add_name( rset, keyid );  
     }  
     return rset;  
 } /* keylist_enum_recipients */  
   
   
 void  
 seclist_destroy (keylist_t * list)  
 {  
     keylist_t l2;  
     while (*list) {  
         l2 = (*list)->next;  
         safe_free (*list);  
         *list = l2;      
     }  
     list = NULL;  
 } /* seclist_destroy */  
   
   
 void  
 seclist_init (HWND dlg, int ctlid, int flags, keylist_t * ret_list)  
 {      
     gpgme_keycache_t kc = NULL;  
     gpgme_key_t key = NULL;  
     HWND kb;  
     keylist_t list=NULL, l, l2;  
     gpgme_attr_t name_attr = GPGME_ATTR_USERID;  
     long pos = 0;  
   
     SendDlgItemMessage (dlg, ctlid, CB_RESETCONTENT, 0, 0);  
     kb = GetDlgItem (dlg, ctlid);  
     kc = keycache_get_ctx (0);  
     if (!kc)  
         BUG (0);  
     gpgme_keycache_rewind (kc);  
   
     if (flags & KEYLIST_FLAG_SHORT)  
         name_attr = GPGME_ATTR_NAME;  
     while (!gpgme_keycache_next_key (kc, 1, &key)) {  
         char * inf = NULL, * uid = NULL;  
         const char * id;  
         const char * keyid;  
         int algo;  
         size_t size = 0;  
           
         id = gpgme_key_get_string_attr (key, name_attr, NULL, 0);  
         keyid = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID, NULL, 0);  
         algo = gpgme_key_get_ulong_attr (key, GPGME_ATTR_ALGO, NULL, 0);  
         if (!id || !keyid)  
             continue; /* fixme: error? */        
         if (!gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_USABLE, NULL, 0))  
             continue;  
   
         uid = utf8_to_wincp (id, strlen (id));  
         size = strlen( uid ) + strlen( keyid ) + 32;  
         inf = new char[size+1];  
         if( !inf )  
             BUG( NULL );  
         _snprintf(inf, size, _("%s (%s/0x%s)"), uid,  
                   gpgme_key_expand_attr (GPGME_ATTR_ALGO, algo), keyid + 8);  
               
         combox_add_string (kb, inf);  
         free_if_alloc (inf);  
         free (uid);  
         l = (struct keylist_s *)calloc (1, sizeof * l);  
         if (!l)  
             BUG (0);  
         l->key = key;  
         if (!list)  
             list = l;  
         else  
         {  
             for( l2 = list; l2->next; l2 = l2->next )  
                 ;  
             l2->next = l;  
         }  
     }  
     for( pos = 0, l2=list; pos < SendMessage( kb, CB_GETCOUNT, 0, 0 ); pos++, l2=l2->next )  
         SendMessage( kb, CB_SETITEMDATA, pos, (LPARAM)(DWORD)l2->key );  
     SendMessage( kb, CB_SETCURSEL, 0, 0 );  
     *ret_list = list;  
 } /* seclist_init */  
           
   
 int  
 seclist_select_key (HWND dlg, int ctlid, gpgme_key_t * ret_key)  
 {  
     int pos;  
     DWORD k = 0;  
   
     pos = SendDlgItemMessage( dlg, ctlid, CB_GETCURSEL, 0, 0 );  
     if( pos == CB_ERR ) {  
         msg_box( dlg, _("No key was selected."), _("Secret Key List"), MB_ERR );  
         *ret_key = NULL;  
     }  
     else {  
         k = SendDlgItemMessage( dlg, ctlid, CB_GETITEMDATA, pos, 0 );  
         *ret_key = (gpgme_key_t)k;  
     }  
     return k? 0 : -1;  
 } /* seclist_dlg_proc */  
1    /* wptKeylist.cpp - Keylist element
2     *      Copyright (C) 2001-2006 Timo Schulz
3     *      Copyright (C) 2004 Andreas Jobs
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 <time.h>
29    
30    #include "wptCommonCtl.h"
31    #include "wptTypes.h"
32    #include "wptGPG.h"
33    #include "wptKeylist.h"
34    #include "wptKeyManager.h"
35    #include "wptW32API.h"
36    #include "wptNLS.h"
37    #include "wptErrors.h"
38    #include "wptUTF8.h"
39    #include "wptRegistry.h"
40    #include "wptContext.h"
41    #include "wptVersion.h"
42    #include "resource.h"
43    
44    #define key_is_useable(key) (!(key)->revoked && !(key)->expired && !(key)->disabled)
45    
46    struct key_array_s {
47        char keyid[32];
48        int checked;
49    };
50    
51    static int find_secret_key (gpgme_key_t key);
52    
53    
54    static key_array_s*
55    key_array_new (int items)
56    {
57        key_array_s *ka;
58        int j;
59        
60        if (items == 0)
61            return NULL;
62        ka = new key_array_s[items + 1];
63        if (!ka)
64            BUG (NULL);
65        for (j = 0; j < items; j++)
66            ka[j].checked = 0;
67        return ka;
68    }
69    
70    
71    static void
72    key_array_release (key_array_s *ka)
73    {
74        free_if_alloc (ka);
75    }
76    
77    
78    /* Check if the keyid @keyid is in the key array @ka.
79       Return value: 1 if it exists, 0 otherwise. */
80    static int
81    key_array_search (key_array_s *ka, int items, const char *keyid)
82    {
83        int j;
84        
85        for (j = 0; j < items; j++) {
86            if (!strcmp (keyid, ka[j].keyid ))
87                return 1;  
88        }
89        return 0;
90    }
91    
92    
93    gpgme_user_id_t
94    get_nth_userid (gpgme_key_t key, int idx)
95    {
96        gpgme_user_id_t t;
97    
98        if (!key->uids)
99            return NULL;
100        t = key->uids;
101        while (idx-- && t->next)
102            t = t->next;
103        return t;
104    }
105    
106    
107    int
108    count_userids (gpgme_key_t key)
109    {
110        gpgme_user_id_t u;
111        int n = 1;
112    
113        u = key->uids;
114        if (!u)
115            return 0;
116        while (u->next) {
117            u = u->next;
118            n++;
119        }
120        return n;
121    }
122    
123    
124    gpgme_subkey_t
125    get_nth_key (gpgme_key_t key, int idx)
126    {
127        gpgme_subkey_t t;
128    
129        if (!key->subkeys)
130            return NULL;
131        t = key->subkeys;
132        while (idx-- && t->next)
133            t = t->next;
134        return t;
135    }
136    
137    
138    int
139    count_subkeys (gpgme_key_t key)
140    {
141        gpgme_subkey_t k;
142        int n = 1;
143    
144        k = key->subkeys;
145        if (!k)
146            return 0;
147        while (k->next) {
148            k = k->next;
149            n++;
150        }
151        return n;
152    }
153    
154    
155    /* Return the self signature of the key @keyid.
156       If first is set, the first self sig will be returned. */
157    gpgme_key_sig_t
158    get_selfsig (gpgme_user_id_t uid, const char *keyid, int first)
159    {
160        gpgme_key_sig_t s, self_sig=NULL;
161        long timestamp=0;
162        int off = 0;
163    
164        if (strlen (keyid) == 8)
165            off = 8;
166    
167        for (s = uid->signatures; s; s = s->next) {
168            if (!strcmp (s->keyid+off, keyid) && s->timestamp > timestamp) {
169                self_sig = s;
170                timestamp = s->timestamp;
171                if (first)
172                    break;
173            }
174        }
175        return self_sig;
176    }
177    
178    
179    
180    const char*
181    get_key_algo (gpgme_key_t key, int keyidx)
182    {
183        static char algo_id[128];
184        gpgme_subkey_t k;
185        char alg[32];
186        const char *subalg;
187        int n=0;
188        
189        if (keyidx > 0) {
190            k = get_nth_key (key, keyidx-1);
191            subalg =  get_key_pubalgo (k->pubkey_algo);
192            _snprintf (algo_id, DIM (algo_id)-1, "%s", subalg);
193            return algo_id;
194        }
195        strcpy (alg, get_key_pubalgo (key->subkeys->pubkey_algo));
196        n = count_subkeys (key);
197        if (n > 1) {
198            k = get_nth_key (key, n-1);
199            subalg = get_key_pubalgo (k->pubkey_algo);
200            _snprintf (algo_id, DIM (algo_id)-1, "%s/%s", alg, subalg);
201            return algo_id;
202        }
203        return get_key_pubalgo (key->subkeys->pubkey_algo);
204    }
205    
206    
207    const char*
208    get_key_created (long timestamp)
209    {
210        static char timebuf[128];
211        struct tm *warp;
212        const char *dat;
213    
214        if (timestamp < 1)
215            return "????" "-??" "-??";
216        dat = get_locale_date (timestamp, timebuf, sizeof (timebuf)-1);
217        if (dat)
218            return dat;
219        warp = localtime (&timestamp);
220        _snprintf (timebuf, sizeof timebuf - 1, "%04d-%02d-%02d",
221                   warp->tm_year + 1900, warp->tm_mon + 1, warp->tm_mday);
222        return timebuf;
223    }
224    
225    
226    /* Return a string presentation of the time @timestamp. */
227    const char*
228    get_key_expire_date (long timestamp)
229    {
230        static char timebuf[64];
231        struct tm *warp;
232        const char *dat;
233    
234        if (timestamp == 0)
235            return _("Never");
236        dat = get_locale_date (timestamp, timebuf, sizeof (timebuf)-1);
237        if (dat)
238            return dat;
239        warp = localtime (&timestamp);
240        _snprintf (timebuf, sizeof timebuf -1, "%04d-%02d-%02d",
241                   warp->tm_year + 1900, warp->tm_mon + 1, warp->tm_mday);
242        return timebuf;
243    }
244    
245    
246    const char*
247    get_key_type (gpgme_key_t key)
248    {
249        int type = find_secret_key (key);
250    
251        if (type == 1)
252            return _("Key Pair");
253        else if (type == 2)
254            return _("Key Pair (Card)");
255        return _("Public Key");
256    }
257    
258    
259    const char*
260    get_key_size (gpgme_key_t key, int keyidx)
261    {
262        static char size_id[64];
263        gpgme_subkey_t k;
264        int n, size_main, size_sub;
265        
266        if (keyidx > 0) {
267            k = get_nth_key (key, keyidx-1);
268            size_main = k->length;
269            _snprintf (size_id, DIM (size_id)-1, "%d", size_main);
270            return size_id;
271        }
272        size_main =  key->subkeys->length;
273        n = count_subkeys (key);
274        if (n > 1) {
275            k = get_nth_key (key, n-1);
276            size_sub = k->length;
277            _snprintf (size_id, sizeof (size_id) - 1, "%d/%d",
278                        size_main, size_sub);
279            return size_id;
280        }
281        _snprintf( size_id, sizeof (size_id) - 1, "%d", size_main );
282        return size_id;
283    }
284    
285    
286    const char*
287    get_key_pubalgo2 (gpgme_pubkey_algo_t alg)
288    {
289        switch (alg) {
290        case GPGME_PK_DSA: return "D";
291        case GPGME_PK_RSA: return "R";
292        case GPGME_PK_ELG: return "G";
293        default: return "?";
294        }
295        return "?";
296    }
297    
298    
299    const char*
300    get_key_pubalgo (gpgme_pubkey_algo_t alg)
301    {
302        switch (alg) {
303        case GPGME_PK_DSA: return "DSA";
304        case GPGME_PK_ELG:
305        case GPGME_PK_ELG_E: return "ELG";
306        case GPGME_PK_RSA: return "RSA";
307        default: return "???";
308        }
309        return "???";
310    }
311    
312    const char*
313    get_key_fpr (gpgme_key_t key)
314    {
315        static char fpr_md[64];
316        const char *fpr;
317        char t[16], tmp[40];
318        size_t i=0;
319        
320        memset (fpr_md, 0, sizeof (fpr_md));
321        fpr = key->subkeys->fpr;
322        if (!fpr || !*fpr) {
323            memset (tmp, '0', 40);
324            fpr = tmp;
325        }
326        if (strlen (fpr) == 32) {
327            strcat (fpr_md, "        ");
328            for (i=0; i < strlen (fpr)/2; i++) {
329                sprintf (t, "%c%c ", fpr[2*i], fpr[2*i+1]);
330                strcat (fpr_md, t);
331            }
332        }
333        else {
334            strcat (fpr_md, " ");
335            for (i = 0; i < strlen (fpr) / 4; i++) {
336                sprintf (t, "%c%c%c%c ", fpr[4*i], fpr[4*i+1], fpr[4*i+2], fpr[4*i+3]);
337                strcat (fpr_md, t);
338            }
339        }
340        return fpr_md;
341    }
342    
343    
344    const char*
345    get_key_trust2 (gpgme_key_t key, int val, int uididx, int listmode)
346    {
347        if (key)
348            val = key->owner_trust; /* uididx?? */
349        switch (val) {
350        case GPGME_VALIDITY_UNKNOWN:
351        case GPGME_VALIDITY_UNDEFINED:    
352            return _("None");
353        case GPGME_VALIDITY_NEVER:    
354            return _("Never");
355        case GPGME_VALIDITY_MARGINAL:
356            return _("Marginal");
357        case GPGME_VALIDITY_FULL:
358        case GPGME_VALIDITY_ULTIMATE:
359            return _("Full");
360        }
361        return "";
362    }
363    
364    
365    const char*
366    get_key_trust (gpgme_key_t key, int uididx, int listmode)
367    {
368        return get_key_trust2 (key, 0, uididx, listmode);
369    }
370    
371    
372    const char*
373    get_key_trust_str (int val)
374    {
375        return get_key_trust2 (NULL, val, 0, 0);
376    }
377    
378    
379    /* Return the status of the key @key. */
380    char*
381    get_key_status (gpgme_key_t key, int uididx, int listmode)
382    {
383        gpgme_user_id_t u;
384        const char *attr;
385        u32 key_attr =0;
386    
387        if (uididx < 0 || count_userids (key) > uididx)
388            uididx = 0;
389        if (listmode) {
390            const char *s;
391            if (key->revoked)
392                s = _("Revoked");
393            else if (key->expired)
394                s = _("Expired");
395            else if (key->disabled)
396                s = _("Disabled");
397            else
398                s = "";
399            /* if the key has a special status, we don't continue to figure out
400               the user-id validities. */
401            if (*s)
402                return m_strdup (s);
403        }
404        u = get_nth_userid (key, uididx);
405        key_attr = u->validity;
406        attr = get_key_trust2 (NULL, key_attr, 0, 0);
407        return m_strdup (attr);
408    }
409    
410    
411    /* Return human readable description of the key @key. */
412    char*
413    get_key_desc (gpgme_key_t key)
414    {
415        gpgme_key_t sk;
416        const char *state, *alg, *type;
417        char *p;
418    
419        /* XXX: problems with the German translation. */
420        state = "";
421        if (key->disabled)
422            state = _("Disabled");
423        if (key->expired)
424            state = _("Expired");
425        if (key->revoked)
426            state = _("Revoked");
427        alg = "OpenPGP";
428        if (strlen (key->subkeys->fpr) == 32)
429            alg = "RSA Legacy";
430        type = _("public key");
431        if (!get_seckey (key->subkeys->keyid+8, &sk))
432            type = _("key pair");
433        p = new char[strlen (state) + strlen (alg) + strlen (type) + 4 + 1];
434        if (!p)
435            BUG (0);
436        sprintf (p, "%s %s %s", state, alg, type);
437        return p;
438    }
439    
440    
441    /* Integer comparsion of @a and @b.
442       Return values: same as in strcmp. */
443    static inline int
444    int_cmp (int a, int b)
445    {
446        if (a == b) return 0;      
447        else if (a > b) return 1;
448        else return -1;
449        return 0;
450    }
451    
452    
453    /* To allow to sort the keys, we need to take care of
454       the expired/revoke status also. */
455    static int
456    get_ext_validity (gpgme_key_t k)
457    {
458        if (k->revoked)
459            return GPGME_VALIDITY_ULTIMATE+1;
460        else if (k->expired)
461            return GPGME_VALIDITY_ULTIMATE+2;
462        else if (k->disabled)
463            return GPGME_VALIDITY_ULTIMATE+3;
464        return k->uids->validity;
465    }
466    
467    
468    /* List view sorting callback. */
469    static int CALLBACK
470    keylist_cmp_cb (LPARAM first, LPARAM second, LPARAM sortby)
471    {
472        gpgme_key_t a, b;
473        int cmpresult = 0;
474        
475        a = (gpgme_key_t)first;
476        b = (gpgme_key_t)second;
477        if (!a || !b)
478            BUG (NULL);
479        
480        switch (sortby & ~KEYLIST_SORT_DESC) {
481        case KEY_SORT_USERID:
482            cmpresult = strcmpi (a->uids->uid, b->uids->uid);
483            break;
484            
485        case KEY_SORT_KEYID:
486            cmpresult = strcmpi (a->subkeys->keyid+8,
487                                 b->subkeys->keyid+8);
488            break;
489    
490        case KEY_SORT_VALIDITY:
491            cmpresult = int_cmp (get_ext_validity (a),
492                                 get_ext_validity (b));
493            break;
494    
495        case KEY_SORT_OTRUST:
496            cmpresult = int_cmp (a->owner_trust, b->owner_trust);
497            break;
498    
499        case KEY_SORT_IS_SECRET:
500            get_seckey (a->subkeys->keyid, &a);
501            get_seckey (b->subkeys->keyid, &b);
502            cmpresult = int_cmp (a? a->secret : 0, b? b->secret : 0);
503            break;
504    
505        case KEY_SORT_LEN:
506            cmpresult = int_cmp (a->subkeys->length,
507                                 b->subkeys->length);
508            break;
509    
510        case KEY_SORT_CREATED:
511            cmpresult = int_cmp (a->subkeys->timestamp,
512                                 b->subkeys->timestamp);
513            break;
514    
515        case KEY_SORT_ALGO:
516            cmpresult = int_cmp (a->subkeys->pubkey_algo,
517                                 b->subkeys->pubkey_algo);
518            break;
519            
520        default:
521            cmpresult = strcmpi (a->uids->uid, b->uids->uid);
522            break;
523        }
524        if (sortby & KEYLIST_SORT_DESC)
525            return (~cmpresult + 1);
526        else
527            return cmpresult;
528    }
529    
530    
531    int
532    keylist_add_groups (listview_ctrl_t lv)
533    {
534        return 0;
535    }
536    
537    
538    /* Create a listview for listing keys. Use the mode given in @mode
539       and the control is given in @ctrl. */
540    static int
541    keylist_build (listview_ctrl_t *r_lv, HWND ctrl, int mode)
542    {
543        struct listview_column_s klist_enc[] = {
544        {0, 242, (char *)_("User ID")},
545        {1, 80, (char *)_("Key ID")},
546        {3, 46, (char *)_("Size")},
547        {4, 50, (char *)_("Cipher")},
548        {5, 70, (char *)_("Validity")},
549        {0, 0, NULL}
550        };
551        struct listview_column_s klist[] = {
552        {0, 240, (char *)_("User ID")},
553        {1, 78, (char *)_("Key ID")},
554        {2, 52, (char *)_("Type")},    
555        {3, 66, (char *)_("Size")},
556        {4, 60, (char *)_("Cipher")},
557        {5, 66, (char *)_("Validity")},
558        {6, 58, (char *)_("Trust")},
559        {7, 72, (char *)_("Creation")},
560        {0, 0, NULL}
561        };
562        HICON ico[2];
563        listview_ctrl_t lv;
564        listview_column_t col;
565        int j, n = 0, ext_chk = 0;
566        int rc = 0;
567        
568        rc = listview_new (&lv);
569        if (rc)
570            return rc;
571        
572        lv->ctrl = ctrl;
573        if (mode & KEYLIST_ENCRYPT_MIN) {
574            col = klist_enc;
575            n = (DIM(klist_enc) -1);
576            ext_chk = 1;
577        }  
578        else if ((mode & KEYLIST_SIGN)) {
579            col = klist_enc;
580            n = (DIM(klist_enc) - 1) - 1;
581            ext_chk = 1;
582        }
583        else {
584            col = klist;
585            n = (DIM(klist) - 1);
586        }
587        
588        for (j = 0; j < n; j++)
589            listview_add_column (lv, &col[j]);    
590        listview_set_ext_style (lv);
591        if (ext_chk)
592            listview_set_chkbox_style (lv);
593        ico[0] = LoadIcon (glob_hinst, (LPCTSTR)IDI_PUBKEY);
594        ico[1] = LoadIcon (glob_hinst, (LPCTSTR)IDI_KEYPAIR);
595        listview_set_image_list (lv, 22, 14, ico, 2);
596        listview_del_all_items (lv);
597    
598        *r_lv = lv;
599        return 0;
600    }
601    
602    
603    static void
604    keylist_load_keycache (listview_ctrl_t lv, int mode,
605                           gpg_keycache_t pubkc, gpg_keycache_t seckc)
606    {
607        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
608        gpgme_key_t key, skey;
609        const char * keyid;
610    
611        if (pubkc && seckc) {
612            gpg_keycache_rewind (pubkc);
613            while (!gpg_keycache_next_key (pubkc, 0, &key)) {
614                keyid = key->subkeys->keyid;
615                if (keyid && !gpg_keycache_find_key (seckc, keyid, 0, &skey))
616                    keylist_add_key (lv, mode, key);
617            }      
618        }
619        else if (pubkc) {
620            gpg_keycache_rewind (pubkc);
621            while (!err) {    
622                err = gpg_keycache_next_key (pubkc, 0, &key);
623                if (!err)
624                    keylist_add_key (lv, mode, key);
625            }
626        }
627    }
628    
629    
630    /* Load the list view @ctrl with the keys from the cache.
631       Return value: list view context on success. */
632    listview_ctrl_t
633    keylist_load (HWND ctrl, gpg_keycache_t pubkc, gpg_keycache_t seckc,
634                  int mode, int sortby)
635    {    
636        listview_ctrl_t lv;
637        int rc = 0;    
638    
639        rc = keylist_build (&lv, ctrl, mode);
640        if (rc)
641            return NULL;            
642        keylist_load_keycache (lv, mode, pubkc, seckc);
643        keylist_sort (lv, sortby);
644        if (mode & KEYLIST_ENCRYPT_MIN)
645            keylist_add_groups (lv);
646        return lv;
647    }
648    
649    
650    /* Reload the given key list control @lv. */
651    int
652    keylist_reload (listview_ctrl_t lv, gpg_keycache_t pubkc, int mode, int sortby)
653    {
654        listview_del_all_items (lv);
655        keylist_load_keycache (lv, mode, pubkc, NULL);
656        keylist_sort (lv, sortby);
657        return 0;
658    }
659    
660    
661    void
662    keylist_delete (listview_ctrl_t lv)
663    {
664        if (lv) {
665            listview_release (lv);
666        }
667    }
668    
669    
670    /* Return if there is a secret for @key.
671       0 means success. */
672    static int
673    find_secret_key (gpgme_key_t key)
674    {
675        const char *keyid;
676        winpt_key_s skey;
677        
678        memset (&skey, 0, sizeof (skey));
679        keyid = key->subkeys->keyid;
680        if (!keyid)
681            return 0;
682        winpt_get_seckey (keyid, &skey);
683        if (skey.ext && skey.ext->gloflags.divert_to_card)
684            return 2;
685        return skey.ctx? 1 : 0;
686    }
687    
688    
689    static int
690    do_addkey (listview_ctrl_t lv, gpgme_key_t key, int uididx, int keyidx, int list)
691    {    
692        LV_ITEM lvi;
693        gpgme_user_id_t u;
694        gpgme_subkey_t k;
695        char fmt[128], *p;
696        const char *attr;
697        u32 key_attr;
698        int idx = 0;    
699    
700        /* we check the pubkey algorithm here to make sure that no ElGamal
701           sign+encrypt key is used in _any_ mode */
702        if (list != 1 && key->subkeys->pubkey_algo == GPGME_PK_ELG) {
703            log_debug ("ElGamal (E+S) key found: %s (%s)\n",
704                       key->uids->name, key->subkeys->keyid);
705            return 0;
706        }
707            
708        if (listview_add_item2 (lv, " ", (void *)key))
709            return WPTERR_GENERAL;
710    
711        attr = key->uids->uid;
712        memset (&lvi, 0, sizeof lvi);
713        lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
714        lvi.pszText = (char *)attr;
715        lvi.iImage = find_secret_key (key)? 1 : 0;
716        lvi.lParam = (LPARAM )key;
717        if (ListView_SetItem (lv->ctrl, &lvi) == FALSE)
718            return WPTERR_GENERAL;
719            
720        if (uididx == -1) { /* request the primary user-id of the key. */
721            attr = key->uids->uid;
722            uididx = 0;
723        }
724        else {
725            u = get_nth_userid (key, uididx);
726            if (!u || u->revoked || uididx < 0)
727                uididx = 0;
728            u = get_nth_userid (key, uididx);
729            attr = u->uid;
730        }
731        if (attr == NULL || strlen (attr) < 5) { /* normal userids are > 5 chars */
732            attr = _("Invalid User ID");
733            listview_add_sub_item (lv, 0, idx++, attr);
734        }  
735        else {
736            char *uid = utf8_to_native (attr);
737            if (uid) {
738                listview_add_sub_item (lv, 0, idx++, uid);
739                free (uid);
740            }
741        }
742        k = get_nth_key (key, keyidx);
743        if (k && k->keyid) {
744            _snprintf (fmt, sizeof fmt -1, "0x%s", k->keyid + 8);
745            listview_add_sub_item( lv, 0, idx++, fmt );
746        }
747        if (list > 0) {
748            key_attr = find_secret_key (key);
749            if (!key_attr)
750                attr = "pub";
751            else
752                attr = key_attr == 1? "pub/sec" : "pub/crd";
753            listview_add_sub_item (lv, 0, idx++, attr);
754        }
755        if (lv->cols >= 2) {
756            attr = get_key_size (key, list == -1? keyidx+1 : 0);
757            if (attr)
758                listview_add_sub_item (lv, 0, idx++, attr);
759        }
760        if (lv->cols >= 3) {
761            attr = get_key_algo (key, list == -1? keyidx+1 : 0);
762            if (attr)
763                listview_add_sub_item( lv, 0, idx++, attr);
764        }
765        if (lv->cols >= 4) {
766            p = get_key_status( key, uididx, list > 0? 1 : 0 );
767            if (!p)
768                return WPTERR_GENERAL;
769            listview_add_sub_item (lv, 0, idx++, p);
770            free_if_alloc (p);
771        }
772        if (lv->cols >= 5) {
773            attr = get_key_trust (key, uididx, list > 0? 1 : 0);
774            listview_add_sub_item (lv, 0, idx++, attr);
775        }
776        if( lv->cols >= 6 ) {
777            k = get_nth_key (key, keyidx);
778            key_attr = k->timestamp;
779            if( key_attr ) {
780                attr = get_key_created (key_attr);
781                listview_add_sub_item( lv, 0, idx++, attr );
782            }      
783        }
784    
785        return 0;
786    }
787    
788    
789    /* Update a single column @col but for each element in the
790       listview @lv. */
791    void
792    keylist_upd_col (listview_ctrl_t lv, int col)
793    {
794        gpgme_key_t key;
795        const char *s;
796        char buf[32], *p;
797        int i;
798    
799        for (i=0; i < listview_count_items (lv, 0); i++) {
800            key = (gpgme_key_t)listview_get_item2 (lv, i);
801            if (!key)
802                continue;
803            switch (col) {
804            case KM_COL_KEYID:
805                _snprintf (buf, sizeof (buf)-1, "0x%s", key->subkeys->keyid+8);
806                listview_add_sub_item (lv, i, col, buf);
807                break;
808    
809            case KM_COL_CIPHER:
810                s = get_key_algo (key, 0);
811                listview_add_sub_item (lv, i, col, s);
812                break;
813    
814            case KM_COL_TYPE:
815                s = find_secret_key (key)? "pub/sec" : "pub";
816                listview_add_sub_item (lv, i, col, s);
817                break;
818    
819            case KM_COL_CREAT:
820                s = get_key_created (key->subkeys->timestamp);
821                listview_add_sub_item (lv, i, col, s);
822                break;
823    
824            case KM_COL_DESC:
825                p = get_key_desc (key);
826                listview_add_sub_item (lv, i, col, p);
827                free_if_alloc (p);
828                break;
829            }
830        }
831    }
832    
833    
834    /* Update the listview item at position @pos with the data from
835       the key @key. */
836    void
837    keylist_upd_key (listview_ctrl_t lv, int pos, gpgme_key_t key)
838    {
839        const char *s;
840        char *uid, *p;
841        char tmp[32];
842    
843        listview_set_item2 (lv, pos, (void *)key);
844        /* the only mode we support is KYLIST_LIST in the Key Manager */
845        
846        s = key->uids->uid;
847        if (s) {
848            uid = utf8_to_native (s);
849            listview_add_sub_item (lv, pos, KM_COL_UID, uid);
850            free (uid);
851        }
852    
853        s = key->subkeys->keyid;
854        if (s) {
855            sprintf (tmp, "0x%s", s+8);
856            listview_add_sub_item (lv, pos, KM_COL_KEYID, tmp);
857        }
858    
859        s = find_secret_key (key)? "pub/sec" : "pub";
860        listview_add_sub_item (lv, pos, KM_COL_TYPE, s);
861    
862        s = get_key_size (key, 0);
863        if (s)
864            listview_add_sub_item (lv, pos, KM_COL_SIZE, s);
865    
866        s = get_key_algo (key, 0);
867        if (s)
868            listview_add_sub_item (lv, pos, KM_COL_CIPHER, s);
869    
870        p = get_key_status (key, 0, 1);
871        if (p) {
872            listview_add_sub_item (lv, pos, KM_COL_VALID, p);
873            free_if_alloc (p);
874        }
875    
876        s = get_key_trust (key, 0, 1);
877        if (s)
878            listview_add_sub_item (lv, pos, KM_COL_TRUST, s);
879    
880        long t = key->subkeys->timestamp;
881        s = get_key_created (t);
882        if (s)
883            listview_add_sub_item (lv, pos, KM_COL_CREAT, s);
884    }
885    
886    
887    int
888    keylist_add_key (listview_ctrl_t lv, int mode, gpgme_key_t key)
889    {
890        int uids, rc = 0, i;
891        gpgme_subkey_t k;
892    
893        /* if the entire key is disabled, just return. */
894        if (key->disabled && !(mode & KEYLIST_LIST))
895            return 0;
896    
897        for (k=key->subkeys, i = 0; i < count_subkeys (key); i++, k=k->next) {
898            if (k->invalid) {
899                log_debug ("keylist_add_key: invalid key \"%s\"\n", key->uids->name);
900                continue; /* Don't use invalid keys */
901            }
902    
903            if (mode & KEYLIST_ALL) {
904                uids = count_userids (key);
905                rc = do_addkey (lv, key, uids, i, 0);
906                if (rc)
907                    return rc;
908            }
909            else if (mode & KEYLIST_LIST)
910                return do_addkey (lv, key, -1, i, 1);
911            else if (mode & KEYLIST_ENCRYPT) {
912                if (k->can_encrypt && key_is_useable (k)) {
913                    if (mode & KEYLIST_FLAG_FILE) {
914                        rc = do_addkey (lv, key, -1, i, -1);
915                        if (rc)
916                            return rc;
917                    }
918                    else {
919                        for (uids = 0;  uids < count_userids (key); uids++) {
920                            rc = do_addkey (lv, key, uids, i, -1);
921                            if (rc)
922                                return rc;
923                        }
924                    }
925                }
926            }
927            else if (mode & KEYLIST_ENCRYPT_MIN) {
928                if( k->can_encrypt && key_is_useable (k))
929                {
930                    rc = do_addkey (lv, key, -1, i, -1);
931                    return rc;
932                }
933            }      
934            else if (mode & KEYLIST_SIGN) {
935                if (k->can_sign
936                    && find_secret_key (key)
937                    && key_is_useable (k)) {
938                    rc = do_addkey (lv, key, -1, i, -1);
939                    if (rc)
940                        return rc;  
941                }
942            }      
943        }
944    
945        return rc;  
946    }
947    
948    
949    int
950    keylist_sort (listview_ctrl_t lv, int sortby)
951    {
952        return listview_sort_items (lv, sortby, keylist_cmp_cb);
953    }
954    
955    
956    /* Check that the validity @validity is at least >= marginal. */
957    static int
958    key_check_validity (gpgme_key_t key)
959    {
960        gpgme_user_id_t u;
961    
962        for (u=key->uids; u; u =u->next) {
963            if (u->validity >= GPGME_VALIDITY_MARGINAL)
964                return -1;
965        }
966    
967        return 0;
968    }
969    
970    
971    /* Extract all selected recipients from the list @lv and return them
972       as a vector. @r_force_trust is >= 1 if one of the recipients is not
973       fully trusted. @r_count returns the number of selected keys.
974       Return value: the key list on success, NULL otherwise. */
975    gpgme_key_t*
976    keylist_get_recipients (listview_ctrl_t lv, int *r_force_trust, int *r_count)
977    {
978        key_array_s *ka = NULL;
979        gpgme_key_t *keybuf, key;
980        int count = 0, force_trust = 0;
981        int n, j, ka_pos = 0, rc = 0;
982        int k_pos=0;
983    
984        n = listview_count_items (lv, 0);
985        
986        ka = key_array_new (n);
987        if (!ka)
988            BUG (NULL);
989    
990        keybuf = (gpgme_key_t*)calloc (n+1, sizeof (gpgme_key_t));
991        if (!keybuf)
992            BUG (NULL);
993            
994        for (j = 0; j < n; j++) {
995            if (listview_get_item_state (lv, j) || n == 1) {
996                key = (gpgme_key_t)listview_get_item2 (lv, j);
997                if (!key)
998                    BUG (0);
999                if (!key_check_validity (key) &&
1000                    !key_array_search (ka, ka_pos, key->subkeys->keyid)) {
1001                    char *utf8_uid = utf8_to_native (key->uids->uid);
1002                    char *warn = new char[512+strlen (utf8_uid) + 1];
1003                    if (!warn)
1004                        BUG (0);
1005                    sprintf (warn,
1006                        _("It is NOT certain that the key belongs to the person\n"
1007                          "named in the user ID.  If you *really* know what you are\n"
1008                          "doing, you may answer the next question with yes\n"
1009                          "\n"
1010                          "Use \"%s\" anyway?"), utf8_uid);
1011                    if (reg_prefs.always_trust)
1012                        rc = IDYES;
1013                    else
1014                        rc = msg_box (NULL, warn, _("Recipients"), MB_ERR_ASK);
1015                    if (rc == IDYES) {
1016                        keybuf[k_pos++] = key;
1017                        force_trust++;
1018                        ka[ka_pos].checked = 1;
1019                        strcpy (ka[ka_pos++].keyid, key->subkeys->keyid);
1020                        count++;
1021                    }
1022                    safe_free (utf8_uid);
1023                    free_if_alloc (warn);
1024                }
1025                else {
1026                    keybuf[k_pos++] = key;
1027                    count++;        
1028                }
1029            }
1030        }
1031        key_array_release (ka);
1032        if (r_force_trust)
1033            *r_force_trust = force_trust;
1034        if (r_count)
1035            *r_count = count;
1036        return keybuf;
1037    }
1038    
1039    
1040    static int
1041    keylist_get_keyflags (gpgme_key_t key)
1042    {
1043        int flags = KEYFLAG_NONE;
1044    
1045        if (key->revoked)
1046            flags |= KEYFLAG_REVOKED;
1047        if (key->expired)
1048            flags |= KEYFLAG_EXPIRED;
1049        if (key->disabled)
1050            flags |= KEYFLAG_DISABLED;
1051    
1052        return flags;
1053    }
1054    
1055    
1056    gpgme_key_t*
1057    keylist_enum_recipients (listview_ctrl_t lv,  int listype, int *r_count)
1058    {
1059        gpgme_key_t *rset;
1060        gpgme_key_t key;
1061        int i, n, id, k_pos=0;
1062    
1063        n = listview_count_items (lv, 0);
1064        if (!n)
1065            return 0;
1066        rset = (gpgme_key_t*)calloc (n+1, sizeof (gpgme_key_t));
1067        if (!rset)
1068            BUG (NULL);
1069        for (i = 0; i < n; i++) {
1070            if (!listview_get_item_state (lv, i))
1071                continue;
1072            key = (gpgme_key_t)listview_get_item2 (lv, i);
1073            if (!key)
1074                BUG (0);
1075            switch (listype) {
1076            case KEYLIST_LIST:
1077                if (keylist_get_keyflags (key) & KEYFLAG_REVOKED) {
1078                    id = printf_box (_("Recipients"), MB_INFO|MB_YESNO,
1079                    _("KeyID %s.\nDo you really want to export a revoked key?"),
1080                                     key->uids->uid);
1081                    if (id == IDNO)
1082                        continue;
1083                }
1084                break;
1085            }
1086            rset[k_pos++] = key;
1087        }
1088        if (r_count)
1089            *r_count = k_pos;
1090        return rset;
1091    }
1092    
1093    
1094    void
1095    seclist_destroy (keylist_t *list)
1096    {
1097        keylist_t l2;
1098        while (*list) {
1099            l2 = (*list)->next;
1100            safe_free (*list);
1101            *list = l2;    
1102        }
1103        list = NULL;
1104    }
1105    
1106    
1107    void
1108    seclist_init (HWND dlg, int ctlid, int flags, keylist_t * ret_list)
1109    {    
1110        gpg_keycache_t kc = NULL;
1111        gpgme_key_t key = NULL;
1112        HWND kb;
1113        keylist_t list=NULL, l, l2;    
1114        long pos = 0;
1115    
1116        SendDlgItemMessage (dlg, ctlid, CB_RESETCONTENT, 0, 0);
1117        kb = GetDlgItem (dlg, ctlid);
1118        kc = keycache_get_ctx (0);
1119        if (!kc)
1120            BUG (0);
1121        gpg_keycache_rewind (kc);
1122        
1123        while (!gpg_keycache_next_key (kc, 1, &key)) {
1124            char *inf = NULL, *uid = NULL;
1125            const char *id;
1126            const char *keyid;
1127            int algo;
1128            size_t size = 0;
1129    
1130            if (flags & KEYLIST_FLAG_SHORT)
1131                id = key->uids->name;
1132            else
1133                id = key->uids->uid;
1134            keyid = key->subkeys->keyid;
1135            algo = key->subkeys->pubkey_algo;
1136            if (!id || !keyid)
1137                continue;
1138            if (key->disabled || !key_is_useable (key->subkeys))
1139                continue;
1140    
1141            uid = utf8_to_native (id);
1142            size = strlen (uid) + strlen (keyid) + 32;
1143            inf = new char[size+1];
1144            if (!inf)
1145                BUG (NULL);
1146            _snprintf (inf, size, "%s (%s/0x%s)", uid,
1147                       get_key_pubalgo (key->subkeys->pubkey_algo), keyid + 8);
1148            combox_add_string (kb, inf);
1149            free_if_alloc (inf);
1150            free (uid);
1151            l = (struct keylist_s *)calloc (1, sizeof * l);
1152            if (!l)
1153                BUG (0);
1154            l->key = key;
1155            if (!list)
1156                list = l;
1157            else {
1158                for( l2 = list; l2->next; l2 = l2->next )
1159                    ;
1160                l2->next = l;
1161            }
1162        }
1163        for (pos = 0, l2=list; pos < SendMessage (kb, CB_GETCOUNT, 0, 0);
1164             pos++, l2=l2->next)
1165            SendMessage (kb, CB_SETITEMDATA, pos, (LPARAM)(DWORD)l2->key);
1166        SendMessage (kb, CB_SETCURSEL, 0, 0);
1167        *ret_list = list;
1168    }
1169            
1170    
1171    /* Select a secret key from the combo box with the ID @ctlid.
1172       Return the code on success in @ret_key. */
1173    int
1174    seclist_select_key (HWND dlg, int ctlid, gpgme_key_t *ret_key)
1175    {
1176        int pos;
1177        DWORD k = 0;
1178    
1179        pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0);
1180        if (pos == CB_ERR) {
1181            msg_box (dlg, _("No key was selected."), _("Secret Key List"), MB_ERR);
1182            *ret_key = NULL;
1183        }
1184        else {
1185            k = SendDlgItemMessage (dlg, ctlid, CB_GETITEMDATA, pos, 0);
1186            *ret_key = (gpgme_key_t)k;
1187        }
1188        return k? 0 : -1;
1189    }

Legend:
Removed from v.2  
changed lines
  Added in v.197

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26