diff --git a/Makefile.am b/Makefile.am index c0c6f41..d1429be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,4 +2,4 @@ SUBDIRS = lib src man ACLOCAL_AMFLAGS = -I m4 --install -dist_doc_DATA = AUTHORS COPYING README +dist_doc_DATA = AUTHORS COPYING README.md NEWS diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..fcba84e --- /dev/null +++ b/NEWS @@ -0,0 +1,5 @@ +Changes in fmail 0.1.0 (2018-02-25) + + * Make User-Agent and Date headers optional. + * Specify correct hash algorithm in micalg parameter. + * Abort properly upon signing error. diff --git a/README b/README deleted file mode 100644 index 3ef3174..0000000 --- a/README +++ /dev/null @@ -1,44 +0,0 @@ -fmail - Incenp.org’s mail formatter -=================================== - -Description ------------ -Fmail is a mail formatter. It reads a draft message on its standard -input and writes to its standard output a suitably formatted message -ready to be sent to a mail submission agent. - -The name “fmail” stands for something like “Formatting MAIL”. - - -Copying -------- -Fmail is distributed under the terms of the GNU General Public License -(see COPYING file). Source code and other informations are available on -. - - -Homepage and contact --------------------- -The latest source code, the repository and some informations are -available at . - -Contact: Damien Goutte-Gattat - - -Install -------- -Fmail depends on the following libraries: - - – libgpgme , to sign messages; - - – libmagic , to guess file type and - encoding of attachments. - -I expect Fmail to compile cleanly (and behave correctly) on most POSIX -systems, although I have only tested it on my GNU/Linux box. Should you -find a portability issue on your system, please let me know. - -Run the provided “configure” script to prepare the sources for build; -run “configure --help” to know the available configuration parameters. -Then run “make” to effectively build the program, and “make install” to -install it on your system. diff --git a/README.md b/README.md new file mode 100644 index 0000000..32b8be4 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +fmail - Incenp.org’s mail formatter +=================================== + +Description +----------- +Fmail is a mail formatter. It reads a draft message on its standard +input and writes to its standard output a suitably formatted message +ready to be sent to a mail submission agent. + +The name “fmail” stands for something like “Formatting MAIL”. + +The main feature of Fmail is its ability to add attachments to the +input message and to sign the whole message (including attachments) +using [PGP/MIME](https://tools.ietf.org/html/rfc3156). + +The signing feature makes Fmail usable as a “signing filter”, +taking a complete (but unsigned) mail on its standard input and +emitting a PGP/MIME-signed message on its standard output (ready to +be sent to a mail submission agent such as `/usr/sbin/sendmail`). + + +Install +------- +Fmail depends on the following libraries: + +- [libgpgme](http://www.gnupg.org/gpgme.html), to sign messages; + +- [libmagic](http://www.darwinsys.com/file/), to guess file type and + encoding of attachments. + +I expect Fmail to compile cleanly (and behave correctly) on most POSIX +systems, although I have only tested it on my GNU/Linux box. Should you +find a portability issue on your system, please let me know. + +Run the provided `configure` script to prepare the sources for build; +run `configure --help` to know the available configuration parameters. +Then run `make` to effectively build the program, and `make install` to +install it on your system. + + +Copying +------- +Fmail is distributed under the terms of the GNU General Public License, +version 3 or higher. The full text of the license is included in the +[COPYING file](COPYING) of the source distribution. + + +Homepage and repository +----------------------- +The project is located at https://incenp.org/dvlpt/fmail.html. The +latest source code is available in a Git repository at +git://git.incenp.org/fmail.git and may also be browsed at +https://incenp.org/gitweb/?p=fmail.git;a=summary. diff --git a/configure.ac b/configure.ac index 4c6c3a1..c2abc09 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Configure template for the fmail package -AC_INIT([fmail], [0.1.0], +AC_INIT([fmail], [0.1.1], [dgouttegattat@incenp.org]) AC_CONFIG_SRCDIR([configure.ac]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/man/fmail.1.in b/man/fmail.1.in index f01c745..b18057a 100644 --- a/man/fmail.1.in +++ b/man/fmail.1.in @@ -23,6 +23,8 @@ fmail \- mail formatter .IR recipient ] .RB [ \-S | --subject .IR subject ] +.RB [ \-U | --user-agent ] +.RB [ \-D | --date ] .YS .SH DESCRIPTION @@ -95,6 +97,16 @@ header. Set the .B Subject: header. +.TP +.BR -U ", " --user-agent +Add a +.B User-Agent: +header. +.TP +.BR -D "; " --date +Add an automatically generated +.B Date: +header with the current date. .SH REPORTING BUGS .PP @@ -106,7 +118,7 @@ Damien Goutte-Gattat .SH COPYRIGHT .ad l .PP -Copyright \(co 2011 Damien Goutte-Gattat +Copyright \(co 2011,2018 Damien Goutte-Gattat .PP This program is released under the GNU General Public License. See the COPYING file in the source distribution or diff --git a/src/fmail.c b/src/fmail.c index c7d1695..a5051b3 100644 --- a/src/fmail.c +++ b/src/fmail.c @@ -1,6 +1,6 @@ /* * fmail - Mail formatter - * Copyright (C) 2011 Damien Goutte-Gattat + * Copyright (C) 2011,2018 Damien Goutte-Gattat * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,8 @@ for submission to a mail submission agent.\n"); -T, --to TEXT Add a To: header.\n\ -C, --cc TEXT Add a Cc: header.\n\ -S, --subject TEXT Set the Subject: header.\n\ + -U, --user-agent Add a User-Agent: header.\n\ + -D, --date Add a Date: header with the current date.\n\ "); puts("\ @@ -89,7 +92,7 @@ info(void) { printf("\ fmail %s\n\ -Copyright (C) 2011 Damien Goutte-Gattat\n\ +Copyright (C) 2018 Damien Goutte-Gattat\n\ \n\ This program is released under the GNU General Public License.\n\ See the COPYING file or .\n\ @@ -119,7 +122,7 @@ typedef struct fmail_ctx static char * generate_boundary(char *buffer, size_t len) { - int i; + unsigned i; for ( i = 0; i < len - 1; i++ ) buffer[i] = base64_chars[rand() % (sizeof(base64_chars) - 1)]; @@ -256,7 +259,7 @@ static void process_text_body(fmail_ctx_t *ctx, FILE *out) { char boundary[32]; - int i; + unsigned i; if ( ctx->att_count > 0 ) { generate_boundary(boundary, sizeof(boundary)); @@ -317,26 +320,57 @@ initialize_gpgme(void) return ctx; } +static const char * +hash_algo_to_string(gpgme_hash_algo_t algo) +{ + switch ( algo ) { + case GPGME_MD_MD5: return "pgp-md5"; + case GPGME_MD_SHA1: return "pgp-sha1"; + case GPGME_MD_RMD160: return "pgp-ripemd160"; + case GPGME_MD_MD2: return "pgp-md2"; + case GPGME_MD_TIGER: return "pgp-tiger192"; + case GPGME_MD_HAVAL: return "php-haval-5-160"; + case GPGME_MD_SHA256: return "pgp-sha256"; + case GPGME_MD_SHA384: return "pgp-sha384"; + case GPGME_MD_SHA512: return "pgp-sha512"; + case GPGME_MD_SHA224: return "pgp-sha224"; + case GPGME_MD_MD4: return "pgp-md4"; + case GPGME_MD_CRC32: return "pgp-crc32"; + case GPGME_MD_CRC32_RFC1510: return "pgp-crc32-rfc1510"; + case GPGME_MD_CRC24_RFC2440: return "pgp-crc24-rfc2440"; + case GPGME_MD_NONE: return ""; + } + + return ""; /* FIXME: What to do here? */ +} + static void sign_stream(gpgme_ctx_t ctx, FILE *in, FILE *out) { gpgme_data_t gin, gout; + gpgme_sign_result_t result; + gpgme_error_t gerr; char boundary[32], buffer[512]; int n; gpgme_data_new_from_stream(&gin, in); gpgme_data_new(&gout); - gpgme_op_sign(ctx, gin, gout, GPGME_SIG_MODE_DETACH); + gerr = gpgme_op_sign(ctx, gin, gout, GPGME_SIG_MODE_DETACH); + if ( gerr != GPG_ERR_NO_ERROR ) + errx(EXIT_FAILURE, "signing failed: %s", gpgme_strerror(gerr)); + result = gpgme_op_sign_result(ctx); generate_boundary(boundary, sizeof(boundary)); fprintf(out, "Content-Type: multipart/signed;\r\n" " boundary=\"%s\";\r\n" " protocol=\"application/pgp-signature\";\r\n" - " micalg=pgp-sha1\r\n" + " micalg=%s\r\n" "\r\n" "--%s\r\n", - boundary, boundary); + boundary, + hash_algo_to_string(result->signatures->hash_algo), + boundary); fseek(in, 0, SEEK_SET); while ( (n = fread(buffer, 1, sizeof(buffer), in)) > 0 ) @@ -490,22 +524,24 @@ read_input_from_editor(void) int main(int argc, char *argv[]) { - char c; + char c, with_useragent, with_date; string_buffer_t *headers; fmail_ctx_t ctx; struct option options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'v' }, - { "sign", 0, NULL, 's' }, - { "attach", 1, NULL, 'a' }, - { "edit", 0, NULL, 'e' }, - { "footer", 1, NULL, 'f' }, - { "header", 1, NULL, 'H' }, - { "from", 1, NULL, 'F' }, - { "to", 1, NULL, 'T' }, - { "cc", 1, NULL, 'C' }, - { "subject", 1, NULL, 'S' }, + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'v' }, + { "sign", 0, NULL, 's' }, + { "attach", 1, NULL, 'a' }, + { "edit", 0, NULL, 'e' }, + { "footer", 1, NULL, 'f' }, + { "header", 1, NULL, 'H' }, + { "from", 1, NULL, 'F' }, + { "to", 1, NULL, 'T' }, + { "cc", 1, NULL, 'C' }, + { "subject", 1, NULL, 'S' }, + { "user-agent", 0, NULL, 'U' }, + { "date", 0, NULL, 'D' }, { NULL, 0, NULL, 0 } }; @@ -513,6 +549,8 @@ main(int argc, char *argv[]) setlocale(LC_ALL, ""); srand(time(NULL)); + with_useragent = with_date = 0; + headers = sb_new(0); ctx.signing_ctx = NULL; ctx.magic_ctx = initialize_magic(); @@ -537,7 +575,8 @@ main(int argc, char *argv[]) break; case 's': - ctx.signing_ctx = initialize_gpgme(); + if ( ! ctx.signing_ctx ) + ctx.signing_ctx = initialize_gpgme(); break; case 'a': @@ -573,12 +612,22 @@ main(int argc, char *argv[]) case 'S': sb_addf(headers, "Subject: %s\r\n", optarg); break; + + case 'U': + with_useragent = 1; + break; + + case 'D': + with_date = 1; + break; } } /* Generate automatic headers */ - sb_addf(headers, "Date: %s\r\n", rfc2822_date()); - sb_addf(headers, "User-Agent: fmail %s\r\n", VERSION); + if ( with_date ) + sb_addf(headers, "Date: %s\r\n", rfc2822_date()); + if ( with_useragent ) + sb_addf(headers, "User-Agent: fmail %s\r\n", VERSION); /* Fire editor instead of reading from stdin? */ if ( ! ctx.input )