int colclean(Column *c) { int i, clean; clean = TRUE; for(i=0; i<c->nw; i++) clean &= winclean(c->w[i], TRUE); return clean; }
void replywindow(Article *m) { Biobuf *b; char *p, *ep, *q, tmp[40]; int fd, copy; Article *reply; sprint(tmp, "%d/article", m->n); p = estrstrdup(dir, tmp); if((fd = open(p, OREAD)) < 0){ free(p); return; } free(p); reply = newpost(); winopenbody(reply->w, OWRITE); b = emalloc(sizeof(*b)); Binit(b, fd, OREAD); copy = 0; while(p = Brdline(b, '\n')){ if(Blinelen(b)==1) break; ep = p+Blinelen(b); if(!isspace(*p)){ copy = 0; if(cistrncmp(p, "newsgroups:", 11)==0){ for(q=p+11; *q!='\n'; q++) if(*q==',') *q = ' '; copy = 1; }else if(cistrncmp(p, "subject:", 8)==0){ if(!strstr(p, " Re:") && !strstr(p, " RE:") && !strstr(p, " re:")){ p = skip(p, "subject:"); ep[-1] = '\0'; Bprint(reply->w->body, "Subject: Re: %s\n", p); }else copy = 1; }else if(cistrncmp(p, "message-id:", 11)==0){ Bprint(reply->w->body, "References: "); p += 11; copy = 1; } } if(copy) Bwrite(reply->w->body, p, ep-p); } Bterm(b); close(fd); free(b); Bprint(reply->w->body, "\n"); winclean(reply->w); winselect(reply->w, "$", 0); }
void wikithread(void *v) { char tmp[40]; Event *e; Wiki *w; w = v; if(w->isnew){ sprint(tmp, "+new+%d", w->isnew); wikiname(w->win, tmp); if(w->arg){ winopenbody(w->win, OWRITE); Bprint(w->win->body, "%s\n\n", w->arg); } winclean(w->win); }else if(!w->special){ wikiget(w); wikiname(w->win, w->arg); if(w->addr) winselect(w->win, w->addr, 1); } fprint(w->win->ctl, "menu\n"); wintagwrite(w->win, "Get History Diff New", 4+8+4+4); winclean(w->win); while(!w->dead && (e = recvp(w->win->cevent))) acmeevent(w, e); windormant(w->win); unlink(w); free(w->win); free(w->arg); free(w); threadexits(nil); }
/* * Show the first nshow messages in the window. * This depends on nntpfs presenting contiguously * numbered directories, and on the qid version being * the topmost numbered directory. */ void dirwindow(Window *w) { if((hi=gethi()) < 0) return; if(w->data < 0) w->data = winopenfile(w, "data"); fprint(w->ctl, "dirty\n"); winopenbody(w, OWRITE); lo = adddir(w->body, hi, 0, nshow); winclean(w); }
void mesgmenumark(Window *w, char *which, char *mark) { char *buf; if(w->data < 0) w->data = winopenfile(w, "data"); buf = name2regexp(deletedrx01, which); if(winsetaddr(w, buf, 1) && winsetaddr(w, "+0-#1", 1)) /* go to end of line */ write(w->data, mark, strlen(mark)); free(buf); close(w->data); close(w->addr); w->addr = w->data = -1; if(!mbox.dirty) winclean(w); }
/* one new message has arrived, as mbox->tail */ void mesgmenunew(Window *w, Message *mbox) { Biobuf *b; 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); /* select tag line plus following indented lines, but not final newline (it's distinctive) */ winselect(w, "0/.*\\n((\t.*\\n)*\t.*)?/", 1); close(w->addr); close(w->data); w->addr = -1; w->data = -1; }
void rewritembox(Window *w, Message *mbox) { Message *m, *next; char *deletestr, *t; int nopen; deletestr = estrstrdup("delete ", fsname); nopen = 0; for(m=mbox->head; m!=nil; m=next){ next = m->next; if(m->deleted == 0) continue; if(m->opened){ nopen++; continue; } if(m->writebackdel){ /* messages deleted by plumb message are not removed again */ t = estrdup(m->name); if(strlen(t) > 0) t[strlen(t)-1] = '\0'; deletestr = egrow(deletestr, " ", t); } mesgmenudel(w, mbox, m); mesgdel(mbox, m); } if(write(mbox->ctlfd, deletestr, strlen(deletestr)) < 0) fprint(2, "Mail: warning: error removing mail message files: %r\n"); free(deletestr); winselect(w, "0", 0); if(nopen == 0) winclean(w); mbox->dirty = 0; }
void wikiget(Wiki *w) { char *p; int fd, normal; Biobuf *bin; fprint(w->win->ctl, "dirty\n"); p = emalloc(strlen(w->arg)+8+1); strcpy(p, w->arg); normal = 1; if(p[strlen(p)-1] == '/'){ normal = 0; strcat(p, "current"); }else if(strlen(p)>8 && strcmp(p+strlen(p)-8, "/current")==0){ normal = 0; w->arg[strlen(w->arg)-7] = '\0'; } if((fd = open(p, OREAD)) < 0){ fprint(2, "Wiki: cannot read %s: %r\n", p); winclean(w->win); return; } free(p); winopenbody(w->win, OWRITE); bin = emalloc(sizeof(*bin)); Binit(bin, fd, OREAD); p = nil; if(!normal){ if((p = Brdline(bin, '\n')) == nil){ fprint(2, "Wiki: cannot read title: %r\n"); winclean(w->win); close(fd); free(bin); return; } p[Blinelen(bin)-1] = '\0'; } /* clear window */ if(w->win->data < 0) w->win->data = winopenfile(w->win, "data"); if(winsetaddr(w->win, ",", 0)) write(w->win->data, "", 0); if(!normal) Bprint(w->win->body, "%s\n\n", p); while(p = Brdline(bin, '\n')){ p[Blinelen(bin)-1] = '\0'; if(normal) Bprint(w->win->body, "%s\n", p); else{ if(p[0]=='D') w->time = strtoul(p+1, 0, 10); else if(p[0]=='#') Bprint(w->win->body, "%s\n", p+1); } } winclean(w->win); free(bin); close(fd); }
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 = "******"; 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(); }
int mesgopen(Message *mbox, char *dir, char *s, Message *mesg, int plumbed, char *digest) { char *t, *u, *v; Message *m; char *direlem[10]; int i, ndirelem, reuse; /* find white-space-delimited first word */ for(t=s; *t!='\0' && !isspace(*t); t++) ; u = emalloc(t-s+1); memmove(u, s, t-s); /* separate it on slashes */ ndirelem = tokenizec(u, direlem, nelem(direlem), "/"); if(ndirelem <= 0){ Error: free(u); return 0; } if(plumbed){ write(wctlfd, "top", 3); write(wctlfd, "current", 7); } /* open window for message */ m = mesglookup(mbox, direlem[0], digest); if(m == nil) goto Error; if(mesg!=nil && m!=mesg) /* string looked like subpart but isn't part of this message */ goto Error; if(m->opened == 0){ if(m->w == nil){ reuse = 0; m->w = newwindow(); }else{ reuse = 1; /* re-use existing window */ if(winsetaddr(m->w, "0,$", 1)){ if(m->w->data < 0) m->w->data = winopenfile(m->w, "data"); write(m->w->data, "", 0); } } v = estrstrdup(mbox->name, m->name); winname(m->w, v); free(v); if(!reuse){ if(m->deleted) wintagwrite(m->w, "Q Reply all UnDelmesg Save ", 2+6+4+10+5); else wintagwrite(m->w, "Q Reply all Delmesg Save ", 2+6+4+8+5); } threadcreate(mesgctl, m, STACK); winopenbody(m->w, OWRITE); mesgload(m, dir, m->name, m->w); winclosebody(m->w); winclean(m->w); m->opened = 1; if(ndirelem == 1){ free(u); return 1; } } if(ndirelem == 1 && plumbport(m->type, m->filename) <= 0){ /* make sure dot is visible */ ctlprint(m->w->ctl, "show\n"); return 0; } /* walk to subpart */ dir = estrstrdup(dir, m->name); for(i=1; i<ndirelem; i++){ m = mesglookup(m, direlem[i], digest); if(m == nil) break; dir = egrow(dir, m->name, nil); } if(m != nil && plumbport(m->type, m->filename) > 0) plumb(m, dir); free(dir); free(u); return 1; }
int acmecmd(Article *m, Window *w, char *s) { int n; Biobuf *b; //fprint(2, "cmd %s\n", s); s = skip(s, ""); if(iscmd(s, "Del")){ if(m == nil){ /* don't close dir until messages close */ if(mlist != nil){ ctlprint(mlist->w->ctl, "show\n"); return 1; } if(windel(w, 0)) threadexitsall(nil); return 1; }else{ if(windel(w, 0)) m->dead = 1; return 1; } } if(m==nil && iscmd(s, "More")){ s = skip(s, "More"); if(n = atoi(s)) nshow = n; if(w->data < 0) w->data = winopenfile(w, "data"); winsetaddr(w, "$", 1); fprint(w->ctl, "dirty\n"); b = emalloc(sizeof(*b)); Binit(b, w->data, OWRITE); lo = adddir(b, lo, 0, nshow); Bterm(b); free(b); winclean(w); winsetaddr(w, ".,", 0); } if(m!=nil && !m->ispost && iscmd(s, "Headers")){ m->headers = !m->headers; fillmesgwindow(-1, m); return 1; } if(iscmd(s, "Newpost")){ m = newpost(); winopenbody(m->w, OWRITE); Bprint(m->w->body, "%s\nsubject: \n\n", group); winclean(m->w); winselect(m->w, "$", 0); return 1; } if(m!=nil && !m->ispost && iscmd(s, "Reply")){ replywindow(m); return 1; } // if(m!=nil && iscmd(s, "Replymail")){ // fprint(2, "no replymail yet\n"); // return 1; // } if(iscmd(s, "Post")){ mesgpost(m); return 1; } return 0; }
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 xfidctlwrite(Xfid *x, Window *w) { Fcall fc; int i, m, n, nb, nr, nulls; Rune *r; char *err, *p, *pp, *q, *e; int isfbuf, scrdraw, settag; Text *t; err = nil; e = x->fcall.data+x->fcall.count; scrdraw = FALSE; settag = FALSE; isfbuf = TRUE; if(x->fcall.count < RBUFSIZE) r = fbufalloc(); else{ isfbuf = FALSE; r = emalloc(x->fcall.count*UTFmax+1); } x->fcall.data[x->fcall.count] = 0; textcommit(&w->tag, TRUE); for(n=0; n<x->fcall.count; n+=m){ p = x->fcall.data+n; if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */ qlock(&w->ctllock); w->ctlfid = x->f->fid; m = 4; }else if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */ w->ctlfid = ~0; qunlock(&w->ctllock); m = 6; }else if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */ t = &w->body; t->eq0 = ~0; filereset(t->file); t->file->mod = FALSE; w->dirty = FALSE; settag = TRUE; m = 5; }else if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */ t = &w->body; /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */ t->file->mod = TRUE; w->dirty = TRUE; settag = TRUE; m = 5; }else if(strncmp(p, "show", 4) == 0){ /* show dot */ t = &w->body; textshow(t, t->q0, t->q1, 1); m = 4; }else if(strncmp(p, "name ", 5) == 0){ /* set file name */ pp = p+5; m = 5; q = memchr(pp, '\n', e-pp); if(q==nil || q==pp){ err = Ebadctl; break; } *q = 0; nulls = FALSE; cvttorunes(pp, q-pp, r, &nb, &nr, &nulls); if(nulls){ err = "nulls in file name"; break; } for(i=0; i<nr; i++) if(r[i] <= ' '){ err = "bad character in file name"; goto out; } out: seq++; filemark(w->body.file); winsetname(w, r, nr); m += (q+1) - pp; }else if(strncmp(p, "dump ", 5) == 0){ /* set dump string */ pp = p+5; m = 5; q = memchr(pp, '\n', e-pp); if(q==nil || q==pp){ err = Ebadctl; break; } *q = 0; nulls = FALSE; cvttorunes(pp, q-pp, r, &nb, &nr, &nulls); if(nulls){ err = "nulls in dump string"; break; } w->dumpstr = runetobyte(r, nr); m += (q+1) - pp; }else if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */ pp = p+8; m = 8; q = memchr(pp, '\n', e-pp); if(q==nil || q==pp){ err = Ebadctl; break; } *q = 0; nulls = FALSE; cvttorunes(pp, q-pp, r, &nb, &nr, &nulls); if(nulls){ err = "nulls in dump directory string"; break; } w->dumpdir = runetobyte(r, nr); m += (q+1) - pp; }else if(strncmp(p, "delete", 6) == 0){ /* delete for sure */ colclose(w->col, w, TRUE); m = 6; }else if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */ if(!winclean(w, TRUE)){ err = "file dirty"; break; } colclose(w->col, w, TRUE); m = 3; }else if(strncmp(p, "get", 3) == 0){ /* get file */ get(&w->body, nil, nil, FALSE, XXX, nil, 0); m = 3; }else if(strncmp(p, "put", 3) == 0){ /* put file */ put(&w->body, nil, nil, XXX, XXX, nil, 0); m = 3; }else if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */ textcommit(&w->body, TRUE); clampaddr(w); w->body.q0 = w->addr.q0; w->body.q1 = w->addr.q1; textsetselect(&w->body, w->body.q0, w->body.q1); settag = TRUE; m = 8; }else if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */ w->addr.q0 = w->body.q0; w->addr.q1 = w->body.q1; m = 8; }else if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */ textcommit(&w->body, TRUE); clampaddr(w); w->limit.q0 = w->addr.q0; w->limit.q1 = w->addr.q1; m = 10; }else if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */ w->nomark = TRUE; m = 6; }else if(strncmp(p, "mark", 4) == 0){ /* mark file */ seq++; filemark(w->body.file); settag = TRUE; m = 4; }else if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */ w->filemenu = FALSE; m = 6; }else if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */ w->filemenu = TRUE; m = 4; }else if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */ w->noscroll = TRUE; m = 8; }else if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */ wincleartag(w); settag = TRUE; m = 8; }else if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */ w->noscroll = FALSE; m = 6; }else{ err = Ebadctl; break; } while(p[m] == '\n') m++; } if(isfbuf) fbuffree(r); else free(r); if(err) n = 0; fc.count = n; respond(x, &fc, err); if(settag) winsettag(w); if(scrdraw) textscrdraw(&w->body); }
void mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext) { char buf[100]; CFid *fd; Message *r; char *dir, *t; int quotereply; Plumbattr *a; quotereply = (label[0] == 'Q'); if(quotereply && m && m->replywinid > 0){ snprint(buf, sizeof buf, "%d/body", m->replywinid); if((fd = fsopen(acmefs, 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) r->replyname = estrdup(m->name); r->next = replies.head; r->prev = nil; if(replies.head != nil) replies.head->prev = r; replies.head = r; if(replies.tail == nil) replies.tail = r; 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); r->tagposted = 1; threadcreate(mesgctl, r, STACK); winopenbody(r->w, OWRITE); if(to!=nil && to[0]!='\0') fsprint(r->w->body, "%s\n", to); for(a=attr; a; a=a->next) fsprint(r->w->body, "%s: %s\n", a->name, a->value); dir = nil; if(m != nil){ dir = estrstrdup(mbox.name, m->name); if(to == nil && attr == nil){ /* Reply goes to replyto; Reply all goes to From and To and CC */ if(strstr(label, "all") == nil) fsprint(r->w->body, "To: %s\n", m->replyto); else{ /* Replyall */ if(strlen(m->from) > 0) fsprint(r->w->body, "To: %s\n", m->from); if(strlen(m->to) > 0) fsprint(r->w->body, "To: %s\n", m->to); if(strlen(m->cc) > 0) fsprint(r->w->body, "CC: %s\n", m->cc); } } if(strlen(m->subject) > 0){ t = "Subject: Re: "; if(strlen(m->subject) >= 3) if(tolower(m->subject[0])=='r' && tolower(m->subject[1])=='e' && m->subject[2]==':') t = "Subject: "; fsprint(r->w->body, "%s%s\n", t, m->subject); } if(!quotereply){ fsprint(r->w->body, "Include: %sraw\n", dir); free(dir); } } fsprint(r->w->body, "\n"); if(m == nil) fsprint(r->w->body, "\n"); else if(quotereply){ quote(m, r->w->body, dir, quotetext); free(dir); } winclosebody(r->w); if(m==nil && (to==nil || to[0]=='\0')) winselect(r->w, "0", 0); else winselect(r->w, "$", 0); winclean(r->w); windormant(r->w); }
void mesgsend(Message *m) { char *s, *body, *to; int i, j, h, n, natt, p[2]; struct Exec *e; Channel *sync; int first, nfld, delit, ofd; char *copy, *fld[100], *now; body = winreadbody(m->w, &n); /* assemble to: list from first line, to: line, and cc: line */ nto = 0; natt = 0; ncc = 0; nbcc = 0; first = 1; to = body; for(;;){ for(s=to; *s!='\n'; s++) if(*s == '\0'){ free(body); return; } if(s++ == to) /* blank line */ break; /* make copy of line to tokenize */ copy = emalloc(s-to); memmove(copy, to, s-to); copy[s-to-1] = '\0'; nfld = tokenizec(copy, fld, nelem(fld), ", \t"); if(nfld == 0){ free(copy); break; } n -= s-to; switch(h = whichheader(fld[0])){ case TO: case FROM: delit = 1; commas(to+strlen(fld[0]), s-1); for(i=1; i<nfld && nto<nelem(tolist); i++) if(!addressed(fld[i])) tolist[nto++] = estrdup(fld[i]); break; case BCC: delit = 1; commas(to+strlen(fld[0]), s-1); for(i=1; i<nfld && nbcc<nelem(bcclist); i++) if(!addressed(fld[i])) bcclist[nbcc++] = estrdup(fld[i]); break; case CC: delit = 1; commas(to+strlen(fld[0]), s-1); for(i=1; i<nfld && ncc<nelem(cclist); i++) if(!addressed(fld[i])) cclist[ncc++] = estrdup(fld[i]); break; case ATTACH: case INCLUDE: delit = 1; for(i=1; i<nfld && natt<nelem(attlist); i++){ attlist[natt] = estrdup(fld[i]); included[natt++] = (h == INCLUDE); } break; default: if(first){ delit = 1; for(i=0; i<nfld && nto<nelem(tolist); i++) tolist[nto++] = estrdup(fld[i]); }else /* ignore it */ delit = 0; break; } if(delit){ /* delete line from body */ memmove(to, s, n+1); }else to = s; free(copy); first = 0; } ofd = open(outgoing, OWRITE|OCEXEC); /* no error check necessary */ 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); for(i=0; i<natt; i++) if(included[i]) fprint(ofd, "Include: %s\n", attlist[i]); else fprint(ofd, "Attach: %s\n", attlist[i]); /* needed because mail is by default Latin-1 */ fprint(ofd, "Content-Type: text/plain; charset=\"UTF-8\"\n"); fprint(ofd, "Content-Transfer-Encoding: 8bit\n"); } e = emalloc(sizeof(struct Exec)); if(pipe(p) < 0) error("can't create pipe: %r"); e->p[0] = p[0]; e->p[1] = p[1]; e->prog = unsharp("#9/bin/upas/marshal"); e->argv = emalloc((1+1+2+4*natt+1)*sizeof(char*)); e->argv[0] = estrdup("marshal"); e->argv[1] = estrdup("-8"); j = 2; if(m->replyname){ e->argv[j++] = estrdup("-R"); e->argv[j++] = estrstrdup(mbox.name, m->replyname); } for(i=0; i<natt; i++){ if(included[i]) e->argv[j++] = estrdup("-A"); else e->argv[j++] = estrdup("-a"); e->argv[j++] = estrdup(attlist[i]); } sync = chancreate(sizeof(int), 0); e->sync = sync; proccreate(execproc, e, EXECSTACK); recvul(sync); /* close(p[0]); */ /* using marshal -8, so generate rfc822 headers */ if(nto > 0){ print2(p[1], ofd, "To: "); for(i=0; i<nto-1; i++) print2(p[1], ofd, "%s, ", tolist[i]); print2(p[1], ofd, "%s\n", tolist[i]); } if(ncc > 0){ print2(p[1], ofd, "CC: "); for(i=0; i<ncc-1; i++) print2(p[1], ofd, "%s, ", cclist[i]); print2(p[1], ofd, "%s\n", cclist[i]); } if(nbcc > 0){ print2(p[1], ofd, "BCC: "); for(i=0; i<nbcc-1; i++) print2(p[1], ofd, "%s, ", bcclist[i]); print2(p[1], ofd, "%s\n", bcclist[i]); } i = strlen(body); if(i > 0) write2(p[1], ofd, body, i, 1); /* guarantee a blank line, to ensure attachments are separated from body */ if(i==0 || body[i-1]!='\n') write2(p[1], ofd, "\n\n", 2, 0); else if(i>1 && body[i-2]!='\n') write2(p[1], ofd, "\n", 1, 0); /* these look like pseudo-attachments in the "outgoing" box */ if(ofd>0 && natt>0){ for(i=0; i<natt; i++) if(included[i]) fprint(ofd, "=====> Include: %s\n", attlist[i]); else fprint(ofd, "=====> Attach: %s\n", attlist[i]); } if(ofd > 0) write(ofd, "\n", 1); for(i=0; i<natt; i++) free(attlist[i]); close(ofd); close(p[1]); free(body); if(m->replyname != nil) mesgmenumark(mbox.w, m->replyname, "\t[replied]"); if(m->name[0] == '/') s = estrdup(m->name); else s = estrstrdup(mbox.name, m->name); s = egrow(s, "-R", nil); winname(m->w, s); free(s); winclean(m->w); /* mark message unopened because it's no longer the original message */ m->opened = 0; }
void mesgpost(Article *m) { Biobuf *b; char *p, *ep; int isfirst, ishdr, havegroup, havefrom; p = estrstrdup(dir, "post"); if((b = Bopen(p, OWRITE)) == nil){ fprint(2, "cannot open %s: %r\n", p); free(p); return; } free(p); winopenbody(m->w, OREAD); ishdr = 1; isfirst = 1; havegroup = havefrom = 0; while(p = Brdline(m->w->body, '\n')){ ep = p+Blinelen(m->w->body); if(ishdr && p+1==ep){ if(!havegroup) Bprint(b, "Newsgroups: %s\n", group); if(!havefrom) Bprint(b, "From: %s\n", from); ishdr = 0; } if(ishdr){ ep[-1] = '\0'; if(isfirst && strchr(p, ':')==0){ /* group list */ commas(p, ep); Bprint(b, "newsgroups: %s\n", p); havegroup = 1; isfirst = 0; continue; } if(cistrncmp(p, "newsgroup:", 10)==0){ commas(skip(p, "newsgroup:"), ep); Bprint(b, "newsgroups: %s\n", skip(p, "newsgroup:")); havegroup = 1; continue; } if(cistrncmp(p, "newsgroups:", 11)==0){ commas(skip(p, "newsgroups:"), ep); Bprint(b, "newsgroups: %s\n", skip(p, "newsgroups:")); havegroup = 1; continue; } if(cistrncmp(p, "from:", 5)==0) havefrom = 1; ep[-1] = '\n'; } Bwrite(b, p, ep-p); } winclosebody(m->w); Bflush(b); if(write(Bfildes(b), "", 0) == 0) winclean(m->w); else fprint(2, "post: %r\n"); Bterm(b); }
int fillmesgwindow(int fd, Article *m) { Biobuf *b; char *p, tmp[40]; int i, inhdr, copy, xfd; Window *w; xfd = -1; if(fd == -1){ sprint(tmp, "%d/article", m->n); p = estrstrdup(dir, tmp); if((xfd = open(p, OREAD)) < 0){ free(p); return 0; } free(p); fd = xfd; } w = m->w; if(w->data < 0) w->data = winopenfile(w, "data"); if(winsetaddr(w, ",", 0)) write(w->data, "", 0); winopenbody(m->w, OWRITE); b = emalloc(sizeof(*b)); Binit(b, fd, OREAD); inhdr = 1; copy = 1; while(p = Brdline(b, '\n')){ if(Blinelen(b)==1) inhdr = 0, copy=1; if(inhdr && !isspace(p[0])){ copy = 1; if(!m->headers){ if(cistrncmp(p, "from:", 5)==0){ p[Blinelen(b)-1] = '\0'; p = fixfrom(skip(p, "from:")); Bprint(m->w->body, "From: %s\n", p); free(p); copy = 0; continue; } for(i=0; i<nelem(skipheader); i++) if(cistrncmp(p, skipheader[i], strlen(skipheader[i]))==0) copy=0; } } if(copy) Bwrite(m->w->body, p, Blinelen(b)); } Bterm(b); free(b); winclean(m->w); if(xfd != -1) close(xfd); return 1; }