tttm

git clone https://orangeshoelaces.net/git/tttm.git

7bcc5bd475e234561a3561b60eb9c0e773057a8f

Author: Vasily Kolobkov on 05/22/2016

Committer: Vasily Kolobkov on 05/22/2016

Refactor command handling in lieu of fetches cached to disk

Keep track of total number of messages in mailbox.

Stats

imap.c    | 183 +++++---
imap.h    |   3 +
parser.c  |   6 +-
parser.h  |   1 +
pshades.c |   1 +
5 files changed, 124 insertions(+), 70 deletions(-)

Patch

diff --git a/imap.c b/imap.c
index f78f684..8222e8e 100644
--- a/imap.c
+++ b/imap.c
@@ -1,3 +1,4 @@
+#include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <strings.h>
@@ -22,11 +23,22 @@ static struct capmap {
 	{ 0 },
 };
 
+static int imap_cmd(struct imapctx *, int, int, const char *, ...);
 static int imap_begreeted(struct imapctx *);
-static int imap_digcapdata(struct imapctx *, union parnode *);
-static int imap_digunsol(struct imapctx *);
+static int imap_parcaps(struct imapctx *, union parnode *);
 static int imap_readln(struct imapctx *);
-static int imap_pollres(struct imapctx *);
+
+/*
+   Dig functions pertain to be used within expressions hence
+   the call semantics - they return 1 on recognizing current
+   reply and 0 otherwise.
+*/
+static int dig_bye(struct imapctx *, int, int *);
+static int dig_caps(struct imapctx *, int, int *);
+static int dig_exists(struct imapctx *, int, int *);
+static int dig_res(struct imapctx *, int, int *);
+static int dig_unsol(struct imapctx *, int, int *);
+
 static int state2res(union parnode *);
 static int str2cap(struct capmap *, char *, size_t);
 static int isprod(union parnode *, int);
@@ -53,19 +65,12 @@ int
 imap_discocap(struct imapctx *con)
 {
 	int e;
-	union parnode *n;
 
+	e = 0;
 	if (dprintf(con->out, "%u CAPABILITY\r\n", con->tag++) < 0)
 		goto eout;
-
-	while (!(e = imap_readln(con))) {
-		if ((n = par_sel(con->par, IP_RESPDATA, IP_CAPDATA, -1))) {
-			e = imap_digcapdata(con, n);
-			break;
-		}
-		if ((e = imap_digunsol(con)))
-			goto exit;
-	}
+	while (!e && !(e = imap_readln(con)) && !dig_res(con, 1, &e))
+		dig_caps(con, 1, &e) || dig_unsol(con, 1, &e);
  exit:
 	return e;
  eout:
@@ -76,63 +81,73 @@ imap_discocap(struct imapctx *con)
 int
 imap_login(struct imapctx *con, const char *name, const char *pass)
 {
-	int e;
-	union parnode *s;
-
-	if (dprintf(con->out, "%u LOGIN %s %s\r\n", con->tag++, name, pass) < 0)
-		goto eout;
-	e = imap_pollres(con);
- exit:
-	return e;
- eout:
-	e = TE_OUT;
-	goto exit;
+	return imap_cmd(con, IS_AUTH, 0, "%u LOGIN %s %s\r\n",
+	    con->tag++, name, pass);
 }
 
 int
 imap_select(struct imapctx *con, const char *mb)
 {
-	int e;
+	int e, exists;
 
+	e = exists = 0;
 	if (dprintf(con->out, "%u SELECT %s\r\n", con->tag++, mb) < 0)
 		goto eout;
-	if (!(e = imap_pollres(con)))
+	while (!e && !(e = imap_readln(con)) && !dig_res(con, 1, &e)) {
+		if (dig_exists(con, 1, &e)) {
+			exists = 1;
+			continue;
+		}
+		dig_unsol(con, 1, &e);
+	}
+
+	if (!exists)
+		goto eproto;
+	if (!e)
 		con->state = IS_SEL;
  exit:
 	return e;
  eout:
 	e = TE_OUT;
 	goto exit;
+ eproto:
+	e = TE_PROTO;
+	goto exit;
 }
 
 int
 imap_close(struct imapctx *con)
 {
-	int e;
-
-	if (dprintf(con->out, "%u CLOSE\r\n", con->tag++) < 0)
-		goto eout;
-	if (!(e = imap_pollres(con)))
-		con->state = IS_AUTH;
- exit:
-	return e;
- eout:
-	e = TE_OUT;
-	goto exit;
+	return imap_cmd(con, IS_AUTH, 0, "%u CLOSE\r\n", con->tag++);
 }
 
 int
 imap_logout(struct imapctx *con)
+{
+	return imap_cmd(con, IS_LOGOUT, 1, "%u LOGOUT\r\n", con->tag++);
+}
+
+int
+imap_cmd(struct imapctx *con, int nstate, int ebye, const char *cmd, ...)
 {
 	int e;
+	va_list ap;
 
-	if (dprintf(con->out, "%u LOGOUT\r\n", con->tag++) < 0)
+	e = 0;
+	va_start(ap, cmd);
+	if (vdprintf(con->out, cmd, ap) < 0)
 		goto eout;
-	e = imap_pollres(con);
-	if (e != TE_BYE)
-		goto exit;
-	e = imap_pollres(con);
+	while (!e && !(e = imap_readln(con)) && !dig_res(con, 1, &e)) {
+		if (ebye && dig_bye(con, 1, &e)) {
+			e = 0;
+			continue;
+		}
+		dig_unsol(con, 1, &e);
+	}
+	if (!e)
+		con->state = nstate;
  exit:
+	va_end(ap);
 	return e;
  eout:
 	e = TE_OUT;
@@ -159,8 +174,7 @@ imap_begreeted(struct imapctx *con)
 	}
 
 	if ((n = par_seld(n, IP_RESPTXTCODE, IP_CAPDATA, -1)))
-		e = imap_digcapdata(con, n);
-
+		e = imap_parcaps(con, n);
  exit:
 	return e;
  eproto:
@@ -169,7 +183,7 @@ imap_begreeted(struct imapctx *con)
 }
 
 int
-imap_digcapdata(struct imapctx *con, union parnode *n)
+imap_parcaps(struct imapctx *con, union parnode *n)
 {
 	union parnode *nend, *atom;
 	char *str;
@@ -192,45 +206,76 @@ imap_digcapdata(struct imapctx *con, union parnode *n)
 }
 
 int
-imap_digunsol(struct imapctx *con)
+imap_readln(struct imapctx *con)
 {
-	return 0;
+	return par_readln(&con->in, con->rep, LEN(con->rep),
+	    -1, con->par, LEN(con->par));
 }
 
 int
-imap_readln(struct imapctx *con)
+dig_bye(struct imapctx *con, int buf, int *e)
 {
-	int e;
+	int accept;
 
-	e = par_readln(&con->in, con->rep, LEN(con->rep),
-	    -1, con->par, LEN(con->par));
-	if (!e && par_sel(con->par, IP_RESPDATA, IP_RESPBYE, -1)) {
+	if ((accept = par_sel(con->par, IP_RESPDATA, IP_RESPBYE, -1) != 0)) {
 		con->state = IS_LOGOUT;
-		e = TE_BYE;
+		*e = TE_BYE;
 	}
-	return e;
+	return accept;
 }
 
 int
-imap_pollres(struct imapctx *con)
+dig_caps(struct imapctx *con, int buf, int *e)
 {
-	int e;
+	int accept;
+	union parnode *c;
+
+	c = par_sel(con->par, IP_RESPDATA, IP_CAPDATA, -1);
+	if (!(accept = c != 0))
+		goto exit;
+	*e = buf ? imap_parcaps(con, c) : 0;
+ exit:
+	return accept;
+}
+
+int
+dig_exists(struct imapctx *con, int buf, int *e)
+{
+	int accept;
+	union parnode *exists;
+
+	exists = par_sel(con->par, IP_RESPDATA, IP_EXISTS, -1);
+	if (!(accept = exists != 0))
+		goto exit;
+	con->mb.exists = (exists + 1)->num.val;
+	*e = 0;
+ exit:
+	return accept;
+}
+
+int
+dig_res(struct imapctx *con, int buf, int *e)
+{
+	int accept;
 	union parnode *s, *c;
 
-	while (!(e = imap_readln(con))) {
-		if ((s = par_sel(con->par, IP_TAGGEDRESP, IP_RESPSTATE, -1))) {
-			if ((c = par_seld(s, IP_RESPTXTCODE, IP_CAPDATA, -1))) {
-				e = imap_digcapdata(con, c);
-			}
-			if (!e) {
-				e = state2res(s);
-			}
-			break;
-		}
-		if ((e = imap_digunsol(con)))
-			break;
+	s = par_sel(con->par, IP_TAGGEDRESP, IP_RESPSTATE, -1);
+	if (!(accept = s != 0))
+		goto exit;
+	if (buf && (c = par_seld(s, IP_RESPTXTCODE, IP_CAPDATA, -1))) {
+		*e = imap_parcaps(con, c);
 	}
-	return e;
+	if (!*e) {
+		*e = state2res(s);
+	}
+ exit:
+	return accept;
+}
+
+int
+dig_unsol(struct imapctx *con, int buf, int *e)
+{
+	return dig_exists(con, buf, e) || dig_bye(con, buf, e);
 }
 
 int
diff --git a/imap.h b/imap.h
index 0a69c29..0681f2a 100644
--- a/imap.h
+++ b/imap.h
@@ -12,6 +12,9 @@ struct imapctx {
 	union parnode par[1024];
 
 	int           caps;
+	struct {
+		uint32_t exists;
+	} mb;
 };
 
 int	imap_init(struct imapctx *, int, int);
diff --git a/parser.c b/parser.c
index 547e94f..08eaa53 100644
--- a/parser.c
+++ b/parser.c
@@ -1502,7 +1502,11 @@ p_mbdata(struct parctx *p)
 int
 p_mbexists(struct parctx *p)
 {
-	return p_r3xcombo(p, p_num, IL_SP, IL_EXISTS);
+	struct parcur b;
+
+	return p_beg(p, &b, IP_EXISTS) &&
+	    p_r3xcombo(p, p_num, IL_SP, IL_EXISTS) &&
+	    p_end(p, &b) || p_rwd(p, &b);
 }
 
 int
diff --git a/parser.h b/parser.h
index 9645553..36fb094 100644
--- a/parser.h
+++ b/parser.h
@@ -20,6 +20,7 @@ enum {
 	IP_CAP,
 	IP_CAPDATA,
 	IP_CONTREQ,
+	IP_EXISTS,
 	IP_RESPAUTH,
 	IP_RESPBYE,
 	IP_RESPDATA,
diff --git a/pshades.c b/pshades.c
index e3fabc1..e276748 100644
--- a/pshades.c
+++ b/pshades.c
@@ -16,6 +16,7 @@ char *prod[] = {
 	"CAP",
 	"CAPDATA",
 	"CONTREQ",
+	"EXISTS",
 	"RESPAUTH",
 	"RESPBYE",
 	"RESPDATA",