diff --git a/NEWS b/NEWS index 8e0506502..185104f91 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ - * + * New options --[no-]utf8-strings. + * New edit-menu commands "enable" and "disable" for entire keys. + + * You will be asked for a filename if gpg cannot deduce one. Noteworthy changes in version 0.9.8 ----------------------------------- diff --git a/TODO b/TODO index 49203445b..34b009b03 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ - * add keylength and type to status output. - * add some status output put for signing and encryption. replace the putc in primegen with some kind of status-fd outputs. @@ -21,7 +19,7 @@ * find a way to allow the import of non-self-signed keys. This is needed for the IN ENCR/SIGN hack. - * convert the given user ID to UTF-8 and add an option to suppress this. + * Not all user names are correctly converted to UTF8. Nice to have @@ -52,4 +50,3 @@ Nice to have verification status of the message to the output (i.e. write something to the --output file and not only to stderr. - diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 30d2ddd22..77a3e4b82 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,9 @@ +Thu Jul 1 12:47:31 CEST 1999 Werner Koch + + + * primegen.c, elgamal.c, dsa.c (progess): New and replaced all + fputc with a call to this function. + Sat Jun 26 12:15:59 CEST 1999 Werner Koch diff --git a/cipher/dsa.c b/cipher/dsa.c index 14854635c..cbd90ac5f 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -52,6 +52,13 @@ static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors ); static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey); static int verify(MPI r, MPI s, MPI input, DSA_public_key *pkey); +static void +progress( int c ) +{ + fputc( c, stderr ); +} + + /**************** * Generate a random secret exponent k less than q */ @@ -65,7 +72,7 @@ gen_k( MPI q ) log_debug("choosing a random k "); for(;;) { if( DBG_CIPHER ) - fputc('.', stderr); + progress('.'); { char *p = get_random_bits( nbits, 1, 1 ); mpi_set_buffer( k, p, (nbits+7)/8, 0 ); m_free(p); @@ -84,7 +91,7 @@ gen_k( MPI q ) break; /* okay */ } if( DBG_CIPHER ) - fputc('\n', stderr); + progress('\n'); return k; } @@ -170,7 +177,7 @@ generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors ) rndbuf = NULL; do { if( DBG_CIPHER ) - fputc('.', stderr); + progress('.'); if( !rndbuf ) rndbuf = get_random_bits( qbits, 2, 1 ); else { /* change only some of the higher bits (= 2 bytes)*/ @@ -190,7 +197,7 @@ generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors ) mpi_powm( y, g, x, p ); if( DBG_CIPHER ) { - fputc('\n', stderr); + progress('\n'); log_mpidump("dsa p= ", p ); log_mpidump("dsa q= ", q ); log_mpidump("dsa g= ", g ); diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 9d9058f97..0e6b992c0 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -56,6 +56,13 @@ static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey); static int verify(MPI a, MPI b, MPI input, ELG_public_key *pkey); +static void +progress( int c ) +{ + fputc( c, stderr ); +} + + static void test_keys( ELG_secret_key *sk, unsigned nbits ) { @@ -108,7 +115,7 @@ gen_k( MPI p ) mpi_sub_ui( p_1, p, 1); for(;;) { if( DBG_CIPHER ) - fputc('.', stderr); + progress('.'); { char *pp = get_random_bits( nbits, 1, 1 ); mpi_set_buffer( k, pp, (nbits+7)/8, 0 ); m_free(pp); @@ -128,7 +135,7 @@ gen_k( MPI p ) break; /* okay, k is relatively prime to (p-1) */ } if( DBG_CIPHER ) - fputc('\n', stderr); + progress('\n'); mpi_free(p_1); mpi_free(temp); @@ -179,7 +186,7 @@ generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors ) rndbuf = NULL; do { if( DBG_CIPHER ) - fputc('.', stderr); + progress('.'); if( rndbuf ) { /* change only some of the higher bits */ if( nbits < 16 ) {/* should never happen ... */ m_free(rndbuf); @@ -202,7 +209,7 @@ generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors ) mpi_powm( y, g, x, p ); if( DBG_CIPHER ) { - fputc('\n', stderr); + progress('\n'); log_mpidump("elg p= ", p ); log_mpidump("elg g= ", g ); log_mpidump("elg y= ", y ); diff --git a/cipher/primegen.c b/cipher/primegen.c index 9019e2839..9bf108531 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -39,6 +39,13 @@ static int is_prime( MPI n, int steps, int *count ); static void m_out_of_n( char *array, int m, int n ); +static void +progress( int c ) +{ + fputc( c, stderr ); +} + + /**************** * Generate a prime number (stored in secure memory) */ @@ -48,7 +55,7 @@ generate_secret_prime( unsigned nbits ) MPI prime; prime = gen_prime( nbits, 1, 2 ); - fputc('\n', stderr); + progress('\n'); return prime; } @@ -58,7 +65,7 @@ generate_public_prime( unsigned nbits ) MPI prime; prime = gen_prime( nbits, 0, 2 ); - fputc('\n', stderr); + progress('\n'); return prime; } @@ -152,7 +159,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, } if( i == n ) { m_free(perms); perms = NULL; - fputc('!', stderr); + progress('!'); goto next_try; /* allocate new primes */ } } @@ -169,7 +176,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, if( ++count1 > 20 ) { count1 = 0; qbits++; - fputc('>', stderr); + progress('>'); q = gen_prime( qbits, 0, 1 ); goto next_try; } @@ -180,7 +187,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, if( ++count2 > 20 ) { count2 = 0; qbits--; - fputc('<', stderr); + progress('<'); q = gen_prime( qbits, 0, 1 ); goto next_try; } @@ -190,7 +197,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, } while( !(nprime == pbits && check_prime( prime, val_2 )) ); if( DBG_CIPHER ) { - putc('\n', stderr); + progress('\n'); log_mpidump( "prime : ", prime ); log_mpidump( "factor q: ", q ); if( mode == 1 ) @@ -202,7 +209,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, fprintf(stderr, ", q0=%u", mpi_get_nbits(q_factor) ); for(i=0; i < n; i++ ) fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) ); - putc('\n', stderr); + progress('\n'); } if( ret_factors ) { /* caller wants the factors */ @@ -237,7 +244,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, mpi_print( stderr, g, 1 ); } else - fputc('^', stderr); + progress('^'); for(i=0; i < n+2; i++ ) { /*fputc('~', stderr);*/ mpi_fdiv_q(tmp, pmin1, factors[i] ); @@ -247,7 +254,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, break; } if( DBG_CIPHER ) - fputc('\n', stderr); + progress('\n'); } while( i < n+2 ); mpi_free(factors[n+1]); mpi_free(tmp); @@ -255,7 +262,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, mpi_free(pmin1); } if( !DBG_CIPHER ) - putc('\n', stderr); + progress('\n'); m_free( factors ); /* (factors are shallow copies) */ for(i=0; i < m; i++ ) @@ -335,7 +342,7 @@ gen_prime( unsigned nbits, int secret, int randomlevel ) /* perform stronger tests */ if( is_prime(ptest, 5, &count2 ) ) { if( !mpi_test_bit( ptest, nbits-1 ) ) { - fputc('\n', stderr); + progress('\n'); log_debug("overflow in prime generation\n"); break; /* step loop, continue with a new prime */ } @@ -350,11 +357,11 @@ gen_prime( unsigned nbits, int secret, int randomlevel ) } } if( ++dotcount == 10 ) { - fputc('.', stderr); + progress('.'); dotcount = 0; } } - fputc(':', stderr); /* restart with a new random value */ + progress(':'); /* restart with a new random value */ } } @@ -383,7 +390,7 @@ check_prime( MPI prime, MPI val_2 ) mpi_free( pminus1 ); if( mpi_cmp_ui( result, 1 ) ) { /* if composite */ mpi_free( result ); - fputc('.', stderr); + progress('.'); return 0; } mpi_free( result ); @@ -392,7 +399,7 @@ check_prime( MPI prime, MPI val_2 ) /* perform stronger tests */ if( is_prime(prime, 5, &count ) ) return 1; /* is probably a prime */ - fputc('.', stderr); + progress('.'); return 0; } @@ -452,7 +459,7 @@ is_prime( MPI n, int steps, int *count ) if( mpi_cmp( y, nminus1 ) ) goto leave; /* not a prime */ } - fputc('+', stderr); + progress('+'); } rc = 1; /* may be a prime */ diff --git a/doc/DETAILS b/doc/DETAILS index 84b42833b..6ff7cb656 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -85,8 +85,11 @@ more arguments in future versions. unique ids - others may yield duplicated ones when they have been created in the same second. - ENC_TO + ENC_TO The message is encrypted to this keyid. + keytype is the numerical value of the public key algorithm, + kenlength is the length of the key or 0 if it is not known + (which is currently always the case). NODATA No data has been found. Codes for what are: @@ -122,8 +125,11 @@ more arguments in future versions. SHM_GET_BOOL SHM_GET_HIDDEN - NEED_PASSPHRASE + NEED_PASSPHRASE Issued whenever a passphrase is needed. + keytype is the numerical value of the public key algorithm + or 0 if this is not applicable, keylength is the length + of the key or 0 if it is not known (this is currently always the case). NEED_PASSPHRASE_SYM Issued whenever a passphrase for symmetric encryption is needed. diff --git a/doc/gpg.sgml b/doc/gpg.sgml index 82e069b56..21d74fc83 100644 --- a/doc/gpg.sgml +++ b/doc/gpg.sgml @@ -268,6 +268,12 @@ certificate should be generated. Change the owner trust value. This updates the trust-db immediately and no save is required. + + disable + enable + +Disable or enable an entire key. A disabled key can normally not be used +for encryption. adduid @@ -537,7 +543,8 @@ in the options file and may be used together with an own user-id as an "encrypt-to-self". These keys are only used when there are other recipients given either by use of --recipient or by the asked user id. -No trust checking is performed for these user ids. +No trust checking is performed for these user ids and +even disabled keys can be used. @@ -698,6 +705,18 @@ Valid values for &ParmName; are: + +--utf8-strings +--no-utf8-strings + +Assume that the arguments are already given as UTF8 strings. The default +(--no-utf8-strings) +is to assume that arguments are encoded in the character set as specified +by --charset. These options effects all following arguments. Both options may +used multiple times. + + + --options &ParmFile; diff --git a/g10/ChangeLog b/g10/ChangeLog index 9db45bb4a..ca68a142a 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,28 @@ +Thu Jul 1 12:47:31 CEST 1999 Werner Koch + + + * keyedit.c (show_key_with_all_names): Print a notice for disabled keys. + (enable_disable_keys): Add functionality + * pkclist.c (edit_ownertrust): preserve disabled state. + (build_pk_list): Skip disabled keys. + * trustdb.c (upd_one_ownertrust): Ditto. + (build_cert_tree): Mask the ownertrust. + (trust_letter): Mask the value. + (do_check): Take disabled flag into account. + + * passphrase.c (passphrase_to_dek): Add a pubkey_alfo arg and changed + all callers. + + * g10.c (utf8_strings): 2 new options. + + * trustdb.c (insert_trust_record_by_pk): New, replaces the next one. + (insert_trust_record): Now takes a keyblock as arg. Changed all + callers to use the appropritae function. + + * openfile.c (ask_outfile_name): New. + * plaintext.c (handle_plaintext): Ask for filename if there is + no valid syntax. Don't use fname varbatim but filter it. + Tue Jun 29 21:44:25 CEST 1999 Werner Koch diff --git a/g10/encode.c b/g10/encode.c index 7daec6c64..147607b31 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -102,7 +102,7 @@ encode_simple( const char *filename, int mode ) s2k->mode = opt.rfc1991? 0:opt.s2k_mode; s2k->hash_algo = opt.def_digest_algo ? opt.def_digest_algo : opt.s2k_digest_algo; - cfx.dek = passphrase_to_dek( NULL, + cfx.dek = passphrase_to_dek( NULL, 0, opt.def_cipher_algo ? opt.def_cipher_algo : opt.s2k_cipher_algo , s2k, 2 ); if( !cfx.dek || !cfx.dek->keylen ) { diff --git a/g10/g10.c b/g10/g10.c index 94aa2808f..66a91bf94 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -166,6 +166,8 @@ enum cmd_and_opt_values { aNull = 0, oEncryptTo, oNoEncryptTo, oLoggerFD, + oUtf8Strings, + oNoUtf8Strings, aTest }; @@ -315,13 +317,15 @@ static ARGPARSE_OPTS opts[] = { { oLockMultiple, "lock-multiple", 0, "@" }, { oLoggerFD, "logger-fd",1, "@" }, { oUseEmbeddedFilename, "use-embedded-filename", 0, "@" }, + { oUtf8Strings, "utf8-strings", 0, "@" }, + { oNoUtf8Strings, "no-utf8-strings", 0, "@" }, {0} }; int g10_errors_seen = 0; - +static int utf8_strings = 0; static int maybe_setuid = 1; static char *build_list( const char *text, @@ -761,16 +765,16 @@ main( int argc, char **argv ) case oNoEncryptTo: opt.no_encrypt_to = 1; break; case oEncryptTo: /* store the recipient in the second list */ - sl = add_to_strlist( &remusr, pargs.r.ret_str ); + sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); sl->flags = 1; break; case oRecipient: /* store the recipient */ - add_to_strlist( &remusr, pargs.r.ret_str ); + add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); break; case oTextmodeShort: opt.textmode = 2; break; case oTextmode: opt.textmode=1; break; case oUser: /* store the local users */ - add_to_strlist( &locusr, pargs.r.ret_str ); + add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings ); break; case oCompress: opt.compress = pargs.r.ret_int; break; case oPasswdFD: pwfd = pargs.r.ret_int; break; @@ -788,6 +792,8 @@ main( int argc, char **argv ) case oLockMultiple: opt.lock_once = 0; break; case oKeyServer: opt.keyserver_name = pargs.r.ret_str; break; case oNotation: add_notation_data( pargs.r.ret_str ); break; + case oUtf8Strings: utf8_strings = 1; break; + case oNoUtf8Strings: utf8_strings = 0; break; default : pargs.err = configfp? 1:2; break; } @@ -1025,7 +1031,7 @@ main( int argc, char **argv ) if( argc > 1 ) { sl = NULL; for( argc--, argv++ ; argc; argc--, argv++ ) - append_to_strlist( &sl, *argv ); + append_to_strlist2( &sl, *argv, utf8_strings ); keyedit_menu( fname, locusr, sl ); free_strlist(sl); } @@ -1040,6 +1046,7 @@ main( int argc, char **argv ) if( argc != 1 ) wrong_args(_("--delete-key username")); /* note: fname is the user id! */ + /* fixme: do utf8 conversion */ if( (rc = delete_key(fname, cmd==aDeleteSecretKey)) ) log_error("%s: delete key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) ); break; @@ -1482,11 +1489,8 @@ add_notation_data( const char *string ) highbit = 1; } - if( highbit ) { /* must use UTF8 encoding */ - char *p = native_to_utf8( string ); - sl = add_to_strlist( &opt.notation_data, p ); - m_free( p ); - } + if( highbit ) /* must use UTF8 encoding */ + sl = add_to_strlist2( &opt.notation_data, string, utf8_strings ); else sl = add_to_strlist( &opt.notation_data, string ); diff --git a/g10/helptext.c b/g10/helptext.c index 521df534d..5fb800784 100644 --- a/g10/helptext.c +++ b/g10/helptext.c @@ -208,10 +208,17 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = { "Give the name fo the file to which the signature applies" }, +/* openfile.c (overwrite_filep) */ { N_("openfile.overwrite.okay"), "Answer \"yes\" if it is okay to overwrite the file" }, +/* openfile.c (ask_outfile_name) */ +{ N_("openfile.askoutname"), + "Please enter a new filename. If you just hit RETURN the default\n" + "file (which is shown in brackets) will be used." +}, + /* end of list */ { NULL, NULL } }; diff --git a/g10/import.c b/g10/import.c index 060990e36..a81c7edbf 100644 --- a/g10/import.c +++ b/g10/import.c @@ -376,10 +376,10 @@ import_one( const char *fname, KBNODE keyblock, int fast ) log_info( _("writing to `%s'\n"), keyblock_resource_name(&kbpos) ); if( (rc=lock_keyblock( &kbpos )) ) - log_error(_("can't lock keyring `%s': %s\n"), + log_error(_("can't lock keyring `%s': %s\n"), keyblock_resource_name(&kbpos), g10_errstr(rc) ); else if( (rc=insert_keyblock( &kbpos, keyblock )) ) - log_error( _("error writing keyring `%s': %s\n"), + log_error( _("error writing keyring `%s': %s\n"), keyblock_resource_name(&kbpos), g10_errstr(rc) ); unlock_keyblock( &kbpos ); /* we are ready */ @@ -402,9 +402,6 @@ import_one( const char *fname, KBNODE keyblock, int fast ) goto leave; } - /* See whether we have only non-self-signature on one user id; if not - * ask the user what to do. <--- fixme */ - /* now read the original keyblock */ rc = find_keyblock_bypk( &kbpos, pk_orig ); if( rc ) { @@ -432,7 +429,7 @@ import_one( const char *fname, KBNODE keyblock, int fast ) mod_key = 1; /* keyblock_orig has been updated; write */ if( (rc=lock_keyblock( &kbpos )) ) - log_error( _("can't lock keyring `%s': %s\n"), + log_error( _("can't lock keyring `%s': %s\n"), keyblock_resource_name(&kbpos), g10_errstr(rc) ); else if( (rc=update_keyblock( &kbpos, keyblock_orig )) ) log_error( _("error writing keyring `%s': %s\n"), @@ -475,7 +472,7 @@ import_one( const char *fname, KBNODE keyblock, int fast ) if( rc && rc != -1 ) log_error("trustdb error: %s\n", g10_errstr(rc) ); else if( rc == -1 ) { /* not found trustdb */ - rc = insert_trust_record( new_key? pk : pk_orig ); + rc = insert_trust_record( new_key? keyblock : keyblock_orig ); if( rc ) log_error("key %08lX: trustdb insert failed: %s\n", (ulong)keyid[1], g10_errstr(rc) ); diff --git a/g10/keydb.h b/g10/keydb.h index 236967511..20a8a6325 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -125,7 +125,8 @@ int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, /*-- passphrase.h --*/ int have_static_passphrase(void); void read_passphrase_from_fd( int fd ); -DEK *passphrase_to_dek( u32 *keyid, int cipher_algo, STRING2KEY *s2k, int mode); +DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo, + int cipher_algo, STRING2KEY *s2k, int mode); void set_next_passphrase( const char *s ); char *get_last_passphrase(void); diff --git a/g10/keyedit.c b/g10/keyedit.c index df14f13e1..e93634034 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -451,7 +451,7 @@ change_passphrase( KBNODE keyblock ) for(;;) { s2k->mode = opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; - dek = passphrase_to_dek( NULL, opt.s2k_cipher_algo, s2k, 2 ); + dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 ); if( !dek ) { tty_printf(_("passphrase not correctly repeated; try again.\n")); } @@ -1033,6 +1033,12 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, expirestr_from_pk(pk) ); if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { tty_printf(" trust: %c/%c", otrust, trust ); + if( node->pkt->pkttype == PKT_PUBLIC_KEY + && (get_ownertrust( pk->local_id )&TRUST_FLAG_DISABLED)) { + tty_printf("\n*** "); + tty_printf(_("This key has been disabled")); + } + if( with_fpr ) { tty_printf("\n"); show_fingerprint( pk ); @@ -1872,12 +1878,20 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) static int enable_disable_key( KBNODE keyblock, int disable ) { - int entire; - int changed = 0; + ulong lid = find_kbnode( keyblock, PKT_PUBLIC_KEY ) + ->pkt->pkt.public_key->local_id; + unsigned int trust, newtrust; - - entire = !count_selected_keys( keyblock ); - - return changed; + /* Note: Because the keys have beed displayed, we have + * ensured that local_id has been set */ + trust = newtrust = get_ownertrust( lid ); + newtrust &= ~TRUST_FLAG_DISABLED; + if( disable ) + newtrust |= TRUST_FLAG_DISABLED; + if( trust == newtrust ) + return 0; /* already in that state */ + if( !update_ownertrust( lid, newtrust ) ) + return 1; + return 0; } diff --git a/g10/keygen.c b/g10/keygen.c index 1621d9445..74840e8c6 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -743,7 +743,7 @@ ask_passphrase( STRING2KEY **ret_s2k ) for(;;) { s2k->mode = opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; - dek = passphrase_to_dek( NULL, opt.s2k_cipher_algo, s2k, 2 ); + dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 ); if( !dek ) { tty_printf(_("passphrase not correctly repeated; try again.\n")); } @@ -1045,7 +1045,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) s2k->mode = opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; set_next_passphrase( passphrase ); - dek = passphrase_to_dek( NULL, opt.s2k_cipher_algo, s2k, 2 ); + dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 ); } rc = do_create( algo, nbits, pub_keyblock, sec_keyblock, diff --git a/g10/main.h b/g10/main.h index 5889ccf71..f2c059b33 100644 --- a/g10/main.h +++ b/g10/main.h @@ -97,6 +97,7 @@ int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ); /*-- openfile.c --*/ int overwrite_filep( const char *fname ); char *make_outfile_name( const char *iname ); +char *ask_outfile_name( const char *name, size_t namelen ); int open_outfile( const char *iname, int mode, IOBUF *a ); IOBUF open_sigfile( const char *iname ); void copy_options_file( const char *destdir ); diff --git a/g10/mainproc.c b/g10/mainproc.c index cb2388f06..51d436127 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -163,7 +163,7 @@ proc_symkey_enc( CTX c, PACKET *pkt ) log_error( "symkey_enc packet with session keys are not supported!\n"); else { c->last_was_session_key = 2; - c->dek = passphrase_to_dek( NULL, enc->cipher_algo, &enc->s2k, 0 ); + c->dek = passphrase_to_dek( NULL, 0, enc->cipher_algo, &enc->s2k, 0 ); } free_packet(pkt); } @@ -185,7 +185,8 @@ proc_pubkey_enc( CTX c, PACKET *pkt ) if( is_status_enabled() ) { char buf[50]; - sprintf(buf, "%08lX%08lX", (ulong)enc->keyid[0], (ulong)enc->keyid[1]); + sprintf(buf, "%08lX%08lX %d 0", + (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo ); write_status_text( STATUS_ENC_TO, buf ); } @@ -230,7 +231,7 @@ proc_encrypted( CTX c, PACKET *pkt ) /*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/ if( !c->dek && !c->last_was_session_key ) { /* assume this is old conventional encrypted data */ - c->dek = passphrase_to_dek( NULL, + c->dek = passphrase_to_dek( NULL, 0, opt.def_cipher_algo ? opt.def_cipher_algo : DEFAULT_CIPHER_ALGO, NULL, 0 ); } diff --git a/g10/openfile.c b/g10/openfile.c index af0ab3c1d..ebf954843 100644 --- a/g10/openfile.c +++ b/g10/openfile.c @@ -99,6 +99,44 @@ make_outfile_name( const char *iname ) } +/**************** + * Ask for a outputfilename and use the given one as default. + * Return NULL if no file has been given or it is not possible to + * ask the user. + */ +char * +ask_outfile_name( const char *name, size_t namelen ) +{ + size_t n; + const char *s; + char *prompt; + char *fname; + char *defname; + + if( opt.batch ) + return NULL; + + s = _("Enter new filename"); + + n = strlen(s) + namelen + 10; + defname = name && namelen? make_printable_string( name, namelen, 0): NULL; + prompt = m_alloc(n); + if( defname ) + sprintf(prompt, "%s [%s]: ", s, defname ); + else + sprintf(prompt, "%s: ", s ); + fname = cpr_get("openfile.askoutname", prompt ); + cpr_kill_prompt(); + m_free(prompt); + if( !*fname ) { + m_free( fname ); fname = NULL; + fname = defname; defname = NULL; + } + m_free(defname); + return fname; +} + + /**************** * Make an output filename for the inputfile INAME. diff --git a/g10/passphrase.c b/g10/passphrase.c index 9581246f2..80c6fa33f 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -114,9 +114,11 @@ read_passphrase_from_fd( int fd ) * (only for mode 2) * a dek->keylen of 0 means: no passphrase entered. * (only for mode 2) + * pubkey_algo is only informational. */ DEK * -passphrase_to_dek( u32 *keyid, int cipher_algo, STRING2KEY *s2k, int mode ) +passphrase_to_dek( u32 *keyid, int pubkey_algo, + int cipher_algo, STRING2KEY *s2k, int mode ) { char *pw = NULL; DEK *dek; @@ -139,8 +141,8 @@ passphrase_to_dek( u32 *keyid, int cipher_algo, STRING2KEY *s2k, int mode ) sprintf( buf, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1] ); if( keyid[2] && keyid[3] && keyid[0] != keyid[2] && keyid[1] != keyid[3] ) - sprintf( buf+strlen(buf), " %08lX%08lX", - (ulong)keyid[2], (ulong)keyid[3] ); + sprintf( buf+strlen(buf), " %08lX%08lX %d 0", + (ulong)keyid[2], (ulong)keyid[3], pubkey_algo ); write_status_text( STATUS_NEED_PASSPHRASE, buf ); } else { diff --git a/g10/pkclist.c b/g10/pkclist.c index 39ed0e5f2..d8c25ebba 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -206,7 +206,7 @@ do_edit_ownertrust( ulong lid, int mode, unsigned *new_trust ) int edit_ownertrust( ulong lid, int mode ) { - unsigned trust; + unsigned int trust; for(;;) { switch( do_edit_ownertrust( lid, mode, &trust ) ) { @@ -216,6 +216,8 @@ edit_ownertrust( ulong lid, int mode ) show_paths( lid, 1 ); break; case 1: + trust &= ~TRUST_FLAG_DISABLED; + trust |= get_ownertrust( lid ) & TRUST_FLAG_DISABLED; if( !update_ownertrust( lid, trust ) ) return 1; return 0; @@ -301,7 +303,7 @@ do_we_trust( PKT_public_key *pk, int trustlevel ) switch( (trustlevel & TRUST_MASK) ) { case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */ - rc = insert_trust_record( pk ); + rc = insert_trust_record_by_pk( pk ); if( rc ) { log_error("failed to insert it into the trustdb: %s\n", g10_errstr(rc) ); @@ -462,7 +464,7 @@ check_signatures_trust( PKT_signature *sig ) switch( (trustlevel & TRUST_MASK) ) { case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */ - rc = insert_trust_record( pk ); + rc = insert_trust_record_by_pk( pk ); if( rc ) { log_error("failed to insert it into the trustdb: %s\n", g10_errstr(rc) ); @@ -633,6 +635,9 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) log_error("error checking pk of `%s': %s\n", answer, g10_errstr(rc) ); } + else if( (trustlevel & TRUST_FLAG_DISABLED) ) { + tty_printf(_("Public key is disabled.\n") ); + } else if( do_we_trust_pre( pk, trustlevel ) ) { PK_LIST r; @@ -673,6 +678,11 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) log_error(_("%s: error checking key: %s\n"), remusr->d, g10_errstr(rc) ); } + else if( (trustlevel & TRUST_FLAG_DISABLED) ) { + free_public_key(pk); pk = NULL; + log_info(_("%s: skipped: public key is disabled\n"), + remusr->d); + } else if( do_we_trust_pre( pk, trustlevel ) ) { /* note: do_we_trust may have changed the trustlevel */ diff --git a/g10/plaintext.c b/g10/plaintext.c index 1edca16e5..878bdc46b 100644 --- a/g10/plaintext.c +++ b/g10/plaintext.c @@ -65,15 +65,15 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, } else if( !opt.use_embedded_filename ) { fname = make_outfile_name( iobuf_get_real_fname(pt->buf) ); + if( !fname ) + fname = ask_outfile_name( pt->name, pt->namelen ); if( !fname ) { rc = G10ERR_CREATE_FILE; goto leave; } } else { - fname = m_alloc( pt->namelen +1 ); - memcpy( fname, pt->name, pt->namelen ); - fname[pt->namelen] = 0; + fname = make_printable_string( pt->name, pt->namelen, 0 ); } if( nooutput ) diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 03cf3f2bf..95af40b78 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -64,7 +64,7 @@ do_check( PKT_secret_key *sk ) keyid_from_sk( sk2, keyid+2 ); free_secret_key( sk2 ); } - dek = passphrase_to_dek( keyid, sk->protect.algo, + dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo, &sk->protect.s2k, 0 ); cipher_hd = cipher_open( sk->protect.algo, CIPHER_MODE_AUTO_CFB, 1); diff --git a/g10/sig-check.c b/g10/sig-check.c index 48734370c..e57ae8019 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -412,6 +412,11 @@ check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ) pk = root->pkt->pkt.public_key; sig = node->pkt->pkt.signature; algo = sig->digest_algo; + + if( sig->flags.checked ) + log_debug("check_key_signature: already checked: %s\n", + sig->flags.valid? "good":"bad" ); + if( (rc=check_digest_algo(algo)) ) return rc; diff --git a/g10/tdbdump.c b/g10/tdbdump.c index 2d3502caf..799309e05 100644 --- a/g10/tdbdump.c +++ b/g10/tdbdump.c @@ -503,7 +503,7 @@ import_ownertrust( const char *fname ) if( rc != -1 ) log_error_f(fname, _("Oops: key is now in trustdb???\n")); else { - rc = insert_trust_record( pk ); + rc = insert_trust_record_by_pk( pk ); if( !rc ) goto repeat; /* update the ownertrust */ log_error_f(fname, _("insert trust record failed: %s\n"), diff --git a/g10/trustdb.c b/g10/trustdb.c index 1e804d704..fa1e43a56 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -513,7 +513,7 @@ verify_own_keys(void) /* make sure that the pubkey is in the trustdb */ rc = query_trust_record( pk ); if( rc == -1 ) { /* put it into the trustdb */ - rc = insert_trust_record( pk ); + rc = insert_trust_record_by_pk( pk ); if( rc ) { log_error(_("key %08lX: can't put it into the trustdb\n"), (ulong)keyid[1] ); @@ -633,10 +633,14 @@ print_user_id( FILE *fp, const char *text, u32 *keyid ) +/**************** + * This function returns a letter for a trustvalue Trust flags + * are ignore. + */ int trust_letter( unsigned value ) { - switch( value ) { + switch( (value & TRUST_MASK) ) { case TRUST_UNKNOWN: return '-'; case TRUST_EXPIRED: return 'e'; case TRUST_UNDEFINED: return 'q'; @@ -994,6 +998,10 @@ check_keybinding( KBNODE keyblock, KBNODE keynode, u32 *mainkid, int is_main = (keynode->pkt->pkttype == PKT_PUBLIC_KEY); int rc; + if( DBG_TRUST ) + log_debug("check_keybinding: %08lX.%lu\n", + (ulong)mainkid[1], lid ); + if( is_main ) { /* a primary key is always valid (user IDs are handled elsewhere)*/ keyflags = KEYF_CHECKED | KEYF_VALID; @@ -1134,6 +1142,10 @@ check_uidsigs( KBNODE keyblock, KBNODE keynode, u32 *mainkid, ulong lid ) PKT_signature *selfsig = NULL; /* the latest valid self signature */ int rc; + if( DBG_TRUST ) + log_debug("check_uidsigs: %08lX.%lu\n", + (ulong)mainkid[1], lid ); + /* first we check only the selfsignatures */ for( node=keynode->next; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID @@ -1217,6 +1229,10 @@ check_sig_record( KBNODE keyblock, KBNODE signode, TRUSTREC tmp; int revocation=0, rc; + if( DBG_TRUST ) + log_debug("check_sig_record: %08lX.%lu %lu[%d]\n", + (ulong)keyid[1], lid, siglid, sigidx ); + if( (sig->sig_class&~3) == 0x10 ) /* regular certification */ ; else if( sig->sig_class == 0x30 ) /* cert revocation */ @@ -1447,6 +1463,8 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified ) primary_pk->local_id = drec.recnum; keyid_from_pk( primary_pk, keyid ); + if( DBG_TRUST ) + log_debug("update_trust_record: %08lX.%lu\n", (ulong)keyid[1], drec.recnum ); rc = tdbio_begin_transaction(); if( rc ) @@ -1512,14 +1530,11 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified ) * This function assumes that the record does not yet exist. */ int -insert_trust_record( PKT_public_key *orig_pk ) +insert_trust_record( KBNODE keyblock ) { TRUSTREC dirrec; TRUSTREC shadow; - KBNODE keyblock = NULL; KBNODE node; - byte fingerprint[MAX_FINGERPRINT_LEN]; - size_t fingerlen; int rc = 0; PKT_public_key *pk; @@ -1529,39 +1544,11 @@ insert_trust_record( PKT_public_key *orig_pk ) init_trustdb(); - fingerprint_from_pk( orig_pk, fingerprint, &fingerlen ); - - /* fixme: assert that we do not have this record. - * we can do this by searching for the primary keyid - * - * fixme: If there is no such key we should look whether one - * of the subkeys has been used to sign another key and in this case - * we got the key anyway - this is because a secondary key can't be used - * without a primary key (it is needed to bind the secondary one - * to the primary one which has the user ids etc.) - */ - - if( orig_pk->local_id ) - log_debug("insert_trust_record with pk->local_id=%lu (1)\n", - orig_pk->local_id ); - - /* get the keyblock which has the key */ - rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen ); - if( rc ) { /* that should never happen */ - log_error( _("insert_trust_record: keyblock not found: %s\n"), - g10_errstr(rc) ); - goto leave; - } - - /* make sure that we use the primary key */ pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key; - if( pk->local_id ) { - orig_pk->local_id = pk->local_id; log_debug("insert_trust_record with pk->local_id=%lu (2)\n", pk->local_id ); rc = update_trust_record( keyblock, 1, NULL ); - release_kbnode( keyblock ); return rc; } @@ -1581,9 +1568,8 @@ insert_trust_record( PKT_public_key *orig_pk ) dirrec.r.dir.lid = dirrec.recnum; write_record( &dirrec ); - /* put the LID into the in-memory copy of the keyblock */ + /* put the LID into the keyblock */ pk->local_id = dirrec.r.dir.lid; - orig_pk->local_id = dirrec.r.dir.lid; for( node=keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { @@ -1602,12 +1588,40 @@ insert_trust_record( PKT_public_key *orig_pk ) /* and put all the other stuff into the keydb */ rc = update_trust_record( keyblock, 1, NULL ); - leave: - release_kbnode( keyblock ); do_sync(); return rc; } +/**************** + * Insert a trust record indentified by a PK into the TrustDB + */ +int +insert_trust_record_by_pk( PKT_public_key *pk ) +{ + KBNODE keyblock = NULL; + byte fingerprint[MAX_FINGERPRINT_LEN]; + size_t fingerlen; + int rc; + + /* get the keyblock */ + fingerprint_from_pk( pk, fingerprint, &fingerlen ); + rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen ); + if( rc ) { /* that should never happen */ + log_debug( "insert_trust_record_by_pk: keyblock not found: %s\n", + g10_errstr(rc) ); + } + else { + rc = insert_trust_record( keyblock ); + if( !rc ) /* copy the LID into the PK */ + pk->local_id = find_kbnode( keyblock, PKT_PUBLIC_KEY ) + ->pkt->pkt.public_key->local_id; + } + + release_kbnode( keyblock ); + return rc; +} + + /**************** * Walk over the keyrings and create trustdb records for all keys @@ -1633,8 +1647,9 @@ update_trustdb() rc = update_trust_record( keyblock, 1, &modified ); if( rc == -1 ) { /* not yet in trustdb: insert */ - PKT_public_key *pk = keyblock->pkt->pkt.public_key; - rc = insert_trust_record( pk ); + PKT_public_key *pk; + rc = insert_trust_record( keyblock ); + pk = keyblock->pkt->pkt.public_key; if( rc && !pk->local_id ) { log_error(_("lid ?: insert failed: %s\n"), g10_errstr(rc) ); @@ -1782,7 +1797,7 @@ build_cert_tree( ulong lid, int depth, int max_depth, TN helproot ) m_free(keynode); return NULL; } - keynode->n.k.ownertrust = dirrec.r.dir.ownertrust; + keynode->n.k.ownertrust = dirrec.r.dir.ownertrust & TRUST_MASK; /* loop over all user ids */ for( uidrno = dirrec.r.dir.uidlist; uidrno; uidrno = uidrec.r.uid.next ) { @@ -1872,12 +1887,17 @@ upd_one_ownertrust( ulong lid, unsigned new_trust, unsigned *retflgs ) log_debug("upd_one_ownertrust of %lu from %u to %u\n", lid, (unsigned)rec.r.dir.ownertrust, new_trust ); if( retflgs ) { - if( new_trust > rec.r.dir.ownertrust ) + if( (new_trust & TRUST_MASK) > (rec.r.dir.ownertrust & TRUST_MASK) ) *retflgs |= 16; /* modified up */ else *retflgs |= 32; /* modified down */ } - rec.r.dir.ownertrust = new_trust; + + /* we preserve the disabled state here */ + if( (rec.r.dir.ownertrust & TRUST_FLAG_DISABLED) ) + rec.r.dir.ownertrust = new_trust | TRUST_FLAG_DISABLED; + else + rec.r.dir.ownertrust = new_trust & ~TRUST_FLAG_DISABLED; write_record( &rec ); } @@ -2072,8 +2092,9 @@ do_check( TRUSTREC *dr, unsigned *validity, if( retflgs ) *retflgs &= ~(16|32); /* reset the 2 special flags */ - - if( namehash ) { + if( (dr->r.dir.ownertrust & TRUST_FLAG_DISABLED) ) + *validity = 0; /* no need to check further */ + else if( namehash ) { /* Fixme: use the cache */ *validity = verify_key( opt.max_cert_depth, dr, namehash, add_fnc, retflgs ); @@ -2091,6 +2112,9 @@ do_check( TRUSTREC *dr, unsigned *validity, if( !(*validity & TRUST_MASK) ) *validity = TRUST_UNDEFINED; + if( (dr->r.dir.ownertrust & TRUST_FLAG_DISABLED) ) + *validity |= TRUST_FLAG_DISABLED; + if( dr->r.dir.dirflags & DIRF_REVOKED ) *validity |= TRUST_FLAG_REVOKED; @@ -2223,7 +2247,7 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel, return rc; } else if( rc == -1 ) { /* not found - insert */ - rc = insert_trust_record( pk ); + rc = insert_trust_record_by_pk( pk ); if( rc ) { log_error(_("key %08lX: insert trust record failed: %s\n"), (ulong)keyid[1], g10_errstr(rc)); @@ -2247,7 +2271,7 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel, log_info(_("key %08lX.%lu: expired at %s\n"), (ulong)keyid[1], pk->local_id, asctimestamp( pk->expiredate) ); - trustlevel = TRUST_EXPIRED; + trustlevel = TRUST_EXPIRED; } else { rc = do_check( &rec, &trustlevel, namehash, add_fnc, retflgs ); @@ -2364,7 +2388,7 @@ list_trust_path( const char *username ) username, g10_errstr(rc)); else if( rc == -1 ) { log_info(_("user '%s' not in trustdb - inserting\n"), username); - rc = insert_trust_record( pk ); + rc = insert_trust_record_by_pk( pk ); if( rc ) log_error(_("failed to put '%s' into trustdb: %s\n"), username, g10_errstr(rc)); diff --git a/g10/trustdb.h b/g10/trustdb.h index 9f3e4c35f..6396fde45 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -64,8 +64,9 @@ int keyid_from_lid( ulong lid, u32 *keyid ); ulong lid_from_keyblock( KBNODE keyblock ); int query_trust_record( PKT_public_key *pk ); int clear_trust_checked_flag( PKT_public_key *pk ); -int insert_trust_record( PKT_public_key *pk ); int update_trust_record( KBNODE keyblock, int fast, int *modified ); +int insert_trust_record( KBNODE keyblock ); +int insert_trust_record_by_pk( PKT_public_key *pk ); int update_ownertrust( ulong lid, unsigned new_trust ); int trust_letter( unsigned value ); diff --git a/include/util.h b/include/util.h index d266af412..b36e11bb2 100644 --- a/include/util.h +++ b/include/util.h @@ -153,6 +153,7 @@ const char *strtimevalue( u32 stamp ); const char *strtimestamp( u32 stamp ); /* GMT */ const char *asctimestamp( u32 stamp ); /* localized */ void print_string( FILE *fp, const byte *p, size_t n, int delim ); +char *make_printable_string( const byte *p, size_t n, int delim ); int answer_is_yes( const char *s ); int answer_is_yes_no_quit( const char *s ); @@ -160,7 +161,9 @@ int answer_is_yes_no_quit( const char *s ); void free_strlist( STRLIST sl ); #define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0) STRLIST add_to_strlist( STRLIST *list, const char *string ); +STRLIST add_to_strlist2( STRLIST *list, const char *string, int is_utf8 ); STRLIST append_to_strlist( STRLIST *list, const char *string ); +STRLIST append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ); STRLIST strlist_prev( STRLIST head, STRLIST node ); STRLIST strlist_last( STRLIST node ); const char *memistr( const char *buf, size_t buflen, const char *sub ); diff --git a/util/ChangeLog b/util/ChangeLog index 35e69fb31..e74bf851e 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,3 +1,10 @@ +Thu Jul 1 12:47:31 CEST 1999 Werner Koch + + + * miscutil.c (make_printable_string): New. + + * strgutil.c (add_to_strlist2,append_to_strlist2): New. + Tue Jun 29 21:44:25 CEST 1999 Werner Koch diff --git a/util/miscutil.c b/util/miscutil.c index d982e64af..4244ccce0 100644 --- a/util/miscutil.c +++ b/util/miscutil.c @@ -149,6 +149,60 @@ print_string( FILE *fp, const byte *p, size_t n, int delim ) putc(*p, fp); } +/**************** + * This function returns a string which is suitable for printing + * Caller must release it with m_free() + */ +char * +make_printable_string( const byte *p, size_t n, int delim ) +{ + size_t save_n, buflen; + const byte *save_p; + char *buffer, *d; + + /* first count length */ + for(save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) { + if( iscntrl( *p ) || *p == delim ) { + if( *p=='\n' || *p=='\r' || *p=='\f' + || *p=='\v' || *p=='\b' || !*p ) + buflen += 2; + else + buflen += 3; + } + else + buflen++; + } + p = save_p; + n = save_n; + /* and now make the string */ + d = buffer = m_alloc( buflen ); + for( ; n; n--, p++ ) { + if( iscntrl( *p ) || *p == delim ) { + *d++ = '\\'; + if( *p == '\n' ) + *d++ = 'n'; + else if( *p == '\r' ) + *d++ = 'r'; + else if( *p == '\f' ) + *d++ = 'f'; + else if( *p == '\v' ) + *d++ = 'v'; + else if( *p == '\b' ) + *d++ = 'b'; + else if( !*p ) + *d++ = '0'; + else { + sprintf(d, "x%02x", *p ); + d += 2; + } + } + else + *d++ = *p; + } + *d = 0; + return buffer; +} + int answer_is_yes( const char *s ) diff --git a/util/strgutil.c b/util/strgutil.c index 94f8a5d6c..b27f9b7b6 100644 --- a/util/strgutil.c +++ b/util/strgutil.c @@ -94,6 +94,25 @@ add_to_strlist( STRLIST *list, const char *string ) return sl; } +/**************** + * ame as add_to_strlist() but if is_utf8 is *not* set a conversion + * to UTF8 is done + */ +STRLIST +add_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) +{ + STRLIST sl; + + if( is_utf8 ) + sl = add_to_strlist( list, string ); + else { + char *p = native_to_utf8( string ); + sl = add_to_strlist( list, p ); + m_free( p ); + } + return sl; +} + STRLIST append_to_strlist( STRLIST *list, const char *string ) { @@ -113,6 +132,20 @@ append_to_strlist( STRLIST *list, const char *string ) return sl; } +STRLIST +append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) +{ + STRLIST sl; + + if( is_utf8 ) + sl = append_to_strlist( list, string ); + else { + char *p = native_to_utf8( string ); + sl = append_to_strlist( list, p ); + m_free( p ); + } + return sl; +} STRLIST