+ 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;