1*7dd7cddfSDavid du Colombier #include <u.h> 2*7dd7cddfSDavid du Colombier #include <libc.h> 3*7dd7cddfSDavid du Colombier #include <bio.h> 4*7dd7cddfSDavid du Colombier #include <thread.h> 5*7dd7cddfSDavid du Colombier #include <ctype.h> 6*7dd7cddfSDavid du Colombier #include <plumb.h> 7*7dd7cddfSDavid du Colombier #include "dat.h" 8*7dd7cddfSDavid du Colombier 9*7dd7cddfSDavid du Colombier static int replyid; 10*7dd7cddfSDavid du Colombier 11*7dd7cddfSDavid du Colombier int 12*7dd7cddfSDavid du Colombier EQUAL(char *s, char *t) 13*7dd7cddfSDavid du Colombier { 14*7dd7cddfSDavid du Colombier while(tolower(*s) == tolower(*t++)) 15*7dd7cddfSDavid du Colombier if(*s++ == '\0') 16*7dd7cddfSDavid du Colombier return 1; 17*7dd7cddfSDavid du Colombier return 0; 18*7dd7cddfSDavid du Colombier } 19*7dd7cddfSDavid du Colombier 20*7dd7cddfSDavid du Colombier void 21*7dd7cddfSDavid du Colombier mkreply(Message *m, char *label, char *to) 22*7dd7cddfSDavid du Colombier { 23*7dd7cddfSDavid du Colombier Message *r; 24*7dd7cddfSDavid du Colombier char *dir, *t; 25*7dd7cddfSDavid du Colombier 26*7dd7cddfSDavid du Colombier r = emalloc(sizeof(Message)); 27*7dd7cddfSDavid du Colombier r->isreply = 1; 28*7dd7cddfSDavid du Colombier if(m != nil) 29*7dd7cddfSDavid du Colombier r->replyname = estrdup(m->name); 30*7dd7cddfSDavid du Colombier r->next = replies.head; 31*7dd7cddfSDavid du Colombier r->prev = nil; 32*7dd7cddfSDavid du Colombier if(replies.head != nil) 33*7dd7cddfSDavid du Colombier replies.head->prev = r; 34*7dd7cddfSDavid du Colombier replies.head = r; 35*7dd7cddfSDavid du Colombier if(replies.tail == nil) 36*7dd7cddfSDavid du Colombier replies.tail = r; 37*7dd7cddfSDavid du Colombier r->name = emalloc(strlen(mbox.name)+strlen(label)+10); 38*7dd7cddfSDavid du Colombier sprint(r->name, "%s%s%d", mbox.name, label, ++replyid); 39*7dd7cddfSDavid du Colombier r->w = newwindow(); 40*7dd7cddfSDavid du Colombier winname(r->w, r->name); 41*7dd7cddfSDavid du Colombier wintagwrite(r->w, "|fmt Post", 5+4); 42*7dd7cddfSDavid du Colombier r->tagposted = 1; 43*7dd7cddfSDavid du Colombier threadcreate(mesgctl, r, STACK); 44*7dd7cddfSDavid du Colombier winopenbody(r->w, OWRITE); 45*7dd7cddfSDavid du Colombier if(to!=nil && to[0]!='\0') 46*7dd7cddfSDavid du Colombier Bprint(r->w->body, "%s\n", to); 47*7dd7cddfSDavid du Colombier if(m != nil){ 48*7dd7cddfSDavid du Colombier dir = estrstrdup(mbox.name, m->name); 49*7dd7cddfSDavid du Colombier if(to == nil){ 50*7dd7cddfSDavid du Colombier /* Reply goes to replyto; Reply all goes to From and To and CC */ 51*7dd7cddfSDavid du Colombier if(strcmp(label, "Reply") == 0) 52*7dd7cddfSDavid du Colombier Bprint(r->w->body, "To: %s\n", m->replyto); 53*7dd7cddfSDavid du Colombier else{ /* Replyall */ 54*7dd7cddfSDavid du Colombier if(strlen(m->from) > 0) 55*7dd7cddfSDavid du Colombier Bprint(r->w->body, "To: %s\n", m->from); 56*7dd7cddfSDavid du Colombier if(strlen(m->to) > 0) 57*7dd7cddfSDavid du Colombier Bprint(r->w->body, "To: %s\n", m->to); 58*7dd7cddfSDavid du Colombier if(strlen(m->cc) > 0) 59*7dd7cddfSDavid du Colombier Bprint(r->w->body, "CC: %s\n", m->cc); 60*7dd7cddfSDavid du Colombier } 61*7dd7cddfSDavid du Colombier } 62*7dd7cddfSDavid du Colombier if(strlen(m->subject) > 0){ 63*7dd7cddfSDavid du Colombier t = "Subject: Re: "; 64*7dd7cddfSDavid du Colombier if(strlen(m->subject) >= 3) 65*7dd7cddfSDavid du Colombier if(tolower(m->subject[0])=='r' && tolower(m->subject[1])=='e' && m->subject[2]==':') 66*7dd7cddfSDavid du Colombier t = "Subject: "; 67*7dd7cddfSDavid du Colombier Bprint(r->w->body, "%s%s\n", t, m->subject); 68*7dd7cddfSDavid du Colombier } 69*7dd7cddfSDavid du Colombier Bprint(r->w->body, "Include: %sraw\n", dir); 70*7dd7cddfSDavid du Colombier free(dir); 71*7dd7cddfSDavid du Colombier } 72*7dd7cddfSDavid du Colombier Bprint(r->w->body, "\n"); 73*7dd7cddfSDavid du Colombier if(m == nil) 74*7dd7cddfSDavid du Colombier Bprint(r->w->body, "\n"); 75*7dd7cddfSDavid du Colombier winclosebody(r->w); 76*7dd7cddfSDavid du Colombier if(m == nil) 77*7dd7cddfSDavid du Colombier winselect(r->w, "0", 0); 78*7dd7cddfSDavid du Colombier else 79*7dd7cddfSDavid du Colombier winselect(r->w, "$", 0); 80*7dd7cddfSDavid du Colombier winclean(r->w); 81*7dd7cddfSDavid du Colombier windormant(r->w); 82*7dd7cddfSDavid du Colombier } 83*7dd7cddfSDavid du Colombier 84*7dd7cddfSDavid du Colombier void 85*7dd7cddfSDavid du Colombier delreply(Message *m) 86*7dd7cddfSDavid du Colombier { 87*7dd7cddfSDavid du Colombier if(m->next == nil) 88*7dd7cddfSDavid du Colombier replies.tail = m->prev; 89*7dd7cddfSDavid du Colombier else 90*7dd7cddfSDavid du Colombier m->next->prev = m->prev; 91*7dd7cddfSDavid du Colombier if(m->prev == nil) 92*7dd7cddfSDavid du Colombier replies.head = m->next; 93*7dd7cddfSDavid du Colombier else 94*7dd7cddfSDavid du Colombier m->prev->next = m->next; 95*7dd7cddfSDavid du Colombier mesgfreeparts(m); 96*7dd7cddfSDavid du Colombier free(m); 97*7dd7cddfSDavid du Colombier } 98*7dd7cddfSDavid du Colombier 99*7dd7cddfSDavid du Colombier enum 100*7dd7cddfSDavid du Colombier { 101*7dd7cddfSDavid du Colombier NARGS = 100, 102*7dd7cddfSDavid du Colombier NARGCHAR = 8*1024, 103*7dd7cddfSDavid du Colombier EXECSTACK = STACK+(NARGS+1)*sizeof(char*)+NARGCHAR 104*7dd7cddfSDavid du Colombier }; 105*7dd7cddfSDavid du Colombier 106*7dd7cddfSDavid du Colombier struct Exec 107*7dd7cddfSDavid du Colombier { 108*7dd7cddfSDavid du Colombier char **argv; 109*7dd7cddfSDavid du Colombier int p[2]; 110*7dd7cddfSDavid du Colombier Channel *sync; 111*7dd7cddfSDavid du Colombier }; 112*7dd7cddfSDavid du Colombier 113*7dd7cddfSDavid du Colombier /* copy argv to stack and free the incoming strings, so we don't leak argument vectors */ 114*7dd7cddfSDavid du Colombier void 115*7dd7cddfSDavid du Colombier buildargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR]) 116*7dd7cddfSDavid du Colombier { 117*7dd7cddfSDavid du Colombier int i, n; 118*7dd7cddfSDavid du Colombier char *s, *a; 119*7dd7cddfSDavid du Colombier 120*7dd7cddfSDavid du Colombier s = args; 121*7dd7cddfSDavid du Colombier for(i=0; i<NARGS; i++){ 122*7dd7cddfSDavid du Colombier a = inargv[i]; 123*7dd7cddfSDavid du Colombier if(a == nil) 124*7dd7cddfSDavid du Colombier break; 125*7dd7cddfSDavid du Colombier n = strlen(a)+1; 126*7dd7cddfSDavid du Colombier if((s-args)+n >= NARGCHAR) /* too many characters */ 127*7dd7cddfSDavid du Colombier break; 128*7dd7cddfSDavid du Colombier argv[i] = s; 129*7dd7cddfSDavid du Colombier memmove(s, a, n); 130*7dd7cddfSDavid du Colombier s += n; 131*7dd7cddfSDavid du Colombier free(a); 132*7dd7cddfSDavid du Colombier } 133*7dd7cddfSDavid du Colombier argv[i] = nil; 134*7dd7cddfSDavid du Colombier } 135*7dd7cddfSDavid du Colombier 136*7dd7cddfSDavid du Colombier void 137*7dd7cddfSDavid du Colombier execproc(void *v) 138*7dd7cddfSDavid du Colombier { 139*7dd7cddfSDavid du Colombier struct Exec *e; 140*7dd7cddfSDavid du Colombier int p[2]; 141*7dd7cddfSDavid du Colombier char *argv[NARGS+1], args[NARGCHAR]; 142*7dd7cddfSDavid du Colombier 143*7dd7cddfSDavid du Colombier e = v; 144*7dd7cddfSDavid du Colombier p[0] = e->p[0]; 145*7dd7cddfSDavid du Colombier p[1] = e->p[1]; 146*7dd7cddfSDavid du Colombier rfork(RFFDG); 147*7dd7cddfSDavid du Colombier sendul(e->sync, 1); 148*7dd7cddfSDavid du Colombier buildargv(e->argv, argv, args); 149*7dd7cddfSDavid du Colombier free(e->argv); 150*7dd7cddfSDavid du Colombier chanfree(e->sync); 151*7dd7cddfSDavid du Colombier free(e); 152*7dd7cddfSDavid du Colombier dup(p[0], 0); 153*7dd7cddfSDavid du Colombier close(p[1]); 154*7dd7cddfSDavid du Colombier procexec(nil, "/bin/upas/marshal", argv); 155*7dd7cddfSDavid du Colombier threadprint(2, "Mail: can't exec %s: %r\n", argv[0]); 156*7dd7cddfSDavid du Colombier threadexits("can't exec"); 157*7dd7cddfSDavid du Colombier } 158*7dd7cddfSDavid du Colombier 159*7dd7cddfSDavid du Colombier enum{ 160*7dd7cddfSDavid du Colombier ATTACH, 161*7dd7cddfSDavid du Colombier BCC, 162*7dd7cddfSDavid du Colombier CC, 163*7dd7cddfSDavid du Colombier FROM, 164*7dd7cddfSDavid du Colombier INCLUDE, 165*7dd7cddfSDavid du Colombier TO, 166*7dd7cddfSDavid du Colombier }; 167*7dd7cddfSDavid du Colombier 168*7dd7cddfSDavid du Colombier char *headers[] = { 169*7dd7cddfSDavid du Colombier "attach:", 170*7dd7cddfSDavid du Colombier "bcc:", 171*7dd7cddfSDavid du Colombier "cc:", 172*7dd7cddfSDavid du Colombier "from:", 173*7dd7cddfSDavid du Colombier "include:", 174*7dd7cddfSDavid du Colombier "to:", 175*7dd7cddfSDavid du Colombier nil, 176*7dd7cddfSDavid du Colombier }; 177*7dd7cddfSDavid du Colombier 178*7dd7cddfSDavid du Colombier int 179*7dd7cddfSDavid du Colombier whichheader(char *h) 180*7dd7cddfSDavid du Colombier { 181*7dd7cddfSDavid du Colombier int i; 182*7dd7cddfSDavid du Colombier 183*7dd7cddfSDavid du Colombier for(i=0; headers[i]!=nil; i++) 184*7dd7cddfSDavid du Colombier if(EQUAL(h, headers[i])) 185*7dd7cddfSDavid du Colombier return i; 186*7dd7cddfSDavid du Colombier return -1; 187*7dd7cddfSDavid du Colombier } 188*7dd7cddfSDavid du Colombier 189*7dd7cddfSDavid du Colombier char *tolist[200]; 190*7dd7cddfSDavid du Colombier char *cclist[200]; 191*7dd7cddfSDavid du Colombier char *bcclist[200]; 192*7dd7cddfSDavid du Colombier int ncc, nbcc, nto; 193*7dd7cddfSDavid du Colombier char *attlist[200]; 194*7dd7cddfSDavid du Colombier int rfc822[200]; 195*7dd7cddfSDavid du Colombier 196*7dd7cddfSDavid du Colombier int 197*7dd7cddfSDavid du Colombier addressed(char *name) 198*7dd7cddfSDavid du Colombier { 199*7dd7cddfSDavid du Colombier int i; 200*7dd7cddfSDavid du Colombier 201*7dd7cddfSDavid du Colombier for(i=0; i<nto; i++) 202*7dd7cddfSDavid du Colombier if(strcmp(name, tolist[i]) == 0) 203*7dd7cddfSDavid du Colombier return 1; 204*7dd7cddfSDavid du Colombier for(i=0; i<ncc; i++) 205*7dd7cddfSDavid du Colombier if(strcmp(name, cclist[i]) == 0) 206*7dd7cddfSDavid du Colombier return 1; 207*7dd7cddfSDavid du Colombier for(i=0; i<nbcc; i++) 208*7dd7cddfSDavid du Colombier if(strcmp(name, bcclist[i]) == 0) 209*7dd7cddfSDavid du Colombier return 1; 210*7dd7cddfSDavid du Colombier return 0; 211*7dd7cddfSDavid du Colombier } 212*7dd7cddfSDavid du Colombier 213*7dd7cddfSDavid du Colombier char* 214*7dd7cddfSDavid du Colombier skipbl(char *s, char *e) 215*7dd7cddfSDavid du Colombier { 216*7dd7cddfSDavid du Colombier while(s < e){ 217*7dd7cddfSDavid du Colombier if(*s!=' ' && *s!='\t' && *s!=',') 218*7dd7cddfSDavid du Colombier break; 219*7dd7cddfSDavid du Colombier s++; 220*7dd7cddfSDavid du Colombier } 221*7dd7cddfSDavid du Colombier return s; 222*7dd7cddfSDavid du Colombier } 223*7dd7cddfSDavid du Colombier 224*7dd7cddfSDavid du Colombier char* 225*7dd7cddfSDavid du Colombier findbl(char *s, char *e) 226*7dd7cddfSDavid du Colombier { 227*7dd7cddfSDavid du Colombier while(s < e){ 228*7dd7cddfSDavid du Colombier if(*s==' ' || *s=='\t' || *s==',') 229*7dd7cddfSDavid du Colombier break; 230*7dd7cddfSDavid du Colombier s++; 231*7dd7cddfSDavid du Colombier } 232*7dd7cddfSDavid du Colombier return s; 233*7dd7cddfSDavid du Colombier } 234*7dd7cddfSDavid du Colombier 235*7dd7cddfSDavid du Colombier /* 236*7dd7cddfSDavid du Colombier * comma-separate possibly blank-separated strings in line; e points before newline 237*7dd7cddfSDavid du Colombier */ 238*7dd7cddfSDavid du Colombier void 239*7dd7cddfSDavid du Colombier commas(char *s, char *e) 240*7dd7cddfSDavid du Colombier { 241*7dd7cddfSDavid du Colombier char *t; 242*7dd7cddfSDavid du Colombier 243*7dd7cddfSDavid du Colombier /* may have initial blanks */ 244*7dd7cddfSDavid du Colombier s = skipbl(s, e); 245*7dd7cddfSDavid du Colombier while(s < e){ 246*7dd7cddfSDavid du Colombier s = findbl(s, e); 247*7dd7cddfSDavid du Colombier if(s == e) 248*7dd7cddfSDavid du Colombier break; 249*7dd7cddfSDavid du Colombier t = skipbl(s, e); 250*7dd7cddfSDavid du Colombier if(t == e) /* no more words */ 251*7dd7cddfSDavid du Colombier break; 252*7dd7cddfSDavid du Colombier /* patch comma */ 253*7dd7cddfSDavid du Colombier *s++ = ','; 254*7dd7cddfSDavid du Colombier while(s < t) 255*7dd7cddfSDavid du Colombier *s++ = ' '; 256*7dd7cddfSDavid du Colombier } 257*7dd7cddfSDavid du Colombier } 258*7dd7cddfSDavid du Colombier 259*7dd7cddfSDavid du Colombier void 260*7dd7cddfSDavid du Colombier mesgsend(Message *m) 261*7dd7cddfSDavid du Colombier { 262*7dd7cddfSDavid du Colombier char *s, *body, *to; 263*7dd7cddfSDavid du Colombier int i, j, h, n, natt, p[2]; 264*7dd7cddfSDavid du Colombier struct Exec *e; 265*7dd7cddfSDavid du Colombier Channel *sync; 266*7dd7cddfSDavid du Colombier int first, nfld, delit; 267*7dd7cddfSDavid du Colombier char *copy, *fld[100]; 268*7dd7cddfSDavid du Colombier 269*7dd7cddfSDavid du Colombier body = winreadbody(m->w, &n); 270*7dd7cddfSDavid du Colombier /* assemble to: list from first line, to: line, and cc: line */ 271*7dd7cddfSDavid du Colombier nto = 0; 272*7dd7cddfSDavid du Colombier natt = 0; 273*7dd7cddfSDavid du Colombier ncc = 0; 274*7dd7cddfSDavid du Colombier nbcc = 0; 275*7dd7cddfSDavid du Colombier first = 1; 276*7dd7cddfSDavid du Colombier to = body; 277*7dd7cddfSDavid du Colombier for(;;){ 278*7dd7cddfSDavid du Colombier for(s=to; *s!='\n'; s++) 279*7dd7cddfSDavid du Colombier if(*s == '\0'){ 280*7dd7cddfSDavid du Colombier free(body); 281*7dd7cddfSDavid du Colombier return; 282*7dd7cddfSDavid du Colombier } 283*7dd7cddfSDavid du Colombier if(s++ == to) /* blank line */ 284*7dd7cddfSDavid du Colombier break; 285*7dd7cddfSDavid du Colombier /* make copy of line to tokenize */ 286*7dd7cddfSDavid du Colombier copy = emalloc(s-to); 287*7dd7cddfSDavid du Colombier memmove(copy, to, s-to); 288*7dd7cddfSDavid du Colombier copy[s-to-1] = '\0'; 289*7dd7cddfSDavid du Colombier nfld = tokenizec(copy, fld, nelem(fld), ", \t"); 290*7dd7cddfSDavid du Colombier if(nfld == 0){ 291*7dd7cddfSDavid du Colombier free(copy); 292*7dd7cddfSDavid du Colombier break; 293*7dd7cddfSDavid du Colombier } 294*7dd7cddfSDavid du Colombier n -= s-to; 295*7dd7cddfSDavid du Colombier switch(h = whichheader(fld[0])){ 296*7dd7cddfSDavid du Colombier case TO: 297*7dd7cddfSDavid du Colombier case FROM: 298*7dd7cddfSDavid du Colombier delit = (h == FROM); 299*7dd7cddfSDavid du Colombier commas(to+strlen(fld[0]), s-1); 300*7dd7cddfSDavid du Colombier for(i=1; i<nfld && nto<nelem(tolist); i++) 301*7dd7cddfSDavid du Colombier if(!addressed(fld[i])) 302*7dd7cddfSDavid du Colombier tolist[nto++] = estrdup(fld[i]); 303*7dd7cddfSDavid du Colombier break; 304*7dd7cddfSDavid du Colombier case BCC: 305*7dd7cddfSDavid du Colombier delit = 1; 306*7dd7cddfSDavid du Colombier commas(to+strlen(fld[0]), s-1); 307*7dd7cddfSDavid du Colombier for(i=1; i<nfld && nbcc<nelem(bcclist); i++) 308*7dd7cddfSDavid du Colombier if(!addressed(fld[i])) 309*7dd7cddfSDavid du Colombier bcclist[nbcc++] = estrdup(fld[i]); 310*7dd7cddfSDavid du Colombier break; 311*7dd7cddfSDavid du Colombier case CC: 312*7dd7cddfSDavid du Colombier delit = 0; 313*7dd7cddfSDavid du Colombier commas(to+strlen(fld[0]), s-1); 314*7dd7cddfSDavid du Colombier for(i=1; i<nfld && ncc<nelem(cclist); i++) 315*7dd7cddfSDavid du Colombier if(!addressed(fld[i])) 316*7dd7cddfSDavid du Colombier cclist[ncc++] = estrdup(fld[i]); 317*7dd7cddfSDavid du Colombier break; 318*7dd7cddfSDavid du Colombier case ATTACH: 319*7dd7cddfSDavid du Colombier case INCLUDE: 320*7dd7cddfSDavid du Colombier delit = 1; 321*7dd7cddfSDavid du Colombier for(i=1; i<nfld && natt<nelem(attlist); i++){ 322*7dd7cddfSDavid du Colombier attlist[natt] = estrdup(fld[i]); 323*7dd7cddfSDavid du Colombier rfc822[natt++] = (h == INCLUDE); 324*7dd7cddfSDavid du Colombier } 325*7dd7cddfSDavid du Colombier break; 326*7dd7cddfSDavid du Colombier default: 327*7dd7cddfSDavid du Colombier if(first){ 328*7dd7cddfSDavid du Colombier delit = 1; 329*7dd7cddfSDavid du Colombier for(i=0; i<nfld && nto<nelem(tolist); i++) 330*7dd7cddfSDavid du Colombier tolist[nto++] = estrdup(fld[i]); 331*7dd7cddfSDavid du Colombier }else /* ignore it */ 332*7dd7cddfSDavid du Colombier delit = 0; 333*7dd7cddfSDavid du Colombier break; 334*7dd7cddfSDavid du Colombier } 335*7dd7cddfSDavid du Colombier if(delit){ 336*7dd7cddfSDavid du Colombier /* delete line from body */ 337*7dd7cddfSDavid du Colombier memmove(to, s, n+1); 338*7dd7cddfSDavid du Colombier }else 339*7dd7cddfSDavid du Colombier to = s; 340*7dd7cddfSDavid du Colombier free(copy); 341*7dd7cddfSDavid du Colombier first = 0; 342*7dd7cddfSDavid du Colombier } 343*7dd7cddfSDavid du Colombier 344*7dd7cddfSDavid du Colombier e = emalloc(sizeof(struct Exec)); 345*7dd7cddfSDavid du Colombier if(pipe(p) < 0) 346*7dd7cddfSDavid du Colombier error("Mail: can't create pipe\n"); 347*7dd7cddfSDavid du Colombier e->p[0] = p[0]; 348*7dd7cddfSDavid du Colombier e->p[1] = p[1]; 349*7dd7cddfSDavid du Colombier e->argv = emalloc((1+4*natt+nto+ncc+nbcc+1)*sizeof(char*)); 350*7dd7cddfSDavid du Colombier e->argv[0] = estrdup("marshal"); 351*7dd7cddfSDavid du Colombier j = 1; 352*7dd7cddfSDavid du Colombier for(i=0; i<natt; i++){ 353*7dd7cddfSDavid du Colombier if(rfc822[i]){ 354*7dd7cddfSDavid du Colombier e->argv[j++] = estrdup("-t"); 355*7dd7cddfSDavid du Colombier e->argv[j++] = estrdup("message/rfc822"); 356*7dd7cddfSDavid du Colombier e->argv[j++] = estrdup("-A"); 357*7dd7cddfSDavid du Colombier }else 358*7dd7cddfSDavid du Colombier e->argv[j++] = estrdup("-a"); 359*7dd7cddfSDavid du Colombier e->argv[j++] = attlist[i]; 360*7dd7cddfSDavid du Colombier } 361*7dd7cddfSDavid du Colombier for(i=0; i<nto; i++) 362*7dd7cddfSDavid du Colombier e->argv[j++] = tolist[i]; 363*7dd7cddfSDavid du Colombier for(i=0; i<ncc; i++) 364*7dd7cddfSDavid du Colombier e->argv[j++] = cclist[i]; 365*7dd7cddfSDavid du Colombier for(i=0; i<nbcc; i++) 366*7dd7cddfSDavid du Colombier e->argv[j++] = bcclist[i]; 367*7dd7cddfSDavid du Colombier sync = chancreate(sizeof(int), 0); 368*7dd7cddfSDavid du Colombier e->sync = sync; 369*7dd7cddfSDavid du Colombier proccreate(execproc, e, EXECSTACK); 370*7dd7cddfSDavid du Colombier recvul(sync); 371*7dd7cddfSDavid du Colombier close(p[0]); 372*7dd7cddfSDavid du Colombier 373*7dd7cddfSDavid du Colombier i = strlen(body); 374*7dd7cddfSDavid du Colombier if(i > 0) 375*7dd7cddfSDavid du Colombier write(p[1], body, i); 376*7dd7cddfSDavid du Colombier 377*7dd7cddfSDavid du Colombier /* guarantee a blank line, to ensure attachments are separated from body */ 378*7dd7cddfSDavid du Colombier if(i==0 || body[i-1]!='\n') 379*7dd7cddfSDavid du Colombier write(p[1], "\n\n", 2); 380*7dd7cddfSDavid du Colombier else if(i>1 && body[i-2]!='\n') 381*7dd7cddfSDavid du Colombier write(p[1], "\n", 1); 382*7dd7cddfSDavid du Colombier close(p[1]); 383*7dd7cddfSDavid du Colombier free(body); 384*7dd7cddfSDavid du Colombier 385*7dd7cddfSDavid du Colombier if(m->replyname != nil) 386*7dd7cddfSDavid du Colombier mesgmenumark(mbox.w, m->replyname, "\t[replied]"); 387*7dd7cddfSDavid du Colombier if(m->name[0] == '/') 388*7dd7cddfSDavid du Colombier s = estrdup(m->name); 389*7dd7cddfSDavid du Colombier else 390*7dd7cddfSDavid du Colombier s = estrstrdup(mbox.name, m->name); 391*7dd7cddfSDavid du Colombier s = egrow(s, "-R", nil); 392*7dd7cddfSDavid du Colombier winname(m->w, s); 393*7dd7cddfSDavid du Colombier free(s); 394*7dd7cddfSDavid du Colombier winclean(m->w); 395*7dd7cddfSDavid du Colombier } 396