/* Commit state. */ int imap_state_commit(struct account *a, struct fetch_ctx *fctx) { struct fetch_imap_data *data = a->data; char *line; if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0) return (FETCH_ERROR); if (line == NULL) return (FETCH_BLOCK); if (!imap_okay(line)) return (imap_bad(a, line)); data->committed++; fctx->state = imap_state_next; return (FETCH_AGAIN); }
/* Mail state. */ int imap_state_mail(struct account *a, struct fetch_ctx *fctx) { struct fetch_imap_data *data = a->data; char *line; if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0) return (FETCH_ERROR); if (line == NULL) return (FETCH_BLOCK); if (!imap_okay(line)) return (imap_bad(a, line)); if (data->capa & IMAP_CAPA_GMEXT) { fctx->state = imap_state_gmext_start; return (FETCH_AGAIN); } fctx->state = imap_state_next; return (FETCH_MAIL); }
/* STARTTLS state. */ int imap_state_starttls(struct account *a, struct fetch_ctx *fctx) { struct fetch_imap_data *data = a->data; char *line, *cause; if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0) return (FETCH_ERROR); if (line == NULL) return (FETCH_BLOCK); if (!imap_okay(line)) return (imap_bad(a, line)); data->io->ssl = makessl(&data->server, data->io->fd, conf.verify_certs && data->server.verify, conf.timeout, &cause); if (data->io->ssl == NULL) { log_warnx("%s: STARTTLS failed: %s", a->name, cause); xfree(cause); return (FETCH_ERROR); } return (imap_pick_auth(a, fctx)); }
/* Close state. */ int imap_state_close(struct account *a, struct fetch_ctx *fctx) { struct fetch_imap_data *data = a->data; char *line; if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0) return (FETCH_ERROR); if (line == NULL) return (FETCH_BLOCK); if (!imap_okay(line)) return (imap_bad(a, line)); data->folder++; if (data->folder != ARRAY_LENGTH(data->folders)) { fctx->state = imap_state_select1; return (FETCH_AGAIN); } if (imap_putln(a, "%u LOGOUT", ++data->tag) != 0) return (FETCH_ERROR); fctx->state = imap_state_quit; return (FETCH_BLOCK); }
/* Select state 4. Hold until select completes. */ int imap_state_select4(struct account *a, struct fetch_ctx *fctx) { struct fetch_imap_data *data = a->data; char *line; if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0) return (FETCH_ERROR); if (line == NULL) return (FETCH_BLOCK); if (!imap_okay(line)) return (imap_bad(a, line)); /* If no mails, stop early. */ if (data->total == 0) { if (imap_putln(a, "%u CLOSE", ++data->tag) != 0) return (FETCH_ERROR); fctx->state = imap_state_close; return (FETCH_BLOCK); } fctx->state = imap_state_search1; return (FETCH_AGAIN); }
int deliver_imap_deliver(struct deliver_ctx *dctx, struct actitem *ti) { struct account *a = dctx->account; struct mail *m = dctx->mail; struct deliver_imap_data *data = ti->data; struct io *io; struct fetch_ctx fctx; struct fetch_imap_data fdata; char *cause, *folder, *ptr, *line; size_t len, maillen; u_int total, body; /* Connect to the IMAP server. */ io = connectproxy(&data->server, conf.verify_certs, conf.proxy, IO_CRLF, conf.timeout, &cause); if (io == NULL) { log_warnx("%s: %s", a->name, cause); xfree(cause); return (DELIVER_FAILURE); } if (conf.debug > 3 && !conf.syslog) io->dup_fd = STDOUT_FILENO; /* Work out the folder name. */ folder = replacestr(&data->folder, m->tags, m, &m->rml); if (folder == NULL || *folder == '\0') { log_warnx("%s: empty folder", a->name); goto error; } /* Fake up the fetch context for the fetch code. */ memset(&fdata, 0, sizeof fdata); fdata.user = data->user; fdata.pass = data->pass; fdata.nocrammd5 = data->nocrammd5; fdata.nologin = data->nologin; memcpy(&fdata.server, &data->server, sizeof fdata.server); fdata.io = io; fdata.only = FETCH_ONLY_ALL; a->data = &fdata; fetch_imap_state_init(a, &fctx); fctx.state = imap_state_connected; fctx.llen = IO_LINESIZE; fctx.lbuf = xmalloc(fctx.llen); /* Use the fetch code until the select1 state is reached. */ if (deliver_imap_pollto(imap_state_select1, a, io, &fctx) != 0) goto error; retry: /* Send an append command. */ if (imap_putln(a, "%u APPEND {%zu}", ++fdata.tag, strlen(folder)) != 0) goto error; switch (deliver_imap_waitappend(a, &fctx, io, &line)) { case IMAP_TAG_ERROR: if (line != NULL) imap_invalid(a, line); goto error; case IMAP_TAG_CONTINUE: break; default: if (imap_no(line) && strstr(line, "[TRYCREATE]") != NULL) goto try_create; imap_invalid(a, line); goto error; } /* * Send the mail size, not forgetting lines are CRLF terminated. The * Google IMAP server is written strangely, so send the size as if * every CRLF was a CR if the server has XYZZY. */ count_lines(m, &total, &body); maillen = m->size + total - 1; if (fdata.capa & IMAP_CAPA_XYZZY) { log_debug2("%s: adjusting size: actual %zu", a->name, maillen); maillen = m->size; } if (fdata.capa & IMAP_CAPA_NOSPACE) { if (imap_putln(a, "%s{%zu}", folder, maillen) != 0) goto error; } else { if (imap_putln(a, "%s {%zu}", folder, maillen) != 0) goto error; } switch (deliver_imap_waitappend(a, &fctx, io, &line)) { case IMAP_TAG_ERROR: if (line != NULL) imap_invalid(a, line); goto error; case IMAP_TAG_CONTINUE: break; default: if (imap_no(line) && strstr(line, "[TRYCREATE]") != NULL) goto try_create; imap_invalid(a, line); goto error; } /* Send the mail data. */ line_init(m, &ptr, &len); while (ptr != NULL) { if (len > 1) io_write(io, ptr, len - 1); io_writeline(io, NULL); /* Update if necessary. */ if (io_update(io, conf.timeout, &cause) != 1) { log_warnx("%s: %s", a->name, cause); xfree(cause); goto error; } line_next(m, &ptr, &len); } /* Wait for an okay from the server. */ switch (deliver_imap_waitappend(a, &fctx, io, &line)) { case IMAP_TAG_ERROR: case IMAP_TAG_CONTINUE: if (line != NULL) imap_invalid(a, line); goto error; default: if (imap_okay(line)) break; if (strstr(line, "[TRYCREATE]") != NULL) goto try_create; imap_invalid(a, line); goto error; } xfree(fctx.lbuf); xfree(folder); if (imap_putln(a, "%u LOGOUT", ++fdata.tag) != 0) goto error; if (deliver_imap_waitokay(a, &fctx, io, &line) != 0) goto error; fdata.disconnect(a); return (DELIVER_SUCCESS); try_create: /* XXX function? */ /* Try to create the folder. */ if (imap_putln(a, "%u CREATE {%zu}", ++fdata.tag, strlen(folder)) != 0) goto error; if (deliver_imap_waitcontinue(a, &fctx, io, &line) != 0) goto error; if (imap_putln(a, "%s", folder) != 0) goto error; if (deliver_imap_waitokay(a, &fctx, io, &line) != 0) goto error; goto retry; error: io_writeline(io, "QUIT"); io_flush(io, conf.timeout, NULL); xfree(fctx.lbuf); if (folder != NULL) xfree(folder); fdata.disconnect(a); return (DELIVER_FAILURE); }