1*25388Sbloom /* 2*25388Sbloom * Copyright (c) 1983 Regents of the University of California. 3*25388Sbloom * All rights reserved. The Berkeley software License Agreement 4*25388Sbloom * specifies the terms and conditions for redistribution. 5*25388Sbloom */ 6*25388Sbloom 714552Ssam #ifndef lint 8*25388Sbloom char copyright[] = 9*25388Sbloom "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10*25388Sbloom All rights reserved.\n"; 11*25388Sbloom #endif not lint 1214552Ssam 13*25388Sbloom #ifndef lint 14*25388Sbloom static char sccsid[] = "@(#)bugfiler.c 5.3 (Berkeley) 85/11/04"; 15*25388Sbloom #endif not lint 16*25388Sbloom 1712375Sralph /* 1812375Sralph * Bug report processing program. 1914809Ssam * It is designed to be invoked by alias(5) 2014809Ssam * and to be compatible with mh. 2112375Sralph */ 2212375Sralph 2312375Sralph #include <stdio.h> 2412375Sralph #include <ctype.h> 2512375Sralph #include <signal.h> 2614809Ssam #include <pwd.h> 2714809Ssam 2812375Sralph #include <sys/types.h> 2912375Sralph #include <sys/stat.h> 3012695Sralph #include <sys/dir.h> 3112375Sralph 32*25388Sbloom #ifndef BUGS_NAME 3314809Ssam #define BUGS_NAME "4bsd-bugs" 34*25388Sbloom #endif 35*25388Sbloom #ifndef BUGS_HOME 36*25388Sbloom #define BUGS_HOME "@ucbarpa.BERKELEY.EDU" 37*25388Sbloom #endif 3814809Ssam #define MAILCMD "/usr/lib/sendmail -i -t" 3914809Ssam 4025387Sbloom char unixtomh[] = "/ra/bugs/bin/unixtomh"; 4114809Ssam char *bugperson = "bugs"; 4214809Ssam char *maildir = "mail"; 4312375Sralph char ackfile[] = ".ack"; 4412375Sralph char errfile[] = ".format"; 4512375Sralph char sumfile[] = "summary"; 4612375Sralph char logfile[] = "errors/log"; 4714809Ssam char redistfile[] = ".redist"; 4812375Sralph char tmpname[] = "BfXXXXXX"; 4912375Sralph char draft[] = "RpXXXXXX"; 5014809Ssam char disttmp[] = "RcXXXXXX"; 5112375Sralph 5212695Sralph char buf[8192]; 5312375Sralph char folder[MAXNAMLEN]; 5412375Sralph int num; 5512375Sralph int msg_prot = 0664; 5612375Sralph 5712375Sralph int debug; 5812375Sralph 5912375Sralph char *index(); 6012375Sralph char *rindex(); 6112375Sralph char *fixaddr(); 6214809Ssam char *any(); 6312375Sralph 6412375Sralph main(argc, argv) 6512375Sralph char *argv[]; 6612375Sralph { 6712375Sralph register char *cp; 6812695Sralph register int n; 6912695Sralph int pfd[2]; 7012375Sralph 7115686Sralph if (argc > 4) { 7212375Sralph usage: 7312695Sralph fprintf(stderr, "Usage: bugfiler [-d] [-mmsg_mode] [maildir]\n"); 7412375Sralph exit(1); 7512375Sralph } 7612375Sralph while (--argc > 0) { 7712375Sralph cp = *++argv; 7812695Sralph if (*cp == '-') 7912695Sralph switch (cp[1]) { 8012375Sralph case 'd': 8112375Sralph debug++; 8212375Sralph break; 8312695Sralph 8412695Sralph case 'm': /* set message protection */ 8512695Sralph n = 0; 8612695Sralph for (cp += 2; *cp >= '0' && *cp <= '7'; ) 8712695Sralph n = (n << 3) + (*cp++ - '0'); 8812695Sralph msg_prot = n & 0777; 8912695Sralph break; 9012695Sralph 9112375Sralph default: 9212375Sralph goto usage; 9312375Sralph } 9412375Sralph else 9512375Sralph maildir = cp; 9612375Sralph } 9712695Sralph if (!debug) 9812695Sralph freopen(logfile, "a", stderr); 9912695Sralph 10014809Ssam if (bugperson) { 10114809Ssam struct passwd *pwd = getpwnam(bugperson); 10214809Ssam 10314809Ssam if (pwd == NULL) { 10414809Ssam fprintf(stderr, "%s: bugs person is unknown\n", 10514809Ssam bugperson); 10614809Ssam exit(1); 10714809Ssam } 10814809Ssam if (chdir(pwd->pw_dir) < 0) { 10914809Ssam fprintf(stderr, "can't chdir to %s\n", pwd->pw_dir); 11014809Ssam exit(1); 11114809Ssam } 11215686Sralph setuid(pwd->pw_uid); 11314809Ssam } 11412375Sralph if (chdir(maildir) < 0) { 11512375Sralph fprintf(stderr, "can't chdir to %s\n", maildir); 11612375Sralph exit(1); 11712375Sralph } 11812695Sralph umask(0); 11912695Sralph 12012695Sralph #ifdef UNIXCOMP 12112695Sralph /* 12212695Sralph * Convert UNIX style mail to mh style by filtering stdin through 12312695Sralph * unixtomh. 12412695Sralph */ 12512695Sralph if (pipe(pfd) >= 0) { 12612695Sralph while ((n = fork()) == -1) 12712695Sralph sleep(5); 12812695Sralph if (n == 0) { 12912695Sralph close(pfd[0]); 13012695Sralph dup2(pfd[1], 1); 13112695Sralph close(pfd[1]); 13212695Sralph execl(unixtomh, "unixtomh", 0); 13312695Sralph _exit(127); 13412695Sralph } 13512695Sralph close(pfd[1]); 13612695Sralph dup2(pfd[0], 0); 13712695Sralph close(pfd[0]); 13812695Sralph } 13912695Sralph #endif 14012695Sralph while (process()) 14112695Sralph ; 14212695Sralph exit(0); 14312375Sralph } 14412375Sralph 14512695Sralph /* states */ 14612695Sralph 14712695Sralph #define EOM 0 /* End of message seen */ 14812695Sralph #define FLD 1 /* Looking for header lines */ 14912695Sralph #define BODY 2 /* Looking for message body lines */ 15012695Sralph 15112375Sralph /* defines used for tag attributes */ 15212375Sralph 15312375Sralph #define H_REQ 01 15412695Sralph #define H_SAV 02 15512695Sralph #define H_HDR 04 15612695Sralph #define H_FND 010 15712375Sralph 15815738Sralph #define FROM &headers[0] 15912375Sralph #define FROM_I headers[0].h_info 16012375Sralph #define SUBJECT_I headers[1].h_info 16112375Sralph #define INDEX &headers[2] 16212375Sralph #define INDEX_I headers[2].h_info 16312375Sralph #define DATE_I headers[3].h_info 16412375Sralph #define MSGID_I headers[4].h_info 16512375Sralph #define REPLYTO_I headers[5].h_info 16614981Sralph #define TO_I headers[6].h_info 16714981Sralph #define CC_I headers[7].h_info 16814981Sralph #define FIX headers[10] 16912375Sralph 17012375Sralph struct header { 17112375Sralph char *h_tag; 17212375Sralph int h_flags; 17312375Sralph char *h_info; 17412375Sralph } headers[] = { 17512695Sralph "From", H_REQ|H_SAV|H_HDR, 0, 17614981Sralph "Subject", H_REQ|H_SAV, 0, 17712375Sralph "Index", H_REQ|H_SAV, 0, 17812695Sralph "Date", H_SAV|H_HDR, 0, 17912695Sralph "Message-Id", H_SAV|H_HDR, 0, 18012695Sralph "Reply-To", H_SAV|H_HDR, 0, 18112695Sralph "To", H_SAV|H_HDR, 0, 18212695Sralph "Cc", H_SAV|H_HDR, 0, 18312375Sralph "Description", H_REQ, 0, 18414955Sralph "Repeat-By", 0, 0, 18512695Sralph "Fix", 0, 0, 18612375Sralph 0, 0, 0, 18712375Sralph }; 18812375Sralph 18912695Sralph struct header *findheader(); 19012695Sralph 19112375Sralph process() 19212375Sralph { 19312375Sralph register struct header *hp; 19412375Sralph register char *cp; 19512695Sralph register int c; 19612375Sralph char *info; 19715738Sralph int state, tmp, no_reply = 0; 19812695Sralph FILE *tfp, *fs; 19912375Sralph 20012375Sralph /* 20112375Sralph * Insure all headers are in a consistent 20212375Sralph * state. Anything left there is free'd. 20312375Sralph */ 20412375Sralph for (hp = headers; hp->h_tag; hp++) { 20512695Sralph hp->h_flags &= ~H_FND; 20612375Sralph if (hp->h_info) { 20712695Sralph free(hp->h_info); 20812375Sralph hp->h_info = 0; 20912375Sralph } 21012375Sralph } 21112375Sralph /* 21212375Sralph * Read the report and make a copy. Must conform to RFC822 and 21312375Sralph * be of the form... <tag>: <info> 21412695Sralph * Note that the input is expected to be in mh mail format 21512695Sralph * (i.e., messages are separated by lines of ^A's). 21612375Sralph */ 21712695Sralph while ((c = getchar()) == '\001' && peekc(stdin) == '\001') 21812695Sralph while (getchar() != '\n') 21912695Sralph ; 22012695Sralph if (c == EOF) 22112695Sralph return(0); /* all done */ 22212695Sralph 22312375Sralph mktemp(tmpname); 22412695Sralph if ((tmp = creat(tmpname, msg_prot)) < 0) { 22512695Sralph fprintf(stderr, "cannont create %s\n", tmpname); 22612695Sralph exit(1); 22712695Sralph } 22812695Sralph if ((tfp = fdopen(tmp, "w")) == NULL) { 22912695Sralph fprintf(stderr, "cannot fdopen temp file\n"); 23012695Sralph exit(1); 23112695Sralph } 23212695Sralph 23312695Sralph for (state = FLD; state != EOF && state != EOM; c = getchar()) { 23412695Sralph switch (state) { 23512695Sralph case FLD: 23612695Sralph if (c == '\n' || c == '-') 23712695Sralph goto body; 23812695Sralph for (cp = buf; c != ':'; c = getchar()) { 23912695Sralph if (cp < buf+sizeof(buf)-1 && c != '\n' && c != EOF) { 24012695Sralph *cp++ = c; 24112695Sralph continue; 24212695Sralph } 24312695Sralph *cp = '\0'; 24412695Sralph fputs(buf, tfp); 24512695Sralph state = EOF; 24612695Sralph while (c != EOF) { 24712695Sralph if (c == '\n') 24812695Sralph if ((tmp = peekc(stdin)) == EOF) 24912695Sralph break; 25012695Sralph else if (tmp == '\001') { 25112695Sralph state = EOM; 25212695Sralph break; 25312695Sralph } 25412695Sralph putc(c, tfp); 25512695Sralph c = getchar(); 25612695Sralph } 25712695Sralph fclose(tfp); 25812695Sralph goto badfmt; 25912695Sralph } 26012695Sralph *cp = '\0'; 26112695Sralph fprintf(tfp, "%s:", buf); 26212695Sralph hp = findheader(buf, state); 26312695Sralph 26412695Sralph for (cp = buf; ; ) { 26512695Sralph if (cp >= buf+sizeof(buf)-1) { 26612695Sralph fprintf(stderr, "field truncated\n"); 26712695Sralph while ((c = getchar()) != EOF && c != '\n') 26812695Sralph putc(c, tfp); 26912695Sralph } 27012695Sralph if ((c = getchar()) == EOF) { 27112695Sralph state = EOF; 27212695Sralph break; 27312695Sralph } 27412695Sralph putc(c, tfp); 27512695Sralph *cp++ = c; 27612695Sralph if (c == '\n') 27712695Sralph if ((c = peekc(stdin)) != ' ' && c != '\t') { 27812695Sralph if (c == EOF) 27912695Sralph state = EOF; 28012695Sralph else if (c == '\001') 28112695Sralph state = EOM; 28212695Sralph break; 28312695Sralph } 28412695Sralph } 28512695Sralph *cp = '\0'; 28612695Sralph cp = buf; 28712695Sralph break; 28812695Sralph 28912695Sralph body: 29012695Sralph state = BODY; 29112695Sralph case BODY: 29212695Sralph for (cp = buf; ; c = getchar()) { 29312695Sralph if (c == EOF) { 29412695Sralph state = EOF; 29512695Sralph break; 29612695Sralph } 29712695Sralph if (c == '\001' && peekc(stdin) == '\001') { 29812695Sralph state = EOM; 29912695Sralph break; 30012695Sralph } 30112695Sralph putc(c, tfp); 30212695Sralph *cp++ = c; 30312695Sralph if (cp >= buf+sizeof(buf)-1 || c == '\n') 30412695Sralph break; 30512695Sralph } 30612695Sralph *cp = '\0'; 30712695Sralph if ((cp = index(buf, ':')) == NULL) 30812695Sralph continue; 30912695Sralph *cp++ = '\0'; 31012695Sralph hp = findheader(buf, state); 31112695Sralph } 31212695Sralph 31312695Sralph /* 31412695Sralph * Don't save the info if the header wasn't found, we don't 31512695Sralph * care about the info, or the header is repeated. 31612695Sralph */ 31712695Sralph if (hp == NULL || !(hp->h_flags & H_SAV) || hp->h_info) 31812375Sralph continue; 31912375Sralph while (isspace(*cp)) 32012375Sralph cp++; 32112375Sralph if (*cp) { 32212375Sralph info = cp; 32312375Sralph while (*cp++); 32412375Sralph cp--; 32512375Sralph while (isspace(cp[-1])) 32612375Sralph *--cp = '\0'; 32712375Sralph hp->h_info = (char *) malloc(strlen(info) + 1); 32812695Sralph if (hp->h_info == NULL) { 32912695Sralph fprintf(stderr, "ran out of memory\n"); 33012375Sralph continue; 33112695Sralph } 33212375Sralph strcpy(hp->h_info, info); 33315738Sralph if (hp == FROM && chkfrom(hp) < 0) 33415738Sralph no_reply = 1; 33512375Sralph if (hp == INDEX) 33612375Sralph chkindex(hp); 33712375Sralph } 33812375Sralph } 33912695Sralph fclose(tfp); 34015738Sralph if (no_reply) { 34115738Sralph unlink(tmpname); 34215738Sralph exit(0); 34315738Sralph } 34412375Sralph /* 34512375Sralph * Verify all the required pieces of information 34612375Sralph * are present. 34712375Sralph */ 34812695Sralph for (hp = headers; hp->h_tag; hp++) { 34912375Sralph /* 35012375Sralph * Mail the bug report back to the sender with a note 35112375Sralph * explaining they must conform to the specification. 35212375Sralph */ 35312695Sralph if ((hp->h_flags & H_REQ) && !(hp->h_flags & H_FND)) { 35412695Sralph if (debug) 35512695Sralph printf("Missing %s\n", hp->h_tag); 35612695Sralph badfmt: 35712695Sralph reply(FROM_I, errfile, tmpname); 35812695Sralph file(tmpname, "errors"); 35912695Sralph return(state == EOM); 36012695Sralph } 36112375Sralph } 36212375Sralph /* 36312695Sralph * Acknowledge receipt. 36412695Sralph */ 36512695Sralph reply(FROM_I, ackfile, (char *)0); 36612695Sralph file(tmpname, folder); 36712695Sralph /* 36812375Sralph * Append information about the new bug report 36912375Sralph * to the summary file. 37012375Sralph */ 37112695Sralph if ((fs = fopen(sumfile, "a")) == NULL) 37212375Sralph fprintf(stderr, "Can't open %s\n", sumfile); 37312695Sralph else { 37412695Sralph fprintf(fs, "%14.14s/%-3d ", folder, num); 37512695Sralph fprintf(fs, "%-51.51s Recv\n", INDEX_I); 37612695Sralph fprintf(fs, "\t\t %-51.51s\n", SUBJECT_I); 37712375Sralph } 37812375Sralph fclose(fs); 37914809Ssam /* 38014809Ssam * Check redistribution list and, if members, 38114809Ssam * mail a copy of the bug report to these people. 38214809Ssam */ 38314809Ssam redistribute(folder, num); 38412695Sralph return(state == EOM); 38512375Sralph } 38612375Sralph 38712375Sralph /* 38812695Sralph * Lookup the string in the list of headers and return a pointer 38912695Sralph * to the entry or NULL. 39012695Sralph */ 39112695Sralph 39212695Sralph struct header * 39312695Sralph findheader(name, state) 39412695Sralph char *name; 39512695Sralph int state; 39612695Sralph { 39712695Sralph register struct header *hp; 39812695Sralph 39912695Sralph if (debug) 40012695Sralph printf("findheader(%s, %d)\n", name, state); 40112695Sralph 40212695Sralph for (hp = headers; hp->h_tag; hp++) { 40312695Sralph if (!streq(hp->h_tag, buf)) 40412695Sralph continue; 40512695Sralph if ((hp->h_flags & H_HDR) && state != FLD) 40612695Sralph continue; 40712695Sralph hp->h_flags |= H_FND; 40812695Sralph return(hp); 40912695Sralph } 41012695Sralph return(NULL); 41112695Sralph } 41212695Sralph 41312695Sralph /* 41415738Sralph * Check the FROM line to eliminate loops. 41515738Sralph */ 41615738Sralph 41715738Sralph chkfrom(hp) 41815738Sralph struct header *hp; 41915738Sralph { 42015738Sralph register char *cp1, *cp2; 42115738Sralph register char c; 42215738Sralph 42315738Sralph if (debug) 42425387Sbloom printf("chkfrom(%s)\n", hp->h_info); 42515738Sralph 42625387Sbloom if (substr(hp->h_info, BUGS_NAME)) 42725387Sbloom return(-1); 42815738Sralph if (substr(hp->h_info, "MAILER-DAEMON")) 42915738Sralph return(-1); 43015738Sralph return(0); 43115738Sralph } 43215738Sralph 43315738Sralph /* 43412375Sralph * Check the format of the Index information. 43512375Sralph * A side effect is to set the name of the folder if all is well. 43612375Sralph */ 43712375Sralph 43812375Sralph chkindex(hp) 43912375Sralph struct header *hp; 44012375Sralph { 44112695Sralph register char *cp1, *cp2; 44212375Sralph register char c; 44312375Sralph struct stat stbuf; 44412375Sralph 44512375Sralph if (debug) 44612695Sralph printf("chkindex(%s)\n", hp->h_info); 44712375Sralph /* 44816165Sralph * Strip of leading "/", ".", "usr/", or "src/". 44912695Sralph */ 45012695Sralph cp1 = hp->h_info; 45116165Sralph while (*cp1 == '/' || *cp1 == '.') 45212695Sralph cp1++; 45314865Ssam while (substr(cp1, "usr/") || substr(cp1, "src/")) 45412695Sralph cp1 += 4; 45512695Sralph /* 45612375Sralph * Read the folder name and remove it from the index line. 45712375Sralph */ 45812695Sralph for (cp2 = folder; ;) { 45912695Sralph switch (c = *cp1++) { 46012695Sralph case '/': 46112695Sralph if (cp2 == folder) 46212695Sralph continue; 46312375Sralph break; 46412695Sralph case '\0': 46512695Sralph cp1--; 46612695Sralph break; 46712695Sralph case ' ': 46812695Sralph case '\t': 46912695Sralph while (isspace(*cp1)) 47012695Sralph cp1++; 47112695Sralph break; 47212695Sralph default: 47312695Sralph if (cp2 < folder+sizeof(folder)-1) 47412695Sralph *cp2++ = c; 47512695Sralph continue; 47612375Sralph } 47712695Sralph *cp2 = '\0'; 47812695Sralph for (cp2 = hp->h_info; *cp2++ = *cp1++; ) 47912695Sralph ; 48012695Sralph break; 48112375Sralph } 48212695Sralph if (debug) 48312695Sralph printf("folder = %s\n", folder); 48412375Sralph /* 48512375Sralph * Check to make sure we have a valid folder name 48612375Sralph */ 48712375Sralph if (stat(folder, &stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR) 48812375Sralph return; 48912375Sralph /* 49012375Sralph * The Index line is not in the correct format so clear 49112695Sralph * the H_FND flag to mail back the correct format. 49212375Sralph */ 49312695Sralph hp->h_flags &= ~H_FND; 49412375Sralph } 49512375Sralph 49612375Sralph /* 49712375Sralph * Move or copy the file msg to the folder (directory). 49814809Ssam * As a side effect, num is set to the number under which 49914809Ssam * the message is filed in folder. 50012375Sralph */ 50112375Sralph 50212375Sralph file(fname, folder) 50312375Sralph char *fname, *folder; 50412375Sralph { 50516504Sralph register char *cp; 50616504Sralph register int n; 50712375Sralph char msgname[MAXNAMLEN*2+2]; 50812375Sralph struct stat stbuf; 50912375Sralph DIR *dirp; 51012375Sralph struct direct *d; 51112375Sralph 51212375Sralph if (debug) 51312695Sralph printf("file(%s, %s)\n", fname, folder); 51412375Sralph /* 51512375Sralph * Get the next number to use by finding the last message number 51612375Sralph * in folder and adding one. 51712375Sralph */ 51812375Sralph if ((dirp = opendir(folder)) == NULL) { 51912375Sralph fprintf(stderr, "Cannot open %s/%s\n", maildir, folder); 52012375Sralph return; 52112375Sralph } 52212375Sralph num = 0; 52312375Sralph while ((d = readdir(dirp)) != NULL) { 52412375Sralph cp = d->d_name; 52512375Sralph n = 0; 52612375Sralph while (isdigit(*cp)) 52712375Sralph n = n * 10 + (*cp++ - '0'); 52812375Sralph if (*cp == '\0' && n > num) 52912375Sralph num = n; 53012375Sralph } 53112375Sralph closedir(dirp); 53212375Sralph num++; 53312375Sralph /* 53412375Sralph * Create the destination file "folder/num" and copy fname to it. 53512375Sralph */ 53612375Sralph sprintf(msgname, "%s/%d", folder, num); 53712375Sralph if (link(fname, msgname) < 0) { 53812375Sralph int fin, fout; 53912375Sralph 54012695Sralph if ((fin = open(fname, 0)) < 0) { 54112695Sralph fprintf(stderr, "cannot open %s\n", fname); 54212375Sralph return; 54312695Sralph } 54412695Sralph if ((fout = creat(msgname, msg_prot)) < 0) { 54512695Sralph fprintf(stderr, "cannot create %s\n", msgname); 54612375Sralph return; 54712695Sralph } 54812695Sralph while ((n = read(fin, buf, sizeof(buf))) > 0) 54912695Sralph write(fout, buf, n); 55012375Sralph close(fin); 55112375Sralph close(fout); 55212375Sralph } 55312375Sralph unlink(fname); 55412375Sralph } 55512375Sralph 55612375Sralph /* 55714809Ssam * Redistribute a bug report to those people indicated 55814809Ssam * in the redistribution list file. Perhaps should also 55914809Ssam * annotate bug report with this information for future 56014809Ssam * reference? 56114809Ssam */ 56214809Ssam redistribute(folder, num) 56314809Ssam char *folder; 56414809Ssam int num; 56514809Ssam { 56614809Ssam FILE *fredist, *fbug, *ftemp; 56714809Ssam char line[BUFSIZ], bug[2 * MAXNAMLEN + 1]; 56814809Ssam register char *cp; 56914809Ssam int redistcnt, continuation, first; 57014809Ssam 57114809Ssam fredist = fopen(redistfile, "r"); 57214809Ssam if (fredist == NULL) { 57314809Ssam if (debug) 57414809Ssam printf("redistribute(%s, %d), no distribution list\n", 57514809Ssam folder, num); 57614809Ssam return; 57714809Ssam } 57814809Ssam continuation = 0; 57914809Ssam first = 1; 58014809Ssam redistcnt = 0; 58114809Ssam while (fgets(line, sizeof (line) - 1, fredist) != NULL) { 58214809Ssam if (debug) 58314809Ssam printf("%s: %s", redistfile, line); 58414809Ssam if (continuation && index(line, '\\')) 58514809Ssam continue; 58614809Ssam continuation = 0; 58714809Ssam cp = any(line, " \t"); 58814809Ssam if (cp == NULL) 58914809Ssam continue; 59014809Ssam *cp++ = '\0'; 59114809Ssam if (strcmp(folder, line) == 0) 59214809Ssam goto found; 59314809Ssam if (index(cp, '\\')) 59414809Ssam continuation = 1; 59514809Ssam } 59614809Ssam if (debug) 59714809Ssam printf("no redistribution list found\n"); 59814809Ssam fclose(fredist); 59914809Ssam return; 60014809Ssam found: 60114809Ssam mktemp(disttmp); 60214809Ssam ftemp = fopen(disttmp, "w+r"); 60314809Ssam if (ftemp == NULL) { 60414809Ssam if (debug) 60514809Ssam printf("%s: couldn't create\n", disttmp); 60614809Ssam return; 60714809Ssam } 60814809Ssam again: 60914809Ssam if (debug) 61014809Ssam printf("redistribution list %s", cp); 61114809Ssam while (cp) { 61214809Ssam char *user, terminator; 61314809Ssam 61414809Ssam while (*cp && (*cp == ' ' || *cp == '\t' || *cp == ',')) 61514809Ssam cp++; 61614809Ssam user = cp, cp = any(cp, ", \t\n\\"); 61714809Ssam if (cp) { 61814809Ssam terminator = *cp; 61914809Ssam *cp++ = '\0'; 62014809Ssam if (terminator == '\n') 62114809Ssam cp = 0; 62214809Ssam if (terminator == '\\') 62314809Ssam continuation++; 62414809Ssam } 62514809Ssam if (*user == '\0') 62614809Ssam continue; 62714809Ssam if (debug) 62814809Ssam printf("copy to %s\n", user); 62914809Ssam if (first) { 63025387Sbloom fprintf(ftemp, "Resent-To: %s", user); 63114809Ssam first = 0; 63214809Ssam } else 63314809Ssam fprintf(ftemp, ", %s", user); 63414809Ssam redistcnt++; 63514809Ssam } 63614809Ssam if (!first) 63714809Ssam putc('\n', ftemp); 63814809Ssam if (continuation) { 63914809Ssam first = 1; 64014809Ssam continuation = 0; 64114809Ssam cp = line; 64214809Ssam if (fgets(line, sizeof (line) - 1, fredist)) 64314809Ssam goto again; 64414809Ssam } 64514809Ssam fclose(fredist); 64614809Ssam if (redistcnt == 0) 64714809Ssam goto cleanup; 64825387Sbloom if (! SUBJECT_I) { 64925387Sbloom fprintf(ftemp, "Subject: "); 65014809Ssam fprintf(ftemp, "Untitled bug report\n"); 65125387Sbloom } 65214809Ssam /* 65314809Ssam * Create copy of bug report. Perhaps we should 65414809Ssam * truncate large messages and just give people 65514809Ssam * a pointer to the original? 65614809Ssam */ 65714809Ssam sprintf(bug, "%s/%d", folder, num); 65814809Ssam fbug = fopen(bug, "r"); 65914809Ssam if (fbug == NULL) { 66014809Ssam if (debug) 66114809Ssam printf("%s: disappeared?\n", bug); 66214809Ssam goto cleanup; 66314809Ssam } 66414809Ssam first = 1; 66514809Ssam while (fgets(line, sizeof (line) - 1, fbug)) { 66614809Ssam /* first blank line indicates start of mesg */ 66714809Ssam if (first && line[0] == '\n') { 66814809Ssam first = 0; 66914809Ssam } 67014809Ssam fputs(line, ftemp); 67114809Ssam } 67214809Ssam fclose(fbug); 67314809Ssam if (first) { 67414809Ssam if (debug) 67514809Ssam printf("empty bug report?\n"); 67614809Ssam goto cleanup; 67714809Ssam } 67814809Ssam if (dodeliver(ftemp)) 67914809Ssam unlink(disttmp); 68014809Ssam fclose(ftemp); 68114809Ssam return; 68214809Ssam cleanup: 68314809Ssam fclose(ftemp); 68414809Ssam unlink(disttmp); 68514809Ssam } 68614809Ssam 68714809Ssam dodeliver(fd) 68814809Ssam FILE *fd; 68914809Ssam { 69014809Ssam char buf[BUFSIZ], cmd[BUFSIZ]; 69114809Ssam FILE *pf, *popen(); 69214809Ssam 69314809Ssam strcpy(cmd, MAILCMD); 69414809Ssam if (debug) { 69514809Ssam strcat(cmd, " -v"); 69614809Ssam printf("dodeliver \"%s\"\n", cmd); 69714809Ssam } 69814809Ssam pf = popen(cmd, "w"); 69914809Ssam if (pf == NULL) { 70014809Ssam if (debug) 70114809Ssam printf("dodeliver, \"%s\" failed\n", cmd); 70214809Ssam return (0); 70314809Ssam } 70414809Ssam rewind(fd); 70514809Ssam while (fgets(buf, sizeof (buf) - 1, fd)) { 70614809Ssam if (debug) 70714809Ssam printf("%s", buf); 70814809Ssam (void) fputs(buf, pf); 70914809Ssam } 71014809Ssam if (debug) 71114809Ssam printf("EOF\n"); 71214809Ssam (void) pclose(pf); 71314809Ssam return (1); 71414809Ssam } 71514809Ssam 71614809Ssam /* 71712375Sralph * Mail file1 and file2 back to the sender. 71812375Sralph */ 71912375Sralph 72012375Sralph reply(to, file1, file2) 72112375Sralph char *to, *file1, *file2; 72212375Sralph { 72314809Ssam int pfd[2], in, w; 72412375Sralph FILE *fout; 72512375Sralph 72612375Sralph if (debug) 72712695Sralph printf("reply(%s, %s, %s)\n", to, file1, file2); 72812695Sralph 72912375Sralph /* 73012375Sralph * Create a temporary file to put the message in. 73112375Sralph */ 73212375Sralph mktemp(draft); 73314809Ssam if ((fout = fopen(draft, "w+r")) == NULL) { 73412375Sralph fprintf(stderr, "Can't create %s\n", draft); 73512375Sralph return; 73612375Sralph } 73712375Sralph /* 73812375Sralph * Output the proper header information. 73912375Sralph */ 74014809Ssam fprintf(fout, "Reply-To: %s%s\n", BUGS_NAME, BUGS_HOME); 74114819Skarels fprintf(fout, "From: %s%s (Bugs Bunny)\n", BUGS_NAME, BUGS_HOME); 74212375Sralph if (REPLYTO_I != NULL) 74312375Sralph to = REPLYTO_I; 74412375Sralph if ((to = fixaddr(to)) == 0) { 74512375Sralph fprintf(stderr, "No one to reply to\n"); 74612375Sralph return; 74712375Sralph } 74812375Sralph fprintf(fout, "To: %s\n", to); 74912375Sralph if (SUBJECT_I) { 75012375Sralph fprintf(fout, "Subject: "); 75112375Sralph if ((SUBJECT_I[0] != 'R' && SUBJECT_I[0] != 'r') || 75212375Sralph (SUBJECT_I[1] != 'E' && SUBJECT_I[1] != 'e') || 75312375Sralph SUBJECT_I[2] != ':') 75412375Sralph fprintf(fout, "Re: "); 75512375Sralph fprintf(fout, "%s\n", SUBJECT_I); 75612375Sralph } 75712375Sralph if (DATE_I) { 75812375Sralph fprintf(fout, "In-Acknowledgement-Of: Your message of "); 75912375Sralph fprintf(fout, "%s.\n", DATE_I); 76012375Sralph if (MSGID_I) 76112375Sralph fprintf(fout, " %s\n", MSGID_I); 76212375Sralph } 76314809Ssam fprintf(fout, "\n"); 76412375Sralph if ((in = open(file1, 0)) >= 0) { 76512695Sralph while ((w = read(in, buf, sizeof(buf))) > 0) 76612695Sralph fwrite(buf, 1, w, fout); 76712375Sralph close(in); 76812375Sralph } 76912375Sralph if (file2 && (in = open(file2, 0)) >= 0) { 77012695Sralph while ((w = read(in, buf, sizeof(buf))) > 0) 77112695Sralph fwrite(buf, 1, w, fout); 77212375Sralph close(in); 77312375Sralph } 77414809Ssam if (dodeliver(fout)) 77514809Ssam unlink(draft); 77612375Sralph fclose(fout); 77712375Sralph } 77812375Sralph 77912375Sralph /* 78012375Sralph * fix names like "xxx (something)" to "xxx" and 78112375Sralph * "xxx <something>" to "something". 78212375Sralph */ 78312375Sralph 78412375Sralph char * 78512375Sralph fixaddr(text) 78612375Sralph char *text; 78712375Sralph { 78812375Sralph register char *cp, *lp, c; 78912375Sralph char *tp; 79012375Sralph 79112375Sralph if (!text) 79212375Sralph return(0); 79312375Sralph for (lp = cp = text; ; ) { 79412375Sralph switch (c = *cp++) { 79512375Sralph case '(': 79612375Sralph while (*cp && *cp++ != ')'); 79712375Sralph continue; 79812375Sralph case '<': 79912375Sralph lp = text; 80012375Sralph case '>': 80112375Sralph continue; 80212375Sralph case '\0': 80312375Sralph while (lp != text && (*lp == ' ' || *lp == '\t')) 80412375Sralph lp--; 80512375Sralph *lp = c; 80612375Sralph return(text); 80712375Sralph } 80812375Sralph *lp++ = c; 80912375Sralph } 81012375Sralph } 81112375Sralph 81212375Sralph /* 81312375Sralph * Compare two strings and convert any upper case letters to lower case. 81412375Sralph */ 81512375Sralph 81612695Sralph streq(s1, s2) 81712695Sralph register char *s1, *s2; 81812375Sralph { 81912375Sralph register int c; 82012375Sralph 82112695Sralph while (c = *s1++) 82212695Sralph if ((c | 040) != (*s2++ | 040)) 82312375Sralph return(0); 82412695Sralph return(*s2 == '\0'); 82512375Sralph } 82612695Sralph 82712695Sralph /* 82812695Sralph * Return true if string s2 matches the first part of s1. 82912695Sralph */ 83012695Sralph 83112695Sralph substr(s1, s2) 83212695Sralph register char *s1, *s2; 83312695Sralph { 83412695Sralph register int c; 83512695Sralph 83612695Sralph while (c = *s2++) 83712695Sralph if (c != *s1++) 83812695Sralph return(0); 83912695Sralph return(1); 84012695Sralph } 84112695Sralph 84214809Ssam char * 84314809Ssam any(cp, set) 84414809Ssam register char *cp; 84514809Ssam char *set; 84614809Ssam { 84714809Ssam register char *sp; 84814809Ssam 84914809Ssam if (cp == 0 || set == 0) 85014809Ssam return (0); 85114809Ssam while (*cp) { 85214809Ssam for (sp = set; *sp; sp++) 85314809Ssam if (*cp == *sp) 85414809Ssam return (cp); 85514809Ssam cp++; 85614809Ssam } 85714809Ssam return ((char *)0); 85814809Ssam } 85914809Ssam 86012695Sralph peekc(fp) 86112695Sralph FILE *fp; 86212695Sralph { 86312695Sralph register c; 86412695Sralph 86512695Sralph c = getc(fp); 86612695Sralph ungetc(c, fp); 86712695Sralph return(c); 86812695Sralph } 869