Browse Source

Implement encryption only.

Allow the use of -E option to specify a recipient to encrypt the
message to. If several -E options are used, the message will be
encrypted to all specified recipients.
tags/fmail-0.2.0^2
parent
commit
03d5348f49
1 changed files with 113 additions and 8 deletions
  1. +113
    -8
      src/fmail.c

+ 113
- 8
src/fmail.c View File

@@ -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_encrypt )
if ( do_sign && ctx.rcp_count )
errx(EXIT_FAILURE, "encrypt and sign is not currently supported");
if ( do_sign || do_encrypt )
if ( do_sign || ctx.rcp_count )
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;


Loading…
Cancel
Save