git clone https://orangeshoelaces.net/git/tttm.git
Author: Vasily Kolobkov on 05/24/2016
Committer: Vasily Kolobkov on 05/24/2016
Get at ease running commands
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(-)
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);