@ -114,6 +114,8 @@ typedef struct fmail_ctx
{
const char * * attachments ;
size_t att_count ;
const char * * recipients ;
size_t rcp_count ;
const char * footer ;
magic_t magic_ctx ;
gpgme_ctx_t crypto_ctx ;
@ -300,7 +302,7 @@ process_text_body(fmail_ctx_t *ctx, FILE *out)
/* Signing stuff. */
/* Crypto stuff. */
gpgme_ctx_t
initialize_gpgme ( void )
@ -402,6 +404,99 @@ sign_stream(gpgme_ctx_t ctx, FILE *in, FILE *out)
gpgme_data_release ( gout ) ;
}
static gpgme_key_t *
get_recipient_keys ( gpgme_ctx_t ctx , const char * * recipients , size_t nr )
{
gpgme_key_t * keys , key ;
gpgme_error_t gerr ;
int i , j ;
keys = NULL ;
for ( i = j = gerr = 0 ; i < nr & & ! gerr ; i + + ) {
gerr = gpgme_op_keylist_start ( ctx , recipients [ i ] , 0 ) ;
while ( ! gerr ) {
gerr = gpgme_op_keylist_next ( ctx , & key ) ;
if ( gerr )
break ;
if ( j % 10 = = 0 )
keys = xrealloc ( keys , j + 10 ) ;
keys [ j + + ] = key ;
}
if ( gpgme_err_code ( gerr ) = = GPG_ERR_EOF )
gerr = 0 ;
}
if ( gerr ! = 0 & & gpgme_err_code ( gerr ) ! = GPG_ERR_EOF )
errx ( EXIT_FAILURE , " cannot get recipient keys: %s " , gpgme_strerror ( gerr ) ) ;
/* GpgME expects a NULL-terminated array of keys. */
if ( j % 10 = = 0 )
keys = xrealloc ( keys , j + 1 ) ;
keys [ j + + ] = NULL ;
return keys ;
}
static void
encrypt_stream ( gpgme_ctx_t ctx ,
FILE * in ,
FILE * out ,
const char * * recipients ,
size_t nr )
{
gpgme_data_t gin , gout ;
gpgme_key_t * keys , * key ;
gpgme_error_t gerr ;
char boundary [ 32 ] , buffer [ 512 ] ;
int n ;
keys = get_recipient_keys ( ctx , recipients , nr ) ;
gpgme_data_new_from_stream ( & gin , in ) ;
gpgme_data_new ( & gout ) ;
gerr = gpgme_op_encrypt ( ctx , keys , 0 , gin , gout ) ;
if ( gerr ! = GPG_ERR_NO_ERROR )
errx ( EXIT_FAILURE , " encrypting failed: %s " , gpgme_strerror ( gerr ) ) ;
generate_boundary ( boundary , sizeof ( boundary ) ) ;
fprintf ( out , " Content-Type: multipart/encrypted; \r \n "
" boundary= \" %s \" ; \r \n "
" protocol= \" application/pgp-encrypted \r \n "
" \r \n "
" --%s \r \n "
" Content-Type: application/pgp-encrypted \r \n "
" \r \n "
" Version: 1 \r \n "
" \r \n "
" --%s \r \n "
" Content-Type: application/octet-stream \r \n "
" \r \n " ,
boundary , boundary , boundary ) ;
gpgme_data_seek ( gout , 0 , SEEK_SET ) ;
while ( ( n = gpgme_data_read ( gout , buffer , sizeof ( buffer ) ) ) > 0 ) {
int i = 0 ;
while ( i < n ) {
if ( buffer [ i ] = = ' \n ' )
fputc ( ' \r ' , out ) ;
fputc ( buffer [ i ] , out ) ;
i + = 1 ;
}
}
fprintf ( out , " \r \n --%s-- \r \n " , boundary ) ;
gpgme_data_release ( gin ) ;
gpgme_data_release ( gout ) ;
for ( key = keys ; * key ! = NULL ; key + + )
gpgme_key_release ( * key ) ;
free ( keys ) ;
}
/* Attachments stuff. */
@ -535,7 +630,7 @@ main(int argc, char *argv[])
char c , with_useragent , with_date ;
string_buffer_t * headers ;
fmail_ctx_t ctx ;
int do_sign , do_encrypt ;
int do_sign ;
struct option options [ ] = {
{ " help " , 0 , NULL , ' h ' } ,
@ -559,13 +654,15 @@ main(int argc, char *argv[])
setlocale ( LC_ALL , " " ) ;
srand ( time ( NULL ) ) ;
with_useragent = with_date = do_sign = do_encrypt = 0 ;
with_useragent = with_date = do_sign = 0 ;
headers = sb_new ( 0 ) ;
ctx . crypto_ctx = NULL ;
ctx . magic_ctx = initialize_magic ( ) ;
ctx . attachments = NULL ;
ctx . att_count = 0 ;
ctx . recipients = NULL ;
ctx . rcp_count = 0 ;
ctx . footer = NULL ;
ctx . input = stdin ;
@ -589,7 +686,9 @@ main(int argc, char *argv[])
break ;
case ' E ' :
do_encrypt = 1 ;
if ( ctx . rcp_count % 10 = = 0 )
ctx . recipients = xrealloc ( ctx . recipients , ctx . rcp_count + 10 ) ;
ctx . recipients [ ctx . rcp_count + + ] = optarg ;
break ;
case ' a ' :
@ -636,9 +735,9 @@ main(int argc, char *argv[])
}
}
if ( do_sign & & do_encryp t )
if ( do_sign & & ctx . rcp_coun t )
errx ( EXIT_FAILURE , " encrypt and sign is not currently supported " ) ;
if ( do_sign | | do_encryp t )
if ( do_sign | | ctx . rcp_coun t )
ctx . crypto_ctx = initialize_gpgme ( ) ;
/* Generate automatic headers */
@ -657,12 +756,15 @@ main(int argc, char *argv[])
/* Write all headers. */
fprintf ( stdout , " %s " , sb_get ( headers ) ) ;
if ( do_sign ) {
if ( do_sign | | ctx . rcp_count ) {
FILE * tmp = tmpfile ( ) ;
process_text_body ( & ctx , tmp ) ;
fseek ( tmp , 0 , SEEK_SET ) ;
sign_stream ( ctx . crypto_ctx , tmp , stdout ) ;
if ( do_sign )
sign_stream ( ctx . crypto_ctx , tmp , stdout ) ;
else
encrypt_stream ( ctx . crypto_ctx , tmp , stdout , ctx . recipients , ctx . rcp_count ) ;
fclose ( tmp ) ;
gpgme_release ( ctx . crypto_ctx ) ;
@ -675,6 +777,9 @@ main(int argc, char *argv[])
if ( ctx . attachments )
free ( ctx . attachments ) ;
if ( ctx . recipients )
free ( ctx . recipients ) ;
magic_close ( ctx . magic_ctx ) ;
return EXIT_SUCCESS ;