]> mj.ucw.cz Git - umpf.git/blobdiff - ham.c
allow comments behind #
[umpf.git] / ham.c
diff --git a/ham.c b/ham.c
index f8f96bd007fb7994af99b4d5fc2779fac2700f84..e54ec5e3b099d191a5bd30464f16f6b5ed03c2a5 100644 (file)
--- a/ham.c
+++ b/ham.c
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
+#include <time.h>
 
 #include <unistd.h>
 
@@ -14,7 +15,7 @@ char mbox_write_buf[BUFSIZE];
 int mbox_write_pos;
 int mbox_write_err;
 
-static void
+void
 new_header(char* buf, struct list* h)
 {
        char* p;
@@ -27,7 +28,10 @@ new_header(char* buf, struct list* h)
                new->value = xstrdup("");
        else {
                *p = 0;
-               new->value = xstrdup(p+1);
+               if (*(p + 1) == ' ')
+                       new->value = xstrdup(p + 2);
+               else
+                       new->value = xstrdup(p + 1);
                p = strrchr(new->value, '\n');
                if (p && !*(p+1))
                        *p = 0;
@@ -37,8 +41,61 @@ new_header(char* buf, struct list* h)
        list_add_last(h, &new->car);
 }
 
+int gmc_pos;
+char gmc_buf[BUFSIZE];
+int gmc_init;
+int gmc_read;
+int gmc_unget;
+
+static int
+give_me_char(int fd)
+{
+       if (! gmc_init) {
+               gmc_pos = 0;
+               gmc_read = read(fd, gmc_buf, BUFSIZE);
+               gmc_init = 1;
+               gmc_unget = EOF;
+               curr_email_len = 0;
+       }
+
+       if (gmc_unget != EOF) {
+               int a = gmc_unget;
+               gmc_unget = EOF;
+               curr_email_len++;
+               return a;
+       }
+
+       if (! gmc_read) {
+               gmc_init = 0;
+               return EOF;
+       }
+
+       if (gmc_pos < gmc_read) {
+               curr_email_len++;
+               return gmc_buf[gmc_pos++];
+       } else {
+               gmc_pos = 0;
+               gmc_read = read(fd, gmc_buf, BUFSIZE);
+               if (! gmc_read) {
+                       gmc_init = 0;
+                       return EOF;
+               }
+               else {
+                       curr_email_len++;
+                       return gmc_buf[gmc_pos++];
+               }
+       }
+}
+
+static void
+unget_me(int c)
+{
+       gmc_unget = c;
+       curr_email_len--;
+}
+
 struct list*
-make_hlist(void)
+make_hlist(int fd)
 {
        struct list* l = xmalloc(sizeof(struct list));
        char* buf;
@@ -49,7 +106,7 @@ make_hlist(void)
        buf = xmalloc(BUFSIZE);
        curbufsize = BUFSIZE;
        
-       while ((c = getchar()) != EOF){
+       while ((c = give_me_char(fd)) != EOF){
                if (c == '\r')
                        continue;
 
@@ -60,9 +117,9 @@ make_hlist(void)
                if (c == '\n'){
                        if (last == '\n')
                                break;
-                       if ((c = getchar()) != ' ' && c != '\t'){
+                       if ((c = give_me_char(fd)) != ' ' && c != '\t'){
                                if (c != EOF)
-                                       ungetc(c, stdin);
+                                       unget_me(c);
                                buf[i] = 0;
                                new_header(buf, l);
                                i = 0;
@@ -76,7 +133,7 @@ make_hlist(void)
 }
 
 struct email*
-get_body(void)
+get_body(int rfd)
 {
        char* buf;
        struct email* b;
@@ -94,14 +151,14 @@ get_body(void)
        b->fd = -1;
 
        /* read mail body, if it is too big, try to make tmp file */
-       while ((c = getchar()) != EOF){
+       while ((c = give_me_char(rfd)) != EOF){
                buf[i++] = c;
                if (i >= curbufsize - 1) {
                        tmpfile = xstrdup("/tmp/umpf.XXXXXX");
                        fd = mkstemp(tmpfile);
                        /* cannot create tmpfile, try to continue reading */
                        if (fd < 0)
-                               bye(EX_TEMPFAIL, "%m");
+                               bye(EX_TEMPFAIL, "Cannot create temporary file: %m");
                        else {
                                will_save = 1;
                                b->body = NULL;
@@ -110,7 +167,7 @@ get_body(void)
                                res = write(fd, buf, MAIL_LEN);
                                if (res < MAIL_LEN) {
                                        unlink(b->tmpfile);
-                                       bye(EX_TEMPFAIL, "%m");
+                                       bye(EX_TEMPFAIL, "Cannot write to remporary file: %m");
                                }
                                break;  
                        }
@@ -120,7 +177,7 @@ get_body(void)
        /* save rest of the body to the tmpfile */
        if (will_save) {
                int j = 0;
-               while ((c = getchar()) != EOF){
+               while ((c = give_me_char(rfd)) != EOF){
                        buf[j++] = c;
                        b->body_len++;
                        if (j >= MAIL_LEN) {
@@ -128,14 +185,14 @@ get_body(void)
                                res = write(fd, buf, MAIL_LEN);
                                if (res < MAIL_LEN) {
                                        unlink(b->tmpfile);
-                                       bye(EX_TEMPFAIL, "%m");
+                                       bye(EX_TEMPFAIL, "Cannot write to temporary file: %m");
                                }
                        }
                }
                res = write(fd, buf, j);
                if (res < j) {
                        unlink(b->tmpfile);
-                       bye(EX_TEMPFAIL, "%m");
+                       bye(EX_TEMPFAIL, "Cannot write to temporary file: %m");
                }
        }
        return b; 
@@ -178,6 +235,91 @@ write_char_to_mailbox(char c, int fd)
        mbox_write_buf[mbox_write_pos++] = c;
 }
 
+int email_pos;
+int headers_sent;
+int email_opened;
+
+void
+open_email(void)
+{
+       email_pos = 0;
+       headers_sent = 0;
+       email_opened = 1;
+}
+
+char*
+read_email(struct email* em)
+{
+       char* buf;
+       int r, pos;
+
+       if (! email_opened) {
+               chars_written = 0;      
+               return NULL;
+       }
+
+       if (! headers_sent) {
+               struct hlist* ph;
+               int curbufsize = BUFSIZE;
+               buf = xmalloc(BUFSIZE);
+               pos = 0;
+
+               LIST_FOREACH(ph, em->headers){
+                       int needed = strlen(ph->name) + strlen(ph->value) + 4;
+                       if (curbufsize < pos + needed)
+                               buf = xrealloc(buf, curbufsize*=2);
+                       strcpy(buf + pos, ph->name);
+                       pos += strlen(ph->name);
+                       buf[pos++] = ':';
+                       buf[pos++] = ' ';
+                       strcpy(buf + pos, ph->value);
+                       pos += strlen(ph->value);
+                       buf[pos++] = '\n';
+       
+               }
+               buf[pos++] = '\n';
+               headers_sent = 1;
+               chars_written = pos;
+               return buf;
+       }
+
+       if (em->body) {
+               buf = xstrdup(em->body);
+               chars_written = em->body_len; 
+               //printf("%d: %s\n", em->body_len, em->body); 
+               email_opened = 0;
+               return buf;
+       }
+
+       if (! email_pos)
+               lseek(em->fd, 0, SEEK_SET);
+
+       buf = xmalloc(MAIL_LEN + 1);
+       r = read(em->fd, buf, MAIL_LEN);
+       if (r < MAIL_LEN)
+               email_opened = 0;
+       chars_written = r;
+       
+       return buf;
+}
+
+int
+write_email_to_fd(int fd, struct email* email)
+{
+       char* buf;
+       int wr;
+
+       open_email();
+       do {
+               buf = read_email(email);
+               wr = write(fd, buf, chars_written);
+               if (wr < chars_written)
+                       return 1;
+       } while (chars_written);
+       
+       return 0;
+}
+
 /* try to copy e-mail to mailbox, if it fails,
  truncate mailbox to the original size */
 static int
@@ -193,21 +335,49 @@ copy_email(int fd, struct email* email)
        mbox_write_err = 0;
        mbox_write_pos = 0;
 
-       /* headers */
+       /* From line */
        struct hlist* ph;
+       int i, len;
+       char* fromline;
+       char* from = NULL;
+       time_t t;
+       time(&t);
+       char* date = ctime(&t);
+       int datelen = strlen(date);
+       
+       LIST_FOREACH(ph, email->headers) {
+               if (!strcasecmp(ph->name, "From")) {
+                       from = ph->value;
+                       break;
+               }
+       }
+       len = 5 + datelen + 1; 
+       if (from)
+               len += strlen(from);
+       fromline = xmalloc(len);
+       if (from)
+               sprintf(fromline, "From %s %s", from, date);
+       else
+               sprintf(fromline, "From %s", date);
+
+       len = strlen(fromline);
+       for (i = 0; i < len; i++)
+               write_char_to_mailbox(fromline[i], fd);
+
+       /* headers */
        char* pc;
        LIST_FOREACH(ph, email->headers){
                for (pc = ph->name; *pc; pc++)
                        write_char_to_mailbox(*pc, fd);
                write_char_to_mailbox(':', fd); 
+               write_char_to_mailbox(' ', fd); 
                for (pc = ph->value; *pc; pc++)
                        write_char_to_mailbox(*pc, fd); 
                        write_char_to_mailbox('\n', fd);        
        }
 
        write_char_to_mailbox('\n', fd);
-       /* body */
-       /* FIXME: do not forget change Content-Length */
        if (email->body) {
                for (pc = email->body; pc < email->body + email->body_len; pc++){
                                write_char_to_mailbox(*pc, fd);
@@ -252,51 +422,6 @@ copy_email(int fd, struct email* email)
        return 0; 
 }
 
-int
-write_email_to_fd(int fd, struct email* email)
-{
-       int written; 
-       
-       /* headers */
-       struct hlist* ph;
-       LIST_FOREACH(ph, email->headers){
-               written = write(fd, ph->name, strlen(ph->name));
-               if (written < (ssize_t) strlen(ph->name))
-                       return 1;
-               written = write(fd, ":", 1);
-               if (written < 1)
-                       return 1;
-               written = write(fd, ph->value, strlen(ph->value));
-               if (written < (ssize_t) strlen(ph->value))
-                       return 1;
-               written = write(fd, "\n", 1);
-               if (written < 1)
-                       return 1;
-       }
-       written = write(fd, "\n", 1);
-       if (written < 1)
-               return 1;
-
-       /* body */
-       if (email->body) {
-               written = write(fd, email->body, email->body_len);
-               if (written < email->body_len)
-                       return 1;
-       } else {
-               char buf[MAIL_LEN];
-               int i;
-               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?
-                       write(fd, buf, len);
-               }       
-       }
-
-       return 0;
-}
-
 int
 deliver_local_email(char* folder, struct email* email)
 {