diff -r b820f6ec7729 sys/src/cmd/upas/fs/imap.c --- a/sys/src/cmd/upas/fs/imap.c Tue Nov 19 12:43:53 2019 +1030 +++ b/sys/src/cmd/upas/fs/imap.c Tue Nov 19 12:00:02 2019 -0800 @@ -35,6 +35,7 @@ uvlong uid; ulong sizes; ulong dates; + ulong flags; } Fetchi; typedef struct Imap Imap; @@ -51,6 +52,7 @@ ulong tag; ulong validity; + ulong newvalidity; int nmsg; int size; @@ -163,20 +165,22 @@ Fetch, Cap, Auth, + Expunge, Unknown, }; static char *verblist[] = { -[Ok] "ok", -[No] "no", -[Bad] "bad", -[Bye] "bye", -[Exists] "exists", -[Status] "status", -[Fetch] "fetch", -[Cap] "capability", -[Auth] "authenticate", + [Ok] "ok", + [No] "no", + [Bad] "bad", + [Bye] "bye", + [Exists] "exists", + [Status] "status", + [Fetch] "fetch", + [Cap] "capability", + [Auth] "authenticate", + [Expunge] "expunge", }; static int @@ -187,7 +191,7 @@ if(q = strchr(verb, ' ')) *q = '\0'; - for(i = 0; i < nelem(verblist) - 1; i++) + for(i = 0; i < nelem(verblist); i++) if(strcmp(verblist[i], verb) == 0) break; if(q) @@ -230,26 +234,29 @@ "\\Stored", Fstored, }; -static void -parseflags(Message *m, char *s) +static int +parseflags(char *s) { char *f[10]; - int i, j, j0, n; + int i, j, j0, n, flg; n = tokenize(s, f, nelem(f)); qsort(f, n, sizeof *f, (int (*)(void*,void*))strcmp); j = 0; - for(i = 0; i < n; i++) + flg = 0; + for(i = 0; i < n; i++){ for(j0 = j;; j++){ if(j == nelem(ftab)){ j = j0; /* restart search */ break; } - if(strcmp(f[i], ftab[j].flag) == 0){ - m->flags |= ftab[j].e; + if(cistrcmp(f[i], ftab[j].flag) == 0){ + flg |= ftab[j].e; break; } } + } + return flg; } /* "17-Jul-1996 02:44:25 -0700" */ @@ -311,7 +318,7 @@ int nargs; for(nargs=0; nargs < maxargs; nargs++){ - while(*s!='\0' && utfrune(qsep, *s)!=nil) + while(*s!='\0' && utfrune(qsep, *s) != nil) s++; if(*s == '\0') break; @@ -323,7 +330,7 @@ } static char* -fetchrsp(Imap *imap, char *p, Mailbox *, Message *m) +fetchrsp(Imap *imap, char *p, Mailbox *, Message *m, int idx) { char *f[15], *s, *q; int i, n, a; @@ -332,6 +339,11 @@ static char error[256]; extern void msgrealloc(Message*, ulong); + if(idx < 0 || idx > imap->muid){ + snprint(error, sizeof error, "fetchrsp: bad idx %d", idx); + return error; + } + redux: n = imaptokenize(p, f, nelem(f)); if(n%2) @@ -341,23 +353,26 @@ l = internaltounix(f[i + 1]); if(l < 418319360) abort(); - if(imap->nuid < imap->muid) + if(idx < imap->muid) imap->f[imap->nuid].dates = l; }else if(strcmp(f[i], "rfc822.size") == 0){ l = strtoul(f[i + 1], 0, 0); if(m) m->size = l; - else if(imap->nuid < imap->muid) - imap->f[imap->nuid].sizes = l; + else if(idx < imap->muid) + imap->f[idx].sizes = l; }else if(strcmp(f[i], "uid") == 0){ v = mkuid(imap, f[1]); if(m) m->imapuid = v; - if(imap->nuid < imap->muid) - imap->f[imap->nuid].uid = v; + if(idx < imap->muid) + imap->f[idx].uid = v; }else if(strcmp(f[i], "flags") == 0){ + l = parseflags(f[i + 1]); if(m) - parseflags(m, f[i + 1]); + m->flags = l; + if(idx < imap->muid) + imap->f[idx].flags = l; }else if(strncmp(f[i], "body[]", 6) == 0){ s = f[i]+6; o = 0; @@ -396,7 +411,7 @@ }else return confused; } - return 0; + return nil; } void @@ -428,7 +443,7 @@ imap4resp0(Imap *imap, Mailbox *mb, Message *m) { char *e, *line, *p, *ep, *op, *q, *verb; - int n, unexp; + int n, idx, unexp; static char error[256]; unexp = 0; @@ -484,7 +499,7 @@ if(q = strstr(p, "messages")) imap->nmsg = strtoul(q + 8, 0, 10); if(q = strstr(p, "uidvalidity")) - imap->validity = strtoul(q + 11, 0, 10); + imap->newvalidity = strtoul(q + 11, 0, 10); break; case Fetch: if(*p == '('){ @@ -492,9 +507,23 @@ if(ep[-1] == ')') *--ep = 0; } - if(e = fetchrsp(imap, p, mb, m)) + if(e = fetchrsp(imap, p, mb, m, n - 1)) eprint("imap: fetchrsp: %s\n", e); - imap->nuid++; + idprint(imap, "n = %d, muid = %d, nuid = %d\n", n, imap->muid, imap->nuid); + if(n > 0 && n <= imap->muid && n > imap->nuid) + imap->nuid = n; + break; + case Expunge: + if(n < 1 || n > imap->muid){ + snprint(error, sizeof(error), "bad expunge %d (nmsg %d)", n, imap->nuid); + return error; + } + idx = n - 1; + memcpy(&imap->f[idx], &imap->f[idx + 1], imap->nmsg - idx - 1); + imap->nmsg--; + imap->nuid--; + if(imap->nuid == imap->muid) + imap->muid--; break; case Auth: break; @@ -903,15 +932,26 @@ Fetchi *f; Message *m, **ll; +again: imap4cmd(imap, "status %Z (messages uidvalidity)", imap->mbox); if(!isokay(s = imap4resp(imap))) return s; + /* the world shifted: start over */ + if(imap->validity != imap->newvalidity){ + imap->validity = imap->newvalidity; + imap->nuid = 0; + goto again; + } - imap->nuid = 0; imap->muid = imap->nmsg; imap->f = erealloc(imap->f, imap->nmsg*sizeof imap->f[0]); if(imap->nmsg > 0){ - imap4cmd(imap, "uid fetch 1:* (uid rfc822.size internaldate)"); + n = imap->nuid; + if(n == 0) + n = 1; + if(n > imap->nmsg) + n = imap->nmsg; + imap4cmd(imap, "fetch %d:%d (uid flags rfc822.size internaldate)", n, imap->nmsg); if(!isokay(s = imap4resp(imap))) return s; } @@ -949,6 +989,7 @@ m->imapuid = f[i].uid; m->fileid = datesec(imap, i); m->size = f[i].sizes; + m->flags = f[i].flags; m->next = *ll; *ll = m; ll = &m->next;