]> mj.ucw.cz Git - umpf.git/commitdiff
attempt to cope with big emails
authorAnicka Bernathova <anicka@anicka.net>
Fri, 17 Jul 2009 10:16:03 +0000 (12:16 +0200)
committerAnicka Bernathova <anicka@anicka.net>
Fri, 17 Jul 2009 10:16:03 +0000 (12:16 +0200)
ham.c
int.c
umpf.h

diff --git a/ham.c b/ham.c
index f06fdf3cca2ee88da1d84be33ece973ca45e75e1..4c74d937cd3305590ef64fb7e4e82dfa7b88bfee 100644 (file)
--- a/ham.c
+++ b/ham.c
@@ -5,6 +5,7 @@
 #include <unistd.h>
 
 #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 4133f3453e6ca3564178517060bd0e30a341d7df..7d5fa2e6ef7aaaf5a3c04197673e2aafd4c3c0a8 100644 (file)
--- a/int.c
+++ b/int.c
@@ -5,6 +5,7 @@
 #include <limits.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <stdarg.h>
 
 #include "cond.tab.h"
 #include "umpf.h"
 
 #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 080159ce8729fc9c87ea926106b2fe0e94d11556..2fd1a04aef2a0e43310e50e199f709500450c4cc 100644 (file)
--- 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;
 };