This port is the work of David du Colombier with contributions from Justin Bedo. diff -Nru /n/sources/plan9/acme/mail/src/dat.h /acme/mail/src/dat.h --- /n/sources/plan9/acme/mail/src/dat.h Tue Jan 19 23:37:34 2010 +++ /acme/mail/src/dat.h Tue Apr 17 00:00:00 2012 @@ -7,7 +7,7 @@ { STACK = 8192, EVENTSIZE = 256, - NEVENT = 5, + NEVENT = 5 }; struct Event @@ -25,6 +25,10 @@ struct Window { + /* coordinate wineventproc and window thread */ + QLock lk; + int ref; + /* file descriptors */ int ctl; int event; @@ -57,13 +61,15 @@ uchar tagposted; uchar recursed; uchar level; + uint replywinid; /* header info */ - char *fromcolon; /* from header file; all rest are from info file */ char *from; + char *fromcolon; char *to; char *cc; char *replyto; + char *sender; char *date; char *subject; char *type; @@ -112,6 +118,8 @@ extern char* winreadbody(Window*, int*); extern void windormant(Window*); extern void winsetdump(Window*, char*, char*); +extern void winincref(Window*); +extern void windecref(Window*); extern void readmbox(Message*, char*, char*); extern void rewritembox(Window*, Message*); @@ -133,6 +141,7 @@ extern Message* mesglookup(Message*, char*, char*); extern Message* mesglookupfile(Message*, char*, char*); extern void mesgfreeparts(Message*); +extern int mesgcommand(Message*, char*); extern char* readfile(char*, char*, int*); extern char* readbody(char*, char*, int*); @@ -159,7 +168,10 @@ extern char *home; extern char *outgoing; extern char *mailboxdir; +extern char *mboxname; extern char *user; +extern char *srvname; extern char deleted[]; extern int wctlfd; extern int shortmenu; + diff -Nru /n/sources/plan9/acme/mail/src/html.c /acme/mail/src/html.c --- /n/sources/plan9/acme/mail/src/html.c Thu Jul 17 17:40:59 2003 +++ /acme/mail/src/html.c Tue Apr 17 00:00:00 2012 @@ -6,7 +6,6 @@ #include #include "dat.h" - char* formathtml(char *body, int *np) { @@ -27,7 +26,11 @@ e->argv[0] = estrdup("htmlfmt"); e->argv[1] = estrdup("-cutf-8"); e->argv[2] = nil; +#ifdef PLAN9PORT + e->prog = "htmlfmt"; +#else e->prog = "/bin/htmlfmt"; +#endif sync = chancreate(sizeof(int), 0); e->sync = sync; proccreate(execproc, e, EXECSTACK); diff -Nru /n/sources/plan9/acme/mail/src/mail.c /acme/mail/src/mail.c --- /n/sources/plan9/acme/mail/src/mail.c Sat Sep 17 15:36:59 2005 +++ /acme/mail/src/mail.c Tue Apr 17 00:00:00 2012 @@ -13,6 +13,7 @@ char *fsname; /* filesystem for mailboxdir/mboxname is at maildir/fsname */ char *user; char *outgoing; +char *srvname; Window *wbox; Message mbox; @@ -39,7 +40,7 @@ void usage(void) { - fprint(2, "usage: Mail [-sS] [-o outgoing] [mailboxname [directoryname]]\n"); + fprint(2, "usage: Mail [-sS] [-n srvname] [-o outgoing] [mailboxname [directoryname]]\n"); threadexitsall("usage"); } @@ -82,11 +83,15 @@ quotefmtinstall(); /* open these early so we won't miss notification of new mail messages while we read mbox */ - plumbsendfd = plumbopen("send", OWRITE|OCEXEC); - plumbseemailfd = plumbopen("seemail", OREAD|OCEXEC); - plumbshowmailfd = plumbopen("showmail", OREAD|OCEXEC); + if(plumbsendfd = plumbopen("send", OWRITE|OCEXEC) < 0) + fprint(2, "warning: open plumb/send: %r\n"); + if(plumbseemailfd = plumbopen("seemail", OREAD|OCEXEC) < 0) + fprint(2, "warning: open plumb/seemail: %r\n"); + if(plumbshowmailfd = plumbopen("showmail", OREAD|OCEXEC) < 0) + fprint(2, "warning: open plumb/showmail: %r\n"); shortmenu = 0; + srvname = "mail"; ARGBEGIN{ case 's': shortmenu = 1; @@ -100,6 +105,9 @@ case 'm': smprint(maildir, "%s/", EARGF(usage())); break; + case 'n': + srvname = EARGF(usage()); + break; default: usage(); }ARGEND @@ -116,9 +124,9 @@ if(argc>2 || i==0) usage(); /* see if the name is that of an existing /mail/fs directory */ - if(argc==1 && strchr(argv[0], '/')==0 && ismaildir(argv[0])){ + if(argc==1 && argv[0][0] != '/' && ismaildir(argv[0])){ name = argv[0]; - mboxname = eappend(estrdup(maildir), "", name); + mboxname = estrdup(name); newdir = 0; }else{ if(argv[0][i-1] == '/') @@ -148,8 +156,8 @@ if(outgoing == nil) outgoing = estrstrdup(mailboxdir, "/outgoing"); - s = estrstrdup(maildir, "ctl"); - mbox.ctlfd = open(s, ORDWR|OCEXEC); + s = estrstrdup(estrstrdup(maildir, mboxname), "/ctl"); + mbox.ctlfd = open(s, OWRITE); if(mbox.ctlfd < 0) error("can't open %s: %r", s); @@ -219,6 +227,7 @@ proccreate(plumbproc, nil, STACK); proccreate(plumbshowproc, nil, STACK); threadcreate(plumbshowthread, nil, STACK); + write(mbox.ctlfd, "refresh", 7); /* ... and use this thread to read the messages */ plumbthread(); } @@ -286,26 +295,35 @@ showmesg(char *name, char *digest) { char *n; + char *mb; - if(strncmp(name, mbox.name, strlen(mbox.name)) != 0) + mb = mbox.name; + if(strncmp(name, mb, strlen(mb)) != 0) return; /* message is about another mailbox */ - n = estrdup(name+strlen(mbox.name)); + n = estrdup(name+strlen(mb)); if(n[strlen(n)-1] != '/') n = egrow(n, "/", nil); - mesgopen(&mbox, mbox.name, name+strlen(mbox.name), nil, 1, digest); + mesgopen(&mbox, mbox.name, name+strlen(mb), nil, 1, digest); free(n); } void -delmesg(char *name, char *digest, int dodel) +delmesg(char *name, char *digest, int dodel, char *save) { Message *m; m = mesglookupfile(&mbox, name, digest); if(m != nil){ - mesgmenumarkdel(wbox, &mbox, m, 0); + if(save) + mesgcommand(m, estrstrdup("Save ", save)); if(dodel) - m->writebackdel = 1; + mesgmenumarkdel(wbox, &mbox, m, 1); + else{ + /* notification came from plumber - message is gone */ + mesgmenudel(wbox, &mbox, m); + if(!m->opened) + mesgdel(&mbox, m); + } } } @@ -326,7 +344,7 @@ else if(strcmp(type, "new") == 0) newmesg(m->data, digest); else if(strcmp(type, "delete") == 0) - delmesg(m->data, digest, 0); + delmesg(m->data, digest, 0, nil); else fprint(2, "Mail: unknown plumb attribute %s\n", type); plumbfree(m); @@ -335,10 +353,11 @@ } void -plumbshowthread(void*) +plumbshowthread(void *v) { Plumbmsg *m; + USED(v); threadsetname("plumbshowthread"); while((m = recvp(cplumbshow)) != nil){ showmesg(m->data, plumblookup(m->attr, "digest")); @@ -348,10 +367,11 @@ } void -plumbsendthread(void*) +plumbsendthread(void *v) { Plumbmsg *m; + USED(v); threadsetname("plumbsendthread"); while((m = recvp(cplumbsend)) != nil){ mkreply(nil, "Mail", m->data, m->attr, nil); @@ -363,7 +383,7 @@ int mboxcommand(Window *w, char *s) { - char *args[10], **targs; + char *args[10], **targs, *save; Message *m, *next; int ok, nargs, i, j; char buf[128]; @@ -414,13 +434,14 @@ rewritembox(wbox, &mbox); return 1; } + if(strcmp(s, "Get") == 0){ + write(mbox.ctlfd, "refresh", 7); + return 1; + } if(strcmp(s, "Delmesg") == 0){ - if(nargs > 1){ - for(i=1; i 1) + save = args[1]; s = winselection(w); if(s == nil) return 1; @@ -437,7 +458,7 @@ if(j == 0) continue; snprint(buf, sizeof buf, "%s%d", mbox.name, j); - delmesg(buf, nil, 1); + delmesg(buf, nil, 1, save); } free(s); free(targs); @@ -455,6 +476,7 @@ char *s, *t, *buf; w = v; + winincref(w); proccreate(wineventproc, w, STACK); for(;;){ diff -Nru /n/sources/plan9/acme/mail/src/mesg.c /acme/mail/src/mesg.c --- /n/sources/plan9/acme/mail/src/mesg.c Tue Jan 19 23:44:18 2010 +++ /acme/mail/src/mesg.c Tue Apr 17 00:00:00 2012 @@ -44,16 +44,7 @@ "text/richtext", "text/tab-separated-values", "application/octet-stream", - nil, -}; - -struct{ - char *type; - char *ext; -} exts[] = { - "image/gif", ".gif", - "image/jpeg", ".jpg", - nil, nil + nil }; char *okheaders[] = @@ -71,7 +62,7 @@ "Resent-From:", "Resent-To:", "Sort:", - nil, + nil }; char* @@ -90,56 +81,122 @@ return q; } -void -scanheaders(Message *m, char *dir) +static char* +mkaddrs(char *t, char **colon) { - char *s, *t, *u, *f; - - s = f = readfile(dir, "header", nil); - if(s != nil) - while(*s){ - t = line(s, &s); - if(strncmp(t, "From: ", 6) == 0){ - m->fromcolon = estrdup(t+6); - /* remove all quotes; they're ugly and irregular */ - for(u=m->fromcolon; *u; u++) - if(*u == '"') - memmove(u, u+1, strlen(u)); - } - if(strncmp(t, "Subject: ", 9) == 0) - m->subject = estrdup(t+9); - free(t); + int i, nf, inquote; + char **f, *s; + Fmt fmt; + + inquote = 0; + nf = 2; + for(s=t; *s; s++){ + if(*s == '\'') + inquote = !inquote; + if(*s == ' ' && !inquote) + nf++; + } + f = emalloc(nf*sizeof f[0]); + nf = tokenize(t, f, nf); + if(colon){ + fmtstrinit(&fmt); + for(i=0; i+1 0) + fmtprint(&fmt, ", "); + if(f[i][0] == 0 || strcmp(f[i], f[i+1]) == 0) + fmtprint(&fmt, "%s", f[i+1]); + else + fmtprint(&fmt, "%s <%s>", f[i], f[i+1]); } - if(m->fromcolon == nil) - m->fromcolon = estrdup(m->from); + *colon = fmtstrflush(&fmt); + } + fmtstrinit(&fmt); + for(i=0; i+1 0) + fmtprint(&fmt, ", "); + fmtprint(&fmt, "%s", f[i+1]); + } free(f); + return fmtstrflush(&fmt); } int loadinfo(Message *m, char *dir) { int n; - char *data, *p, *s; + char *data, *p, *s, *t; data = readfile(dir, "info", &n); if(data == nil) return 0; - m->from = line(data, &p); - scanheaders(m, dir); /* depends on m->from being set */ - m->to = line(p, &p); - m->cc = line(p, &p); - m->replyto = line(p, &p); - m->date = line(p, &p); - s = line(p, &p); - if(m->subject == nil) - m->subject = s; - else + + p = data; + while((s = line(p, &p)) != nil && *s != 0){ + t = strchr(s, ' '); + if(t == nil) + continue; + *t++ = 0; + if(strcmp(s, "from") == 0){ + free(m->from); + m->from = mkaddrs(t, &m->fromcolon); + }else if(strcmp(s, "sender") == 0){ + free(m->sender); + m->sender = mkaddrs(t, nil); + }else if(strcmp(s, "to") == 0){ + free(m->to); + m->to = mkaddrs(t, nil); + }else if(strcmp(s, "cc") == 0){ + free(m->cc); + m->cc = mkaddrs(t, nil); + }else if(strcmp(s, "replyto") == 0){ + free(m->replyto); + m->replyto = mkaddrs(t, nil); + }else if(strcmp(s, "subject") == 0){ + free(m->subject); + m->subject = estrdup(t); + }else if(strcmp(s, "type") == 0){ + free(m->type); + m->type = estrdup(t); + }else if(strcmp(s, "unixdate") == 0 && (t=strchr(t, ' ')) != nil){ + free(m->date); + m->date = estrdup(t+1); + }else if(strcmp(s, "digest") == 0){ + free(m->digest); + m->digest = estrdup(t); + }else if(strcmp(s, "filename") == 0){ + free(m->filename); + m->filename = estrdup(t); + } free(s); - m->type = line(p, &p); - m->disposition = line(p, &p); - m->filename = line(p, &p); - m->digest = line(p, &p); + } + free(s); free(data); + if(m->replyto == nil){ + if(m->sender) + m->replyto = estrdup(m->sender); + else if(m->from) + m->replyto = estrdup(m->from); + else + m->replyto = estrdup(""); + } + if(m->from == nil) + m->from = estrdup(""); + if(m->to == nil) + m->to = estrdup(""); + if(m->cc == nil) + m->cc = estrdup(""); + if(m->subject == nil) + m->subject = estrdup(""); + if(m->type == nil) + m->type = estrdup(""); + if(m->date == nil) + m->date = estrdup(""); + if(m->disposition == nil) + m->disposition = estrdup(""); + if(m->filename == nil) + m->filename = estrdup(""); + if(m->digest == nil) + m->digest = estrdup(""); return 1; } @@ -272,6 +329,7 @@ char *file, *data; int fd, len; Dir *d; + char buf[1]; if(np != nil) *np = 0; @@ -280,13 +338,25 @@ if(fd < 0) return nil; d = dirfstat(fd); + if(d && d->length == 0){ + /* some files, e.g. body, are not loaded until we read them */ + read(fd, buf, 1); + seek(fd, 0, 0); + free(d); + d = dirfstat(fd); + } free(file); len = 0; if(d != nil) len = d->length; free(d); data = emalloc(len+1); - read(fd, data, len); + len = read(fd, data, len); + if(len <= 0){ + close(fd); + free(data); + return nil; + } close(fd); if(np != nil) *np = len; @@ -397,9 +467,7 @@ winselect(w, "0", 0); w->data = winopenfile(w, "data"); b = emalloc(sizeof(Biobuf)); - Binit(b, w->data, OWRITE); mesgmenu0(w, mbox, mbox->name, "", 0, b, 1, !shortmenu); - Bterm(b); free(b); if(!mbox->dirty) winclean(w); @@ -457,10 +525,11 @@ } void -mesgmenumarkundel(Window *w, Message*, Message *m) +mesgmenumarkundel(Window *w, Message *v, Message *m) { char *buf; + USED(v); if(m->deleted == 0) return; if(w->data < 0) @@ -481,16 +550,17 @@ { char *buf; + USED(mbox); if(w->data < 0) w->data = winopenfile(w, "data"); - buf = name2regexp(deletedrx, m->name); + buf = name2regexp(deletedrx01, m->name); if(winsetaddr(w, buf, 1) && winsetaddr(w, ".,./.*\\n(\t.*\\n)*/", 1)) write(w->data, "", 0); free(buf); close(w->data); close(w->addr); w->addr = w->data = -1; - mbox->dirty = 1; +/* assume caller knows best mbox->dirty = 1; */ m->deleted = 1; } @@ -517,7 +587,6 @@ { free(m->name); free(m->replyname); - free(m->fromcolon); free(m->from); free(m->to); free(m->cc); @@ -556,11 +625,19 @@ } int -mesgsave(Message *m, char *s) +mesgsave(Message *m, char *s, int save) { int ofd, n, k, ret; char *t, *raw, *unixheader, *all; + if(save){ + if(fprint(mbox.ctlfd, "save %q %q", s, m->name) < 0){ + fprint(2, "Mail: can't save %s to %s: %r\n", m->name, s); + return 0; + } + return 1; + } + t = estrstrdup(mbox.name, m->name); raw = readfile(t, "raw", &n); unixheader = readfile(t, "unixheader", &k); @@ -601,7 +678,7 @@ { char *s; char *args[10]; - int ok, ret, nargs; + int save, ok, ret, nargs; s = cmd; ret = 1; @@ -612,14 +689,18 @@ mesgsend(m); goto Return; } - if(strncmp(args[0], "Save", 4) == 0){ + if(strncmp(args[0], "Save", 4) == 0 || strncmp(args[0], "Write", 5) == 0){ if(m->isreply) goto Return; - s = estrdup("\t[saved"); + save = args[0][0]=='S'; + if(save) + s = estrdup("\t[saved"); + else + s = estrdup("\t[wrote"); if(nargs==1 || strcmp(args[1], "")==0){ - ok = mesgsave(m, "stored"); + ok = mesgsave(m, "stored", save); }else{ - ok = mesgsave(m, args[1]); + ok = mesgsave(m, args[1], save); s = eappend(s, " ", args[1]); } if(ok){ @@ -646,8 +727,7 @@ } if(strcmp(args[0], "Del") == 0){ if(windel(m->w, 0)){ - chanfree(m->w->cevent); - free(m->w); + windecref(m->w); m->w = nil; if(m->isreply) delreply(m); @@ -674,10 +754,10 @@ mesgmenumarkundel(wbox, &mbox, m); goto Return; } -// if(strcmp(args[0], "Headers") == 0){ -// m->showheaders(); -// return True; -// } +/* if(strcmp(args[0], "Headers") == 0){ */ +/* m->showheaders(); */ +/* return True; */ +/* } */ ret = 0; @@ -812,6 +892,7 @@ m = v; w = m->w; threadsetname("mesgctl"); + winincref(w); proccreate(wineventproc, w, STACK); for(;;){ e = recvp(w->cevent); @@ -881,9 +962,9 @@ s += strlen(mbox.name); if(strstr(s, "body") != nil){ /* strip any known extensions */ - for(i=0; exts[i].ext!=nil; i++){ - j = strlen(exts[i].ext); - if(strlen(s)>j && strcmp(s+strlen(s)-j, exts[i].ext)==0){ + for(i=0; ports[i].suffix!=nil; i++){ + j = strlen(ports[i].suffix); + if(strlen(s)>j && strcmp(s+strlen(s)-j, ports[i].suffix)==0){ s[strlen(s)-j] = '\0'; break; } @@ -940,9 +1021,9 @@ { int i; - for(i=0; exts[i].type!=nil; i++) - if(strcmp(type, exts[i].type)==0) - return exts[i].ext; + for(i=0; ports[i].type!=nil; i++) + if(strcmp(type, ports[i].type)==0) + return ports[i].suffix; return ""; } @@ -951,11 +1032,11 @@ { char *dest, *maildest; - if(strcmp(m->disposition, "file")==0 || strlen(m->filename)!=0){ - if(strlen(m->filename) == 0){ - dest = estrdup(m->name); - dest[strlen(dest)-1] = '\0'; - }else + USED(rootdir); + if(strcmp(m->disposition, "file")==0 || strlen(m->filename)!=0 || !fileonly){ + if(strlen(m->filename) == 0) + dest = estrstrdup("a", ext(m->type)); + else dest = estrdup(m->filename); if(maildest = getenv("maildest")){ maildest = eappend(maildest, "/", dest); @@ -967,8 +1048,7 @@ } Bprint(w->body, "\tcp %s%sbody%s %q\n", rootdir, name, ext(m->type), dest); free(dest); - }else if(!fileonly) - Bprint(w->body, "\tfile is %s%sbody%s\n", rootdir, name, ext(m->type)); + } } void @@ -1070,11 +1150,15 @@ int tokenizec(char *str, char **args, int max, char *splitc) { - int na; + int i, na; int intok = 0; + char *p; if(max <= 0) - return 0; + return 0; + +/* if(strchr(str, ',') || strchr(str, '"') || strchr(str, '<') || strchr(str, '(')) */ +/* splitc = ","; */ for(na=0; *str != '\0';str++){ if(strchr(splitc, *str) == nil){ if(intok) @@ -1091,6 +1175,13 @@ } } } + for(i=0; iargs[i] && strchr(" \t\r\n", *(p-1))) + *--p = 0; + } return na; } @@ -1101,7 +1192,7 @@ Message *m; char *t; - if(digest){ + if(digest && digest[0]){ /* can find exactly */ for(m=mbox->head; m!=nil; m=m->next) if(strcmp(digest, m->digest) == 0) @@ -1248,6 +1339,7 @@ winopenbody(m->w, OWRITE); mesgload(m, dir, m->name, m->w); winclosebody(m->w); + /* sleep(100); */ winclean(m->w); m->opened = 1; if(ndirelem == 1){ @@ -1321,7 +1413,7 @@ k = strlen(name); n = strlen(mbox->name); if(k==0 || strncmp(name, mbox->name, n) != 0){ -// fprint(2, "Mail: message %s not in this mailbox\n", name); +/* fprint(2, "Mail: message %s not in this mailbox\n", name); */ return nil; } return mesglookup(mbox, name+n, digest); diff -Nru /n/sources/plan9/acme/mail/src/reply.c /acme/mail/src/reply.c --- /n/sources/plan9/acme/mail/src/reply.c Tue Jan 19 23:44:18 2010 +++ /acme/mail/src/reply.c Tue Apr 17 00:00:00 2012 @@ -69,12 +69,25 @@ void mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext) { + char buf[100]; + Biobuf *fd; Message *r; char *dir, *t; int quotereply; Plumbattr *a; quotereply = (label[0] == 'Q'); + + if(quotereply && m && m->replywinid > 0){ + snprint(buf, sizeof buf, "/mnt/wsys/%d/body", m->replywinid); + if((fd = Bopen(buf, OWRITE)) != nil){ + dir = estrstrdup(mbox.name, m->name); + quote(m, fd, dir, quotetext); + free(dir); + return; + } + } + r = emalloc(sizeof(Message)); r->isreply = 1; if(m != nil) @@ -89,6 +102,8 @@ r->name = emalloc(strlen(mbox.name)+strlen(label)+10); sprint(r->name, "%s%s%d", mbox.name, label, ++replyid); r->w = newwindow(); + if(m) + m->replywinid = r->w->id; winname(r->w, r->name); ctlprint(r->w->ctl, "cleartag"); wintagwrite(r->w, "fmt Look Post Undo", 4+5+5+4); @@ -210,14 +225,6 @@ close(q[1]); } procexec(nil, prog, argv); -//fprint(2, "exec: %s", e->prog); -//{int i; -//for(i=0; argv[i]; i++) print(" '%s'", argv[i]); -//print("\n"); -//} -//argv[0] = "cat"; -//argv[1] = nil; -//procexec(nil, "/bin/cat", argv); fprint(2, "Mail: can't exec %s: %r\n", prog); threadexits("can't exec"); } @@ -228,7 +235,7 @@ CC, FROM, INCLUDE, - TO, + TO }; char *headers[] = { @@ -238,7 +245,7 @@ "from:", "include:", "to:", - nil, + nil }; int @@ -466,6 +473,7 @@ if(ofd > 0){ /* From dhog Fri Aug 24 22:13:00 EDT 2001 */ now = ctime(time(0)); + seek(ofd, 0, 2); fprint(ofd, "From %s %s", user, now); fprint(ofd, "From: %s\n", user); fprint(ofd, "Date: %s", now); @@ -484,7 +492,11 @@ error("can't create pipe: %r"); e->p[0] = p[0]; e->p[1] = p[1]; +#ifdef PLAN9PORT + e->prog = unsharp("#9/bin/upas/marshal"); +#else e->prog = "/bin/upas/marshal"; +#endif e->argv = emalloc((1+1+2+4*natt+1)*sizeof(char*)); e->argv[0] = estrdup("marshal"); e->argv[1] = estrdup("-8"); @@ -504,7 +516,7 @@ e->sync = sync; proccreate(execproc, e, EXECSTACK); recvul(sync); - close(p[0]); + /* close(p[0]); */ /* using marshal -8, so generate rfc822 headers */ if(nto > 0){ diff -Nru /n/sources/plan9/acme/mail/src/win.c /acme/mail/src/win.c --- /n/sources/plan9/acme/mail/src/win.c Sun Oct 6 20:42:35 2002 +++ /acme/mail/src/win.c Tue Apr 17 00:00:00 2012 @@ -22,10 +22,32 @@ w->body = nil; w->data = -1; w->cevent = chancreate(sizeof(Event*), 0); + w->ref = 1; return w; } void +winincref(Window *w) +{ + qlock(&w->lk); + ++w->ref; + qunlock(&w->lk); +} + +void +windecref(Window *w) +{ + qlock(&w->lk); + if(--w->ref > 0){ + qunlock(&w->lk); + return; + } + close(w->event); + chanfree(w->cevent); + free(w); +} + +void winsetdump(Window *w, char *dir, char *cmd) { if(dir != nil) @@ -121,6 +143,7 @@ w->nbuf = read(w->event, w->buf, sizeof w->buf); if(w->nbuf <= 0){ /* probably because window has exited, and only called by wineventproc, so just shut down */ + windecref(w); threadexits(nil); } w->bufp = w->buf;