X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ham.c;h=e54ec5e3b099d191a5bd30464f16f6b5ed03c2a5;hb=6b3d60b53a72a491b6792e3bd08c7835297f8f7b;hp=16d7b36cc115ce8d7e271b06e8d60d13128e136a;hpb=eeee3addfa039494842a173322163e72ef1538a1;p=umpf.git diff --git a/ham.c b/ham.c index 16d7b36..e54ec5e 100644 --- a/ham.c +++ b/ham.c @@ -1,14 +1,21 @@ #include #include #include +#include +#include -#include "brum.h" +#include -#define BUFSIZE 1024 +#include "umpf.h" +#define MAIL_LEN 65536 int curbufsize; -static void +char mbox_write_buf[BUFSIZE]; +int mbox_write_pos; +int mbox_write_err; + +void new_header(char* buf, struct list* h) { char* p; @@ -21,15 +28,74 @@ 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; } new->name = xstrdup(buf); 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; @@ -40,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; @@ -51,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; @@ -62,29 +128,74 @@ make_hlist(void) } last = c; } - free(buf); + free_string(buf); return l; } -char* -get_body(void) +struct email* +get_body(int rfd) { char* buf; - int c; + struct email* b; + int c, fd; + int will_save = 0; int i = 0; - int curbufsize = BUFSIZE; + 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); - while ((c = getchar()) != EOF){ + /* read mail body, if it is too big, try to make tmp file */ + while ((c = give_me_char(rfd)) != EOF){ buf[i++] = c; - - if (i >= curbufsize - 1) - buf = xrealloc(buf, curbufsize *= 2); + 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, "Cannot create temporary file: %m"); + else { + will_save = 1; + b->body = NULL; + b->tmpfile = tmpfile; + b->fd = fd; + res = write(fd, buf, MAIL_LEN); + if (res < MAIL_LEN) { + unlink(b->tmpfile); + bye(EX_TEMPFAIL, "Cannot write to remporary file: %m"); + } + break; + } + } } - - buf[i] = 0; - - return buf; + b->body_len = i; + /* save rest of the body to the tmpfile */ + if (will_save) { + int j = 0; + while ((c = give_me_char(rfd)) != EOF){ + buf[j++] = c; + b->body_len++; + if (j >= MAIL_LEN) { + j = 0; + res = write(fd, buf, MAIL_LEN); + if (res < MAIL_LEN) { + unlink(b->tmpfile); + bye(EX_TEMPFAIL, "Cannot write to temporary file: %m"); + } + } + } + res = write(fd, buf, j); + if (res < j) { + unlink(b->tmpfile); + bye(EX_TEMPFAIL, "Cannot write to temporary file: %m"); + } + } + return b; } void @@ -93,18 +204,253 @@ print_headers(struct list* l) struct hlist* p; LIST_FOREACH(p,l) - printf("%s:%s",p->name,p->value); + printf("%s:%s\n",p->name,p->value); +} + +static void +flush_mbox_buffer(int fd) +{ + if (mbox_write_err || !mbox_write_pos) + return; + + int res; + res = write(fd, mbox_write_buf, mbox_write_pos); + if (res < 0) + mbox_write_err++; + mbox_write_pos = 0; } +static void +write_char_to_mailbox(char c, int fd) +{ + int res; + + if (mbox_write_pos >= BUFSIZE){ + res = write(fd, mbox_write_buf, BUFSIZE); + if (res < 0) + mbox_write_err++; + mbox_write_pos = 0; + return; + } + mbox_write_buf[mbox_write_pos++] = c; +} + +int email_pos; +int headers_sent; +int email_opened; + void -do_action(struct action* a) +open_email(void) { - //just deliver e-mail, do not look at left side now -/* if (! a->r ){ + email_pos = 0; + headers_sent = 0; + email_opened = 1; +} - } else if (!strcmp(a->r,"pipe")){ - 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 +copy_email(int fd, struct email* email) +{ + off_t mb_end; + + mb_end = lseek(fd, 0, SEEK_END); + if (mb_end < 0) + return -1; + + /* init globals */ + mbox_write_err = 0; + mbox_write_pos = 0; + + /* 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); + 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); + } + } + } + } + + flush_mbox_buffer(fd); + + /* errors? */ + if (mbox_write_err){ + /* try to truncate to the original length */ + ftruncate(fd, mb_end); + return -1; } -*/ + return 0; +} + +int +deliver_local_email(char* folder, struct email* email) +{ + int res = -1; + int is_default_mailbox = 0; + int fd; + + if (!strcmp(default_mailbox, folder)) + is_default_mailbox = 1; + + fd = open_mailbox(folder, is_default_mailbox); + if (fd < 0){ + if (is_default_mailbox) + return res; + else /* try to save to default mailbox instead */ + return deliver_local_email(default_mailbox, email); + } + + res = copy_email(fd, email); + if (res < 0){ + + /* try to deliver to the default mailbox */ + if (is_default_mailbox) + return res; + else + return deliver_local_email(default_mailbox, email); + } + + close_mailbox(fd, folder, is_default_mailbox); + + return res; }