114552Ssam #ifndef lint 2*15738Sralph static char sccsid[] = "@(#)bugfiler.c 4.13 (Berkeley) 12/19/83"; 314552Ssam #endif 414552Ssam 512375Sralph /* 612375Sralph * Bug report processing program. 714809Ssam * It is designed to be invoked by alias(5) 814809Ssam * and to be compatible with mh. 912375Sralph */ 1012375Sralph 1112375Sralph #include <stdio.h> 1212375Sralph #include <ctype.h> 1312375Sralph #include <signal.h> 1414809Ssam #include <pwd.h> 1514809Ssam 1612375Sralph #include <sys/types.h> 1712375Sralph #include <sys/stat.h> 1812695Sralph #include <sys/dir.h> 1912375Sralph 2014809Ssam #define BUGS_NAME "4bsd-bugs" 2114809Ssam #define BUGS_HOME "%ucbarpa@BERKELEY" 2214809Ssam #define MAILCMD "/usr/lib/sendmail -i -t" 2314809Ssam 2414808Ssam char unixtomh[] = "/usr/new/lib/mh/unixtomh"; 2514809Ssam char *bugperson = "bugs"; 2614809Ssam char *maildir = "mail"; 2712375Sralph char ackfile[] = ".ack"; 2812375Sralph char errfile[] = ".format"; 2912375Sralph char sumfile[] = "summary"; 3012375Sralph char logfile[] = "errors/log"; 3114809Ssam char redistfile[] = ".redist"; 3212375Sralph char tmpname[] = "BfXXXXXX"; 3312375Sralph char draft[] = "RpXXXXXX"; 3414809Ssam char disttmp[] = "RcXXXXXX"; 3512375Sralph 3612695Sralph char buf[8192]; 3712375Sralph char folder[MAXNAMLEN]; 3812375Sralph int num; 3912375Sralph int msg_prot = 0664; 4012375Sralph 4112375Sralph int debug; 4212375Sralph 4312375Sralph char *index(); 4412375Sralph char *rindex(); 4512375Sralph char *fixaddr(); 4614809Ssam char *any(); 4712375Sralph 4812375Sralph main(argc, argv) 4912375Sralph char *argv[]; 5012375Sralph { 5112375Sralph register char *cp; 5212695Sralph register int n; 5312695Sralph int pfd[2]; 5412375Sralph 5515686Sralph if (argc > 4) { 5612375Sralph usage: 5712695Sralph fprintf(stderr, "Usage: bugfiler [-d] [-mmsg_mode] [maildir]\n"); 5812375Sralph exit(1); 5912375Sralph } 6012375Sralph while (--argc > 0) { 6112375Sralph cp = *++argv; 6212695Sralph if (*cp == '-') 6312695Sralph switch (cp[1]) { 6412375Sralph case 'd': 6512375Sralph debug++; 6612375Sralph break; 6712695Sralph 6812695Sralph case 'm': /* set message protection */ 6912695Sralph n = 0; 7012695Sralph for (cp += 2; *cp >= '0' && *cp <= '7'; ) 7112695Sralph n = (n << 3) + (*cp++ - '0'); 7212695Sralph msg_prot = n & 0777; 7312695Sralph break; 7412695Sralph 7512375Sralph default: 7612375Sralph goto usage; 7712375Sralph } 7812375Sralph else 7912375Sralph maildir = cp; 8012375Sralph } 8112695Sralph if (!debug) 8212695Sralph freopen(logfile, "a", stderr); 8312695Sralph 8414809Ssam if (bugperson) { 8514809Ssam struct passwd *pwd = getpwnam(bugperson); 8614809Ssam 8714809Ssam if (pwd == NULL) { 8814809Ssam fprintf(stderr, "%s: bugs person is unknown\n", 8914809Ssam bugperson); 9014809Ssam exit(1); 9114809Ssam } 9214809Ssam if (chdir(pwd->pw_dir) < 0) { 9314809Ssam fprintf(stderr, "can't chdir to %s\n", pwd->pw_dir); 9414809Ssam exit(1); 9514809Ssam } 9615686Sralph setuid(pwd->pw_uid); 9714809Ssam } 9812375Sralph if (chdir(maildir) < 0) { 9912375Sralph fprintf(stderr, "can't chdir to %s\n", maildir); 10012375Sralph exit(1); 10112375Sralph } 10212695Sralph umask(0); 10312695Sralph 10412695Sralph #ifdef UNIXCOMP 10512695Sralph /* 10612695Sralph * Convert UNIX style mail to mh style by filtering stdin through 10712695Sralph * unixtomh. 10812695Sralph */ 10912695Sralph if (pipe(pfd) >= 0) { 11012695Sralph while ((n = fork()) == -1) 11112695Sralph sleep(5); 11212695Sralph if (n == 0) { 11312695Sralph close(pfd[0]); 11412695Sralph dup2(pfd[1], 1); 11512695Sralph close(pfd[1]); 11612695Sralph execl(unixtomh, "unixtomh", 0); 11712695Sralph _exit(127); 11812695Sralph } 11912695Sralph close(pfd[1]); 12012695Sralph dup2(pfd[0], 0); 12112695Sralph close(pfd[0]); 12212695Sralph } 12312695Sralph #endif 12412695Sralph while (process()) 12512695Sralph ; 12612695Sralph exit(0); 12712375Sralph } 12812375Sralph 12912695Sralph /* states */ 13012695Sralph 13112695Sralph #define EOM 0 /* End of message seen */ 13212695Sralph #define FLD 1 /* Looking for header lines */ 13312695Sralph #define BODY 2 /* Looking for message body lines */ 13412695Sralph 13512375Sralph /* defines used for tag attributes */ 13612375Sralph 13712375Sralph #define H_REQ 01 13812695Sralph #define H_SAV 02 13912695Sralph #define H_HDR 04 14012695Sralph #define H_FND 010 14112375Sralph 142*15738Sralph #define FROM &headers[0] 14312375Sralph #define FROM_I headers[0].h_info 14412375Sralph #define SUBJECT_I headers[1].h_info 14512375Sralph #define INDEX &headers[2] 14612375Sralph #define INDEX_I headers[2].h_info 14712375Sralph #define DATE_I headers[3].h_info 14812375Sralph #define MSGID_I headers[4].h_info 14912375Sralph #define REPLYTO_I headers[5].h_info 15014981Sralph #define TO_I headers[6].h_info 15114981Sralph #define CC_I headers[7].h_info 15214981Sralph #define FIX headers[10] 15312375Sralph 15412375Sralph struct header { 15512375Sralph char *h_tag; 15612375Sralph int h_flags; 15712375Sralph char *h_info; 15812375Sralph } headers[] = { 15912695Sralph "From", H_REQ|H_SAV|H_HDR, 0, 16014981Sralph "Subject", H_REQ|H_SAV, 0, 16112375Sralph "Index", H_REQ|H_SAV, 0, 16212695Sralph "Date", H_SAV|H_HDR, 0, 16312695Sralph "Message-Id", H_SAV|H_HDR, 0, 16412695Sralph "Reply-To", H_SAV|H_HDR, 0, 16512695Sralph "To", H_SAV|H_HDR, 0, 16612695Sralph "Cc", H_SAV|H_HDR, 0, 16712375Sralph "Description", H_REQ, 0, 16814955Sralph "Repeat-By", 0, 0, 16912695Sralph "Fix", 0, 0, 17012375Sralph 0, 0, 0, 17112375Sralph }; 17212375Sralph 17312695Sralph struct header *findheader(); 17412695Sralph 17512375Sralph process() 17612375Sralph { 17712375Sralph register struct header *hp; 17812375Sralph register char *cp; 17912695Sralph register int c; 18012375Sralph char *info; 181*15738Sralph int state, tmp, no_reply = 0; 18212695Sralph FILE *tfp, *fs; 18312375Sralph 18412375Sralph /* 18512375Sralph * Insure all headers are in a consistent 18612375Sralph * state. Anything left there is free'd. 18712375Sralph */ 18812375Sralph for (hp = headers; hp->h_tag; hp++) { 18912695Sralph hp->h_flags &= ~H_FND; 19012375Sralph if (hp->h_info) { 19112695Sralph free(hp->h_info); 19212375Sralph hp->h_info = 0; 19312375Sralph } 19412375Sralph } 19512375Sralph /* 19612375Sralph * Read the report and make a copy. Must conform to RFC822 and 19712375Sralph * be of the form... <tag>: <info> 19812695Sralph * Note that the input is expected to be in mh mail format 19912695Sralph * (i.e., messages are separated by lines of ^A's). 20012375Sralph */ 20112695Sralph while ((c = getchar()) == '\001' && peekc(stdin) == '\001') 20212695Sralph while (getchar() != '\n') 20312695Sralph ; 20412695Sralph if (c == EOF) 20512695Sralph return(0); /* all done */ 20612695Sralph 20712375Sralph mktemp(tmpname); 20812695Sralph if ((tmp = creat(tmpname, msg_prot)) < 0) { 20912695Sralph fprintf(stderr, "cannont create %s\n", tmpname); 21012695Sralph exit(1); 21112695Sralph } 21212695Sralph if ((tfp = fdopen(tmp, "w")) == NULL) { 21312695Sralph fprintf(stderr, "cannot fdopen temp file\n"); 21412695Sralph exit(1); 21512695Sralph } 21612695Sralph 21712695Sralph for (state = FLD; state != EOF && state != EOM; c = getchar()) { 21812695Sralph switch (state) { 21912695Sralph case FLD: 22012695Sralph if (c == '\n' || c == '-') 22112695Sralph goto body; 22212695Sralph for (cp = buf; c != ':'; c = getchar()) { 22312695Sralph if (cp < buf+sizeof(buf)-1 && c != '\n' && c != EOF) { 22412695Sralph *cp++ = c; 22512695Sralph continue; 22612695Sralph } 22712695Sralph *cp = '\0'; 22812695Sralph fputs(buf, tfp); 22912695Sralph state = EOF; 23012695Sralph while (c != EOF) { 23112695Sralph if (c == '\n') 23212695Sralph if ((tmp = peekc(stdin)) == EOF) 23312695Sralph break; 23412695Sralph else if (tmp == '\001') { 23512695Sralph state = EOM; 23612695Sralph break; 23712695Sralph } 23812695Sralph putc(c, tfp); 23912695Sralph c = getchar(); 24012695Sralph } 24112695Sralph fclose(tfp); 24212695Sralph goto badfmt; 24312695Sralph } 24412695Sralph *cp = '\0'; 24512695Sralph fprintf(tfp, "%s:", buf); 24612695Sralph hp = findheader(buf, state); 24712695Sralph 24812695Sralph for (cp = buf; ; ) { 24912695Sralph if (cp >= buf+sizeof(buf)-1) { 25012695Sralph fprintf(stderr, "field truncated\n"); 25112695Sralph while ((c = getchar()) != EOF && c != '\n') 25212695Sralph putc(c, tfp); 25312695Sralph } 25412695Sralph if ((c = getchar()) == EOF) { 25512695Sralph state = EOF; 25612695Sralph break; 25712695Sralph } 25812695Sralph putc(c, tfp); 25912695Sralph *cp++ = c; 26012695Sralph if (c == '\n') 26112695Sralph if ((c = peekc(stdin)) != ' ' && c != '\t') { 26212695Sralph if (c == EOF) 26312695Sralph state = EOF; 26412695Sralph else if (c == '\001') 26512695Sralph state = EOM; 26612695Sralph break; 26712695Sralph } 26812695Sralph } 26912695Sralph *cp = '\0'; 27012695Sralph cp = buf; 27112695Sralph break; 27212695Sralph 27312695Sralph body: 27412695Sralph state = BODY; 27512695Sralph case BODY: 27612695Sralph for (cp = buf; ; c = getchar()) { 27712695Sralph if (c == EOF) { 27812695Sralph state = EOF; 27912695Sralph break; 28012695Sralph } 28112695Sralph if (c == '\001' && peekc(stdin) == '\001') { 28212695Sralph state = EOM; 28312695Sralph break; 28412695Sralph } 28512695Sralph putc(c, tfp); 28612695Sralph *cp++ = c; 28712695Sralph if (cp >= buf+sizeof(buf)-1 || c == '\n') 28812695Sralph break; 28912695Sralph } 29012695Sralph *cp = '\0'; 29112695Sralph if ((cp = index(buf, ':')) == NULL) 29212695Sralph continue; 29312695Sralph *cp++ = '\0'; 29412695Sralph hp = findheader(buf, state); 29512695Sralph } 29612695Sralph 29712695Sralph /* 29812695Sralph * Don't save the info if the header wasn't found, we don't 29912695Sralph * care about the info, or the header is repeated. 30012695Sralph */ 30112695Sralph if (hp == NULL || !(hp->h_flags & H_SAV) || hp->h_info) 30212375Sralph continue; 30312375Sralph while (isspace(*cp)) 30412375Sralph cp++; 30512375Sralph if (*cp) { 30612375Sralph info = cp; 30712375Sralph while (*cp++); 30812375Sralph cp--; 30912375Sralph while (isspace(cp[-1])) 31012375Sralph *--cp = '\0'; 31112375Sralph hp->h_info = (char *) malloc(strlen(info) + 1); 31212695Sralph if (hp->h_info == NULL) { 31312695Sralph fprintf(stderr, "ran out of memory\n"); 31412375Sralph continue; 31512695Sralph } 31612375Sralph strcpy(hp->h_info, info); 317*15738Sralph if (hp == FROM && chkfrom(hp) < 0) 318*15738Sralph no_reply = 1; 31912375Sralph if (hp == INDEX) 32012375Sralph chkindex(hp); 32112375Sralph } 32212375Sralph } 32312695Sralph fclose(tfp); 324*15738Sralph if (no_reply) { 325*15738Sralph unlink(tmpname); 326*15738Sralph exit(0); 327*15738Sralph } 32812375Sralph /* 32912375Sralph * Verify all the required pieces of information 33012375Sralph * are present. 33112375Sralph */ 33212695Sralph for (hp = headers; hp->h_tag; hp++) { 33312375Sralph /* 33412375Sralph * Mail the bug report back to the sender with a note 33512375Sralph * explaining they must conform to the specification. 33612375Sralph */ 33712695Sralph if ((hp->h_flags & H_REQ) && !(hp->h_flags & H_FND)) { 33812695Sralph if (debug) 33912695Sralph printf("Missing %s\n", hp->h_tag); 34012695Sralph badfmt: 34112695Sralph reply(FROM_I, errfile, tmpname); 34212695Sralph file(tmpname, "errors"); 34312695Sralph return(state == EOM); 34412695Sralph } 34512375Sralph } 34612375Sralph /* 34712695Sralph * Acknowledge receipt. 34812695Sralph */ 34912695Sralph reply(FROM_I, ackfile, (char *)0); 35012695Sralph file(tmpname, folder); 35112695Sralph /* 35212375Sralph * Append information about the new bug report 35312375Sralph * to the summary file. 35412375Sralph */ 35512695Sralph if ((fs = fopen(sumfile, "a")) == NULL) 35612375Sralph fprintf(stderr, "Can't open %s\n", sumfile); 35712695Sralph else { 35812695Sralph fprintf(fs, "%14.14s/%-3d ", folder, num); 35912695Sralph fprintf(fs, "%-51.51s Recv\n", INDEX_I); 36012695Sralph fprintf(fs, "\t\t %-51.51s\n", SUBJECT_I); 36112375Sralph } 36212375Sralph fclose(fs); 36314809Ssam /* 36414809Ssam * Check redistribution list and, if members, 36514809Ssam * mail a copy of the bug report to these people. 36614809Ssam */ 36714809Ssam redistribute(folder, num); 36812695Sralph return(state == EOM); 36912375Sralph } 37012375Sralph 37112375Sralph /* 37212695Sralph * Lookup the string in the list of headers and return a pointer 37312695Sralph * to the entry or NULL. 37412695Sralph */ 37512695Sralph 37612695Sralph struct header * 37712695Sralph findheader(name, state) 37812695Sralph char *name; 37912695Sralph int state; 38012695Sralph { 38112695Sralph register struct header *hp; 38212695Sralph 38312695Sralph if (debug) 38412695Sralph printf("findheader(%s, %d)\n", name, state); 38512695Sralph 38612695Sralph for (hp = headers; hp->h_tag; hp++) { 38712695Sralph if (!streq(hp->h_tag, buf)) 38812695Sralph continue; 38912695Sralph if ((hp->h_flags & H_HDR) && state != FLD) 39012695Sralph continue; 39112695Sralph hp->h_flags |= H_FND; 39212695Sralph return(hp); 39312695Sralph } 39412695Sralph return(NULL); 39512695Sralph } 39612695Sralph 39712695Sralph /* 398*15738Sralph * Check the FROM line to eliminate loops. 399*15738Sralph */ 400*15738Sralph 401*15738Sralph chkfrom(hp) 402*15738Sralph struct header *hp; 403*15738Sralph { 404*15738Sralph register char *cp1, *cp2; 405*15738Sralph register char c; 406*15738Sralph 407*15738Sralph if (debug) 408*15738Sralph printf("chkindex(%s)\n", hp->h_info); 409*15738Sralph 410*15738Sralph if (substr(hp->h_info, "MAILER-DAEMON")) 411*15738Sralph return(-1); 412*15738Sralph return(0); 413*15738Sralph } 414*15738Sralph 415*15738Sralph /* 41612375Sralph * Check the format of the Index information. 41712375Sralph * A side effect is to set the name of the folder if all is well. 41812375Sralph */ 41912375Sralph 42012375Sralph chkindex(hp) 42112375Sralph struct header *hp; 42212375Sralph { 42312695Sralph register char *cp1, *cp2; 42412375Sralph register char c; 42512375Sralph struct stat stbuf; 42612375Sralph 42712375Sralph if (debug) 42812695Sralph printf("chkindex(%s)\n", hp->h_info); 42912375Sralph /* 43014865Ssam * Strip of leading "/", "usr/", or "src/". 43112695Sralph */ 43212695Sralph cp1 = hp->h_info; 43312695Sralph while (*cp1 == '/') 43412695Sralph cp1++; 43514865Ssam while (substr(cp1, "usr/") || substr(cp1, "src/")) 43612695Sralph cp1 += 4; 43712695Sralph /* 43812375Sralph * Read the folder name and remove it from the index line. 43912375Sralph */ 44012695Sralph for (cp2 = folder; ;) { 44112695Sralph switch (c = *cp1++) { 44212695Sralph case '/': 44312695Sralph if (cp2 == folder) 44412695Sralph continue; 44512375Sralph break; 44612695Sralph case '\0': 44712695Sralph cp1--; 44812695Sralph break; 44912695Sralph case ' ': 45012695Sralph case '\t': 45112695Sralph while (isspace(*cp1)) 45212695Sralph cp1++; 45312695Sralph break; 45412695Sralph default: 45512695Sralph if (cp2 < folder+sizeof(folder)-1) 45612695Sralph *cp2++ = c; 45712695Sralph continue; 45812375Sralph } 45912695Sralph *cp2 = '\0'; 46012695Sralph for (cp2 = hp->h_info; *cp2++ = *cp1++; ) 46112695Sralph ; 46212695Sralph break; 46312375Sralph } 46412695Sralph if (debug) 46512695Sralph printf("folder = %s\n", folder); 46612375Sralph /* 46712375Sralph * Check to make sure we have a valid folder name 46812375Sralph */ 46912375Sralph if (stat(folder, &stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR) 47012375Sralph return; 47112375Sralph /* 47212375Sralph * The Index line is not in the correct format so clear 47312695Sralph * the H_FND flag to mail back the correct format. 47412375Sralph */ 47512695Sralph hp->h_flags &= ~H_FND; 47612375Sralph } 47712375Sralph 47812375Sralph /* 47912375Sralph * Move or copy the file msg to the folder (directory). 48014809Ssam * As a side effect, num is set to the number under which 48114809Ssam * the message is filed in folder. 48212375Sralph */ 48312375Sralph 48412375Sralph file(fname, folder) 48512375Sralph char *fname, *folder; 48612375Sralph { 48712375Sralph register char *cp, n; 48812375Sralph char msgname[MAXNAMLEN*2+2]; 48912375Sralph struct stat stbuf; 49012375Sralph DIR *dirp; 49112375Sralph struct direct *d; 49212375Sralph 49312375Sralph if (debug) 49412695Sralph printf("file(%s, %s)\n", fname, folder); 49512375Sralph /* 49612375Sralph * Get the next number to use by finding the last message number 49712375Sralph * in folder and adding one. 49812375Sralph */ 49912375Sralph if ((dirp = opendir(folder)) == NULL) { 50012375Sralph fprintf(stderr, "Cannot open %s/%s\n", maildir, folder); 50112375Sralph return; 50212375Sralph } 50312375Sralph num = 0; 50412375Sralph while ((d = readdir(dirp)) != NULL) { 50512375Sralph cp = d->d_name; 50612375Sralph n = 0; 50712375Sralph while (isdigit(*cp)) 50812375Sralph n = n * 10 + (*cp++ - '0'); 50912375Sralph if (*cp == '\0' && n > num) 51012375Sralph num = n; 51112375Sralph } 51212375Sralph closedir(dirp); 51312375Sralph num++; 51412375Sralph /* 51512375Sralph * Create the destination file "folder/num" and copy fname to it. 51612375Sralph */ 51712375Sralph sprintf(msgname, "%s/%d", folder, num); 51812375Sralph if (link(fname, msgname) < 0) { 51912375Sralph int fin, fout; 52012375Sralph 52112695Sralph if ((fin = open(fname, 0)) < 0) { 52212695Sralph fprintf(stderr, "cannot open %s\n", fname); 52312375Sralph return; 52412695Sralph } 52512695Sralph if ((fout = creat(msgname, msg_prot)) < 0) { 52612695Sralph fprintf(stderr, "cannot create %s\n", msgname); 52712375Sralph return; 52812695Sralph } 52912695Sralph while ((n = read(fin, buf, sizeof(buf))) > 0) 53012695Sralph write(fout, buf, n); 53112375Sralph close(fin); 53212375Sralph close(fout); 53312375Sralph } 53412375Sralph unlink(fname); 53512375Sralph } 53612375Sralph 53712375Sralph /* 53814809Ssam * Redistribute a bug report to those people indicated 53914809Ssam * in the redistribution list file. Perhaps should also 54014809Ssam * annotate bug report with this information for future 54114809Ssam * reference? 54214809Ssam */ 54314809Ssam redistribute(folder, num) 54414809Ssam char *folder; 54514809Ssam int num; 54614809Ssam { 54714809Ssam FILE *fredist, *fbug, *ftemp; 54814809Ssam char line[BUFSIZ], bug[2 * MAXNAMLEN + 1]; 54914809Ssam register char *cp; 55014809Ssam int redistcnt, continuation, first; 55114809Ssam 55214809Ssam fredist = fopen(redistfile, "r"); 55314809Ssam if (fredist == NULL) { 55414809Ssam if (debug) 55514809Ssam printf("redistribute(%s, %d), no distribution list\n", 55614809Ssam folder, num); 55714809Ssam return; 55814809Ssam } 55914809Ssam continuation = 0; 56014809Ssam first = 1; 56114809Ssam redistcnt = 0; 56214809Ssam while (fgets(line, sizeof (line) - 1, fredist) != NULL) { 56314809Ssam if (debug) 56414809Ssam printf("%s: %s", redistfile, line); 56514809Ssam if (continuation && index(line, '\\')) 56614809Ssam continue; 56714809Ssam continuation = 0; 56814809Ssam cp = any(line, " \t"); 56914809Ssam if (cp == NULL) 57014809Ssam continue; 57114809Ssam *cp++ = '\0'; 57214809Ssam if (strcmp(folder, line) == 0) 57314809Ssam goto found; 57414809Ssam if (index(cp, '\\')) 57514809Ssam continuation = 1; 57614809Ssam } 57714809Ssam if (debug) 57814809Ssam printf("no redistribution list found\n"); 57914809Ssam fclose(fredist); 58014809Ssam return; 58114809Ssam found: 58214809Ssam mktemp(disttmp); 58314809Ssam ftemp = fopen(disttmp, "w+r"); 58414809Ssam if (ftemp == NULL) { 58514809Ssam if (debug) 58614809Ssam printf("%s: couldn't create\n", disttmp); 58714809Ssam return; 58814809Ssam } 58914809Ssam again: 59014809Ssam if (debug) 59114809Ssam printf("redistribution list %s", cp); 59214809Ssam while (cp) { 59314809Ssam char *user, terminator; 59414809Ssam 59514809Ssam while (*cp && (*cp == ' ' || *cp == '\t' || *cp == ',')) 59614809Ssam cp++; 59714809Ssam user = cp, cp = any(cp, ", \t\n\\"); 59814809Ssam if (cp) { 59914809Ssam terminator = *cp; 60014809Ssam *cp++ = '\0'; 60114809Ssam if (terminator == '\n') 60214809Ssam cp = 0; 60314809Ssam if (terminator == '\\') 60414809Ssam continuation++; 60514809Ssam } 60614809Ssam if (*user == '\0') 60714809Ssam continue; 60814809Ssam if (debug) 60914809Ssam printf("copy to %s\n", user); 61014809Ssam if (first) { 61114809Ssam fprintf(ftemp, "To: %s", user); 61214809Ssam first = 0; 61314809Ssam } else 61414809Ssam fprintf(ftemp, ", %s", user); 61514809Ssam redistcnt++; 61614809Ssam } 61714809Ssam if (!first) 61814809Ssam putc('\n', ftemp); 61914809Ssam if (continuation) { 62014809Ssam first = 1; 62114809Ssam continuation = 0; 62214809Ssam cp = line; 62314809Ssam if (fgets(line, sizeof (line) - 1, fredist)) 62414809Ssam goto again; 62514809Ssam } 62614809Ssam fclose(fredist); 62714809Ssam if (redistcnt == 0) 62814809Ssam goto cleanup; 62914809Ssam fprintf(ftemp, "Subject: "); 63014809Ssam if (SUBJECT_I) 63114809Ssam fprintf(ftemp, "%s\n", SUBJECT_I); 63214809Ssam else 63314809Ssam fprintf(ftemp, "Untitled bug report\n"); 63414809Ssam fprintf(ftemp, "\nRedistributed-by: %s%s\n", BUGS_NAME, BUGS_HOME); 63514809Ssam /* 63614809Ssam * Create copy of bug report. Perhaps we should 63714809Ssam * truncate large messages and just give people 63814809Ssam * a pointer to the original? 63914809Ssam */ 64014809Ssam sprintf(bug, "%s/%d", folder, num); 64114809Ssam fbug = fopen(bug, "r"); 64214809Ssam if (fbug == NULL) { 64314809Ssam if (debug) 64414809Ssam printf("%s: disappeared?\n", bug); 64514809Ssam goto cleanup; 64614809Ssam } 64714809Ssam first = 1; 64814809Ssam while (fgets(line, sizeof (line) - 1, fbug)) { 64914809Ssam /* first blank line indicates start of mesg */ 65014809Ssam if (first && line[0] == '\n') { 65114809Ssam first = 0; 65214809Ssam continue; 65314809Ssam } 65414809Ssam fputs(line, ftemp); 65514809Ssam } 65614809Ssam fclose(fbug); 65714809Ssam if (first) { 65814809Ssam if (debug) 65914809Ssam printf("empty bug report?\n"); 66014809Ssam goto cleanup; 66114809Ssam } 66214809Ssam if (dodeliver(ftemp)) 66314809Ssam unlink(disttmp); 66414809Ssam fclose(ftemp); 66514809Ssam return; 66614809Ssam cleanup: 66714809Ssam fclose(ftemp); 66814809Ssam unlink(disttmp); 66914809Ssam } 67014809Ssam 67114809Ssam dodeliver(fd) 67214809Ssam FILE *fd; 67314809Ssam { 67414809Ssam char buf[BUFSIZ], cmd[BUFSIZ]; 67514809Ssam FILE *pf, *popen(); 67614809Ssam 67714809Ssam strcpy(cmd, MAILCMD); 67814809Ssam if (debug) { 67914809Ssam strcat(cmd, " -v"); 68014809Ssam printf("dodeliver \"%s\"\n", cmd); 68114809Ssam } 68214809Ssam pf = popen(cmd, "w"); 68314809Ssam if (pf == NULL) { 68414809Ssam if (debug) 68514809Ssam printf("dodeliver, \"%s\" failed\n", cmd); 68614809Ssam return (0); 68714809Ssam } 68814809Ssam rewind(fd); 68914809Ssam while (fgets(buf, sizeof (buf) - 1, fd)) { 69014809Ssam if (debug) 69114809Ssam printf("%s", buf); 69214809Ssam (void) fputs(buf, pf); 69314809Ssam } 69414809Ssam if (debug) 69514809Ssam printf("EOF\n"); 69614809Ssam (void) pclose(pf); 69714809Ssam return (1); 69814809Ssam } 69914809Ssam 70014809Ssam /* 70112375Sralph * Mail file1 and file2 back to the sender. 70212375Sralph */ 70312375Sralph 70412375Sralph reply(to, file1, file2) 70512375Sralph char *to, *file1, *file2; 70612375Sralph { 70714809Ssam int pfd[2], in, w; 70812375Sralph FILE *fout; 70912375Sralph 71012375Sralph if (debug) 71112695Sralph printf("reply(%s, %s, %s)\n", to, file1, file2); 71212695Sralph 71312375Sralph /* 71412375Sralph * Create a temporary file to put the message in. 71512375Sralph */ 71612375Sralph mktemp(draft); 71714809Ssam if ((fout = fopen(draft, "w+r")) == NULL) { 71812375Sralph fprintf(stderr, "Can't create %s\n", draft); 71912375Sralph return; 72012375Sralph } 72112375Sralph /* 72212375Sralph * Output the proper header information. 72312375Sralph */ 72414809Ssam fprintf(fout, "Reply-To: %s%s\n", BUGS_NAME, BUGS_HOME); 72514819Skarels fprintf(fout, "From: %s%s (Bugs Bunny)\n", BUGS_NAME, BUGS_HOME); 72612375Sralph if (REPLYTO_I != NULL) 72712375Sralph to = REPLYTO_I; 72812375Sralph if ((to = fixaddr(to)) == 0) { 72912375Sralph fprintf(stderr, "No one to reply to\n"); 73012375Sralph return; 73112375Sralph } 73212375Sralph fprintf(fout, "To: %s\n", to); 73312375Sralph if (SUBJECT_I) { 73412375Sralph fprintf(fout, "Subject: "); 73512375Sralph if ((SUBJECT_I[0] != 'R' && SUBJECT_I[0] != 'r') || 73612375Sralph (SUBJECT_I[1] != 'E' && SUBJECT_I[1] != 'e') || 73712375Sralph SUBJECT_I[2] != ':') 73812375Sralph fprintf(fout, "Re: "); 73912375Sralph fprintf(fout, "%s\n", SUBJECT_I); 74012375Sralph } 74112375Sralph if (DATE_I) { 74212375Sralph fprintf(fout, "In-Acknowledgement-Of: Your message of "); 74312375Sralph fprintf(fout, "%s.\n", DATE_I); 74412375Sralph if (MSGID_I) 74512375Sralph fprintf(fout, " %s\n", MSGID_I); 74612375Sralph } 74714809Ssam fprintf(fout, "\n"); 74812375Sralph if ((in = open(file1, 0)) >= 0) { 74912695Sralph while ((w = read(in, buf, sizeof(buf))) > 0) 75012695Sralph fwrite(buf, 1, w, fout); 75112375Sralph close(in); 75212375Sralph } 75312375Sralph if (file2 && (in = open(file2, 0)) >= 0) { 75412695Sralph while ((w = read(in, buf, sizeof(buf))) > 0) 75512695Sralph fwrite(buf, 1, w, fout); 75612375Sralph close(in); 75712375Sralph } 75814809Ssam if (dodeliver(fout)) 75914809Ssam unlink(draft); 76012375Sralph fclose(fout); 76112375Sralph } 76212375Sralph 76312375Sralph /* 76412375Sralph * fix names like "xxx (something)" to "xxx" and 76512375Sralph * "xxx <something>" to "something". 76612375Sralph */ 76712375Sralph 76812375Sralph char * 76912375Sralph fixaddr(text) 77012375Sralph char *text; 77112375Sralph { 77212375Sralph register char *cp, *lp, c; 77312375Sralph char *tp; 77412375Sralph 77512375Sralph if (!text) 77612375Sralph return(0); 77712375Sralph for (lp = cp = text; ; ) { 77812375Sralph switch (c = *cp++) { 77912375Sralph case '(': 78012375Sralph while (*cp && *cp++ != ')'); 78112375Sralph continue; 78212375Sralph case '<': 78312375Sralph lp = text; 78412375Sralph case '>': 78512375Sralph continue; 78612375Sralph case '\0': 78712375Sralph while (lp != text && (*lp == ' ' || *lp == '\t')) 78812375Sralph lp--; 78912375Sralph *lp = c; 79012375Sralph return(text); 79112375Sralph } 79212375Sralph *lp++ = c; 79312375Sralph } 79412375Sralph } 79512375Sralph 79612375Sralph /* 79712375Sralph * Compare two strings and convert any upper case letters to lower case. 79812375Sralph */ 79912375Sralph 80012695Sralph streq(s1, s2) 80112695Sralph register char *s1, *s2; 80212375Sralph { 80312375Sralph register int c; 80412375Sralph 80512695Sralph while (c = *s1++) 80612695Sralph if ((c | 040) != (*s2++ | 040)) 80712375Sralph return(0); 80812695Sralph return(*s2 == '\0'); 80912375Sralph } 81012695Sralph 81112695Sralph /* 81212695Sralph * Return true if string s2 matches the first part of s1. 81312695Sralph */ 81412695Sralph 81512695Sralph substr(s1, s2) 81612695Sralph register char *s1, *s2; 81712695Sralph { 81812695Sralph register int c; 81912695Sralph 82012695Sralph while (c = *s2++) 82112695Sralph if (c != *s1++) 82212695Sralph return(0); 82312695Sralph return(1); 82412695Sralph } 82512695Sralph 82614809Ssam char * 82714809Ssam any(cp, set) 82814809Ssam register char *cp; 82914809Ssam char *set; 83014809Ssam { 83114809Ssam register char *sp; 83214809Ssam 83314809Ssam if (cp == 0 || set == 0) 83414809Ssam return (0); 83514809Ssam while (*cp) { 83614809Ssam for (sp = set; *sp; sp++) 83714809Ssam if (*cp == *sp) 83814809Ssam return (cp); 83914809Ssam cp++; 84014809Ssam } 84114809Ssam return ((char *)0); 84214809Ssam } 84314809Ssam 84412695Sralph peekc(fp) 84512695Sralph FILE *fp; 84612695Sralph { 84712695Sralph register c; 84812695Sralph 84912695Sralph c = getc(fp); 85012695Sralph ungetc(c, fp); 85112695Sralph return(c); 85212695Sralph } 853