tttm

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

/parser.c

   1 /*
   2    Be warned! p_* functions bear unconventional call semantics
   3    returning 1 on success and 0 otherwise. Specific error code
   4    is dispensed to the parse context.
   5 */
   6 
   7 #include <errno.h>
   8 #include <poll.h>
   9 #include <stdarg.h>
  10 #include <stdint.h>
  11 #include <stdlib.h>
  12 #include <string.h>
  13 #include <strings.h>
  14 #include <unistd.h>
  15 #include <sys/mman.h>
  16 #include <sys/stat.h>
  17 
  18 #include "errors.h"
  19 #include "parser.h"
  20 
  21 #define LEN(x) (sizeof(x) / sizeof((x)[0]))
  22 #define MAX(a, b) ((a) >= (b) ? (a) : (b))
  23 #define MIN(a, b) ((a) <= (b) ? (a) : (b))
  24 
  25 #define ASCII_CTL \
  26         "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
  27         "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
  28 
  29 static int timeout = 2 * 60 * 1000;
  30 static size_t minstrcap = 1 << 13;
  31 
  32 static struct literal {
  33         char  *srep;
  34         size_t slen;
  35 } literals[] = {
  36         [IL_7BIT]               = { "7BIT",              4  },
  37         [IL_8BIT]               = { "8BIT",              4  },
  38         [IL_ALERT]              = { "ALERT",             5  },
  39         [IL_APP]                = { "APPLICATION",       11 },
  40         [IL_APR]                = { "Apr",               3  },
  41         [IL_ASTERISK]           = { "*",                 1  },
  42         [IL_AUDIO]              = { "AUDIO",             5  },
  43         [IL_AUG]                = { "Aug",               3  },
  44         [IL_AUTHEQ]             = { "AUTH=",             5  },
  45         [IL_B64]                = { "BASE64",            6  },
  46         [IL_BAD]                = { "BAD",               3  },
  47         [IL_BADCS]              = { "BADCHARSET",        10 },
  48         [IL_BIN]                = { "BINARY",            6  },
  49         [IL_BODY]               = { "BODY",              4  },
  50         [IL_BSLASH]             = { "\\",                1  },
  51         [IL_BYE]                = { "BYE",               3  },
  52         [IL_CAP]                = { "CAPABILITY",        10 },
  53         [IL_CBRACE]             = { "}",                 1  },
  54         [IL_CBRACK]             = { "]",                 1  },
  55         [IL_COLON]              = { ":",                 1  },
  56         [IL_CPAR]               = { ")",                 1  },
  57         [IL_DEC]                = { "Dec",               3  },
  58         [IL_DHDR]               = { ".HEADER",           7  },
  59         [IL_DNOT]               = { ".NOT",              4  },
  60         [IL_DOT]                = { ".",                 1  },
  61         [IL_DQUOTE]             = { "\"",                1  },
  62         [IL_DTXT]               = { ".TEXT",             5  },
  63         [IL_ENVELOPE]           = { "ENVELOPE",          8  },
  64         [IL_EOL]                = { "\r\n",              2  },
  65         [IL_EXISTS]             = { "EXISTS",            6  },
  66         [IL_EXPUNGE]            = { "EXPUNGE",           7  },
  67         [IL_FEB]                = { "Feb",               3  },
  68         [IL_FETCH]              = { "FETCH",             5  },
  69         [IL_FLAGS]              = { "FLAGS",             5  },
  70         [IL_FLANSWERED]         = { "\\Answered",        9  },
  71         [IL_FLANY]              = { "\\*",               2  },
  72         [IL_FLDELETED]          = { "\\Deleted",         8  },
  73         [IL_FLDRAFT]            = { "\\Draft",           6  },
  74         [IL_FLFLAGGED]          = { "\\Flagged",         8  },
  75         [IL_FLMARKED]           = { "\\Marked",          7  },
  76         [IL_FLNOINFERIORS]      = { "\\Noinferiors",     12 },
  77         [IL_FLNOSEL]            = { "\\Noselect",        9  },
  78         [IL_FLRECENT]           = { "\\Recent",          7  },
  79         [IL_FLSEEN]             = { "\\Seen",            5  },
  80         [IL_FLUNMARKED]         = { "\\Unmarked",        9  },
  81         [IL_GT]                 = { ">",                 1  },
  82         [IL_HDR]                = { "HEADER",            6  },
  83         [IL_HDRFIELDS]          = { "HEADER.FIELDS",     13 },
  84         [IL_IMG]                = { "IMAGE",             5  },
  85         [IL_INBOX]              = { "INBOX",             5  },
  86         [IL_INTDATE]            = { "INTERNALDATE",      12 },
  87         [IL_JAN]                = { "Jan",               3  },
  88         [IL_JUL]                = { "Jul",               3  },
  89         [IL_JUN]                = { "Jun",               3  },
  90         [IL_LIST]               = { "LIST",              4  },
  91         [IL_LSUB]               = { "LSUB",              4  },
  92         [IL_LT]                 = { "<",                 1  },
  93         [IL_MAR]                = { "Mar",               3  },
  94         [IL_MAY]                = { "May",               3  },
  95         [IL_MIME]               = { "MIME",              4  },
  96         [IL_MINUS]              = { "-",                 1  },
  97         [IL_MSG]                = { "MESSAGE",           7  },
  98         [IL_MSGS]               = { "MESSAGES",          8  },
  99         [IL_NIL]                = { "NIL",               3  },
 100         [IL_NO]                 = { "NO",                2  },
 101         [IL_NOV]                = { "Nov",               3  },
 102         [IL_OBRACE]             = { "{",                 1  },
 103         [IL_OBRACK]             = { "[",                 1  },
 104         [IL_OCT]                = { "Oct",               3  },
 105         [IL_OK]                 = { "OK",                2  },
 106         [IL_OPAR]               = { "(",                 1  },
 107         [IL_PARSE]              = { "PARSE",             5  },
 108         [IL_PERMFL]             = { "PERMANENTFLAGS",    14 },
 109         [IL_PLUS]               = { "+",                 1  },
 110         [IL_PREAUTH]            = { "PREAUTH",           7  },
 111         [IL_QPRN]               = { "QUOTED-PRINTABLE",  16 },
 112         [IL_RECENT]             = { "RECENT",            6  },
 113         [IL_RFC822]             = { "RFC822",            6  },
 114         [IL_RFC822SIZE]         = { "RFC822.SIZE",       11 },
 115         [IL_RO]                 = { "READ-ONLY",         9  },
 116         [IL_RW]                 = { "READ-WRITE",        10 },
 117         [IL_SEARCH]             = { "SEARCH",            6  },
 118         [IL_SEP]                = { "Sep",               3  },
 119         [IL_SP]                 = { " ",                 1  },
 120         [IL_STATUS]             = { "STATUS",            6  },
 121         [IL_STRUCT]             = { "STRUCTURE",         9  },
 122         [IL_TRYC]               = { "TRYCREATE",         9  },
 123         [IL_TXT]                = { "TEXT",              4  },
 124         [IL_UID]                = { "UID",               3  },
 125         [IL_UIDNEXT]            = { "UIDNEXT",           7  },
 126         [IL_UIDVAL]             = { "UIDVALIDITY",       11 },
 127         [IL_UNSEEN]             = { "UNSEEN",            6  },
 128         [IL_VIDEO]              = { "VIDEO",             5  },
 129 };
 130 
 131 static const char astr_specials[] = ASCII_CTL " \"%()*\\{\x7f";
 132 
 133 static const char atom_specials[] = ASCII_CTL " \"%()*\\]{\x7f";
 134 
 135 static const char tag_specials[] = ASCII_CTL " \"%()*+\\{\x7f";
 136 
 137 struct parcur {
 138         size_t         off;
 139         union parnode *pt;
 140 };
 141 
 142 struct parctx {
 143         int            e;
 144         int            src;
 145         char          *str;
 146         size_t         strcap;
 147         size_t         strlen;
 148         size_t         stroff;
 149         struct parcur  cur;
 150         union parnode *pt;
 151         union parnode *ptend;
 152         size_t         ptlen;
 153 };
 154 
 155 typedef int parfn(struct parctx *);
 156 
 157 static union parnode * par_vseld(union parnode *, va_list);
 158 static int cmpchr(const void *, const void *);
 159 static int contains(const char *, size_t, char);
 160 
 161 static void par_init(struct parctx *, int,
 162     char *, size_t, size_t, size_t, union parnode *, size_t);
 163 static int par_fillstr(struct parctx *, size_t);
 164 
 165 static int p_chk(struct parctx *, struct parcur *);
 166 static int p_insint(struct parctx *, int, size_t);
 167 static int p_inslit(struct parctx *, int);
 168 static int p_insnum(struct parctx *, uint32_t);
 169 static int p_insstr(struct parctx *, int, size_t, uint32_t);
 170 static int p_beg(struct parctx *, struct parcur *, int);
 171 static int p_end(struct parctx *, struct parcur *);
 172 static int p_rwd(struct parctx *, struct parcur *);
 173 static int p_opt(struct parctx *);
 174 static int p_list(struct parctx *, parfn *);
 175 static int p_listsep(struct parctx *, parfn *, int);
 176 static int p_rep(struct parctx *, parfn *);
 177 static int p_repchr(struct parctx *, const char *, size_t, int);
 178 static int p_2xcombo(struct parctx *, int, parfn *);
 179 static int p_3xcombo(struct parctx *, int, int, parfn *);
 180 static int p_r3xcombo(struct parctx *, parfn *, int, int);
 181 static int p_sss(struct parctx *);
 182 
 183 static int p_addr(struct parctx *);
 184 static int p_astr(struct parctx *);
 185 static int p_atom(struct parctx *);
 186 static int p_authtype(struct parctx *);
 187 static int p_badcscode(struct parctx *);
 188 static int p_badcsopt(struct parctx *);
 189 static int p_base64(struct parctx *);
 190 static int p_body(struct parctx *);
 191 static int p_body1pt(struct parctx *);
 192 static int p_bodybas(struct parctx *);
 193 static int p_bodyext(struct parctx *);
 194 static int p_bodyf(struct parctx *);
 195 static int p_bodyfdes(struct parctx *);
 196 static int p_bodyfdsp(struct parctx *);
 197 static int p_bodyfenc(struct parctx *);
 198 static int p_bodyfid(struct parctx *);
 199 static int p_bodyflan(struct parctx *);
 200 static int p_bodyflin(struct parctx *);
 201 static int p_bodyfloc(struct parctx *);
 202 static int p_bodyfmd5(struct parctx *);
 203 static int p_bodyfoct(struct parctx *);
 204 static int p_bodyfpar(struct parctx *);
 205 static int p_bodympt(struct parctx *);
 206 static int p_bodymsg(struct parctx *);
 207 static int p_bodytxt(struct parctx *);
 208 static int p_bodyx1pt(struct parctx *);
 209 static int p_bodyxcmn(struct parctx *);
 210 static int p_bodyxmpt(struct parctx *);
 211 static int p_cap(struct parctx *);
 212 static int p_capdata(struct parctx *);
 213 static int p_contreq(struct parctx *);
 214 static int p_datetime(struct parctx *);
 215 static int p_dayfix(struct parctx *);
 216 static int p_dig(struct parctx *, size_t);
 217 static int p_dquotedchar(struct parctx *);
 218 static int p_env(struct parctx *);
 219 static int p_envaddr(struct parctx *);
 220 static int p_expunge(struct parctx *);
 221 static int p_fetch(struct parctx *);
 222 static int p_flag(struct parctx *);
 223 static int p_flext(struct parctx *);
 224 static int p_flfetch(struct parctx *);
 225 static int p_flkeyword(struct parctx *);
 226 static int p_gencode(struct parctx *);
 227 static int p_genctext(struct parctx *);
 228 static int p_hdrfname(struct parctx *);
 229 static int p_hdrlist(struct parctx *);
 230 static int p_lit(struct parctx *, int);
 231 static int p_lstr(struct parctx *);
 232 static int p_mailbox(struct parctx *);
 233 static int p_mat822body(struct parctx *);
 234 static int p_matbody(struct parctx *);
 235 static int p_matbsect(struct parctx *);
 236 static int p_matenv(struct parctx *);
 237 static int p_mathdrotxt(struct parctx *);
 238 static int p_matintdate(struct parctx *);
 239 static int p_matsize(struct parctx *);
 240 static int p_matuid(struct parctx *);
 241 static int p_mbdata(struct parctx *);
 242 static int p_mbexists(struct parctx *);
 243 static int p_mbflags(struct parctx *);
 244 static int p_mblist(struct parctx *);
 245 static int p_mblistdata(struct parctx *);
 246 static int p_mblistfl(struct parctx *);
 247 static int p_mblistofl(struct parctx *);
 248 static int p_mblistosfl(struct parctx *);
 249 static int p_mblistsfl(struct parctx *);
 250 static int p_mblsub(struct parctx *);
 251 static int p_mbrecent(struct parctx *);
 252 static int p_mbsearch(struct parctx *);
 253 static int p_mbstatus(struct parctx *);
 254 static int p_medbas(struct parctx *);
 255 static int p_medmsg(struct parctx *);
 256 static int p_medsubt(struct parctx *);
 257 static int p_medtxt(struct parctx *);
 258 static int p_month(struct parctx *);
 259 static int p_msgdata(struct parctx *);
 260 static int p_msgatt(struct parctx *);
 261 static int p_msgattdyn(struct parctx *);
 262 static int p_msgattstat(struct parctx *);
 263 static int p_nstr(struct parctx *);
 264 static int p_num(struct parctx *);
 265 static int p_nznum(struct parctx *);
 266 static int p_permfl(struct parctx *);
 267 static int p_permflcode(struct parctx *);
 268 static int p_qchar(struct parctx *);
 269 static int p_qchars(struct parctx *);
 270 static int p_qstr(struct parctx *);
 271 static int p_respauth(struct parctx *);
 272 static int p_respbye(struct parctx *);
 273 static int p_respdata(struct parctx *);
 274 static int p_respln(struct parctx *);
 275 static int p_respstate(struct parctx *);
 276 static int p_resptext(struct parctx *);
 277 static int p_resptextcode(struct parctx *);
 278 static int p_secmsgtxt(struct parctx *);
 279 static int p_secpt(struct parctx *);
 280 static int p_secspec(struct parctx *);
 281 static int p_section(struct parctx *);
 282 static int p_sectxt(struct parctx *);
 283 static int p_statt(struct parctx *);
 284 static int p_stattrec(struct parctx *);
 285 static int p_str(struct parctx *);
 286 static int p_tag(struct parctx *);
 287 static int p_taggedresp(struct parctx *);
 288 static int p_text(struct parctx *);
 289 static int p_time(struct parctx *);
 290 static int p_uid(struct parctx *);
 291 static int p_uidncode(struct parctx *);
 292 static int p_uidvcode(struct parctx *);
 293 static int p_unseencode(struct parctx *);
 294 static int p_year(struct parctx *);
 295 static int p_zone(struct parctx *);
 296 
 297 static int p_cpar(struct parctx *);
 298 static int p_dquote(struct parctx *);
 299 static int p_opar(struct parctx *);
 300 static int p_sp(struct parctx *);
 301 
 302 int
 303 par_parseln(int src, char **str, size_t *strcap, size_t *strlen, size_t *stroff,
 304     union parnode *pt, size_t ptlen)
 305 {
 306         struct parctx p;
 307 
 308         par_init(&p, src, *str, *strcap, *strlen, *stroff, pt, ptlen);
 309         p_respln(&p);
 310         *str = p.str;
 311         *strcap = p.strcap;
 312         *strlen = p.strlen;
 313         *stroff = p.cur.off;
 314         return p.e;
 315 }
 316 
 317 union parnode *
 318 par_nn(union parnode *n)
 319 {
 320         if (n->type == PN_INTER)
 321             n += n->inter.len;
 322 
 323         return n + 1;
 324 }
 325 
 326 union parnode *
 327 par_sel(union parnode *n, ...)
 328 {
 329         int prod;
 330         va_list ap;
 331 
 332         va_start(ap, n);
 333         prod = va_arg(ap, int);
 334         if (prod != -1 && n->type == PN_INTER && n->inter.prod == prod) {
 335                 n = par_vseld(n, ap);
 336         } else {
 337                 n = 0;
 338         }
 339         va_end(ap);
 340         return n;
 341 }
 342 
 343 union parnode *
 344 par_seld(union parnode *n, ...)
 345 {
 346         va_list ap;
 347 
 348         va_start(ap, n);
 349         n = par_vseld(n, ap);
 350         va_end(ap);
 351         return n;
 352 }
 353 
 354 union parnode *
 355 par_vseld(union parnode *n, va_list ap)
 356 {
 357         int prod;
 358         union parnode *end;
 359 
 360         if (n->type == PN_INTER) {
 361                 end = n + n->inter.len + 1;
 362         } else {
 363                 n = 0;
 364                 goto exit;
 365         }
 366 
 367         while ((prod = va_arg(ap, int)) != -1) {
 368                 for (n++; n < end; n = par_nn(n)) {
 369                         if (n->type == PN_INTER && n->inter.prod == prod)
 370                                 break;
 371                 }
 372                 if (n == end) {
 373                         n = 0;
 374                         break;
 375                 }
 376         }
 377  exit:
 378         return n;
 379 }
 380 
 381 int
 382 cmpchr(const void *a, const void *b)
 383 {
 384         return *(char *)a - *(char *)b;
 385 }
 386 
 387 int
 388 contains(const char *s, size_t slen, char c)
 389 {
 390         return bsearch(&c, s, slen, sizeof(char), cmpchr) != 0;
 391 }
 392 
 393 void
 394 par_init(struct parctx *p, int src, char *str, size_t strcap, size_t strlen,
 395     size_t stroff, union parnode *pt, size_t ptlen)
 396 {
 397         bzero(p, sizeof(*p));
 398         p->src = src;
 399         p->str = str;
 400         p->strcap = strcap;
 401         p->strlen = strlen;
 402         p->stroff = stroff;
 403         p->cur.off = stroff;
 404         p->cur.pt = pt;
 405         p->pt = pt;
 406         p->ptend = pt + ptlen;
 407         p->ptlen = ptlen;
 408 }
 409 
 410 int
 411 par_fillstr(struct parctx *p, size_t len)
 412 {
 413         char *newstr;
 414         struct pollfd pd;
 415         int ready;
 416         ssize_t n;
 417 
 418         if (len <= p->strlen) {
 419                 p->e = TE_OK;
 420                 goto exit;
 421         }
 422         if (len > p->strcap) {
 423                 p->strcap = MAX(minstrcap, p->strcap);
 424                 do {
 425                         p->strcap *= 2;
 426                 } while (len > p->strcap);
 427                 newstr = realloc(p->str, p->strcap);
 428                 if (newstr == 0) {
 429                         goto emem;
 430                 }
 431                 p->str = newstr;
 432         }
 433 
 434         pd.fd = p->src;
 435         pd.events = POLLIN | POLLHUP;
 436 
 437         while (len > p->strlen) {
 438                 ready = poll(&pd, 1, timeout);
 439 
 440                 if (ready == -1) goto ein;
 441                 if (ready == 0) goto eto;
 442 
 443                 if (pd.revents & (POLLIN | POLLHUP)) {
 444                         n = read(pd.fd, p->str + p->strlen, p->strcap - p->strlen);
 445                         if (n == 0) {
 446                                 goto eof;
 447                         } else if (n == -1) {
 448                                 if (errno == EINTR || errno == EAGAIN)
 449                                         continue;
 450                                 else goto ein;
 451                         }
 452                         p->strlen += n;
 453                 }
 454         }
 455 
 456  exit:
 457         return p->e;
 458  emem:
 459         p->e = TE_NOMEM;
 460         goto exit;
 461  ein:
 462         p->e = TE_IN;
 463         goto exit;
 464  eto:
 465         p->e = TE_TIMEOUT;
 466         goto exit;
 467  eof:
 468         p->e = TE_EOF;
 469         goto exit;
 470 }
 471 
 472 /*
 473   Combinators and misc meta critters
 474 */
 475 
 476 int
 477 p_chk(struct parctx *p, struct parcur *cp)
 478 {
 479         *cp = p->cur;
 480         return p->e <= TE_PARSE;
 481 }
 482 
 483 int
 484 p_insint(struct parctx *p, int prod, size_t len)
 485 {
 486         union parnode *cur;
 487 
 488         cur = p->cur.pt;
 489         if (cur == p->ptend) {
 490                 p->e = TE_PTOFLOW;
 491                 return 0;
 492         }
 493         cur->inter.type = PN_INTER;
 494         cur->inter.prod = prod;
 495         cur->inter.len = len;
 496         p->cur.pt++;
 497         return 1;
 498 }
 499 
 500 int
 501 p_inslit(struct parctx *p, int val)
 502 {
 503         union parnode *cur;
 504 
 505         cur = p->cur.pt;
 506         if (cur == p->ptend) {
 507                 p->e = TE_PTOFLOW;
 508                 return 0;
 509         }
 510         cur->lit.type = PN_LIT;
 511         cur->lit.val = val;
 512         p->cur.pt++;
 513         return 1;
 514 }
 515 
 516 int
 517 p_insnum(struct parctx *p, uint32_t val)
 518 {
 519         union parnode *cur;
 520 
 521         cur = p->cur.pt;
 522         if (cur == p->ptend) {
 523                 p->e = TE_PTOFLOW;
 524                 return 0;
 525         }
 526         cur->lit.type = PN_NUM;
 527         cur->lit.val = val;
 528         p->cur.pt++;
 529         return 1;
 530 }
 531 
 532 int
 533 p_insstr(struct parctx *p, int type, size_t off, uint32_t len)
 534 {
 535         union parnode *cur;
 536 
 537         cur = p->cur.pt;
 538         if (cur == p->ptend) {
 539                 p->e = TE_PTOFLOW;
 540                 return 0;
 541         }
 542         cur->str.type = type;
 543         cur->str.off = off;
 544         cur->str.len = len;
 545         p->cur.pt++;
 546         return 1;
 547 }
 548 
 549 int
 550 p_beg(struct parctx *p, struct parcur *beg, int prod)
 551 {
 552         return p_chk(p, beg) && p_insint(p, prod, 0);
 553 }
 554 
 555 int
 556 p_end(struct parctx *p, struct parcur *beg)
 557 {
 558         beg->pt->inter.len = p->cur.pt - beg->pt - 1;
 559         return 1;
 560 }
 561 
 562 int
 563 p_rwd(struct parctx *p, struct parcur *cp)
 564 {
 565         p->cur = *cp;
 566         if (!p->e)
 567                 p->e = TE_PARSE;
 568         return 0;
 569 }
 570 
 571 int
 572 p_opt(struct parctx *p)
 573 {
 574         if (p->e == TE_PARSE)
 575                 p->e = TE_OK;
 576         return !p->e;
 577 }
 578 
 579 /* prod *(SP prod) */
 580 int
 581 p_list(struct parctx *p, parfn *prod)
 582 {
 583         int res;
 584 
 585         res = (p->e <= TE_PARSE) && prod(p);
 586         while (res && p_2xcombo(p, IL_SP, prod))
 587                 ;
 588         return res && p_opt(p);
 589 }
 590 
 591 int
 592 p_listsep(struct parctx *p, parfn *prod, int sep)
 593 {
 594         int res;
 595 
 596         res = (p->e <= TE_PARSE) && prod(p);
 597         while (res && p_2xcombo(p, sep, prod))
 598                 ;
 599         return res && p_opt(p);
 600 }
 601 
 602 /* 1*prod */
 603 int
 604 p_rep(struct parctx *p, parfn *prod)
 605 {
 606         int res;
 607 
 608         res = (p->e <= TE_PARSE) && prod(p);
 609         while (res && prod(p))
 610                 ;
 611         return res && p_opt(p);
 612 }
 613 
 614 /* 1*<any char but those in `except'> */
 615 int
 616 p_repchr(struct parctx *p, const char *except, size_t elen, int strtype)
 617 {
 618         size_t pr;
 619         char *prp;
 620         size_t len;
 621 
 622         if (p->e > TE_PARSE)
 623                 goto exit;
 624 
 625         p->e = TE_OK;
 626         pr = p->cur.off;
 627 
 628         while (par_fillstr(p, pr + 1) == TE_OK) {
 629                 for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
 630                         if (contains(except, elen, *prp))
 631                                 goto stop;
 632                 }
 633         }
 634  stop:
 635         len = pr - p->cur.off;
 636         if (p->e == TE_EOF && len)
 637                 p->e = TE_OK;
 638 
 639         if (p->e) goto exit;
 640         if (!len) goto eparse;
 641         if (len > UINT32_MAX) goto exl;
 642         if (!p_insstr(p, strtype, p->cur.off, len)) goto exit;
 643 
 644         p->cur.off = pr;
 645  exit:
 646         return p->e == TE_OK;
 647  eparse:
 648         p->e = TE_PARSE;
 649         goto exit;
 650  exl:
 651         p->e = TE_XLSTR;
 652         goto exit;
 653 }
 654 
 655 int
 656 p_2xcombo(struct parctx *p, int lit, parfn *prod)
 657 {
 658         struct parcur b;
 659 
 660         return p_chk(p, &b) && p_lit(p, lit) && prod(p) || p_rwd(p, &b);
 661 }
 662 
 663 int
 664 p_3xcombo(struct parctx *p, int lit1, int lit2, parfn *prod)
 665 {
 666         struct parcur b;
 667 
 668         return p_chk(p, &b) && p_lit(p, lit1) &&
 669             p_lit(p, lit2) && prod(p) || p_rwd(p, &b);
 670 }
 671 
 672 int
 673 p_r3xcombo(struct parctx *p, parfn *prod, int lit1, int lit2)
 674 {
 675         struct parcur b;
 676 
 677         return p_chk(p, &b) && prod(p) && p_lit(p, lit1) &&
 678             p_lit(p, lit2) || p_rwd(p, &b);
 679 }
 680 
 681 int
 682 p_sss(struct parctx *p)
 683 {
 684         struct parcur b;
 685 
 686         return p_chk(p, &b) && p_str(p) && p_sp(p) && p_str(p) ||
 687             p_rwd(p, &b);
 688 }
 689 
 690 /*
 691   IMAP parsers
 692 */
 693 
 694 int
 695 p_addr(struct parctx *p)
 696 {
 697         struct parcur b;
 698 
 699         return p_chk(p, &b) && p_opar(p) && p_nstr(p) && p_sp(p) &&
 700             p_nstr(p) && p_sp(p) && p_nstr(p) && p_sp(p) &&
 701             p_nstr(p) && p_cpar(p) || p_rwd(p, &b);
 702 }
 703 
 704 int
 705 p_astr(struct parctx *p)
 706 {
 707         struct parcur b;
 708 
 709         return p_chk(p, &b) &&
 710             (p_repchr(p, astr_specials, LEN(astr_specials), PN_STR) ||
 711             p_str(p)) || p_rwd(p, &b);
 712 }
 713 
 714 int
 715 p_atom(struct parctx *p)
 716 {
 717         struct parcur b;
 718 
 719         return p_beg(p, &b, IP_ATOM) &&
 720             p_repchr(p, atom_specials, LEN(atom_specials), PN_STR) &&
 721             p_end(p, &b) || p_rwd(p, &b);
 722 }
 723 
 724 int
 725 p_authtype(struct parctx *p)
 726 {
 727         return p_atom(p);
 728 }
 729 
 730 int
 731 p_badcscode(struct parctx *p)
 732 {
 733         struct parcur b;
 734 
 735         return p_chk(p, &b) && p_lit(p, IL_BADCS) &&
 736             (p_badcsopt(p) || p_opt(p)) || p_rwd(p, &b);
 737 }
 738 
 739 int
 740 p_badcsopt(struct parctx *p)
 741 {
 742         struct parcur b;
 743 
 744         return p_chk(p, &b) && p_sp(p) && p_opar(p) &&
 745             p_list(p, p_astr) && p_cpar(p) || p_rwd(p, &b);
 746 }
 747 
 748 int
 749 p_base64(struct parctx *p)
 750 {
 751         /* brush 6 bit encoding off yet */
 752         if (!p->e)
 753                 p->e = TE_PARSE;
 754         return 0;
 755 }
 756 
 757 int
 758 p_body(struct parctx *p)
 759 {
 760         struct parcur b;
 761 
 762         return p_chk(p, &b) && p_opar(p) && (p_body1pt(p) ||
 763             p_bodympt(p)) && p_cpar(p) || p_rwd(p, &b);
 764 }
 765 
 766 int
 767 p_body1pt(struct parctx *p)
 768 {
 769         struct parcur b, o;
 770 
 771         return p_chk(p, &b) &&
 772             (p_bodybas(p) || p_bodymsg(p) || p_bodytxt(p)) &&
 773             (p_chk(p, &o) && p_sp(p) && p_bodyx1pt(p) ||
 774             p_rwd(p, &o) || p_opt(p)) || p_rwd(p, &b);
 775 }
 776 
 777 int
 778 p_bodybas(struct parctx *p)
 779 {
 780         struct parcur b;
 781 
 782         return p_chk(p, &b) && p_medbas(p) && p_sp(p) &&
 783             p_bodyf(p) || p_rwd(p, &b);
 784 }
 785 
 786 int
 787 p_bodyext(struct parctx *p)
 788 {
 789         struct parcur b;
 790 
 791         return p_chk(p, &b) && p_nstr(p) || p_num(p) ||
 792             (p_opar(p) && p_list(p, p_bodyext) && p_cpar(p)) ||
 793             p_rwd(p, &b);
 794 }
 795 
 796 int
 797 p_bodyf(struct parctx *p)
 798 {
 799         struct parcur b;
 800 
 801         return p_chk(p, &b) && p_bodyfpar(p) && p_sp(p) &&
 802             p_bodyfid(p) && p_sp(p) && p_bodyfdes(p) && p_sp(p) &&
 803             p_bodyfenc(p) && p_sp(p) && p_bodyfoct(p) || p_rwd(p, &b);
 804 }
 805 
 806 int
 807 p_bodyfdes(struct parctx *p)
 808 {
 809         return p_nstr(p);
 810 }
 811 
 812 int
 813 p_bodyfdsp(struct parctx *p)
 814 {
 815         struct parcur b;
 816 
 817         return p_chk(p, &b) && (p_opar(p) && p_str(p) && p_sp(p) &&
 818             p_bodyfpar(p) && p_cpar(p) || p_rwd(p, &b)) || p_lit(p, IL_NIL);
 819 }
 820 
 821 int
 822 p_bodyfenc(struct parctx *p)
 823 {
 824         struct parcur b;
 825 
 826         return p_chk(p, &b) && (p_dquote(p) && (p_lit(p, IL_7BIT) ||
 827             p_lit(p, IL_8BIT) || p_lit(p, IL_BIN) || p_lit(p, IL_B64) ||
 828             p_lit(p, IL_QPRN)) && p_dquote(p) || p_rwd(p, &b)) ||
 829             p_str(p);
 830 }
 831 
 832 int
 833 p_bodyfid(struct parctx *p)
 834 {
 835         return p_nstr(p);
 836 }
 837 
 838 int
 839 p_bodyflan(struct parctx *p)
 840 {
 841         struct parcur b;
 842 
 843         return p_chk(p, &b) && p_nstr(p) || (p_opar(p) &&
 844             p_list(p, p_str) && p_cpar(p) || p_rwd(p, &b));
 845 }
 846 
 847 int
 848 p_bodyflin(struct parctx *p)
 849 {
 850         return p_num(p);
 851 }
 852 
 853 int
 854 p_bodyfloc(struct parctx *p)
 855 {
 856         return p_nstr(p);
 857 }
 858 
 859 int
 860 p_bodyfmd5(struct parctx *p)
 861 {
 862         return p_nstr(p);
 863 }
 864 
 865 int
 866 p_bodyfoct(struct parctx *p)
 867 {
 868         return p_num(p);
 869 }
 870 
 871 int
 872 p_bodyfpar(struct parctx *p)
 873 {
 874         struct parcur b;
 875 
 876         return p_chk(p, &b) && (p_opar(p) && p_list(p, p_sss) &&
 877             p_cpar(p) || p_rwd(p, &b)) || p_lit(p, IL_NIL);
 878 }
 879 
 880 int
 881 p_bodympt(struct parctx *p)
 882 {
 883         struct parcur b, o;
 884 
 885         return p_chk(p, &b) && p_rep(p, p_body) && p_sp(p) &&
 886             p_medsubt(p) && (p_chk(p, &o) && p_sp(p) && p_bodyxmpt(p) ||
 887             p_rwd(p, &o) || p_opt(p)) || p_rwd(p, &b);
 888 }
 889 
 890 int
 891 p_bodymsg(struct parctx *p)
 892 {
 893         struct parcur b;
 894 
 895         return p_chk(p, &b) && p_medmsg(p) && p_sp(p) && p_bodyf(p) &&
 896             p_sp(p) && p_env(p) && p_sp(p) && p_body(p) && p_sp(p) &&
 897             p_bodyflin(p) || p_rwd(p, &b);
 898 }
 899 
 900 int
 901 p_bodytxt(struct parctx *p)
 902 {
 903         struct parcur b;
 904 
 905         return p_chk(p, &b) && p_medtxt(p) && p_sp(p) && p_bodyf(p) &&
 906             p_sp(p) && p_bodyflin(p) || p_rwd(p, &b);
 907 }
 908 
 909 int
 910 p_bodyx1pt(struct parctx *p)
 911 {
 912         struct parcur b;
 913 
 914         return p_chk(p, &b) && p_bodyfmd5(p) &&
 915             p_bodyxcmn(p) || p_rwd(p, &b);
 916 }
 917 
 918 /* TODO: this one's extra gross, prob needs a good factoring */
 919 int
 920 p_bodyxcmn(struct parctx *p)
 921 {
 922         struct parcur o1, o2, o3, o4;
 923 
 924         return p_chk(p, &o1) && p_sp(p) && p_bodyfdsp(p) &&
 925             (p_chk(p, &o2) && p_sp(p) && p_bodyflan(p) &&
 926             (p_chk(p, &o3) && p_sp(p) && p_bodyfloc(p) &&
 927             (p_chk(p, &o4) && p_sp(p) && p_list(p, p_bodyext) ||
 928             p_rwd(p, &o4) || p_opt(p)) ||
 929             p_rwd(p, &o3) || p_opt(p)) ||
 930             p_rwd(p, &o2) || p_opt(p)) ||
 931             p_rwd(p, &o1) || p_opt(p);
 932 }
 933 
 934 int
 935 p_bodyxmpt(struct parctx *p)
 936 {
 937         struct parcur b;
 938 
 939         return p_chk(p, &b) && p_bodyfpar(p) &&
 940             p_bodyxcmn(p) || p_rwd(p, &b);
 941 }
 942 
 943 int
 944 p_cap(struct parctx *p)
 945 {
 946         struct parcur b, c;
 947 
 948         return p_chk(p, &b) && p_sp(p) && p_beg(p, &c, IP_CAP) &&
 949             (p_2xcombo(p, IL_AUTHEQ, p_authtype) || p_atom(p)) &&
 950             p_end(p, &c) || p_rwd(p, &b);
 951 }
 952 
 953 int
 954 p_capdata(struct parctx *p)
 955 {
 956         struct parcur b;
 957 
 958         return p_beg(p, &b, IP_CAPDATA) && (p_lit(p, IL_CAP) &&
 959             p_rep(p, p_cap) || p_rwd(p, &b)) && p_end(p, &b);
 960 }
 961 
 962 int
 963 p_contreq(struct parctx *p)
 964 {
 965         struct parcur b;
 966 
 967         return p_beg(p, &b, IP_CONTREQ) && (p_lit(p, IL_PLUS) && p_sp(p) &&
 968             (p_resptext(p) || p_base64(p)) && p_lit(p, IL_EOL) ||
 969             p_rwd(p, &b)) && p_end(p, &b);
 970 }
 971 
 972 int
 973 p_datetime(struct parctx *p)
 974 {
 975         struct parcur b;
 976 
 977         return p_chk(p, &b) && p_dquote(p) && p_dayfix(p) &&
 978             p_lit(p, IL_MINUS) && p_month(p) && p_lit(p, IL_MINUS) &&
 979             p_year(p) && p_sp(p) && p_time(p) && p_sp(p) && p_zone(p) &&
 980             p_dquote(p) || p_rwd(p, &b);
 981 }
 982 
 983 int
 984 p_dayfix(struct parctx *p)
 985 {
 986         struct parcur b;
 987 
 988         return p_chk(p, &b) && p_sp(p) && p_dig(p, 1) ||
 989             p_rwd(p, &b) || p_dig(p, 2);
 990 }
 991 
 992 int
 993 p_dig(struct parctx *p, size_t count)
 994 {
 995         size_t pr;
 996         char *prp;
 997         size_t len;
 998         uint32_t n, prev;
 999         size_t d;
1000 
1001         if (p->e > TE_PARSE)
1002                 goto exit;
1003 
1004         p->e = TE_OK;
1005         pr = p->cur.off;
1006         n = prev = 0;
1007         d = count == SIZE_MAX ? 0 : 1;
1008 
1009         while (par_fillstr(p, pr + 1) == TE_OK) {
1010                 for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
1011                         if (count == 0 || *prp < '0' || *prp > '9')
1012                                 goto stop;
1013                         prev = n;
1014                         n = UINT32_MAX & (10 * n + (*prp - '0'));
1015                         if (prev > n) {
1016                                 p->e = TE_PARSE;
1017                                 goto stop;
1018                         }
1019                         count -= d;
1020                 }
1021         }
1022  stop:
1023         len = pr - p->cur.off;
1024         if (p->e == TE_EOF && len)
1025                 p->e = TE_OK;
1026 
1027         if (p->e) goto exit;
1028         if (!len) goto eparse;
1029         if (!p_insnum(p, n)) goto exit;
1030 
1031         p->cur.off = pr;
1032  exit:
1033         return p->e == TE_OK;
1034  eparse:
1035         p->e = TE_PARSE;
1036         goto exit;
1037 }
1038 
1039 int
1040 p_dquotedchar(struct parctx *p)
1041 {
1042         struct parcur b;
1043 
1044         return p_chk(p, &b) && p_dquote(p) && p_qchar(p) && p_dquote(p) ||
1045             p_rwd(p, &b);
1046 }
1047 
1048 int
1049 p_env(struct parctx *p)
1050 {
1051         struct parcur b;
1052 
1053         return p_chk(p, &b) && p_opar(p) && p_nstr(p) && p_sp(p) &&
1054             p_nstr(p) && p_sp(p) && p_envaddr(p) && p_sp(p) &&
1055             p_envaddr(p) && p_sp(p) && p_envaddr(p) && p_sp(p) &&
1056             p_envaddr(p) && p_sp(p) && p_envaddr(p) && p_sp(p) &&
1057             p_envaddr(p) && p_sp(p) && p_nstr(p) && p_sp(p) &&
1058             p_nstr(p) && p_cpar(p) || p_rwd(p, &b);
1059 }
1060 
1061 int
1062 p_envaddr(struct parctx *p)
1063 {
1064         struct parcur b;
1065 
1066         return p_chk(p, &b) && p_opar(p) && p_rep(p, p_addr) && p_cpar(p) ||
1067             p_rwd(p, &b) || p_lit(p, IL_NIL);
1068 }
1069 
1070 int
1071 p_expunge(struct parctx *p)
1072 {
1073         struct parcur b;
1074 
1075         return p_beg(p, &b, IP_EXPUNGE) && p_nznum(p) && p_sp(p) &&
1076             p_lit(p, IL_EXPUNGE) && p_end(p, &b) || p_rwd(p, &b);
1077 }
1078 
1079 int
1080 p_fetch(struct parctx *p)
1081 {
1082         struct parcur b;
1083 
1084         return p_beg(p, &b, IP_FETCH) && p_nznum(p) && p_sp(p) &&
1085             p_lit(p, IL_FETCH) && p_sp(p) && p_opar(p) &&
1086             p_list(p, p_msgatt) && p_cpar(p) && p_end(p, &b) ||
1087             p_rwd(p, &b);
1088 }
1089 
1090 int
1091 p_flag(struct parctx *p)
1092 {
1093         return p_lit(p, IL_FLANSWERED) || p_lit(p, IL_FLFLAGGED) ||
1094             p_lit(p, IL_FLDELETED) || p_lit(p, IL_FLSEEN) ||
1095             p_lit(p, IL_FLDRAFT) || p_flkeyword(p) ||
1096             p_flext(p);
1097 }
1098 
1099 int
1100 p_flext(struct parctx *p)
1101 {
1102         struct parcur b;
1103 
1104         return p_chk(p, &b) && p_lit(p, IL_BSLASH) &&
1105             p_atom(p) || p_rwd(p, &b);
1106 }
1107 
1108 int
1109 p_flfetch(struct parctx *p)
1110 {
1111         return p_flag(p) || p_lit(p, IL_FLRECENT);
1112 }
1113 
1114 int
1115 p_flkeyword(struct parctx *p)
1116 {
1117         return p_atom(p);
1118 }
1119 
1120 int
1121 p_gencode(struct parctx *p)
1122 {
1123         struct parcur opt;
1124 
1125         return p_atom(p) && (p_chk(p, &opt) &&
1126             p_sp(p) && p_genctext(p) ||
1127             p_rwd(p, &opt) || p_opt(p));
1128 }
1129 
1130 int
1131 p_genctext(struct parctx *p)
1132 {
1133         size_t pr;
1134         char *prp;
1135         size_t len;
1136 
1137         if (p->e > TE_PARSE)
1138                 goto exit;
1139 
1140         p->e = TE_OK;
1141         pr = p->cur.off;
1142 
1143         while (par_fillstr(p, pr + 1) == TE_OK) {
1144                 for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
1145                         if (*prp == 0 || *prp > '\x7f' || *prp == ']' ||
1146                             *prp == '\r' || *prp == '\n')
1147                                 goto stop;
1148                 }
1149         }
1150  stop:
1151         len = pr - p->cur.off;
1152         if (p->e == TE_EOF && len)
1153                 p->e = TE_OK;
1154 
1155         if (p->e) goto exit;
1156         if (!len) goto eparse;
1157         if (len > UINT32_MAX) goto exl;
1158         if (!p_insstr(p, PN_STR, p->cur.off, len)) goto exit;
1159 
1160         p->cur.off = pr;
1161  exit:
1162         return p->e == TE_OK;
1163  eparse:
1164         p->e = TE_PARSE;
1165         goto exit;
1166  exl:
1167         p->e = TE_XLSTR;
1168         goto exit;
1169 }
1170 
1171 int
1172 p_hdrfname(struct parctx *p)
1173 {
1174         return p_astr(p);
1175 }
1176 
1177 int
1178 p_hdrlist(struct parctx *p)
1179 {
1180         struct parcur b;
1181 
1182         return p_chk(p, &b) && p_opar(p) && p_list(p, p_hdrfname) &&
1183             p_cpar(p) || p_rwd(p, &b);
1184 }
1185 
1186 int
1187 p_lit(struct parctx *p, int val)
1188 {
1189         struct literal *lit;
1190 
1191         if (p->e > TE_PARSE)
1192                 goto exit;
1193 
1194         p->e = TE_OK;
1195         lit = literals + val;
1196 
1197         if (par_fillstr(p, p->cur.off + lit->slen) != TE_OK)
1198                 goto exit;
1199         if (strncasecmp(p->str + p->cur.off, lit->srep, lit->slen) != 0)
1200                 goto eparse;
1201 
1202         if (p_inslit(p, val))
1203                 p->cur.off += lit->slen;
1204  exit:
1205         return p->e == TE_OK;
1206  eparse:
1207         p->e = TE_PARSE;
1208         goto exit;
1209 }
1210 
1211 int
1212 p_lstr(struct parctx *p)
1213 {
1214         int prefix;
1215         size_t len;
1216         struct parcur b, n;
1217 
1218         prefix = p_chk(p, &b) && p_lit(p, IL_OBRACE) &&
1219             p_chk(p, &n) && p_num(p) && p_lit(p, IL_CBRACE) &&
1220             p_lit(p, IL_EOL) || p_rwd(p, &b);
1221 
1222         if (!prefix)
1223                 goto exit;
1224 
1225         p->e = TE_OK;
1226         len = n.pt->num.val;
1227         p->cur.pt = b.pt;
1228 
1229         if (len > UINT32_MAX) goto exl;
1230         if (par_fillstr(p, p->cur.off + len) != TE_OK)
1231                 goto exit;
1232         if (!p_insstr(p, PN_LSTR, p->cur.off, len))
1233                 goto exit;
1234 
1235         p->cur.off += len;
1236  exit:
1237         return p->e == TE_OK;
1238  exl:
1239         p->e = TE_XLSTR;
1240         goto exit;
1241 }
1242 
1243 int
1244 p_mailbox(struct parctx *p)
1245 {
1246         return p_lit(p, IL_INBOX) || p_astr(p);
1247 }
1248 
1249 int
1250 p_mat822body(struct parctx *p)
1251 {
1252         struct parcur b;
1253 
1254         return p_beg(p, &b, IP_822BODY) && p_lit(p, IL_RFC822) &&
1255             p_sp(p) && p_nstr(p) && p_end(p, &b) || p_rwd(p, &b);
1256 }
1257 
1258 int
1259 p_matbody(struct parctx *p)
1260 {
1261         struct parcur b;
1262 
1263         return p_chk(p, &b) && p_lit(p, IL_BODY) &&
1264             (p_lit(p, IL_STRUCT) || p_opt(p)) && p_sp(p) &&
1265             p_body(p) || p_rwd(p, &b);
1266 }
1267 
1268 int
1269 p_matbsect(struct parctx *p)
1270 {
1271         struct parcur b, o;
1272 
1273         return p_chk(p, &b) && p_lit(p, IL_BODY) && p_section(p) &&
1274             (p_chk(p, &o) && p_lit(p, IL_LT) && p_num(p) && p_lit(p, IL_GT) ||
1275             p_rwd(p, &o) || p_opt(p)) && p_sp(p) && p_nstr(p) || p_rwd(p, &b);
1276 }
1277 
1278 int
1279 p_matenv(struct parctx *p)
1280 {
1281         return p_3xcombo(p, IL_ENVELOPE, IL_SP, p_env);
1282 }
1283 
1284 int
1285 p_mathdrotxt(struct parctx *p)
1286 {
1287         struct parcur b;
1288 
1289         return p_chk(p, &b) && p_lit(p, IL_RFC822) &&
1290             (p_lit(p, IL_DHDR) || p_lit(p, IL_DTXT)) && p_sp(p) &&
1291             p_nstr(p) || p_rwd(p, &b);
1292 }
1293 
1294 int
1295 p_matintdate(struct parctx *p)
1296 {
1297         return p_3xcombo(p, IL_INTDATE, IL_SP, p_datetime);
1298 }
1299 
1300 int
1301 p_matsize(struct parctx *p)
1302 {
1303         return p_3xcombo(p, IL_RFC822SIZE, IL_SP, p_num);
1304 }
1305 
1306 int
1307 p_matuid(struct parctx *p)
1308 {
1309         return p_3xcombo(p, IL_UID, IL_SP, p_uid);
1310 }
1311 
1312 int
1313 p_mbdata(struct parctx *p)
1314 {
1315         return p_mbflags(p) || p_mblist(p) ||
1316             p_mblsub(p) || p_mbsearch(p) ||
1317             p_mbstatus(p) || p_mbexists(p) ||
1318             p_mbrecent(p);
1319 }
1320 
1321 int
1322 p_mbexists(struct parctx *p)
1323 {
1324         struct parcur b;
1325 
1326         return p_beg(p, &b, IP_EXISTS) &&
1327             p_r3xcombo(p, p_num, IL_SP, IL_EXISTS) &&
1328             p_end(p, &b) || p_rwd(p, &b);
1329 }
1330 
1331 int
1332 p_mbflags(struct parctx *p)
1333 {
1334         struct parcur b;
1335 
1336         return p_chk(p, &b) && p_lit(p, IL_FLAGS) &&
1337             p_sp(p) && p_opar(p) &&
1338             (p_list(p, p_flag) || p_opt(p)) &&
1339             p_cpar(p) || p_rwd(p, &b);
1340 }
1341 
1342 int
1343 p_mblist(struct parctx *p)
1344 {
1345         struct parcur b;
1346 
1347         return p_chk(p, &b) && p_lit(p, IL_LIST) &&
1348             p_sp(p) && p_mblistdata(p) ||
1349             p_rwd(p, &b);
1350 }
1351 
1352 int
1353 p_mblistdata(struct parctx *p)
1354 {
1355         struct parcur b;
1356 
1357         return p_chk(p, &b) && p_opar(p) &&
1358             (p_list(p, p_mblistfl) || p_opt(p)) &&
1359             p_cpar(p) && p_sp(p) &&
1360             (p_dquotedchar(p) || p_lit(p, IL_NIL)) &&
1361             p_sp(p) && p_mailbox(p) || p_rwd(p, &b);
1362 }
1363 
1364 /*
1365    TODO: will 1*(SFL|OFL) with a soundness check afterwards
1366    be simpler and more readable?
1367 */
1368 int
1369 p_mblistfl(struct parctx *p)
1370 {
1371         return p_mblistosfl(p) || p_list(p, p_mblistofl);
1372 }
1373 
1374 int
1375 p_mblistofl(struct parctx *p)
1376 {
1377         return p_lit(p, IL_FLNOINFERIORS) || p_flext(p);
1378 }
1379 
1380 int
1381 p_mblistosfl(struct parctx *p)
1382 {
1383         int res;
1384         struct parcur b;
1385 
1386         res = p_chk(p, &b) && p_list(p, p_mblistofl) &&
1387             p_sp(p) || p_rwd(p, &b) || p_opt(p);
1388 
1389         res = res && p_mblistsfl(p);
1390 
1391         res = res && (p_chk(p, &b) && p_sp(p) &&
1392             p_list(p, p_mblistofl) || p_rwd(p, &b) || p_opt(p));
1393 
1394         return res;
1395 }
1396 
1397 int
1398 p_mblistsfl(struct parctx *p)
1399 {
1400         return p_lit(p, IL_FLNOSEL) || p_lit(p, IL_FLMARKED) ||
1401             p_lit(p, IL_FLUNMARKED);
1402 }
1403 
1404 int
1405 p_mblsub(struct parctx *p)
1406 {
1407         struct parcur b;
1408 
1409         return p_chk(p, &b) && p_lit(p, IL_LSUB) &&
1410             p_sp(p) && p_mblistdata(p) ||
1411             p_rwd(p, &b);
1412 }
1413 
1414 int
1415 p_mbrecent(struct parctx *p)
1416 {
1417         return p_r3xcombo(p, p_num, IL_SP, IL_RECENT);
1418 }
1419 
1420 int
1421 p_mbsearch(struct parctx *p)
1422 {
1423         struct parcur b, o;
1424 
1425         return p_chk(p, &b) && p_lit(p, IL_SEARCH) &&
1426             (p_chk(p, &o) && p_sp(p) &&
1427             p_list(p, p_nznum) || p_rwd(p, &o) || p_opt(p)) ||
1428             p_rwd(p, &b);
1429 }
1430 
1431 int
1432 p_mbstatus(struct parctx *p)
1433 {
1434         struct parcur b;
1435 
1436         return p_chk(p, &b) && p_lit(p, IL_STATUS) && p_sp(p) &&
1437             p_mailbox(p) && p_sp(p) && p_opar(p) &&
1438             (p_list(p, p_stattrec) || p_opt(p)) && p_cpar(p) ||
1439             p_rwd(p, &b);
1440 }
1441 
1442 int
1443 p_medbas(struct parctx *p)
1444 {
1445         struct parcur b;
1446 
1447         return p_chk(p, &b) && (p_dquote(p) &&
1448             (p_lit(p, IL_APP) || p_lit(p, IL_AUDIO) || p_lit(p, IL_IMG) ||
1449             p_lit(p, IL_MSG) || p_lit(p, IL_VIDEO)) && p_dquote(p) ||
1450             (p_rwd(p, &b) || p_str(p))) &&
1451             p_sp(p) && p_medsubt(p) || p_rwd(p, &b);
1452 }
1453 
1454 int
1455 p_medmsg(struct parctx *p)
1456 {
1457         struct parcur b;
1458 
1459         return p_chk(p, &b) &&
1460             p_dquote(p) && p_lit(p, IL_MSG) && p_dquote(p) && p_sp(p) &&
1461             p_dquote(p) && p_lit(p, IL_RFC822) && p_dquote(p) || p_rwd(p, &b);
1462 }
1463 
1464 int
1465 p_medsubt(struct parctx *p)
1466 {
1467         return p_str(p);
1468 }
1469 
1470 int
1471 p_medtxt(struct parctx *p)
1472 {
1473         struct parcur b;
1474 
1475         return p_chk(p, &b) && p_dquote(p) && p_lit(p, IL_TXT) && p_dquote(p) &&
1476             p_sp(p) && p_medsubt(p) || p_rwd(p, &b);
1477 }
1478 
1479 int
1480 p_month(struct parctx *p)
1481 {
1482         return p_lit(p, IL_JAN) || p_lit(p, IL_FEB) || p_lit(p, IL_MAR) ||
1483             p_lit(p, IL_APR) || p_lit(p, IL_MAY) || p_lit(p, IL_JUN) ||
1484             p_lit(p, IL_JUL) || p_lit(p, IL_AUG) || p_lit(p, IL_SEP) ||
1485             p_lit(p, IL_OCT) || p_lit(p, IL_NOV) || p_lit(p, IL_DEC);
1486 }
1487 
1488 int
1489 p_msgdata(struct parctx *p)
1490 {
1491         return p_expunge(p) || p_fetch(p);
1492 }
1493 
1494 int
1495 p_msgatt(struct parctx *p)
1496 {
1497         return p_msgattstat(p) || p_msgattdyn(p);
1498 }
1499 
1500 int
1501 p_msgattdyn(struct parctx *p)
1502 {
1503         struct parcur b;
1504 
1505         return p_chk(p, &b) && p_lit(p, IL_FLAGS) && p_sp(p) && p_opar(p) &&
1506             (p_list(p, p_flfetch) || p_opt(p)) && p_cpar(p) || p_rwd(p, &b);
1507 }
1508 
1509 int
1510 p_msgattstat(struct parctx *p)
1511 {
1512         return p_matenv(p) || p_matintdate(p) || p_mat822body(p) ||
1513             p_mathdrotxt(p) || p_matsize(p) || p_matbody(p) ||
1514             p_matbsect(p) || p_matuid(p);
1515 }
1516 
1517 int
1518 p_nstr(struct parctx *p)
1519 {
1520         return p_str(p) || p_lit(p, IL_NIL);
1521 }
1522 
1523 int
1524 p_num(struct parctx *p)
1525 {
1526         return p_dig(p, SIZE_MAX);
1527 }
1528 
1529 int
1530 p_nznum(struct parctx *p)
1531 {
1532         const char *prp;
1533 
1534         if (p->e > TE_PARSE)
1535                 goto exit;
1536 
1537         p->e = TE_OK;
1538 
1539         if (par_fillstr(p, p->cur.off + 1) != TE_OK)
1540                 goto exit;
1541 
1542         prp = p->str + p->cur.off;
1543         if (*prp < '1' || *prp > '9')
1544                 goto eparse;
1545 
1546         p_num(p);
1547  exit:
1548         return p->e == TE_OK;
1549  eparse:
1550         p->e = TE_PARSE;
1551         goto exit;
1552 }
1553 
1554 int
1555 p_permfl(struct parctx *p)
1556 {
1557         return p_flag(p) || p_lit(p, IL_FLANY);
1558 }
1559 
1560 int
1561 p_permflcode(struct parctx *p)
1562 {
1563         struct parcur b;
1564 
1565         return p_chk(p, &b) && p_lit(p, IL_PERMFL) &&
1566             p_sp(p) && p_opar(p) &&
1567             (p_list(p, p_permfl) || p_opt(p)) &&
1568             p_cpar(p) || p_rwd(p, &b);
1569 }
1570 
1571 int
1572 p_qchar(struct parctx *p)
1573 {
1574         char x, y;
1575         int len;
1576 
1577         if (p->e > TE_PARSE)
1578                 goto exit;
1579 
1580         p->e = TE_OK;
1581 
1582         if (par_fillstr(p, p->cur.off + 1) != TE_OK)
1583                 goto exit;
1584         x = p->str[p->cur.off];
1585         if (x >= '\1' && x <= '\x7f' && x != '\r' &&
1586             x != '\n' && x != '"' && x != '\\') {
1587                 len = 1;
1588                 goto ins;
1589         }
1590         if (par_fillstr(p, p->cur.off + 2) != TE_OK)
1591                 goto exit;
1592         y = p->str[p->cur.off + 1];
1593         if (x == '\\' && (y == '"' || y == '\\')) {
1594                 len = 2;
1595                 goto ins;
1596         }
1597         goto eparse;
1598 
1599  ins:
1600         if (!p_insstr(p, PN_QSTR, p->cur.off, len))
1601                 goto exit;
1602 
1603         p->cur.off += len;
1604  exit:
1605         return p->e == TE_OK;
1606  eparse:
1607         p->e = TE_PARSE;
1608         goto exit;
1609 }
1610 
1611 int
1612 p_qchars(struct parctx *p)
1613 {
1614         size_t pr;
1615         char *prp;
1616         size_t len;
1617         int esc;
1618 
1619         if (p->e > TE_PARSE)
1620                 goto exit;
1621 
1622         p->e = TE_OK;
1623         pr = p->cur.off;
1624         esc = 0;
1625 
1626         while (par_fillstr(p, pr + 1) == TE_OK) {
1627                 for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
1628                         if (esc) {
1629                                 if (*prp == '"' || *prp == '\\') {
1630                                         esc = 0;
1631                                 } else {
1632                                         goto eparse;
1633                                 }
1634                         } else if (*prp == '\\') {
1635                                 esc = 1;
1636                         } else if (*prp == 0 || *prp > '\x7f' ||
1637                             *prp == '\r' || *prp == '\n' || *prp == '"') {
1638                                 goto stop;
1639                         }
1640                 }
1641         }
1642  stop:
1643         len = pr - p->cur.off;
1644         if (p->e == TE_EOF && len)
1645                 p->e = TE_OK;
1646 
1647         if (p->e) goto exit;
1648         if (!len) goto eparse;
1649         if (len > UINT32_MAX) goto exl;
1650         if (!p_insstr(p, PN_QSTR, p->cur.off, len)) goto exit;
1651 
1652         p->cur.off = pr;
1653  exit:
1654         return p->e == TE_OK;
1655  eparse:
1656         p->e = TE_PARSE;
1657         goto exit;
1658  exl:
1659         p->e = TE_XLSTR;
1660         goto exit;
1661 }
1662 
1663 int
1664 p_qstr(struct parctx *p)
1665 {
1666         struct parcur b;
1667 
1668         return p_chk(p, &b) && p_dquote(p) && (p_qchars(p) || p_opt(p)) &&
1669             p_dquote(p) || p_rwd(p, &b);
1670 }
1671 
1672 int
1673 p_respauth(struct parctx *p)
1674 {
1675         struct parcur b;
1676 
1677         return p_beg(p, &b, IP_RESPAUTH) && (p_lit(p, IL_PREAUTH) && p_sp(p) &&
1678             p_resptext(p) || p_rwd(p, &b)) && p_end(p, &b);
1679 }
1680 
1681 int
1682 p_respbye(struct parctx *p)
1683 {
1684         struct parcur b;
1685 
1686         return p_beg(p, &b, IP_RESPBYE) && (p_lit(p, IL_BYE) && p_sp(p) &&
1687             p_resptext(p) || p_rwd(p, &b)) && p_end(p, &b);
1688 }
1689 
1690 int
1691 p_respdata(struct parctx *p)
1692 {
1693         struct parcur b;
1694 
1695         return p_beg(p, &b, IP_RESPDATA) && (p_lit(p, IL_ASTERISK) && p_sp(p) &&
1696             (p_respauth(p) || p_respstate(p) || p_respbye(p) ||
1697             p_mbdata(p) || p_msgdata(p) || p_capdata(p)) &&
1698             p_lit(p, IL_EOL) || p_rwd(p, &b)) && p_end(p, &b);
1699 }
1700 
1701 int
1702 p_respln(struct parctx *p)
1703 {
1704         return p_contreq(p) || p_respdata(p) || p_taggedresp(p);
1705 }
1706 
1707 int
1708 p_respstate(struct parctx *p)
1709 {
1710         struct parcur b;
1711 
1712         return p_beg(p, &b, IP_RESPSTATE) &&
1713             ((p_lit(p, IL_OK) || p_lit(p, IL_NO) || p_lit(p, IL_BAD)) &&
1714             p_sp(p) && p_resptext(p) || p_rwd(p, &b)) && p_end(p, &b);
1715 }
1716 
1717 int
1718 p_resptext(struct parctx *p)
1719 {
1720         int res;
1721         struct parcur b;
1722 
1723         res = p_chk(p, &b) && p_lit(p, IL_OBRACK) &&
1724             p_resptextcode(p) && p_lit(p, IL_CBRACK) &&
1725             p_sp(p) || p_rwd(p, &b) || p_opt(p);
1726 
1727         return res && p_text(p);
1728 }
1729 
1730 int
1731 p_resptextcode(struct parctx *p)
1732 {
1733         struct parcur b;
1734 
1735         return p_beg(p, &b, IP_RESPTXTCODE) &&
1736             (p_lit(p, IL_ALERT) || p_badcscode(p) || p_capdata(p) ||
1737             p_lit(p, IL_PARSE) || p_permflcode(p) || p_lit(p, IL_RO) ||
1738             p_lit(p, IL_RW) || p_lit(p, IL_TRYC) || p_uidncode(p) ||
1739             p_uidvcode(p) || p_unseencode(p) || p_gencode(p) ||
1740             p_rwd(p, &b)) && p_end(p, &b);
1741 }
1742 
1743 int
1744 p_secmsgtxt(struct parctx *p)
1745 {
1746         struct parcur b;
1747 
1748         return p_chk(p, &b) && p_lit(p, IL_HDR) ||
1749             (p_lit(p, IL_HDRFIELDS) && (p_lit(p, IL_DNOT) || p_opt(p)) &&
1750             p_sp(p) && p_hdrlist(p) || p_rwd(p, &b)) || p_lit(p, IL_TXT);
1751 }
1752 
1753 int
1754 p_secpt(struct parctx *p)
1755 {
1756         return p_listsep(p, p_nznum, IL_DOT);
1757 }
1758 
1759 int
1760 p_secspec(struct parctx *p)
1761 {
1762         struct parcur b, o;
1763 
1764         return p_chk(p, &b) && p_secmsgtxt(p) || (p_secpt(p) &&
1765             (p_chk(p, &o) && p_lit(p, IL_DOT) && p_sectxt(p) ||
1766             p_rwd(p, &o) || p_opt(p))) || p_rwd(p, &b);
1767 }
1768 
1769 int
1770 p_section(struct parctx *p)
1771 {
1772         struct parcur b;
1773 
1774         return p_chk(p, &b) && p_lit(p, IL_OBRACK) &&
1775             (p_secspec(p) || p_opt(p)) &&
1776             p_lit(p, IL_CBRACK) || p_rwd(p, &b);
1777 }
1778 
1779 int
1780 p_sectxt(struct parctx *p)
1781 {
1782         return p_secmsgtxt(p) || p_lit(p, IL_MIME);
1783 }
1784 
1785 int
1786 p_statt(struct parctx *p)
1787 {
1788         return p_lit(p, IL_MSGS) || p_lit(p, IL_RECENT) ||
1789             p_lit(p, IL_UIDNEXT) || p_lit(p, IL_UIDVAL) ||
1790             p_lit(p, IL_UNSEEN);
1791 }
1792 
1793 int
1794 p_stattrec(struct parctx *p)
1795 {
1796         struct parcur b;
1797 
1798         return p_chk(p, &b) && p_statt(p) && p_sp(p) &&
1799             p_num(p) || p_rwd(p, &b);
1800 }
1801 
1802 int
1803 p_str(struct parctx *p)
1804 {
1805         return p_qstr(p) || p_lstr(p);
1806 }
1807 
1808 int
1809 p_tag(struct parctx *p)
1810 {
1811         return p_repchr(p, tag_specials, LEN(tag_specials), PN_STR);
1812 }
1813 
1814 int
1815 p_taggedresp(struct parctx *p)
1816 {
1817         struct parcur b;
1818 
1819         return p_beg(p, &b, IP_TAGGEDRESP) && (p_tag(p) && p_sp(p) &&
1820             p_respstate(p) && p_lit(p, IL_EOL) || p_rwd(p, &b)) &&
1821             p_end(p, &b);
1822 }
1823 
1824 int
1825 p_text(struct parctx *p)
1826 {
1827         size_t pr;
1828         char *prp;
1829         size_t len;
1830 
1831         if (p->e > TE_PARSE)
1832                 goto exit;
1833 
1834         p->e = TE_OK;
1835         pr = p->cur.off;
1836 
1837         while (par_fillstr(p, pr + 1) == TE_OK) {
1838                 for (prp = p->str + pr; pr < p->strlen; ++pr, ++prp) {
1839                         if (*prp == 0 || *prp > '\x7f' ||
1840                             *prp == '\r' || *prp == '\n')
1841                                 goto stop;
1842                 }
1843         }
1844  stop:
1845         len = pr - p->cur.off;
1846         if (p->e == TE_EOF && len)
1847                 p->e = TE_OK;
1848 
1849         if (p->e) goto exit;
1850         if (!len) goto eparse;
1851         if (len > UINT32_MAX) goto exl;
1852         if (!p_insstr(p, PN_STR, p->cur.off, len)) goto exit;
1853 
1854         p->cur.off = pr;
1855  exit:
1856         return p->e == TE_OK;
1857  eparse:
1858         p->e = TE_PARSE;
1859         goto exit;
1860  exl:
1861         p->e = TE_XLSTR;
1862         goto exit;
1863 }
1864 
1865 int
1866 p_time(struct parctx *p)
1867 {
1868         struct parcur b;
1869 
1870         return p_chk(p, &b) && p_dig(p, 2) && p_lit(p, IL_COLON) &&
1871             p_dig(p, 2) && p_lit(p, IL_COLON) && p_dig(p, 2) || p_rwd(p, &b);
1872 }
1873 
1874 int
1875 p_uid(struct parctx *p)
1876 {
1877         return p_nznum(p);
1878 }
1879 
1880 int
1881 p_uidncode(struct parctx *p)
1882 {
1883         return p_3xcombo(p, IL_UIDNEXT, IL_SP, p_nznum);
1884 }
1885 
1886 int
1887 p_uidvcode(struct parctx *p)
1888 {
1889         return p_3xcombo(p, IL_UIDVAL, IL_SP, p_nznum);
1890 }
1891 
1892 int
1893 p_unseencode(struct parctx *p)
1894 {
1895         return p_3xcombo(p, IL_UNSEEN, IL_SP, p_nznum);
1896 }
1897 
1898 int
1899 p_year(struct parctx *p)
1900 {
1901         return p_dig(p, 4);
1902 }
1903 
1904 int
1905 p_zone(struct parctx *p)
1906 {
1907         struct parcur b;
1908 
1909         return p_chk(p, &b) &&
1910             (p_lit(p, IL_PLUS) || p_lit(p, IL_MINUS)) &&
1911             p_dig(p, 4) || p_rwd(p, &b);
1912 }
1913 
1914 /* shortcuts for some common literals and means
1915    of imrpoving legibility of bulky productions */
1916 
1917 int
1918 p_cpar(struct parctx *p)
1919 {
1920         return p_lit(p, IL_CPAR);
1921 }
1922 
1923 int
1924 p_dquote(struct parctx *p)
1925 {
1926         return p_lit(p, IL_DQUOTE);
1927 }
1928 
1929 int
1930 p_opar(struct parctx *p)
1931 {
1932         return p_lit(p, IL_OPAR);
1933 }
1934 
1935 int
1936 p_sp(struct parctx *p)
1937 {
1938         return p_lit(p, IL_SP);
1939 }