further pop_mx_ng work
[apps/madmutt.git] / lib-mx / pop-new.c
index a46cc82..fcc17df 100644 (file)
@@ -33,17 +33,16 @@ enum pop_state {
     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 {
@@ -51,12 +50,10 @@ 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;
 
@@ -142,39 +139,17 @@ static __fini void pop_shutdown(void)
         __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 (;;) {
@@ -185,51 +160,84 @@ static int pop_check_capa(job_t *w, pop_data_t *pd)
         }
         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);
@@ -244,8 +252,10 @@ static int pop_on_event(job_t *w, el_event evt)
 
       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)
@@ -268,7 +278,6 @@ static void pop_finalize(job_t *w, el_status reason)
       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;