11244Skas # 21244Skas 31244Skas #include "rcv.h" 41244Skas #ifdef VMUNIX 51244Skas #include <wait.h> 61244Skas #endif 7*3239Skas #include <ctype.h> 81244Skas 91244Skas /* 101244Skas * Mail -- a mail program 111244Skas * 121244Skas * Mail to others. 131244Skas */ 141244Skas 15*3239Skas static char *SccsId = "@(#)send.c 1.4 03/13/81"; 161244Skas 171244Skas /* 181244Skas * Send message described by the passed pointer to the 191244Skas * passed output buffer. Return -1 on error, but normally 201487Skas * the number of lines written. Adjust the status: field 211487Skas * if need be. 221244Skas */ 231244Skas 241244Skas send(mailp, obuf) 251244Skas struct message *mailp; 261244Skas FILE *obuf; 271244Skas { 281244Skas register struct message *mp; 291244Skas register int t; 301244Skas unsigned int c; 311244Skas FILE *ibuf; 321487Skas char line[LINESIZE]; 33*3239Skas int lc, ishead, infld, fline; 341244Skas 351244Skas mp = mailp; 361244Skas ibuf = setinput(mp); 371244Skas c = msize(mp); 381487Skas ishead = (mailp->m_flag & MSTATUS) != 0; 39*3239Skas infld = 0; 40*3239Skas fline = 1; 411244Skas lc = 0; 421487Skas while (c > 0) { 431487Skas fgets(line, LINESIZE, ibuf); 441487Skas c -= strlen(line); 451487Skas lc++; 461487Skas if (ishead) { 47*3239Skas if (fline) { 48*3239Skas fline = 0; 49*3239Skas goto writeit; 50*3239Skas } 511487Skas if (line[0] == '\n') { 521487Skas statusput(mailp, obuf); 531487Skas ishead = 0; 541487Skas goto writeit; 551487Skas } 56*3239Skas if (isspace(line[0]) && infld) 571487Skas goto writeit; 58*3239Skas infld = 0; 59*3239Skas if (!headerp(line)) { 60*3239Skas statusput(mailp, obuf); 61*3239Skas putc('\n', obuf); 62*3239Skas ishead = 0; 63*3239Skas goto writeit; 64*3239Skas } 65*3239Skas infld++; 661487Skas if (icisname(line, "status", 6)) { 671487Skas statusput(mailp, obuf); 681487Skas ishead = 0; 691487Skas continue; 701487Skas } 711487Skas } 721487Skas writeit: 731487Skas fputs(line, obuf); 741244Skas if (ferror(obuf)) 751244Skas return(-1); 761244Skas } 771487Skas if (ferror(obuf)) 781487Skas return(-1); 791487Skas if (ishead && (mailp->m_flag & MSTATUS)) 801487Skas printf("failed to fix up status field\n"); 811244Skas return(lc); 821244Skas } 831244Skas 841244Skas /* 85*3239Skas * Test if the passed line is a header line, RFC 733 style. 86*3239Skas */ 87*3239Skas headerp(line) 88*3239Skas register char *line; 89*3239Skas { 90*3239Skas register char *cp = line; 91*3239Skas 92*3239Skas while (*cp && !isspace(*cp) && *cp != ':') 93*3239Skas cp++; 94*3239Skas while (*cp && isspace(*cp)) 95*3239Skas cp++; 96*3239Skas return(*cp == ':'); 97*3239Skas } 98*3239Skas 99*3239Skas /* 1001487Skas * Output a reasonable looking status field. 1011487Skas */ 1021487Skas 1031487Skas statusput(mp, obuf) 1041487Skas register struct message *mp; 1051487Skas register FILE *obuf; 1061487Skas { 1071487Skas char statout[3]; 1081487Skas 1091487Skas if ((mp->m_flag & (MNEW|MREAD)) == MNEW) 1101487Skas return; 1111487Skas if (mp->m_flag & MREAD) 1121487Skas strcpy(statout, "R"); 1131487Skas else 1141487Skas strcpy(statout, ""); 1151487Skas if ((mp->m_flag & MNEW) == 0) 1161487Skas strcat(statout, "O"); 1171487Skas fprintf(obuf, "Status: %s\n", statout); 1181487Skas } 1191487Skas 1201487Skas 1211487Skas /* 1221244Skas * Interface between the argument list and the mail1 routine 1231244Skas * which does all the dirty work. 1241244Skas */ 1251244Skas 1261244Skas mail(people) 1271244Skas char **people; 1281244Skas { 1291244Skas register char *cp2; 1301244Skas register int s; 1311244Skas char *buf, **ap; 1321244Skas struct header head; 1331244Skas 1341244Skas for (s = 0, ap = people; *ap != (char *) -1; ap++) 1351244Skas s += strlen(*ap) + 1; 1361244Skas buf = salloc(s+1); 1371244Skas cp2 = buf; 1381244Skas for (ap = people; *ap != (char *) -1; ap++) { 1391244Skas cp2 = copy(*ap, cp2); 1401244Skas *cp2++ = ' '; 1411244Skas } 1421244Skas if (cp2 != buf) 1431244Skas cp2--; 1441244Skas *cp2 = '\0'; 1451244Skas head.h_to = buf; 1461244Skas head.h_subject = NOSTR; 1471244Skas head.h_cc = NOSTR; 1481244Skas head.h_bcc = NOSTR; 1491244Skas head.h_seq = 0; 1501244Skas mail1(&head); 1511244Skas return(0); 1521244Skas } 1531244Skas 1541244Skas 1551244Skas /* 1561244Skas * Send mail to a bunch of user names. The interface is through 1571244Skas * the mail routine below. 1581244Skas */ 1591244Skas 1601244Skas sendmail(str) 1611244Skas char *str; 1621244Skas { 1631244Skas register char **ap; 1641244Skas char *bufp; 1651244Skas register int t; 1661244Skas struct header head; 1671244Skas 1681244Skas if (blankline(str)) 1691244Skas head.h_to = NOSTR; 1701244Skas else 1711244Skas head.h_to = str; 1721244Skas head.h_subject = NOSTR; 1731244Skas head.h_cc = NOSTR; 1741244Skas head.h_bcc = NOSTR; 1751244Skas head.h_seq = 0; 1761244Skas mail1(&head); 1771244Skas return(0); 1781244Skas } 1791244Skas 1801244Skas /* 1811244Skas * Mail a message on standard input to the people indicated 1821244Skas * in the passed header. (Internal interface). 1831244Skas */ 1841244Skas 1851244Skas mail1(hp) 1861244Skas struct header *hp; 1871244Skas { 1881244Skas register char *cp; 1891244Skas int pid, i, s, p, gotcha; 1901244Skas char **namelist; 1911244Skas struct name *to, *np; 1921244Skas FILE *mtf, *postage; 1931244Skas int remote = rflag != NOSTR || rmail; 1941244Skas char **t; 1951244Skas 1961244Skas /* 1971244Skas * Collect user's mail from standard input. 1981244Skas * Get the result as mtf. 1991244Skas */ 2001244Skas 2011244Skas pid = -1; 2021244Skas if ((mtf = collect(hp)) == NULL) 2031244Skas return(-1); 2041244Skas hp->h_seq = 1; 2051244Skas if (hp->h_subject == NOSTR) 2061244Skas hp->h_subject = sflag; 2071244Skas if (fsize(mtf) == 0 && hp->h_subject == NOSTR) { 2081244Skas printf("No message !?!\n"); 2091244Skas goto out; 2101244Skas } 2111244Skas if (intty && value("askcc") != NOSTR) 2121244Skas grabh(hp, GCC); 2131244Skas else if (intty) { 2141244Skas printf("EOT\n"); 2151244Skas flush(); 2161244Skas } 2171244Skas 2181244Skas /* 2191244Skas * Now, take the user names from the combined 2201244Skas * to and cc lists and do all the alias 2211244Skas * processing. 2221244Skas */ 2231244Skas 2241244Skas senderr = 0; 2251244Skas to = usermap(cat(extract(hp->h_bcc, GBCC), 2261244Skas cat(extract(hp->h_to, GTO), extract(hp->h_cc, GCC)))); 2271244Skas if (to == NIL) { 2281244Skas printf("No recipients specified\n"); 2291244Skas goto topdog; 2301244Skas } 2311244Skas 2321244Skas /* 2331244Skas * Look through the recipient list for names with /'s 2341244Skas * in them which we write to as files directly. 2351244Skas */ 2361244Skas 2371244Skas to = outof(to, mtf, hp); 2381244Skas rewind(mtf); 2391244Skas to = verify(to); 2401244Skas if (senderr && !remote) { 2411244Skas topdog: 2421244Skas 2431244Skas if (fsize(mtf) != 0) { 2441244Skas remove(deadletter); 2451244Skas exwrite(deadletter, mtf, 1); 2461244Skas rewind(mtf); 2471244Skas } 2481244Skas } 2491244Skas for (gotcha = 0, np = to; np != NIL; np = np->n_flink) 2501244Skas if ((np->n_type & GDEL) == 0) { 2511244Skas gotcha++; 2521244Skas break; 2531244Skas } 2541244Skas if (!gotcha) 2551244Skas goto out; 2561244Skas to = elide(to); 2571244Skas mechk(to); 2581244Skas if (count(to) > 1) 2591244Skas hp->h_seq++; 2601244Skas if (hp->h_seq > 0 && !remote) { 2611244Skas fixhead(hp, to); 2621244Skas if (fsize(mtf) == 0) 2631244Skas printf("Null message body; hope that's ok\n"); 2641244Skas if ((mtf = infix(hp, mtf)) == NULL) { 2651244Skas fprintf(stderr, ". . . message lost, sorry.\n"); 2661244Skas return(-1); 2671244Skas } 2681244Skas } 2691244Skas namelist = unpack(to); 2701244Skas if (debug) { 2711244Skas printf("Recipients of message:\n"); 2721244Skas for (t = namelist; *t != NOSTR; t++) 2731244Skas printf(" \"%s\"", *t); 2741244Skas printf("\n"); 2751244Skas fflush(stdout); 2761244Skas return; 2771244Skas } 2781244Skas if ((cp = value("record")) != NOSTR) 2791244Skas savemail(expand(cp), hp, mtf); 2801244Skas 2811244Skas /* 2821244Skas * Wait, to absorb a potential zombie, then 2831244Skas * fork, set up the temporary mail file as standard 2841244Skas * input for "mail" and exec with the user list we generated 2851244Skas * far above. Return the process id to caller in case he 2861244Skas * wants to await the completion of mail. 2871244Skas */ 2881244Skas 2891244Skas #ifdef VMUNIX 2901244Skas while (wait3(&s, WNOHANG, 0) > 0) 2911244Skas ; 2921244Skas #else 2931244Skas wait(&s); 2941244Skas #endif 2951244Skas rewind(mtf); 2961244Skas pid = fork(); 2971244Skas if (pid == -1) { 2981244Skas perror("fork"); 2991244Skas remove(deadletter); 3001244Skas exwrite(deadletter, mtf, 1); 3011244Skas goto out; 3021244Skas } 3031244Skas if (pid == 0) { 3041244Skas #ifdef SIGTSTP 3051244Skas if (remote == 0) { 3061244Skas signal(SIGTSTP, SIG_IGN); 3071244Skas signal(SIGTTIN, SIG_IGN); 3081244Skas signal(SIGTTOU, SIG_IGN); 3091244Skas } 3101244Skas #endif 3111244Skas for (i = SIGHUP; i <= SIGQUIT; i++) 3121244Skas signal(i, SIG_IGN); 3131244Skas if ((postage = fopen("/crp/kurt/postage", "a")) != NULL) { 3141244Skas fprintf(postage, "%s %d %d\n", myname, 3151244Skas count(to), fsize(mtf)); 3161244Skas fclose(postage); 3171244Skas } 3181244Skas s = fileno(mtf); 3191244Skas for (i = 3; i < 15; i++) 3201244Skas if (i != s) 3211244Skas close(i); 3221244Skas close(0); 3231244Skas dup(s); 3241244Skas close(s); 3251244Skas #ifdef CC 3261244Skas submit(getpid()); 3271244Skas #endif CC 3281244Skas #ifdef DELIVERMAIL 3291244Skas execv(DELIVERMAIL, namelist); 3301244Skas #endif DELIVERMAIL 3311244Skas execv(MAIL, namelist); 3321244Skas perror(MAIL); 3331244Skas exit(1); 3341244Skas } 3351244Skas 3361244Skas out: 3371244Skas if (remote) { 3381244Skas while ((p = wait(&s)) != pid && p != -1) 3391244Skas ; 3401244Skas if (s != 0) 3411244Skas senderr++; 3421244Skas pid = 0; 3431244Skas } 3441244Skas fclose(mtf); 3451244Skas return(pid); 3461244Skas } 3471244Skas 3481244Skas /* 3491244Skas * Fix the header by glopping all of the expanded names from 3501244Skas * the distribution list into the appropriate fields. 3511244Skas * If there are any ARPA net recipients in the message, 3521244Skas * we must insert commas, alas. 3531244Skas */ 3541244Skas 3551244Skas fixhead(hp, tolist) 3561244Skas struct header *hp; 3571244Skas struct name *tolist; 3581244Skas { 3591244Skas register struct name *nlist; 3601244Skas register int f; 3611244Skas register struct name *np; 3621244Skas 3631244Skas for (f = 0, np = tolist; np != NIL; np = np->n_flink) 3641244Skas if (any('@', np->n_name)) { 3651244Skas f |= GCOMMA; 3661244Skas break; 3671244Skas } 3681244Skas 3691244Skas if (debug && f & GCOMMA) 3701244Skas fprintf(stderr, "Should be inserting commas in recip lists\n"); 3711244Skas hp->h_to = detract(tolist, GTO|f); 3721244Skas hp->h_cc = detract(tolist, GCC|f); 3731244Skas } 3741244Skas 3751244Skas /* 3761244Skas * Prepend a header in front of the collected stuff 3771244Skas * and return the new file. 3781244Skas */ 3791244Skas 3801244Skas FILE * 3811244Skas infix(hp, fi) 3821244Skas struct header *hp; 3831244Skas FILE *fi; 3841244Skas { 3851244Skas extern char tempMail[]; 3861244Skas register FILE *nfo, *nfi; 3871244Skas register int c; 3881244Skas 3892062Skas rewind(fi); 3901244Skas if ((nfo = fopen(tempMail, "w")) == NULL) { 3911244Skas perror(tempMail); 3921244Skas return(fi); 3931244Skas } 3941244Skas if ((nfi = fopen(tempMail, "r")) == NULL) { 3951244Skas perror(tempMail); 3961244Skas fclose(nfo); 3971244Skas return(fi); 3981244Skas } 3991244Skas remove(tempMail); 4001244Skas puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL); 4011244Skas c = getc(fi); 4021244Skas while (c != EOF) { 4031244Skas putc(c, nfo); 4041244Skas c = getc(fi); 4051244Skas } 4061244Skas if (ferror(fi)) { 4071244Skas perror("read"); 4081244Skas return(fi); 4091244Skas } 4101244Skas fflush(nfo); 4111244Skas if (ferror(nfo)) { 4121244Skas perror(tempMail); 4131244Skas fclose(nfo); 4141244Skas fclose(nfi); 4151244Skas return(fi); 4161244Skas } 4171244Skas fclose(nfo); 4181244Skas fclose(fi); 4191244Skas rewind(nfi); 4201244Skas return(nfi); 4211244Skas } 4221244Skas 4231244Skas /* 4241244Skas * Dump the to, subject, cc header on the 4251244Skas * passed file buffer. 4261244Skas */ 4271244Skas 4281244Skas puthead(hp, fo, w) 4291244Skas struct header *hp; 4301244Skas FILE *fo; 4311244Skas { 4321244Skas register int gotcha; 4331244Skas 4341244Skas gotcha = 0; 4351244Skas if (hp->h_to != NOSTR && w & GTO) 4361244Skas fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++; 4371244Skas if (hp->h_subject != NOSTR && w & GSUBJECT) 4381244Skas fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 4391244Skas if (hp->h_cc != NOSTR && w & GCC) 4401244Skas fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++; 4411244Skas if (hp->h_bcc != NOSTR && w & GBCC) 4421244Skas fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), gotcha++; 4431244Skas if (gotcha && w & GNL) 4441244Skas putc('\n', fo); 4451244Skas return(0); 4461244Skas } 4471244Skas 4481244Skas /* 4491244Skas * Format the given text to not exceed 72 characters. 4501244Skas */ 4511244Skas 4521244Skas fmt(str, fo) 4531244Skas register char *str; 4541244Skas register FILE *fo; 4551244Skas { 4561244Skas register int col; 4571244Skas register char *cp; 4581244Skas 4591244Skas cp = str; 4601244Skas col = 0; 4611244Skas while (*cp) { 4621244Skas if (*cp == ' ' && col > 65) { 4631244Skas fprintf(fo, "\n "); 4641244Skas col = 4; 4651244Skas cp++; 4661244Skas continue; 4671244Skas } 4681244Skas putc(*cp++, fo); 4691244Skas col++; 4701244Skas } 4711244Skas putc('\n', fo); 4721244Skas } 4731244Skas 4741244Skas /* 4751244Skas * Save the outgoing mail on the passed file. 4761244Skas */ 4771244Skas 4781244Skas savemail(name, hp, fi) 4791244Skas char name[]; 4801244Skas struct header *hp; 4811244Skas FILE *fi; 4821244Skas { 4831244Skas register FILE *fo; 4841244Skas register int c; 4851244Skas long now; 4861244Skas char *n; 4871244Skas 4881244Skas if ((fo = fopen(name, "a")) == NULL) { 4891244Skas perror(name); 4901244Skas return(-1); 4911244Skas } 4921244Skas time(&now); 4931244Skas n = rflag; 4941244Skas if (n == NOSTR) 4951244Skas n = myname; 4961244Skas fprintf(fo, "From %s %s", n, ctime(&now)); 4971244Skas rewind(fi); 4981244Skas for (c = getc(fi); c != EOF; c = getc(fi)) 4991244Skas putc(c, fo); 5001244Skas fprintf(fo, "\n"); 5011244Skas fflush(fo); 5021244Skas if (ferror(fo)) 5031244Skas perror(name); 5041244Skas fclose(fo); 5051244Skas return(0); 5061244Skas } 507