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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26