POP_CONNECTING,
POP_CHECK_CAPA0,
POP_STLS,
- POP_CHECK_CAPA1,
POP_AUTHENTICATE,
- POP_CHECK_CAPA2,
+ POP_CHECK_CAPA1,
POP_STAT,
POP_READY,
};
typedef enum {
- CMD_UNKNOWN, /* unknown whether it is available or not */
CMD_NOT_AVAILABLE,
CMD_AVAILABLE,
+ CMD_UNKNOWN, /* unknown whether it is available or not */
} cmd_status;
typedef struct pop_data_t {
enum pop_state state;
unsigned multiline : 1;
- unsigned known_capa : 1;
+ unsigned capa_done : 1;
unsigned use_stls : 2;
cmd_status cmd_capa : 2; /* optional command CAPA */
cmd_status cmd_stls : 2; /* optional command STLS */
- cmd_status cmd_uidl : 2; /* optional command UIDL */
- cmd_status cmd_top : 2; /* optional command TOP */
cmd_status cmd_user : 2; /* optional command USER */
ACCOUNT act;
__eol + 1; \
})
-static int pop_read_banner(job_t *w, pop_data_t *pd)
+static int pop_parse_capa(job_t *w, pop_data_t *pd, const char *eol)
{
- const char *eol = POP_CHECK_EOL(w, pd);
- const char *p, *q;
-
- if (m_strncmp(pd->ibuf.data, "+OK", 3))
- return el_job_release(w, EL_ERROR);
-
- p = memchr(pd->ibuf.data, '<', eol - pd->ibuf.data);
- if (p && (q = memchr(p + 1, '>', eol - p - 1))) {
- pd->apop_token = p_dupstr(p, q + 1 - p);
- }
- buffer_consume_upto(&pd->ibuf, eol);
-
- /* TODO do not check capa again */
- pd->state = POP_CHECK_CAPA0;
- buffer_addstr(&pd->obuf, "CAPA\r\n");
- return el_job_setmode(w, EL_WRITING);
-}
-
-static int pop_check_capa(job_t *w, pop_data_t *pd)
-{
- const char *p = POP_CHECK_EOL(w, pd);
+ const char *p = pd->ibuf.data;
if (!pd->multiline) {
if (m_strncmp(pd->ibuf.data, "+OK", 3)) {
- pd->cmd_capa = CMD_NOT_AVAILABLE;
- pd->cmd_stls = CMD_NOT_AVAILABLE;
- goto end;
+ buffer_consume_upto(&pd->ibuf, eol);
+ return 1;
}
pd->multiline = true;
- } else {
- p = pd->ibuf.data;
+ p = eol;
}
for (;;) {
}
if (p[0] == '.' && p[1] != '.') {
buffer_consume_upto(&pd->ibuf, q);
- break;
+ return 1;
}
if (m_strcasestart(p, "SASL", &p)) {
p = skipspaces(p);
pd->auth_mechs = p_dupstr(p, q - p);
} else if (m_strcasestart(p, "STLS", NULL)) {
pd->cmd_stls = CMD_AVAILABLE;
- } else if (m_strcasestart(p, "UIDL", NULL)) {
- pd->cmd_uidl = CMD_AVAILABLE;
- } else if (m_strcasestart(p, "TOP", NULL)) {
- pd->cmd_top = CMD_AVAILABLE;
}
p = q;
}
+}
+
+static int pop_do_connect(job_t *w, pop_data_t *pd)
+{
+ const char *eol = POP_CHECK_EOL(w, pd);
+ const char *p, *q;
- end:
- pd->multiline = false;
switch (pd->state) {
+ case POP_CONNECTING:
+ if (m_strncmp(pd->ibuf.data, "+OK", 3))
+ return el_job_release(w, EL_ERROR);
+
+ p = memchr(pd->ibuf.data, '<', eol - pd->ibuf.data);
+ if (p && (q = memchr(p + 1, '>', eol - p - 1))) {
+ pd->apop_token = p_dupstr(p, q + 1 - p);
+ }
+ buffer_consume_upto(&pd->ibuf, eol);
+ if (pd->capa_done)
+ goto capa0_choice;
+ pd->state = POP_CHECK_CAPA0;
+ buffer_addstr(&pd->obuf, "CAPA\r\n");
+ return el_job_setmode(w, EL_WRITING);
+
case POP_CHECK_CAPA0:
- if (!pd->act.has_ssl && (pd->cmd_stls || mod_ssl.force_tls)) {
- buffer_addstr(&pd->obuf, "STLS\r\n");
- pd->state = POP_STLS;
- return el_job_setmode(w, EL_WRITING);
+ if (!pop_parse_capa(w, pd, eol))
+ return 0;
+
+ capa0_choice:
+ pd->multiline = false;
+ if (pd->act.has_ssl || (!pd->cmd_stls && !mod_ssl.force_tls))
+ goto do_authenticate;
+ pd->state = POP_STLS;
+ buffer_addstr(&pd->obuf, "STLS\r\n");
+ return el_job_setmode(w, EL_WRITING);
+
+ case POP_STLS:
+ if (m_strncmp(pd->ibuf.data, "+OK", 3)) {
+ pd->cmd_stls = CMD_NOT_AVAILABLE;
+ buffer_consume_upto(&pd->ibuf, eol);
+ goto do_authenticate;
}
- /* FALLTHROUGH */
- case POP_CHECK_CAPA1:
+ do_authenticate:
pd->state = POP_AUTHENTICATE;
- /* TODO */
- return -1;
+ return el_job_starttls(w);
- case POP_CHECK_CAPA2:
+ case POP_AUTHENTICATE:
+ abort();
+ pd->state = POP_CHECK_CAPA1;
+ buffer_addstr(&pd->obuf, "CAPA\r\n");
+ return el_job_setmode(w, EL_WRITING);
+
+ case POP_CHECK_CAPA1:
+ if (!pop_parse_capa(w, pd, eol))
+ return 0;
+ pd->capa_done = true;
pd->state = POP_STAT;
- return -1;
+ buffer_addstr(&pd->obuf, "STAT\r\n");
+ return el_job_setmode(w, EL_WRITING);
+
+ case POP_STAT:
+ pd->state = POP_READY;
+ return el_job_setmode(w, EL_IDLE);
default:
- return el_job_release(w, EL_ERROR);
+ abort();
}
}
-static int (*pop_actions[])(job_t *, pop_data_t *pd) = {
- [POP_CONNECTING] = pop_read_banner,
- [POP_CHECK_CAPA0] = pop_check_capa,
- NULL,
-};
-
static int pop_setup(job_t *w, void *cfg)
{
pop_data_t *pd = w->ptr = pop_data_dup(cfg);
case EL_EVT_IN:
EL_JOB_CHECK(el_job_read(w, &pd->ibuf));
- EL_JOB_CHECK(pop_actions[pd->state](w, pd));
- /* FALLTHROUGH */
+ if (pd->state <= POP_STAT)
+ return pop_do_connect(w, pd);
+ abort();
+
case EL_EVT_OUT:
EL_JOB_CHECK(el_job_write(w, &pd->obuf));
if (pd->obuf.len == 0)
case POP_STLS:
case POP_CHECK_CAPA1:
case POP_AUTHENTICATE:
- case POP_CHECK_CAPA2:
case POP_STAT:
mutt_error(_("Error connecting to server: %s"), pd->act.host);
break;