From 86856673ebee4258124c2ef19c7a0de1421f784d Mon Sep 17 00:00:00 2001 From: Anicka Bernathova Date: Fri, 17 Jul 2009 12:16:03 +0200 Subject: [PATCH] attempt to cope with big emails --- ham.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++-------- int.c | 52 +++++++++++++++++++++++--- umpf.h | 2 + 3 files changed, 145 insertions(+), 22 deletions(-) diff --git a/ham.c b/ham.c index f06fdf3..4c74d93 100644 --- a/ham.c +++ b/ham.c @@ -5,6 +5,7 @@ #include #include "umpf.h" +#define MAIL_LEN 65536 int curbufsize; @@ -69,7 +70,7 @@ make_hlist(void) } last = c; } - free(buf); + //free(buf); return l; } @@ -78,21 +79,80 @@ get_body(void) { char* buf; struct email* b; - int c; + int c, fd, cannot_save = 0; + int will_save = 0; int i = 0; - int curbufsize = BUFSIZE; + int j = 0; + int curbufsize = MAIL_LEN; + char* tmpfile; + int res; + + buf = xmalloc(MAIL_LEN); + b = xmalloc(sizeof(struct email)); + b->body = buf; + b->tmpfile = NULL; + b->fd = -1; - buf = xmalloc(BUFSIZE); + /* read mail body, if it is too big, try to make tmp file */ while ((c = getchar()) != EOF){ buf[i++] = c; - - if (i >= curbufsize - 1) - buf = xrealloc(buf, curbufsize *= 2); + if (i >= curbufsize - 1) { + if (cannot_save) { + buf = xrealloc(buf, curbufsize *= 2); + continue; + } + tmpfile = xstrdup("/tmp/umpf.XXXXXX"); + fd = mkstemp(tmpfile); + /* cannot create tmpfile, try to continue reading */ + if (fd < 0) { + buf = xrealloc(buf, curbufsize *= 2); + cannot_save = 1; + free(tmpfile); + continue; + } else { + will_save = 1; + b->body = NULL; + b->tmpfile = tmpfile; + b->fd = fd; + break; + } + } } - - b = xmalloc(sizeof(struct email)); - b->body = buf; b->body_len = i; + /* save rest of the body to the tmpfile */ + if (will_save) { + while ((c = getchar()) != EOF){ + buf[j++] = c; + b->body_len++; + if (j >= MAIL_LEN) { + j = 0; + res = write(fd, buf, MAIL_LEN); + if (res < MAIL_LEN) { + int missing = MAIL_LEN - res; + curbufsize = 2*b->body_len; + buf = xrealloc(buf, curbufsize); + // no point to check length here + read(fd, buf, b->body_len - missing); + unlink(b->tmpfile); + b->tmpfile = NULL; + b->fd = -1; + b->body = buf; + break; + } + } + } + /* could not write all the body to the tmpfile, try to read + the rest */ + if (b->body) { + while ((c = getchar()) != EOF){ + buf[j++] = c; + b->body_len++; + if (i >= curbufsize - 1) { + buf = xrealloc(buf, curbufsize *= 2); + } + } + } + } return b; } @@ -165,16 +225,37 @@ copy_email(int fd, struct email* email) write_char_to_mailbox('\n', fd); /* body */ /* FIXME: do not forget change Content-Length */ - for (pc = email->body; pc < email->body + email->body_len; pc++){ - write_char_to_mailbox(*pc, fd); - if (*pc == '\n'){ - if ((pc + 5 < email->body + email->body_len) + if (email->body) { + for (pc = email->body; pc < email->body + email->body_len; pc++){ + write_char_to_mailbox(*pc, fd); + if (*pc == '\n'){ + if ((pc + 5 < email->body + email->body_len) + && pc[1] == 'F' && pc[2] == 'r' + && pc[3] == 'o' && pc[4] == 'm' + && pc[5] == ' ') + write_char_to_mailbox('>', fd); + } + } + } else { + int i; + char buf[MAIL_LEN]; + for(i = 0; i < email->body_len; i+=MAIL_LEN) { + int len = MAIL_LEN; + if (i >= email->body_len) + len = len - (i - email->body_len); + read(email->fd, buf, len); //FIXME: check it? + for (pc = buf; pc < buf + len; pc++) { + write_char_to_mailbox(*pc, fd); + if (*pc == '\n'){ + if ((pc + 5 < email->body + email->body_len) && pc[1] == 'F' && pc[2] == 'r' && pc[3] == 'o' && pc[4] == 'm' && pc[5] == ' ') - write_char_to_mailbox('>', fd); + write_char_to_mailbox('>', fd); + } } - } + } + } flush_mbox_buffer(fd); diff --git a/int.c b/int.c index 4133f34..7d5fa2e 100644 --- a/int.c +++ b/int.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "cond.tab.h" #include "umpf.h" @@ -15,6 +16,23 @@ #define INT_TO_STRING_LEN ((sizeof(int)*4*CHAR_BIT)/10 + 6) +static void __attribute__ ((noreturn)) +bye(int code, char* msg, ...) +{ + va_list args; + + if (current_body->tmpfile) + unlink(current_body->tmpfile); + + if (msg) { + va_start(args, msg); + vfprintf(stderr, msg, args); + fputc('\n', stderr); + va_end(args); + } + exit(code); +} + static void clear_var(int var) { @@ -151,13 +169,29 @@ prepare_email(struct list* hash) modify_headers(current_headers, hash); em.headers = copy_headers(current_headers); - em.body_len = current_body->body_len; - em.body = xmalloc(em.body_len); - memcpy(em.body, current_body->body, em.body_len); + em.body_len = current_body->body_len; + em.fd = current_body->fd; + if (current_body->body) { + em.body = xmalloc(em.body_len); + memcpy(em.body, current_body->body, em.body_len); + em.tmpfile = NULL; + } else { + em.tmpfile = xstrdup(current_body->tmpfile); + em.body = NULL; + } return em; } +static void +destroy_email(struct email em) +{ + if (em.body) + free(em.body); + if(em.tmpfile) + free(em.tmpfile); +} + static void do_string_ternary_op(struct code* p) { @@ -261,8 +295,14 @@ deliver(char* where, int copy, struct list* hash) res = deliver_local_email(where, &em); - if (!copy) - exit(-res); + destroy_email(em); + + if (!copy) { + if (res) + bye(-res, "%m"); + else + bye(0, NULL); + } } void @@ -332,7 +372,7 @@ interp(struct list* ins, struct list* hash) case OPC_CALL_EXT: break; case OPC_DISCARD: - exit(0); + bye(0, NULL); break; }} deliver(default_mailbox, 0, hash); diff --git a/umpf.h b/umpf.h index 080159c..2fd1a04 100644 --- a/umpf.h +++ b/umpf.h @@ -194,6 +194,8 @@ struct hlist { struct email { struct list* headers; char* body; + char* tmpfile; + int fd; int body_len; }; -- 2.39.2