tttm

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

463b0f8dd4ec5a91f62aebe378b133a6774d64b8

Author: Vasily Kolobkov on 05/24/2016

Committer: Vasily Kolobkov on 05/24/2016

Get at ease running commands

Stats

imap.c    | 308 ++++----
laxsrc.c  |  20 +
laxsrc.h  |   1 +
laxsrc.o  | Bin 0 -> 2632 bytes
parser.c  |   4 +-
parser.h  |   3 +-
parser.o  | Bin 0 -> 33032 bytes
pshades.c |   2 +-
8 files changed, 203 insertions(+), 135 deletions(-)

Patch

diff --git a/imap.c b/imap.c
index 5f9d7c2..829d8a3 100644
--- a/imap.c
+++ b/imap.c
@@ -11,9 +11,9 @@
 #define LEN(x) (sizeof(x) / sizeof((x)[0]))
 
 static struct capmap {
-	int           cap;
-	char *        srep;
-	size_t        slen;
+	int    cap;
+	char  *srep;
+	size_t slen;
 } caps[] = {
 	{ CAP_IMAP4R1,    "IMAP4rev1",     9  },
 	{ CAP_NOLOGIN,    "LOGINDISABLED", 13 },
@@ -23,27 +23,58 @@ static struct capmap {
 	{ 0 },
 };
 
-static int imap_cmd(struct imapctx *, int, int, const char *, ...);
-static int imap_begreeted(struct imapctx *);
+struct respcard {
+	int    sel;
+	int  (*handler)(struct imapctx *, int, void *);
+	int    req:1;
+	int    met:1;
+	void  *ctx;
+};
+
+static int imap_cmd(struct imapctx *, int, const char *, struct respcard *,
+    struct respcard *, int, ...);
+static int imap_cooloff(struct imapctx *);
+static int imap_matchres(struct imapctx *, int, int *);
+static int imap_matchresp(struct imapctx *, struct respcard *, int, int, int *);
 static int imap_parcaps(struct imapctx *, union parnode *);
 static int imap_readln(struct imapctx *);
+static int imap_readlnc(struct imapctx *, int, int *);
+static int imap_recvgreets(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 dig_bye(struct imapctx *, int, void *);
+static int dig_uxbye(struct imapctx *, int, void *);
+static int dig_caps(struct imapctx *, int, void *);
+static int dig_exists(struct imapctx *, int, void *);
+static int dig_res(struct imapctx *, int, void *);
 
 static int state2res(union parnode *);
 static int str2cap(struct capmap *, char *, size_t);
 static int isprod(union parnode *, int);
 static int islit(union parnode *, int);
 
+static struct respcard freeresp[] = {
+	{ IP_RESPBYE, dig_uxbye },
+	{ -1 },
+};
+
+#define UNILAT_COMMON \
+	{ IP_EXISTS, dig_exists },\
+	{ IP_RESPBYE, dig_uxbye }
+
+static struct respcard unilat[] = {
+	UNILAT_COMMON,
+	{ -1 },
+};
+
+static struct respcard unisexp[] = {
+	UNILAT_COMMON,
+	{ -1 },
+};
+
+static struct respcard capresp[] = { { IP_CAPDATA, dig_caps, 1 }, { -1 } };
+static struct respcard selresp[] = { { IP_EXISTS, dig_exists, 1 }, { -1 } };
+static struct respcard byeresp[] = { { IP_RESPBYE, dig_bye, 1 }, { -1 } };
+
 int
 imap_init(struct imapctx *con, int in, int out)
 {
@@ -53,7 +84,7 @@ imap_init(struct imapctx *con, int in, int out)
 	con->state = IS_GREET;
 	laxsrc_init(&con->in, in);
 	con->out = out;
-	if ((e = imap_begreeted(con)))
+	if ((e = imap_recvgreets(con)))
 		goto exit;
 	if (!(con->caps & CAP_KNOWN))
 		e = imap_discocap(con);
@@ -64,123 +95,134 @@ imap_init(struct imapctx *con, int in, int out)
 int
 imap_discocap(struct imapctx *con)
 {
-	int e;
-
-	e = 0;
-	if (dprintf(con->out, "%u CAPABILITY\r\n", con->tag++) < 0)
-		goto eout;
-	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:
-	e = TE_OUT;
-	goto exit;
+	return imap_cmd(con, -1, "%u CAPABILITY\r\n", capresp, unilat,
+	    -1, con->tag++);
 }
 
 int
 imap_login(struct imapctx *con, const char *name, const char *pass)
 {
-	return imap_cmd(con, IS_AUTH, 0, "%u LOGIN %s %s\r\n",
-	    con->tag++, name, pass);
+	return imap_cmd(con, IS_AUTH, "%u LOGIN %s %s\r\n", 0, unilat,
+	    -1, con->tag++, name, pass);
 }
 
 int
 imap_select(struct imapctx *con, const char *mb)
 {
-	int e, exists;
-
-	e = exists = 0;
-	if (dprintf(con->out, "%u SELECT %s\r\n", con->tag++, mb) < 0)
-		goto eout;
-	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 (!e) {
-		if (!exists)
-			goto eproto;
-		con->state = IS_SEL;
-	}
- exit:
-	return e;
- eout:
-	e = TE_OUT;
-	goto exit;
- eproto:
-	e = TE_PROTO;
-	goto exit;
+	return imap_cmd(con, IS_SEL, "%u SELECT %s\r\n", selresp, unilat,
+	    -1, con->tag++, mb);
 }
 
 int
 imap_close(struct imapctx *con)
 {
-	return imap_cmd(con, IS_AUTH, 0, "%u CLOSE\r\n", con->tag++);
+	return imap_cmd(con, IS_AUTH, "%u CLOSE\r\n", 0, unilat,
+	    -1, con->tag++);
 }
 
 int
 imap_logout(struct imapctx *con)
 {
-	return imap_cmd(con, IS_LOGOUT, 1, "%u LOGOUT\r\n", con->tag++);
+	return imap_cmd(con, IS_LOGOUT, "%u LOGOUT\r\n", byeresp, unilat,
+	    -1, con->tag++);
 }
 
 int
-imap_cmd(struct imapctx *con, int nstate, int ebye, const char *cmd, ...)
+imap_cmd(struct imapctx *con, int nstate, const char *cmd,
+    struct respcard *cmdresp, struct respcard *unilat, int cache, ...)
 {
-	int e;
+	int e, b;
 	va_list ap;
+	union parnode *s;
+	struct respcard *c;
 
-	e = 0;
-	va_start(ap, cmd);
-	if (vdprintf(con->out, cmd, ap) < 0)
-		goto eout;
-	while (!e && !(e = imap_readln(con)) && !dig_res(con, 1, &e)) {
-		if (ebye && dig_bye(con, 1, &e)) {
-			e = 0;
-			continue;
+	va_start(ap, cache);
+	if ((e = imap_cooloff(con))) {
+		goto exit;
+	}
+	if (vdprintf(con->out, cmd, ap) < 0) {
+		goto exit;
+	}
+	for (c = cmdresp; c && c->sel != -1; c++) {
+		c->met = 0;
+	}
+	while (!(e = imap_readlnc(con, cache, &b))) {
+		if (imap_matchres(con, b, &e)) {
+			break;
+		}
+		if ((imap_matchresp(con, cmdresp, cache, b, &e) ||
+		    imap_matchresp(con, unilat, cache, b, &e)) && e) {
+			break;
 		}
-		dig_unsol(con, 1, &e);
 	}
-	if (!e)
+	if (e) {
+		goto exit;
+	}
+	for (c = cmdresp; c && c->sel != -1; c++) {
+		if (c->req && !c->met)
+			goto eproto;
+	}
+	if (nstate != -1) {
 		con->state = nstate;
+	}
+	e = imap_cooloff(con);
  exit:
 	va_end(ap);
 	return e;
- eout:
-	e = TE_OUT;
+ eproto:
+	e = TE_PROTO;
 	goto exit;
 }
 
 int
-imap_begreeted(struct imapctx *con)
+imap_cooloff(struct imapctx *con)
 {
 	int e;
-	union parnode *n;
 
-	if ((e = imap_readln(con))) {
-		con->state = IS_LOGOUT;
-		goto exit;
+	while (!(e = laxsrc_ishot(&con->in))) {
+		if ((e = imap_readln(con)))
+			goto exit;
+		if (imap_matchresp(con, freeresp, -1, 1, &e) && e)
+			goto exit;
 	}
-
-	if ((n = par_sel(con->par, IP_RESPDATA, IP_RESPAUTH, -1))) {
-		con->state = IS_AUTH;
-	} else if ((n = par_sel(con->par, IP_RESPDATA, IP_RESPSTATE, -1))) {
-		con->state = IS_NAUTH;
-	} else {
-		goto eproto;
+	if (e == TE_TIMEOUT) {
+		e = 0;
 	}
-
-	if ((n = par_seld(n, IP_RESPTXTCODE, IP_CAPDATA, -1)))
-		e = imap_parcaps(con, n);
  exit:
 	return e;
- eproto:
-	e = TE_PROTO;
-	goto exit;
+}
+
+int
+imap_matchres(struct imapctx *con, int buf, int *e)
+{
+	union parnode *s, *c;
+
+	if ((s = par_sel(con->par, IP_TAGGEDRESP, IP_RESPSTATE, -1))) {
+		c = par_seld(s, IP_RESPTXTCODE, IP_CAPDATA, -1);
+		if (buf && c) {
+			imap_parcaps(con, c);
+		}
+		*e = state2res(s);
+	}
+	return s != 0;
+}
+
+int
+imap_matchresp(struct imapctx *con, struct respcard *set, int cache,
+    int buf, int *e)
+{
+	int match;
+	struct respcard *c;
+
+	match = 0;
+	for (c = set; c && c->sel != -1; c++) {
+		if (par_sel(con->par, IP_RESPDATA, c->sel, -1)) {
+			c->met = match = 1;
+			*e = c->handler ? c->handler(con, buf, c->ctx) : 0;
+			break;
+		}
+	}
+	return match;
 }
 
 int
@@ -210,73 +252,75 @@ int
 imap_readln(struct imapctx *con)
 {
 	return par_readln(&con->in, con->rep, LEN(con->rep),
-	    -1, con->par, LEN(con->par));
+	    -1, 0, con->par, LEN(con->par));
 }
 
 int
-dig_bye(struct imapctx *con, int buf, int *e)
+imap_readlnc(struct imapctx *con, int cache, int *buf)
 {
-	int accept;
-
-	if ((accept = par_sel(con->par, IP_RESPDATA, IP_RESPBYE, -1) != 0)) {
-		con->state = IS_LOGOUT;
-		*e = TE_BYE;
-	}
-	return accept;
+	return par_readln(&con->in, con->rep, LEN(con->rep),
+	    cache, buf, con->par, LEN(con->par));
 }
 
 int
-dig_caps(struct imapctx *con, int buf, int *e)
+imap_recvgreets(struct imapctx *con)
 {
-	int accept;
-	union parnode *c;
+	int e;
+	union parnode *n;
 
-	c = par_sel(con->par, IP_RESPDATA, IP_CAPDATA, -1);
-	if (!(accept = c != 0))
+	if ((e = imap_readln(con))) {
+		con->state = IS_LOGOUT;
 		goto exit;
-	*e = buf ? imap_parcaps(con, c) : 0;
+	}
+
+	if ((n = par_sel(con->par, IP_RESPDATA, IP_RESPAUTH, -1))) {
+		con->state = IS_AUTH;
+	} else if ((n = par_sel(con->par, IP_RESPDATA, IP_RESPSTATE, -1))) {
+		con->state = IS_NAUTH;
+	} else {
+		goto eproto;
+	}
+
+	if ((n = par_seld(n, IP_RESPTXTCODE, IP_CAPDATA, -1)))
+		e = imap_parcaps(con, n);
  exit:
-	return accept;
+	return e;
+ eproto:
+	e = TE_PROTO;
+	goto exit;
 }
 
 int
-dig_exists(struct imapctx *con, int buf, int *e)
+dig_bye(struct imapctx *con, int buf, void *ctx)
 {
-	int accept;
-	union parnode *exists;
+	con->state = IS_LOGOUT;
+	return 0;
+}
 
-	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_uxbye(struct imapctx *con, int buf, void *ctx)
+{
+	con->state = IS_LOGOUT;
+	return TE_BYE;
 }
 
 int
-dig_res(struct imapctx *con, int buf, int *e)
+dig_caps(struct imapctx *con, int buf, void *ctx)
 {
-	int accept;
-	union parnode *s, *c;
+	union parnode *c;
 
-	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);
-	}
-	if (!*e) {
-		*e = state2res(s);
-	}
- exit:
-	return accept;
+	c = par_sel(con->par, IP_RESPDATA, IP_CAPDATA, -1);
+	return (c && buf) ? imap_parcaps(con, c) : 0;
 }
 
 int
-dig_unsol(struct imapctx *con, int buf, int *e)
+dig_exists(struct imapctx *con, int buf, void *ctx)
 {
-	return dig_exists(con, buf, e) || dig_bye(con, buf, e);
+	union parnode *ex;
+
+	ex = par_sel(con->par, IP_RESPDATA, IP_EXISTS, -1);
+	con->mb.exists = (ex + 1)->num.val;
+	return 0;
 }
 
 int
diff --git a/laxsrc.c b/laxsrc.c
index 8d75eef..c94feb3 100644
--- a/laxsrc.c
+++ b/laxsrc.c
@@ -19,6 +19,26 @@ laxsrc_init(struct laxsrc *s, int fd)
 	s->fd = fd;
 }
 
+int
+laxsrc_ishot(struct laxsrc *s)
+{
+	int e, ready;
+	struct pollfd pd;
+
+	e = 0;
+	if (s->buflen > 0)
+		goto exit;
+	pd.fd = s->fd;
+	pd.events = POLLIN | POLLHUP;
+	if ((ready = poll(&pd, 1, 0)) == -1) {
+		e = TE_IN;
+	} else if (ready == 0) {
+		e = TE_TIMEOUT;
+	}
+ exit:
+	return e;
+}
+
 int
 laxsrc_read(struct laxsrc *s, char *dst, size_t lo, size_t hi, int *e)
 {
diff --git a/laxsrc.h b/laxsrc.h
index b76eaac..51c829d 100644
--- a/laxsrc.h
+++ b/laxsrc.h
@@ -6,5 +6,6 @@ struct laxsrc {
 };
 
 void	laxsrc_init(struct laxsrc *, int);
+int	laxsrc_ishot(struct laxsrc *);
 int	laxsrc_read(struct laxsrc *, char *, size_t, size_t, int *);
 int	laxsrc_putback(struct laxsrc *, char *, size_t);
diff --git a/laxsrc.o b/laxsrc.o
new file mode 100644
index 0000000..48636ee
Binary files /dev/null and b/laxsrc.o differ
diff --git a/parser.c b/parser.c
index 08eaa53..97cab66 100644
--- a/parser.c
+++ b/parser.c
@@ -309,13 +309,15 @@ static int p_sp(struct parctx *);
 
 int
 par_readln(struct laxsrc *in, char *buf, size_t buflen, int cache,
-    union parnode *pt, size_t ptlen)
+    int *bufd, union parnode *pt, size_t ptlen)
 {
 	int e;
 	struct parctx p;
 
 	par_init(&p, in, buf, buflen, cache, pt, ptlen);
 	p_respln(&p);
+	if (bufd)
+		*bufd = p.strstor == SS_MEM;
 	e = par_free(&p);
 	return e ? e : p.e;
 }
diff --git a/parser.h b/parser.h
index 36fb094..d3d58b5 100644
--- a/parser.h
+++ b/parser.h
@@ -55,7 +55,8 @@ union parnode {
 
 struct laxsrc;
 
-int	par_readln(struct laxsrc *, char *, size_t, int, union parnode *, size_t);
+int	par_readln(struct laxsrc *, char *, size_t, int, int *,
+    union parnode *, size_t);
 union parnode *par_nn(union parnode *);
 union parnode *par_sel(union parnode *, ...);
 union parnode *par_seld(union parnode *, ...);
diff --git a/parser.o b/parser.o
new file mode 100644
index 0000000..1ac54a0
Binary files /dev/null and b/parser.o differ
diff --git a/pshades.c b/pshades.c
index e276748..cfb78a7 100644
--- a/pshades.c
+++ b/pshades.c
@@ -52,7 +52,7 @@ main(int argc, char **argv)
 	union parnode pt[1024];
 
 	laxsrc_init(&in, STDIN_FILENO);
-	if ((e = par_readln(&in, ln, LEN(ln), -1, pt, LEN(pt))))
+	if ((e = par_readln(&in, ln, LEN(ln), -1, 0, pt, LEN(pt))))
 		errx(1, "error parsing input: %s",  errmsgs[e]);
 
 	ptprint(pt, ln, 0);