/* Body state. */ int imap_state_body(struct account *a, struct fetch_ctx *fctx) { struct fetch_imap_data *data = a->data; struct mail *m = fctx->mail; struct fetch_imap_mail *aux; char *line, *ptr; u_int n; if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0) return (FETCH_ERROR); if (line == NULL) return (FETCH_BLOCK); if (sscanf(line, "* %u FETCH (", &n) != 1) return (imap_invalid(a, line)); if ((ptr = strstr(line, "BODY[] {")) == NULL) return (imap_invalid(a, line)); if (sscanf(ptr, "BODY[] {%zu}", &data->size) != 1) return (imap_invalid(a, line)); data->lines = 0; /* Fill in local data. */ aux = xcalloc(1, sizeof *aux); aux->uid = ARRAY_FIRST(&data->wanted); m->auxdata = aux; m->auxfree = imap_free; ARRAY_REMOVE(&data->wanted, 0); /* Open the mail. */ if (mail_open(m, data->size) != 0) { log_warnx("%s: failed to create mail", a->name); return (FETCH_ERROR); } m->size = 0; /* Tag mail. */ default_tags(&m->tags, data->src); if (data->server.host != NULL) { add_tag(&m->tags, "server", "%s", data->server.host); add_tag(&m->tags, "port", "%s", data->server.port); } add_tag(&m->tags, "server_uid", "%u", aux->uid); add_tag(&m->tags, "folder", "%s", ARRAY_ITEM(data->folders, data->folder)); /* If we already know the mail is oversize, start off flushing it. */ data->flushing = data->size > conf.max_size; fctx->state = imap_state_line; return (FETCH_AGAIN); }
/* Fetch mail from stdin. */ int fetch_stdin_state_mail(struct account *a, struct fetch_ctx *fctx) { struct mail *m = fctx->mail; struct io *io; char *line, *cause; /* Open io for stdin. */ io = io_create(STDIN_FILENO, NULL, IO_LF); if (conf.debug > 3 && !conf.syslog) io->dup_fd = STDOUT_FILENO; /* Initialise the mail. */ if (mail_open(m, IO_BLOCKSIZE) != 0) { log_warn("%s: failed to create mail", a->name); goto error; } m->size = 0; /* Add default tags. */ default_tags(&m->tags, NULL); /* Loop reading the mail. */ for (;;) { /* * There can only be one mail on stdin so reentrancy is * irrelevent. This is a good thing since we want to check for * close which means end of mail. */ switch (io_pollline2(io, &line, &fctx->lbuf, &fctx->llen, conf.timeout, &cause)) { case 0: /* Normal close is fine. */ goto out; case -1: if (errno == EAGAIN) continue; log_warnx("%s: %s", a->name, cause); xfree(cause); goto error; } if (append_line(m, line, strlen(line)) != 0) { log_warn("%s: failed to resize mail", a->name); goto error; } if (m->size > conf.max_size) break; } out: if (io != NULL) io_free(io); fctx->state = fetch_stdin_state_exit; return (FETCH_MAIL); error: if (io != NULL) io_free(io); return (FETCH_ERROR); }
/* Mail state. Find and read mail file. */ int fetch_mbox_state_mail(struct account *a, struct fetch_ctx *fctx) { struct fetch_mbox_data *data = a->data; struct mail *m = fctx->mail; struct fetch_mbox_mbox *fmbox; struct fetch_mbox_mail *aux; char *line, *ptr, *lptr; size_t llen; int flushing; /* Find current mbox and check for EOF. */ fmbox = ARRAY_ITEM(&data->fmboxes, data->index); if (data->off == fmbox->size) { fctx->state = fetch_mbox_state_next; return (FETCH_AGAIN); } /* Open the mail. */ if (mail_open(m, IO_BLOCKSIZE) != 0) { log_warn("%s: failed to create mail", a->name); mail_destroy(m); return (FETCH_ERROR); } /* Create aux data. */ aux = xmalloc(sizeof *aux); aux->off = data->off; aux->size = 0; aux->fmbox = fmbox; if (++fmbox->reference == 0) fatalx("reference count overflow"); m->auxdata = aux; m->auxfree = fetch_mbox_free; /* Tag mail. */ default_tags(&m->tags, NULL); add_tag(&m->tags, "mbox", "%s", xbasename(fmbox->path)); add_tag(&m->tags, "mbox_path", "%s", xdirname(fmbox->path)); add_tag(&m->tags, "mbox_file", "%s", fmbox->path); /* * We start at a "From " line and include it in the mail (it can be * trimmed later with minimal penalty). */ flushing = 0; for (;;) { /* Check for EOF. */ if (data->off == fmbox->size) { aux->size = data->off - aux->off; break; } /* Locate the EOL. */ line = fmbox->base + data->off; ptr = memchr(line, '\n', fmbox->size - data->off); if (ptr == NULL) { ptr = fmbox->base + fmbox->size; data->off = fmbox->size; } else data->off += ptr - line + 1; /* Check if the line is "From ". */ if (line > fmbox->base && ptr - line >= 5 && strncmp(line, "From ", 5) == 0) { /* End of mail. */ aux->size = (line - fmbox->base) - aux->off; break; } /* Trim >s from From. */ if (*line == '>') { lptr = line; llen = ptr - line; while (*lptr == '>' && llen > 0) { lptr++; llen--; } if (llen >= 5 && strncmp(lptr, "From ", 5) == 0) line++; } if (flushing) continue; if (append_line(m, line, ptr - line) != 0) { log_warn("%s: failed to resize mail", a->name); mail_destroy(m); return (FETCH_ERROR); } if (m->size > conf.max_size) flushing = 1; } fmbox->total++; /* * Check if there was a blank line between the mails and remove it if * so. */ if (aux->size >= 2 && fmbox->base[aux->off + aux->size - 1] == '\n' && fmbox->base[aux->off + aux->size - 2] == '\n') { aux->size -= 2; m->size -= 2; } return (FETCH_MAIL); }