diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-03-12 17:15:03 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-03-12 17:15:03 +0100 |
commit | 963cfc9a6f6e721f52aa949e6d1af0c3e8dc2ecc (patch) | |
tree | 749b74875dbc49bcf6ed0776648b8f0ef9417407 /sys/src/cmd/upas/imap4d/list.c | |
parent | 8177d20fb2709ba9290dfd41308b8e5bee4e00f8 (diff) | |
download | plan9front-963cfc9a6f6e721f52aa949e6d1af0c3e8dc2ecc.tar.xz |
merging erik quanstros nupas
Diffstat (limited to 'sys/src/cmd/upas/imap4d/list.c')
-rw-r--r-- | sys/src/cmd/upas/imap4d/list.c | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/sys/src/cmd/upas/imap4d/list.c b/sys/src/cmd/upas/imap4d/list.c new file mode 100644 index 000000000..1dd3533eb --- /dev/null +++ b/sys/src/cmd/upas/imap4d/list.c @@ -0,0 +1,425 @@ +#include "imap4d.h" + +enum{ + Mfolder = 0, + Mbox, + Mdir, +}; + + char subscribed[] = "imap.subscribed"; +static int ldebug; + +#define dprint(...) if(ldebug)fprint(2, __VA_ARGS__); else {} + +static int lmatch(char*, char*, char*); + +static int +mopen(char *box, int mode) +{ + char buf[Pathlen]; + + if(!strcmp(box, "..") || strstr(box, "/..")) + return -1; + return cdopen(mboxdir, encfs(buf, sizeof buf, box), mode); +} + +static Dir* +mdirstat(char *box) +{ + char buf[Pathlen]; + + return cddirstat(mboxdir, encfs(buf, sizeof buf, box)); +} + +static long +mtime(char *box) +{ + long mtime; + Dir *d; + + mtime = 0; + if(d = mdirstat(box)) + mtime = d->mtime; + free(d); + return mtime; +} + +static int +mokmbox(char *s) +{ + char *p; + + if(p = strrchr(s, '/')) + s = p + 1; + if(!strcmp(s, "mbox")) + return 1; + return okmbox(s); +} + +/* + * paranoid check to prevent accidents + */ +/* + * BOTCH: we're taking it upon ourselves to + * identify mailboxes. this is a bad idea. + * keep in sync with ../fs/mdir.c + */ +static int +dirskip(Dir *a, uvlong *uv) +{ + char *p; + + if(a->length == 0) + return 1; + *uv = strtoul(a->name, &p, 0); + if(*uv < 1000000 || *p != '.') + return 1; + *uv = *uv<<8 | strtoul(p+1, &p, 10); + if(*p) + return 1; + return 0; +} + +static int +chkmbox(char *path, int mode) +{ + char buf[32]; + int i, r, n, fd, type; + uvlong uv; + Dir *d; + + type = Mbox; + if(mode & DMDIR) + type = Mdir; + fd = mopen(path, OREAD); + if(fd == -1) + return -1; + r = -1; + if(type == Mdir && (n = dirread(fd, &d)) > 0){ + r = Mfolder; + for(i = 0; i < n; i++) + if(!dirskip(d + i, &uv)){ + r = Mdir; + break; + } + free(d); + }else if(type == Mdir) + r = Mdir; + else if(type == Mbox){ + if(pread(fd, buf, sizeof buf, 0) == sizeof buf) + if(!strncmp(buf, "From ", 5)) + r = Mbox; + } + close(fd); + return r; +} + +static int +chkmboxpath(char *f) +{ + int r; + Dir *d; + + r = -1; + if(d = mdirstat(f)) + r = chkmbox(f, d->mode); + free(d); + return r; +} + +static char* +appendwd(char *nwd, int n, char *wd, char *a) +{ + if(wd[0] && a[0] != '/') + snprint(nwd, n, "%s/%s", wd, a); + else + snprint(nwd, n, "%s", a); + return nwd; +} + +static int +output(char *cmd, char *wd, Dir *d, int term) +{ + char path[Pathlen], dec[Pathlen], *s, *flags; + + appendwd(path, sizeof path, wd, d->name); + dprint("Xoutput %s %s %d\n", wd, d->name, term); + switch(chkmbox(path, d->mode)){ + default: + return 0; + case Mfolder: + flags = "(\\Noselect)"; + break; + case Mdir: + case Mbox: + s = impname(path); + if(s != nil && mtime(s) < d->mtime) + flags = "(\\Noinferiors \\Marked)"; + else + flags = "(\\Noinferiors)"; + break; + } + + if(!term) + return 1; + + if(s = strmutf7(decfs(dec, sizeof dec, path))) + Bprint(&bout, "* %s %s \"/\" %#Z\r\n", cmd, flags, s); + return 1; +} + +static int +rematch(char *cmd, char *wd, char *pat, Dir *d) +{ + char nwd[Pathlen]; + + appendwd(nwd, sizeof nwd, wd, d->name); + if(d->mode & DMDIR) + if(chkmbox(nwd, d->mode) == Mfolder) + if(lmatch(cmd, pat, nwd)) + return 1; + return 0; +} + +static int +match(char *cmd, char *wd, char *pat, Dir *d, int i) +{ + char *p, *p1; + int m, n; + Rune r, r1; + + m = 0; + for(p = pat; ; p = p1){ + n = chartorune(&r, p); + p1 = p + n; + dprint("r = %C [%.2ux]\n", r, r); + switch(r){ + case '*': + case '%': + for(r1 = 1; r1;){ + if(match(cmd, wd, p1, d, i)) + if(output(cmd, wd, d, 0)){ + m++; + break; + } + i += chartorune(&r1, d->name + i); + } + if(r == '*' && rematch(cmd, wd, p, d)) + return 1; + if(m > 0) + return 1; + break; + case '/': + return rematch(cmd, wd, p1, d); + default: + chartorune(&r1, d->name + i); + if(r1 != r) + return 0; + if(r == 0) + return output(cmd, wd, d, 1); + dprint(" r %C ~ %C [%.2ux]\n", r, r1, r1); + i += n; + break; + } + } +} + +static int +lmatch(char *cmd, char *pat, char *wd) +{ + char dec[Pathlen]; + int fd, n, m, i; + Dir *d; + + if((fd = mopen(wd[0]? wd: ".", OREAD)) == -1) + return -1; + if(wd[0]) + dprint("wd %s\n", wd); + m = 0; + for(;;){ + n = dirread(fd, &d); + if(n <= 0) + break; + for(i = 0; i < n; i++) + if(mokmbox(d[i].name)){ + d[i].name = decfs(dec, sizeof dec, d[i].name); + m += match(cmd, wd, pat, d + i, 0); + } + free(d); + } + close(fd); + return m; +} + +int +listboxes(char *cmd, char *ref, char *pat) +{ + char buf[Pathlen]; + + pat = appendwd(buf, sizeof buf, ref, pat); + return lmatch(cmd, pat, "") > 0; +} + +static int +opensubscribed(void) +{ + int fd; + + fd = cdopen(mboxdir, subscribed, ORDWR); + if(fd >= 0) + return fd; + fd = cdcreate(mboxdir, subscribed, ORDWR, 0664); + if(fd < 0) + return -1; + fprint(fd, "#imap4 subscription list\nINBOX\n"); + seek(fd, 0, 0); + return fd; +} + +/* + * resistance to hand-edits + */ +static char* +trim(char *s, int l) +{ + int c; + + for(;; l--){ + if(l == 0) + return 0; + c = s[l - 1]; + if(c != '\t' && c != ' ') + break; + } + for(s[l] = 0; c = *s; s++) + if(c != '\t' && c != ' ') + break; + if(c == 0 || c == '#') + return 0; + return s; +} + +static int +poutput(char *cmd, char *f, int term) +{ + char *p, *wd; + int r; + Dir *d; + + if(!mokmbox(f) || !(d = mdirstat(f))) + return 0; + wd = ""; + if(p = strrchr(f, '/')){ + *p = 0; + wd = f; + } + r = output(cmd, wd, d, term); + if(p) + *p = '/'; + free(d); + return r; +} + +static int +pmatch(char *cmd, char *pat, char *f, int i) +{ + char *p, *p1; + int m, n; + Rune r, r1; + + dprint("pmatch pat[%s] f[%s]\n", pat, f + i); + m = 0; + for(p = pat; ; p = p1){ + n = chartorune(&r, p); + p1 = p + n; + switch(r){ + case '*': + case '%': + for(r1 = 1; r1;){ + if(pmatch(cmd, p1, f, i)) + if(poutput(cmd, f, 0)){ + m++; + break; + } + i += chartorune(&r1, f + i); + if(r == '%' && r1 == '/') + break; + } + if(m > 0) + return 1; + break; + default: + chartorune(&r1, f + i); + if(r1 != r) + return 0; + if(r == 0) + return poutput(cmd, f, 1); + i += n; + break; + } + } +} + +int +lsubboxes(char *cmd, char *ref, char *pat) +{ + char *s, buf[Pathlen]; + int r, fd; + Biobuf b; + Mblock *l; + + pat = appendwd(buf, sizeof buf, ref, pat); + if((l = mblock()) == nil) + return 0; + fd = opensubscribed(); + r = 0; + Binit(&b, fd, OREAD); + while(s = Brdline(&b, '\n')) + if(s = trim(s, Blinelen(&b) - 1)) + r += pmatch(cmd, pat, s, 0); + Bterm(&b); + close(fd); + mbunlock(l); + return r; +} + +int +subscribe(char *mbox, int how) +{ + char *s, *in, *ein; + int fd, tfd, ok, l; + Mblock *mb; + + if(cistrcmp(mbox, "inbox") == 0) + mbox = "INBOX"; + if((mb = mblock()) == nil) + return 0; + fd = opensubscribed(); + if(fd < 0 || (in = readfile(fd)) == nil){ + close(fd); + mbunlock(mb); + return 0; + } + l = strlen(mbox); + s = strstr(in, mbox); + while(s != nil && (s != in && s[-1] != '\n' || s[l] != '\n')) + s = strstr(s + 1, mbox); + ok = 0; + if(how == 's' && s == nil){ + if(chkmboxpath(mbox) > 0) + if(fprint(fd, "%s\n", mbox) > 0) + ok = 1; + }else if(how == 'u' && s != nil){ + ein = strchr(s, 0); + memmove(s, &s[l+1], ein - &s[l+1]); + ein -= l + 1; + tfd = cdopen(mboxdir, subscribed, OWRITE|OTRUNC); + if(tfd >= 0 && pwrite(fd, in, ein - in, 0) == ein - in) + ok = 1; + close(tfd); + }else + ok = 1; + close(fd); + mbunlock(mb); + return ok; +} |