|
|
@ -24,10 +24,12 @@ |
|
|
|
#include <stdlib.h> |
|
|
|
#include <getopt.h> |
|
|
|
#include <locale.h> |
|
|
|
#include <string.h> |
|
|
|
#include <ctype.h> |
|
|
|
#include <time.h> |
|
|
|
|
|
|
|
#include <gpgme.h> |
|
|
|
#include <magic.h> |
|
|
|
|
|
|
|
#include <sbuffer.h> |
|
|
|
#include <xmem.h> |
|
|
@ -80,16 +82,17 @@ See the COPYING file or <http://www.gnu.org/licenses/gpl.html>.\n\ |
|
|
|
|
|
|
|
/* Helper functions. */ |
|
|
|
|
|
|
|
const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
|
|
"abcdefghijklmnopqrstuvwxyz" |
|
|
|
"0123456789+/"; |
|
|
|
|
|
|
|
static char * |
|
|
|
generate_boundary(char *buffer, size_t len) |
|
|
|
{ |
|
|
|
static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
|
|
"abcdefghijklmnopqrstuvwxyz" |
|
|
|
"0123456789+/"; |
|
|
|
int i; |
|
|
|
|
|
|
|
for ( i = 0; i < len - 1; i++ ) |
|
|
|
buffer[i] = chars[rand() % (sizeof(chars) - 1)]; |
|
|
|
buffer[i] = base64_chars[rand() % (sizeof(base64_chars) - 1)]; |
|
|
|
buffer[i] = '\0'; |
|
|
|
|
|
|
|
return buffer; |
|
|
@ -143,6 +146,35 @@ qp_encode_stream(FILE *in, FILE *out) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
base64_encode_stream(FILE *in, FILE *out) |
|
|
|
{ |
|
|
|
unsigned char buffer[3]; |
|
|
|
int n, j; |
|
|
|
|
|
|
|
j = 0; |
|
|
|
while ( (n = fread(buffer, 1, 3, in)) > 0 ) { |
|
|
|
char quartet[4]; |
|
|
|
|
|
|
|
if ( n < 3 ) |
|
|
|
buffer[2] = 0; |
|
|
|
if ( n < 2 ) |
|
|
|
buffer[1] = 0; |
|
|
|
|
|
|
|
quartet[0] = base64_chars[buffer[0] >> 2]; |
|
|
|
quartet[1] = base64_chars[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xf0) >> 4)]; |
|
|
|
quartet[2] = (unsigned char) (n > 1 ? base64_chars[((buffer[1] & 0x0f) << 2) | ((buffer[2] & 0x0c) >> 6)] : '=' ); |
|
|
|
quartet[3] = (unsigned char) (n > 2 ? base64_chars[buffer[2] & 0x3f] : '='); |
|
|
|
|
|
|
|
j += 1; |
|
|
|
fwrite(quartet, 1, 4, out); |
|
|
|
if ( j == 16 ) { |
|
|
|
fprintf(out, "\r\n"); |
|
|
|
j = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static char * |
|
|
|
rfc2822_date(void) |
|
|
|
{ |
|
|
@ -269,6 +301,49 @@ sign_stream(gpgme_ctx_t ctx, FILE *in, FILE *out) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Attachments stuff. */ |
|
|
|
|
|
|
|
static magic_t |
|
|
|
initialize_magic(void) |
|
|
|
{ |
|
|
|
magic_t ctx; |
|
|
|
|
|
|
|
if ( ! (ctx = magic_open(MAGIC_SYMLINK | MAGIC_MIME)) ) |
|
|
|
err(EXIT_FAILURE, "cannot obtain libmagic cookie"); |
|
|
|
|
|
|
|
if ( magic_load(ctx, NULL) == -1 ) |
|
|
|
err(EXIT_FAILURE, "cannot load default magic database"); |
|
|
|
|
|
|
|
return ctx; |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
process_attachment(const char *filename, magic_t ctx, FILE *out) |
|
|
|
{ |
|
|
|
const char *mime, *last_eq; |
|
|
|
int binary; |
|
|
|
FILE *f; |
|
|
|
|
|
|
|
mime = magic_file(ctx, filename); |
|
|
|
last_eq = strrchr(mime, '='); |
|
|
|
binary = strcmp(last_eq, "=binary") ? 0 : 1; |
|
|
|
|
|
|
|
fprintf(out, "Content-Type: %s\r\n", mime); |
|
|
|
fprintf(out, "Content-Transfer-Encoding: %s\r\n", binary ? "base64" : "quoted-printable"); |
|
|
|
fprintf(out, "Content-Disposition: attachment; filename=%s\r\n\r\n", filename); |
|
|
|
|
|
|
|
f = fopen(filename, "r"); |
|
|
|
if ( binary ) |
|
|
|
base64_encode_stream(f, out); |
|
|
|
else |
|
|
|
qp_encode_stream(f, out); |
|
|
|
fclose(f); |
|
|
|
|
|
|
|
fprintf(out, "\r\n"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Main function. */ |
|
|
|
|
|
|
|
int |
|
|
@ -277,6 +352,7 @@ main(int argc, char *argv[]) |
|
|
|
char c, **attachments; |
|
|
|
string_buffer_t *headers; |
|
|
|
gpgme_ctx_t sign_ctx; |
|
|
|
magic_t mgc_ctx; |
|
|
|
int att_count; |
|
|
|
|
|
|
|
struct option options[] = { |
|
|
@ -293,6 +369,7 @@ main(int argc, char *argv[]) |
|
|
|
|
|
|
|
headers = sb_new(0); |
|
|
|
sign_ctx = NULL; |
|
|
|
mgc_ctx = initialize_magic(); |
|
|
|
attachments = NULL; |
|
|
|
att_count = 0; |
|
|
|
|
|
|
@ -349,5 +426,7 @@ main(int argc, char *argv[]) |
|
|
|
if ( attachments ) |
|
|
|
free(attachments); |
|
|
|
|
|
|
|
magic_close(mgc_ctx); |
|
|
|
|
|
|
|
return EXIT_SUCCESS; |
|
|
|
} |