#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
+#include <time.h>
-#include "brum.h"
+#include <unistd.h>
-#define BUFSIZE 1024
+#include "umpf.h"
+#define MAIL_LEN 65536
int curbufsize;
-static char*
-buf_double(char* buf, int size)
-{
- buf = realloc(buf, 2*size);
-
- if (!buf)
- die("Low memory");
-
- return buf;
+char mbox_write_buf[BUFSIZE];
+int mbox_write_pos;
+int mbox_write_err;
-}
-
-static struct hlist*
-new_header(char* buf, struct hlist* end)
+void
+new_header(char* buf, struct list* h)
{
char* p;
struct hlist* new;
new = xmalloc(sizeof(struct hlist));
- if (end)
- end->next = new;
-
p = strchr(buf, ':');
-
if (!p)
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);
- new->next = NULL;
- return new;
+ 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 hlist*
-make_hlist(void)
+struct list*
+make_hlist(int fd)
{
- struct hlist* start = NULL, *end = NULL;
+ struct list* l = xmalloc(sizeof(struct list));
char* buf;
int i = 0; /* current position */
int c, last = 0;
+ int first_line = 1;
+ int want_from_line = 0;
+ list_init(l);
buf = xmalloc(BUFSIZE);
curbufsize = BUFSIZE;
- while ((c = getchar()) != EOF){
+ while ((c = give_me_char(fd)) != EOF){
if (c == '\r')
continue;
- if (i >= curbufsize-2){
- buf = buf_double(buf, curbufsize);
- curbufsize *= 2;
+ if (i >= curbufsize-3)
+ buf = xrealloc(buf, curbufsize *= 2);
+
+ if (first_line &&
+ ( (!i && c != 'F') || (i == 1 && c != 'r') || (i == 2 && c != 'o')
+ || (i == 3 && c != 'm') || (i == 4 && c != ' ') )
+ )
+ first_line = 0;
+ else {
+ if (first_line && i == 4)
+ want_from_line = 1;
}
- buf[i++] = c;
+ buf[i++] = c;
if (c == '\n'){
+ if (want_from_line) {
+ buf[i] = 0;
+ fromline = xstrdup(buf);
+ want_from_line = 0;
+ i = 0;
+ continue;
+ }
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;
- end = new_header(buf, end);
- if (!start)
- start = end;
+ new_header(buf, l);
i = 0;
} else
buf[i++] = c;
}
last = c;
}
- free(buf);
- return start;
+ free_string(buf);
+ return l;
+}
+
+struct email*
+get_body(int rfd)
+{
+ char* buf;
+ struct email* b;
+ int c, fd;
+ int will_save = 0;
+ int i = 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;
+
+ /* 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) {
+ 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 temporary file: %m");
+ }
+ break;
+ }
+ }
+ }
+ 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
-print_headers(struct hlist* h)
+print_headers(struct list* l)
+{
+ struct hlist* p;
+
+ LIST_FOREACH(p,l)
+ 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)
{
- struct hlist* p = h;
+ int res;
- while (p){
- printf("%s:%s",p->name,p->value);
- p = p->next;
+ 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)
+{
+ email_pos = 0;
+ headers_sent = 0;
+ email_opened = 1;
+}
+
+char*
+read_email(struct email* em)
{
- puts("--do action--");
- if (a->l)
- puts(a->l);
- printf("->");
- if (a->r)
- puts(a->r);
- putchar(' ');
- if (a->s)
- puts(a->s);
- puts("with email\n");
- print_headers(a->e.headers);
- puts("\n--Muhehehechlemst!--\n");
+ 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;
+ while (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, to_write;
+
+ open_email();
+ for (;;) {
+ buf = read_email(email);
+ if (!chars_written)
+ break;
+
+ to_write = chars_written;
+ while (to_write) {
+ wr = write(fd, buf, to_write);
+ to_write -= wr;
+ }
+ };
+
+ 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;
+ time_t t;
+ time(&t);
+ char* date = ctime(&t);
+ int datelen = strlen(date);
+
+ if (! fromline) {
+ len = 5 + datelen + 1;
+ fromline = xmalloc(len);
+ sprintf(fromline, "From %s", date);
+ len = strlen(fromline);
+ } else
+ 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;
}