/* Capability state 2. Check capabilities and choose login type. */ int imap_state_capability2(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->starttls) { if (!(data->capa & IMAP_CAPA_STARTTLS)) { log_warnx("%s: server doesn't support STARTTLS", a->name); return (FETCH_ERROR); } if (imap_putln(a, "%u STARTTLS", ++data->tag) != 0) return (FETCH_ERROR); fctx->state = imap_state_starttls; return (FETCH_BLOCK); } return (imap_pick_auth(a, fctx)); }
/* Search state 3. */ int imap_state_search3(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)); /* Save the total. */ data->total = ARRAY_LENGTH(&data->wanted); /* Update grand total. */ data->folders_total += data->total; /* If no mails, or polling, stop here. */ if (data->total == 0 || fctx->flags & FETCH_POLL) { if (imap_putln(a, "%u CLOSE", ++data->tag) != 0) return (FETCH_ERROR); fctx->state = imap_state_close; return (FETCH_BLOCK); } fctx->state = imap_state_next; return (FETCH_AGAIN); }
/* Search state 2. */ int imap_state_search2(struct account *a, struct fetch_ctx *fctx) { struct fetch_imap_data *data = a->data; char *line, *ptr; u_int uid; if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0) return (FETCH_ERROR); if (line == NULL) return (FETCH_BLOCK); /* Skip the header. */ if (strncasecmp(line, "* SEARCH", 8) != 0) return (imap_bad(a, line)); line += 8; /* Read each UID and save it. */ do { while (isspace((u_char) *line)) line++; ptr = strchr(line, ' '); if (ptr == NULL) ptr = strchr(line, '\0'); if (ptr == line) break; if (sscanf(line, "%u", &uid) != 1) return (imap_bad(a, line)); ARRAY_ADD(&data->wanted, uid); log_debug3("%s: fetching UID: %u", a->name, uid); line = ptr; } while (*line == ' '); fctx->state = imap_state_search3; return (FETCH_AGAIN); }
/* Expunge state. */ int imap_state_expunge(struct account *a, struct fetch_ctx *fctx) { 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)); fctx->state = imap_state_next; return (FETCH_AGAIN); }
/* Quit state. */ int imap_state_quit(struct account *a, struct fetch_ctx *fctx) { 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)); imap_abort(a); return (FETCH_EXIT); }
/* Wait for okay. */ int deliver_imap_waitokay(struct account *a, struct fetch_ctx *fctx, struct io *io, char **line) { do { if (deliver_imap_poll(a, io) != 0) return (1); if (imap_getln(a, fctx, IMAP_TAGGED, line) != 0) return (1); } while (*line == NULL); if (!imap_okay(*line)) { imap_bad(a, *line); return (1); } return (0); }
/* 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)); }
/* * Parse line based on type. Returns -1 on error, 0 on success, 1 to ignore * this line. */ int imap_parse(struct account *a, int type, char *line) { struct fetch_imap_data *data = a->data; int tag; if (type == IMAP_RAW) return (0); tag = imap_tag(line); switch (type) { case IMAP_TAGGED: if (tag == IMAP_TAG_NONE) return (1); if (tag == IMAP_TAG_CONTINUE) goto invalid; if (tag != data->tag) goto invalid; break; case IMAP_UNTAGGED: if (tag != IMAP_TAG_NONE) goto invalid; break; case IMAP_CONTINUE: if (tag == IMAP_TAG_NONE) return (1); if (tag != IMAP_TAG_CONTINUE) goto invalid; break; } return (0); invalid: imap_bad(a, line); return (-1); }
/* 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); }