mirror of
https://hacklab.nilfm.cc/acme
synced 2024-10-22 14:31:48 +00:00
645 lines
13 KiB
C
645 lines
13 KiB
C
|
#include <u.h>
|
||
|
#include <libc.h>
|
||
|
#include <bio.h>
|
||
|
#include <thread.h>
|
||
|
#include <9pclient.h>
|
||
|
#include <plumb.h>
|
||
|
#include <ctype.h>
|
||
|
#include "dat.h"
|
||
|
|
||
|
char *maildir = "Mail/"; /* mountpoint of mail file system */
|
||
|
char *mboxname = "mbox"; /* mailboxdir/mboxname is mail spool file */
|
||
|
char *mailboxdir = nil; /* nil == /mail/box/$user */
|
||
|
char *fsname; /* filesystem for mailboxdir/mboxname is at maildir/fsname */
|
||
|
char *user;
|
||
|
char *outgoing;
|
||
|
char *srvname;
|
||
|
|
||
|
Window *wbox;
|
||
|
Message mbox;
|
||
|
Message replies;
|
||
|
char *home;
|
||
|
CFid *plumbsendfd;
|
||
|
CFid *plumbseemailfd;
|
||
|
CFid *plumbshowmailfd;
|
||
|
CFid *plumbsendmailfd;
|
||
|
Channel *cplumb;
|
||
|
Channel *cplumbshow;
|
||
|
Channel *cplumbsend;
|
||
|
int wctlfd;
|
||
|
void mainctl(void*);
|
||
|
void plumbproc(void*);
|
||
|
void plumbshowproc(void*);
|
||
|
void plumbsendproc(void*);
|
||
|
void plumbthread(void);
|
||
|
void plumbshowthread(void*);
|
||
|
void plumbsendthread(void*);
|
||
|
|
||
|
int shortmenu;
|
||
|
|
||
|
CFsys *mailfs;
|
||
|
CFsys *acmefs;
|
||
|
|
||
|
void
|
||
|
usage(void)
|
||
|
{
|
||
|
fprint(2, "usage: Mail [-sS] [-n srvname] [-o outgoing] [mailboxname [directoryname]]\n");
|
||
|
threadexitsall("usage");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
removeupasfs(void)
|
||
|
{
|
||
|
char buf[256];
|
||
|
|
||
|
if(strcmp(mboxname, "mbox") == 0)
|
||
|
return;
|
||
|
snprint(buf, sizeof buf, "close %s", mboxname);
|
||
|
fswrite(mbox.ctlfd, buf, strlen(buf));
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ismaildir(char *s)
|
||
|
{
|
||
|
Dir *d;
|
||
|
int ret;
|
||
|
|
||
|
d = fsdirstat(mailfs, s);
|
||
|
if(d == nil)
|
||
|
return 0;
|
||
|
ret = d->qid.type & QTDIR;
|
||
|
free(d);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
threadmain(int argc, char *argv[])
|
||
|
{
|
||
|
char *s, *name;
|
||
|
char err[ERRMAX], *cmd;
|
||
|
int i, newdir;
|
||
|
Fmt fmt;
|
||
|
|
||
|
doquote = needsrcquote;
|
||
|
quotefmtinstall();
|
||
|
|
||
|
/* open these early so we won't miss notification of new mail messages while we read mbox */
|
||
|
if((plumbsendfd = plumbopenfid("send", OWRITE|OCEXEC)) == nil)
|
||
|
fprint(2, "warning: open plumb/send: %r\n");
|
||
|
if((plumbseemailfd = plumbopenfid("seemail", OREAD|OCEXEC)) == nil)
|
||
|
fprint(2, "warning: open plumb/seemail: %r\n");
|
||
|
if((plumbshowmailfd = plumbopenfid("showmail", OREAD|OCEXEC)) == nil)
|
||
|
fprint(2, "warning: open plumb/showmail: %r\n");
|
||
|
|
||
|
shortmenu = 0;
|
||
|
srvname = "mail";
|
||
|
ARGBEGIN{
|
||
|
case 's':
|
||
|
shortmenu = 1;
|
||
|
break;
|
||
|
case 'S':
|
||
|
shortmenu = 2;
|
||
|
break;
|
||
|
case 'o':
|
||
|
outgoing = EARGF(usage());
|
||
|
break;
|
||
|
case 'm':
|
||
|
smprint(maildir, "%s/", EARGF(usage()));
|
||
|
break;
|
||
|
case 'n':
|
||
|
srvname = EARGF(usage());
|
||
|
break;
|
||
|
default:
|
||
|
usage();
|
||
|
}ARGEND
|
||
|
|
||
|
acmefs = nsmount("acme",nil);
|
||
|
if(acmefs == nil)
|
||
|
error("cannot mount acme: %r");
|
||
|
mailfs = nsmount(srvname, nil);
|
||
|
if(mailfs == nil)
|
||
|
error("cannot mount %s: %r", srvname);
|
||
|
|
||
|
name = "mbox";
|
||
|
|
||
|
newdir = 1;
|
||
|
if(argc > 0){
|
||
|
i = strlen(argv[0]);
|
||
|
if(argc>2 || i==0)
|
||
|
usage();
|
||
|
/* see if the name is that of an existing /mail/fs directory */
|
||
|
if(argc==1 && argv[0][0] != '/' && ismaildir(argv[0])){
|
||
|
name = argv[0];
|
||
|
mboxname = estrdup(name);
|
||
|
newdir = 0;
|
||
|
}else{
|
||
|
if(argv[0][i-1] == '/')
|
||
|
argv[0][i-1] = '\0';
|
||
|
s = strrchr(argv[0], '/');
|
||
|
if(s == nil)
|
||
|
mboxname = estrdup(argv[0]);
|
||
|
else{
|
||
|
*s++ = '\0';
|
||
|
if(*s == '\0')
|
||
|
usage();
|
||
|
mailboxdir = argv[0];
|
||
|
mboxname = estrdup(s);
|
||
|
}
|
||
|
if(argc > 1)
|
||
|
name = argv[1];
|
||
|
else
|
||
|
name = mboxname;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
user = getenv("user");
|
||
|
if(user == nil)
|
||
|
user = "none";
|
||
|
home = getenv("home");
|
||
|
if(home == nil)
|
||
|
home = getenv("HOME");
|
||
|
if(home == nil)
|
||
|
error("can't find $home");
|
||
|
if(mailboxdir == nil)
|
||
|
mailboxdir = estrstrdup(home, "/mail");
|
||
|
if(outgoing == nil)
|
||
|
outgoing = estrstrdup(mailboxdir, "/outgoing");
|
||
|
|
||
|
mbox.ctlfd = fsopen(mailfs, estrstrdup(mboxname, "/ctl"), OWRITE);
|
||
|
if(mbox.ctlfd == nil)
|
||
|
error("can't open %s: %r", estrstrdup(mboxname, "/ctl"));
|
||
|
|
||
|
fsname = estrdup(name);
|
||
|
if(newdir && argc > 0){
|
||
|
s = emalloc(5+strlen(mailboxdir)+strlen(mboxname)+strlen(name)+10+1);
|
||
|
for(i=0; i<10; i++){
|
||
|
sprint(s, "open %s/%s %s", mailboxdir, mboxname, fsname);
|
||
|
if(fswrite(mbox.ctlfd, s, strlen(s)) >= 0)
|
||
|
break;
|
||
|
err[0] = '\0';
|
||
|
errstr(err, sizeof err);
|
||
|
if(strstr(err, "mbox name in use") == nil)
|
||
|
error("can't create directory %s for mail: %s", name, err);
|
||
|
free(fsname);
|
||
|
fsname = emalloc(strlen(name)+10);
|
||
|
sprint(fsname, "%s-%d", name, i);
|
||
|
}
|
||
|
if(i == 10)
|
||
|
error("can't open %s/%s: %r", mailboxdir, mboxname);
|
||
|
free(s);
|
||
|
}
|
||
|
|
||
|
s = estrstrdup(fsname, "/");
|
||
|
mbox.name = estrstrdup(maildir, s);
|
||
|
mbox.level= 0;
|
||
|
readmbox(&mbox, maildir, s);
|
||
|
home = getenv("home");
|
||
|
if(home == nil)
|
||
|
home = "/";
|
||
|
|
||
|
wbox = newwindow();
|
||
|
winname(wbox, mbox.name);
|
||
|
wintagwrite(wbox, "Put Mail Delmesg ", 3+1+4+1+7+1);
|
||
|
threadcreate(mainctl, wbox, STACK);
|
||
|
|
||
|
fmtstrinit(&fmt);
|
||
|
fmtprint(&fmt, "Mail");
|
||
|
if(shortmenu)
|
||
|
fmtprint(&fmt, " -%c", "sS"[shortmenu-1]);
|
||
|
if(outgoing)
|
||
|
fmtprint(&fmt, " -o %s", outgoing);
|
||
|
fmtprint(&fmt, " %s", name);
|
||
|
cmd = fmtstrflush(&fmt);
|
||
|
if(cmd == nil)
|
||
|
sysfatal("out of memory");
|
||
|
winsetdump(wbox, "/acme/mail", cmd);
|
||
|
mbox.w = wbox;
|
||
|
|
||
|
mesgmenu(wbox, &mbox);
|
||
|
winclean(wbox);
|
||
|
|
||
|
/* wctlfd = open("/dev/wctl", OWRITE|OCEXEC); /* for acme window */
|
||
|
wctlfd = -1;
|
||
|
cplumb = chancreate(sizeof(Plumbmsg*), 0);
|
||
|
cplumbshow = chancreate(sizeof(Plumbmsg*), 0);
|
||
|
if(strcmp(name, "mbox") == 0){
|
||
|
/*
|
||
|
* Avoid creating multiple windows to send mail by only accepting
|
||
|
* sendmail plumb messages if we're reading the main mailbox.
|
||
|
*/
|
||
|
plumbsendmailfd = plumbopenfid("sendmail", OREAD|OCEXEC);
|
||
|
cplumbsend = chancreate(sizeof(Plumbmsg*), 0);
|
||
|
proccreate(plumbsendproc, nil, STACK);
|
||
|
threadcreate(plumbsendthread, nil, STACK);
|
||
|
}
|
||
|
/* start plumb reader as separate proc ... */
|
||
|
proccreate(plumbproc, nil, STACK);
|
||
|
proccreate(plumbshowproc, nil, STACK);
|
||
|
threadcreate(plumbshowthread, nil, STACK);
|
||
|
fswrite(mbox.ctlfd, "refresh", 7);
|
||
|
/* ... and use this thread to read the messages */
|
||
|
plumbthread();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
plumbproc(void* v)
|
||
|
{
|
||
|
Plumbmsg *m;
|
||
|
|
||
|
threadsetname("plumbproc");
|
||
|
for(;;){
|
||
|
m = plumbrecvfid(plumbseemailfd);
|
||
|
sendp(cplumb, m);
|
||
|
if(m == nil)
|
||
|
threadexits(nil);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
plumbshowproc(void* v)
|
||
|
{
|
||
|
Plumbmsg *m;
|
||
|
|
||
|
threadsetname("plumbshowproc");
|
||
|
for(;;){
|
||
|
m = plumbrecvfid(plumbshowmailfd);
|
||
|
sendp(cplumbshow, m);
|
||
|
if(m == nil)
|
||
|
threadexits(nil);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
plumbsendproc(void* v)
|
||
|
{
|
||
|
Plumbmsg *m;
|
||
|
|
||
|
threadsetname("plumbsendproc");
|
||
|
for(;;){
|
||
|
m = plumbrecvfid(plumbsendmailfd);
|
||
|
sendp(cplumbsend, m);
|
||
|
if(m == nil)
|
||
|
threadexits(nil);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
newmesg(char *name, char *digest)
|
||
|
{
|
||
|
Dir *d;
|
||
|
|
||
|
if(strncmp(name, mbox.name, strlen(mbox.name)) != 0)
|
||
|
return; /* message is about another mailbox */
|
||
|
if(mesglookupfile(&mbox, name, digest) != nil)
|
||
|
return;
|
||
|
if(strncmp(name, "Mail/", 5) == 0)
|
||
|
name += 5;
|
||
|
d = fsdirstat(mailfs, name);
|
||
|
if(d == nil)
|
||
|
return;
|
||
|
if(mesgadd(&mbox, mbox.name, d, digest))
|
||
|
mesgmenunew(wbox, &mbox);
|
||
|
free(d);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
showmesg(char *name, char *digest)
|
||
|
{
|
||
|
char *n;
|
||
|
char *mb;
|
||
|
|
||
|
mb = mbox.name;
|
||
|
if(strncmp(name, mb, strlen(mb)) != 0)
|
||
|
return; /* message is about another mailbox */
|
||
|
n = estrdup(name+strlen(mb));
|
||
|
if(n[strlen(n)-1] != '/')
|
||
|
n = egrow(n, "/", nil);
|
||
|
mesgopen(&mbox, mbox.name, name+strlen(mb), nil, 1, digest);
|
||
|
free(n);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
delmesg(char *name, char *digest, int dodel, char *save)
|
||
|
{
|
||
|
Message *m;
|
||
|
|
||
|
m = mesglookupfile(&mbox, name, digest);
|
||
|
if(m != nil){
|
||
|
if(save)
|
||
|
mesgcommand(m, estrstrdup("Save ", save));
|
||
|
if(dodel)
|
||
|
mesgmenumarkdel(wbox, &mbox, m, 1);
|
||
|
else{
|
||
|
/* notification came from plumber - message is gone */
|
||
|
mesgmenudel(wbox, &mbox, m);
|
||
|
if(!m->opened)
|
||
|
mesgdel(&mbox, m);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
plumbthread(void)
|
||
|
{
|
||
|
Plumbmsg *m;
|
||
|
Plumbattr *a;
|
||
|
char *type, *digest;
|
||
|
|
||
|
threadsetname("plumbthread");
|
||
|
while((m = recvp(cplumb)) != nil){
|
||
|
a = m->attr;
|
||
|
digest = plumblookup(a, "digest");
|
||
|
type = plumblookup(a, "mailtype");
|
||
|
if(type == nil)
|
||
|
fprint(2, "Mail: plumb message with no mailtype attribute\n");
|
||
|
else if(strcmp(type, "new") == 0)
|
||
|
newmesg(m->data, digest);
|
||
|
else if(strcmp(type, "delete") == 0)
|
||
|
delmesg(m->data, digest, 0, nil);
|
||
|
else
|
||
|
fprint(2, "Mail: unknown plumb attribute %s\n", type);
|
||
|
plumbfree(m);
|
||
|
}
|
||
|
threadexits(nil);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
plumbshowthread(void *v)
|
||
|
{
|
||
|
Plumbmsg *m;
|
||
|
|
||
|
USED(v);
|
||
|
threadsetname("plumbshowthread");
|
||
|
while((m = recvp(cplumbshow)) != nil){
|
||
|
showmesg(m->data, plumblookup(m->attr, "digest"));
|
||
|
plumbfree(m);
|
||
|
}
|
||
|
threadexits(nil);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
plumbsendthread(void *v)
|
||
|
{
|
||
|
Plumbmsg *m;
|
||
|
|
||
|
USED(v);
|
||
|
threadsetname("plumbsendthread");
|
||
|
while((m = recvp(cplumbsend)) != nil){
|
||
|
mkreply(nil, "Mail", m->data, m->attr, nil);
|
||
|
plumbfree(m);
|
||
|
}
|
||
|
threadexits(nil);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
mboxcommand(Window *w, char *s)
|
||
|
{
|
||
|
char *args[10], **targs, *save;
|
||
|
Window *sbox;
|
||
|
Message *m, *next;
|
||
|
int ok, nargs, i, j;
|
||
|
CFid *searchfd;
|
||
|
char buf[128], *res;
|
||
|
|
||
|
nargs = tokenize(s, args, nelem(args));
|
||
|
if(nargs == 0)
|
||
|
return 0;
|
||
|
if(strcmp(args[0], "Mail") == 0){
|
||
|
if(nargs == 1)
|
||
|
mkreply(nil, "Mail", "", nil, nil);
|
||
|
else
|
||
|
mkreply(nil, "Mail", args[1], nil, nil);
|
||
|
return 1;
|
||
|
}
|
||
|
if(strcmp(s, "Del") == 0){
|
||
|
if(mbox.dirty){
|
||
|
mbox.dirty = 0;
|
||
|
fprint(2, "mail: mailbox not written\n");
|
||
|
return 1;
|
||
|
}
|
||
|
if(w != mbox.w){
|
||
|
windel(w, 1);
|
||
|
return 1;
|
||
|
}
|
||
|
ok = 1;
|
||
|
for(m=mbox.head; m!=nil; m=next){
|
||
|
next = m->next;
|
||
|
if(m->w){
|
||
|
if(windel(m->w, 0))
|
||
|
m->w = nil;
|
||
|
else
|
||
|
ok = 0;
|
||
|
}
|
||
|
}
|
||
|
for(m=replies.head; m!=nil; m=next){
|
||
|
next = m->next;
|
||
|
if(m->w){
|
||
|
if(windel(m->w, 0))
|
||
|
m->w = nil;
|
||
|
else
|
||
|
ok = 0;
|
||
|
}
|
||
|
}
|
||
|
if(ok){
|
||
|
windel(w, 1);
|
||
|
removeupasfs();
|
||
|
threadexitsall(nil);
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
if(strcmp(s, "Put") == 0){
|
||
|
rewritembox(wbox, &mbox);
|
||
|
return 1;
|
||
|
}
|
||
|
if(strcmp(s, "Get") == 0){
|
||
|
fswrite(mbox.ctlfd, "refresh", 7);
|
||
|
return 1;
|
||
|
}
|
||
|
if(strcmp(s, "Delmesg") == 0){
|
||
|
save = nil;
|
||
|
if(nargs > 1)
|
||
|
save = args[1];
|
||
|
s = winselection(w);
|
||
|
if(s == nil)
|
||
|
return 1;
|
||
|
nargs = 1;
|
||
|
for(i=0; s[i]; i++)
|
||
|
if(s[i] == '\n')
|
||
|
nargs++;
|
||
|
targs = emalloc(nargs*sizeof(char*)); /* could be too many for a local array */
|
||
|
nargs = getfields(s, targs, nargs, 1, "\n");
|
||
|
for(i=0; i<nargs; i++){
|
||
|
if(!isdigit(targs[i][0]))
|
||
|
continue;
|
||
|
j = atoi(targs[i]); /* easy way to parse the number! */
|
||
|
if(j == 0)
|
||
|
continue;
|
||
|
snprint(buf, sizeof buf, "%s%d", mbox.name, j);
|
||
|
delmesg(buf, nil, 1, save);
|
||
|
}
|
||
|
free(s);
|
||
|
free(targs);
|
||
|
return 1;
|
||
|
}
|
||
|
if(strcmp(s, "Search") == 0){
|
||
|
if(nargs <= 1)
|
||
|
return 1;
|
||
|
s = estrstrdup(mboxname, "/search");
|
||
|
searchfd = fsopen(mailfs, s, ORDWR);
|
||
|
if(searchfd == nil)
|
||
|
return 1;
|
||
|
save = estrdup(args[1]);
|
||
|
for(i=2; i<nargs; i++)
|
||
|
save = eappend(save, " ", args[i]);
|
||
|
fswrite(searchfd, save, strlen(save));
|
||
|
fsseek(searchfd, 0, 0);
|
||
|
j = fsread(searchfd, buf, sizeof buf - 1);
|
||
|
if(j == 0){
|
||
|
fprint(2, "[%s] search %s: no results found\n", mboxname, save);
|
||
|
fsclose(searchfd);
|
||
|
free(save);
|
||
|
return 1;
|
||
|
}
|
||
|
free(save);
|
||
|
buf[j] = '\0';
|
||
|
res = estrdup(buf);
|
||
|
j = fsread(searchfd, buf, sizeof buf - 1);
|
||
|
for(; j != 0; j = fsread(searchfd, buf, sizeof buf - 1), buf[j] = '\0')
|
||
|
res = eappend(res, "", buf);
|
||
|
fsclose(searchfd);
|
||
|
|
||
|
sbox = newwindow();
|
||
|
winname(sbox, s);
|
||
|
free(s);
|
||
|
threadcreate(mainctl, sbox, STACK);
|
||
|
winopenbody(sbox, OWRITE);
|
||
|
|
||
|
/* show results in reverse order */
|
||
|
m = mbox.tail;
|
||
|
save = nil;
|
||
|
for(s=strrchr(res, ' '); s!=nil || save!=res; s=strrchr(res, ' ')){
|
||
|
if(s != nil){
|
||
|
save = s+1;
|
||
|
*s = '\0';
|
||
|
}
|
||
|
else save = res;
|
||
|
save = estrstrdup(save, "/");
|
||
|
for(; m && strcmp(save, m->name) != 0; m=m->prev);
|
||
|
free(save);
|
||
|
if(m == nil)
|
||
|
break;
|
||
|
fsprint(sbox->body, "%s%s\n", m->name, info(m, 0, 0));
|
||
|
m = m->prev;
|
||
|
}
|
||
|
free(res);
|
||
|
winclean(sbox);
|
||
|
winclosebody(sbox);
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
mainctl(void *v)
|
||
|
{
|
||
|
Window *w;
|
||
|
Event *e, *e2, *eq, *ea;
|
||
|
int na, nopen;
|
||
|
char *s, *t, *buf;
|
||
|
|
||
|
w = v;
|
||
|
winincref(w);
|
||
|
proccreate(wineventproc, w, STACK);
|
||
|
|
||
|
for(;;){
|
||
|
e = recvp(w->cevent);
|
||
|
switch(e->c1){
|
||
|
default:
|
||
|
Unknown:
|
||
|
print("unknown message %c%c\n", e->c1, e->c2);
|
||
|
break;
|
||
|
|
||
|
case 'E': /* write to body; can't affect us */
|
||
|
break;
|
||
|
|
||
|
case 'F': /* generated by our actions; ignore */
|
||
|
break;
|
||
|
|
||
|
case 'K': /* type away; we don't care */
|
||
|
break;
|
||
|
|
||
|
case 'M':
|
||
|
switch(e->c2){
|
||
|
case 'x':
|
||
|
case 'X':
|
||
|
ea = nil;
|
||
|
e2 = nil;
|
||
|
if(e->flag & 2)
|
||
|
e2 = recvp(w->cevent);
|
||
|
if(e->flag & 8){
|
||
|
ea = recvp(w->cevent);
|
||
|
na = ea->nb;
|
||
|
recvp(w->cevent);
|
||
|
}else
|
||
|
na = 0;
|
||
|
s = e->b;
|
||
|
/* if it's a known command, do it */
|
||
|
if((e->flag&2) && e->nb==0)
|
||
|
s = e2->b;
|
||
|
if(na){
|
||
|
t = emalloc(strlen(s)+1+na+1);
|
||
|
sprint(t, "%s %s", s, ea->b);
|
||
|
s = t;
|
||
|
}
|
||
|
/* if it's a long message, it can't be for us anyway */
|
||
|
if(!mboxcommand(w, s)) /* send it back */
|
||
|
winwriteevent(w, e);
|
||
|
if(na)
|
||
|
free(s);
|
||
|
break;
|
||
|
|
||
|
case 'l':
|
||
|
case 'L':
|
||
|
buf = nil;
|
||
|
eq = e;
|
||
|
if(e->flag & 2){
|
||
|
e2 = recvp(w->cevent);
|
||
|
eq = e2;
|
||
|
}
|
||
|
s = eq->b;
|
||
|
if(eq->q1>eq->q0 && eq->nb==0){
|
||
|
buf = emalloc((eq->q1-eq->q0)*UTFmax+1);
|
||
|
winread(w, eq->q0, eq->q1, buf);
|
||
|
s = buf;
|
||
|
}
|
||
|
nopen = 0;
|
||
|
do{
|
||
|
/* skip 'deleted' string if present' */
|
||
|
if(strncmp(s, deleted, strlen(deleted)) == 0)
|
||
|
s += strlen(deleted);
|
||
|
/* skip mail box name if present */
|
||
|
if(strncmp(s, mbox.name, strlen(mbox.name)) == 0)
|
||
|
s += strlen(mbox.name);
|
||
|
nopen += mesgopen(&mbox, mbox.name, s, nil, 0, nil);
|
||
|
while(*s!='\0' && *s++!='\n')
|
||
|
;
|
||
|
}while(*s);
|
||
|
if(nopen == 0) /* send it back */
|
||
|
winwriteevent(w, e);
|
||
|
free(buf);
|
||
|
break;
|
||
|
|
||
|
case 'I': /* modify away; we don't care */
|
||
|
case 'D':
|
||
|
case 'd':
|
||
|
case 'i':
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
goto Unknown;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|