114552Ssam #ifndef lint 2*14809Ssam static char sccsid[] = "@(#)bugfiler.c 4.6 (Berkeley) 08/23/83"; 314552Ssam #endif 414552Ssam 512375Sralph /* 612375Sralph * Bug report processing program. 7*14809Ssam * It is designed to be invoked by alias(5) 8*14809Ssam * and to be compatible with mh. 912375Sralph */ 1012375Sralph 1112375Sralph #include <stdio.h> 1212375Sralph #include <ctype.h> 1312375Sralph #include <signal.h> 14*14809Ssam #include <pwd.h> 15*14809Ssam 1612375Sralph #include <sys/types.h> 1712375Sralph #include <sys/stat.h> 1812695Sralph #include <sys/dir.h> 1912375Sralph 20*14809Ssam #define BUGS_NAME "4bsd-bugs" 21*14809Ssam #define BUGS_HOME "%ucbarpa@BERKELEY" 22*14809Ssam #define MAILCMD "/usr/lib/sendmail -i -t" 23*14809Ssam 2414808Ssam char unixtomh[] = "/usr/new/lib/mh/unixtomh"; 25*14809Ssam #ifdef notdef 26*14809Ssam char *bugperson = "bugs"; 27*14809Ssam char *maildir = "mail"; 28*14809Ssam #else 29*14809Ssam char *bugperson = "sam"; 30*14809Ssam char *maildir = "Mail"; 31*14809Ssam #endif 3212375Sralph char ackfile[] = ".ack"; 3312375Sralph char errfile[] = ".format"; 3412375Sralph char sumfile[] = "summary"; 3512375Sralph char logfile[] = "errors/log"; 36*14809Ssam char redistfile[] = ".redist"; 3712375Sralph char tmpname[] = "BfXXXXXX"; 3812375Sralph char draft[] = "RpXXXXXX"; 39*14809Ssam char disttmp[] = "RcXXXXXX"; 4012375Sralph 4112695Sralph char buf[8192]; 4212375Sralph char folder[MAXNAMLEN]; 4312375Sralph int num; 4412375Sralph int msg_prot = 0664; 4512375Sralph 4612375Sralph int debug; 4712375Sralph 4812375Sralph char *index(); 4912375Sralph char *rindex(); 5012375Sralph char *fixaddr(); 51*14809Ssam char *any(); 5212375Sralph 5312375Sralph main(argc, argv) 5412375Sralph char *argv[]; 5512375Sralph { 5612375Sralph register char *cp; 5712695Sralph register int n; 5812695Sralph int pfd[2]; 5912375Sralph 6012375Sralph if (argc > 3) { 6112375Sralph usage: 6212695Sralph fprintf(stderr, "Usage: bugfiler [-d] [-mmsg_mode] [maildir]\n"); 6312375Sralph exit(1); 6412375Sralph } 6512375Sralph while (--argc > 0) { 6612375Sralph cp = *++argv; 6712695Sralph if (*cp == '-') 6812695Sralph switch (cp[1]) { 6912375Sralph case 'd': 7012375Sralph debug++; 7112375Sralph break; 7212695Sralph 7312695Sralph case 'm': /* set message protection */ 7412695Sralph n = 0; 7512695Sralph for (cp += 2; *cp >= '0' && *cp <= '7'; ) 7612695Sralph n = (n << 3) + (*cp++ - '0'); 7712695Sralph msg_prot = n & 0777; 7812695Sralph break; 7912695Sralph 8012375Sralph default: 8112375Sralph goto usage; 8212375Sralph } 8312375Sralph else 8412375Sralph maildir = cp; 8512375Sralph } 8612695Sralph if (!debug) 8712695Sralph freopen(logfile, "a", stderr); 8812695Sralph 89*14809Ssam if (bugperson) { 90*14809Ssam struct passwd *pwd = getpwnam(bugperson); 91*14809Ssam 92*14809Ssam if (pwd == NULL) { 93*14809Ssam fprintf(stderr, "%s: bugs person is unknown\n", 94*14809Ssam bugperson); 95*14809Ssam exit(1); 96*14809Ssam } 97*14809Ssam if (chdir(pwd->pw_dir) < 0) { 98*14809Ssam fprintf(stderr, "can't chdir to %s\n", pwd->pw_dir); 99*14809Ssam exit(1); 100*14809Ssam } 101*14809Ssam } 10212375Sralph if (chdir(maildir) < 0) { 10312375Sralph fprintf(stderr, "can't chdir to %s\n", maildir); 10412375Sralph exit(1); 10512375Sralph } 10612695Sralph umask(0); 10712695Sralph 10812695Sralph #ifdef UNIXCOMP 10912695Sralph /* 11012695Sralph * Convert UNIX style mail to mh style by filtering stdin through 11112695Sralph * unixtomh. 11212695Sralph */ 11312695Sralph if (pipe(pfd) >= 0) { 11412695Sralph while ((n = fork()) == -1) 11512695Sralph sleep(5); 11612695Sralph if (n == 0) { 11712695Sralph close(pfd[0]); 11812695Sralph dup2(pfd[1], 1); 11912695Sralph close(pfd[1]); 12012695Sralph execl(unixtomh, "unixtomh", 0); 12112695Sralph _exit(127); 12212695Sralph } 12312695Sralph close(pfd[1]); 12412695Sralph dup2(pfd[0], 0); 12512695Sralph close(pfd[0]); 12612695Sralph } 12712695Sralph #endif 12812695Sralph while (process()) 12912695Sralph ; 13012695Sralph exit(0); 13112375Sralph } 13212375Sralph 13312695Sralph /* states */ 13412695Sralph 13512695Sralph #define EOM 0 /* End of message seen */ 13612695Sralph #define FLD 1 /* Looking for header lines */ 13712695Sralph #define BODY 2 /* Looking for message body lines */ 13812695Sralph 13912375Sralph /* defines used for tag attributes */ 14012375Sralph 14112375Sralph #define H_REQ 01 14212695Sralph #define H_SAV 02 14312695Sralph #define H_HDR 04 14412695Sralph #define H_FND 010 14512375Sralph 14612375Sralph #define FROM_I headers[0].h_info 14712375Sralph #define SUBJECT_I headers[1].h_info 14812375Sralph #define INDEX &headers[2] 14912375Sralph #define INDEX_I headers[2].h_info 15012375Sralph #define DATE_I headers[3].h_info 15112375Sralph #define MSGID_I headers[4].h_info 15212375Sralph #define REPLYTO_I headers[5].h_info 15312375Sralph #define RETURNPATH_I headers[6].h_info 15412375Sralph #define TO_I headers[7].h_info 15512375Sralph #define CC_I headers[8].h_info 15612375Sralph #define FIX headers[11] 15712375Sralph 15812375Sralph struct header { 15912375Sralph char *h_tag; 16012375Sralph int h_flags; 16112375Sralph char *h_info; 16212375Sralph } headers[] = { 16312695Sralph "From", H_REQ|H_SAV|H_HDR, 0, 16412695Sralph "Subject", H_REQ|H_SAV|H_HDR, 0, 16512375Sralph "Index", H_REQ|H_SAV, 0, 16612695Sralph "Date", H_SAV|H_HDR, 0, 16712695Sralph "Message-Id", H_SAV|H_HDR, 0, 16812695Sralph "Reply-To", H_SAV|H_HDR, 0, 16912695Sralph "Return-Path", H_SAV|H_HDR, 0, 17012695Sralph "To", H_SAV|H_HDR, 0, 17112695Sralph "Cc", H_SAV|H_HDR, 0, 17212375Sralph "Description", H_REQ, 0, 17312375Sralph "Repeat-By", H_REQ, 0, 17412695Sralph "Fix", 0, 0, 17512375Sralph 0, 0, 0, 17612375Sralph }; 17712375Sralph 17812695Sralph struct header *findheader(); 17912695Sralph 18012375Sralph process() 18112375Sralph { 18212375Sralph register struct header *hp; 18312375Sralph register char *cp; 18412695Sralph register int c; 18512375Sralph char *info; 18612695Sralph int state, tmp; 18712695Sralph FILE *tfp, *fs; 18812375Sralph 18912375Sralph /* 19012375Sralph * Insure all headers are in a consistent 19112375Sralph * state. Anything left there is free'd. 19212375Sralph */ 19312375Sralph for (hp = headers; hp->h_tag; hp++) { 19412695Sralph hp->h_flags &= ~H_FND; 19512375Sralph if (hp->h_info) { 19612695Sralph free(hp->h_info); 19712375Sralph hp->h_info = 0; 19812375Sralph } 19912375Sralph } 20012375Sralph /* 20112375Sralph * Read the report and make a copy. Must conform to RFC822 and 20212375Sralph * be of the form... <tag>: <info> 20312695Sralph * Note that the input is expected to be in mh mail format 20412695Sralph * (i.e., messages are separated by lines of ^A's). 20512375Sralph */ 20612695Sralph while ((c = getchar()) == '\001' && peekc(stdin) == '\001') 20712695Sralph while (getchar() != '\n') 20812695Sralph ; 20912695Sralph if (c == EOF) 21012695Sralph return(0); /* all done */ 21112695Sralph 21212375Sralph mktemp(tmpname); 21312695Sralph if ((tmp = creat(tmpname, msg_prot)) < 0) { 21412695Sralph fprintf(stderr, "cannont create %s\n", tmpname); 21512695Sralph exit(1); 21612695Sralph } 21712695Sralph if ((tfp = fdopen(tmp, "w")) == NULL) { 21812695Sralph fprintf(stderr, "cannot fdopen temp file\n"); 21912695Sralph exit(1); 22012695Sralph } 22112695Sralph 22212695Sralph for (state = FLD; state != EOF && state != EOM; c = getchar()) { 22312695Sralph switch (state) { 22412695Sralph case FLD: 22512695Sralph if (c == '\n' || c == '-') 22612695Sralph goto body; 22712695Sralph for (cp = buf; c != ':'; c = getchar()) { 22812695Sralph if (cp < buf+sizeof(buf)-1 && c != '\n' && c != EOF) { 22912695Sralph *cp++ = c; 23012695Sralph continue; 23112695Sralph } 23212695Sralph *cp = '\0'; 23312695Sralph fputs(buf, tfp); 23412695Sralph state = EOF; 23512695Sralph while (c != EOF) { 23612695Sralph if (c == '\n') 23712695Sralph if ((tmp = peekc(stdin)) == EOF) 23812695Sralph break; 23912695Sralph else if (tmp == '\001') { 24012695Sralph state = EOM; 24112695Sralph break; 24212695Sralph } 24312695Sralph putc(c, tfp); 24412695Sralph c = getchar(); 24512695Sralph } 24612695Sralph fclose(tfp); 24712695Sralph goto badfmt; 24812695Sralph } 24912695Sralph *cp = '\0'; 25012695Sralph fprintf(tfp, "%s:", buf); 25112695Sralph hp = findheader(buf, state); 25212695Sralph 25312695Sralph for (cp = buf; ; ) { 25412695Sralph if (cp >= buf+sizeof(buf)-1) { 25512695Sralph fprintf(stderr, "field truncated\n"); 25612695Sralph while ((c = getchar()) != EOF && c != '\n') 25712695Sralph putc(c, tfp); 25812695Sralph } 25912695Sralph if ((c = getchar()) == EOF) { 26012695Sralph state = EOF; 26112695Sralph break; 26212695Sralph } 26312695Sralph putc(c, tfp); 26412695Sralph *cp++ = c; 26512695Sralph if (c == '\n') 26612695Sralph if ((c = peekc(stdin)) != ' ' && c != '\t') { 26712695Sralph if (c == EOF) 26812695Sralph state = EOF; 26912695Sralph else if (c == '\001') 27012695Sralph state = EOM; 27112695Sralph break; 27212695Sralph } 27312695Sralph } 27412695Sralph *cp = '\0'; 27512695Sralph cp = buf; 27612695Sralph break; 27712695Sralph 27812695Sralph body: 27912695Sralph state = BODY; 28012695Sralph case BODY: 28112695Sralph for (cp = buf; ; c = getchar()) { 28212695Sralph if (c == EOF) { 28312695Sralph state = EOF; 28412695Sralph break; 28512695Sralph } 28612695Sralph if (c == '\001' && peekc(stdin) == '\001') { 28712695Sralph state = EOM; 28812695Sralph break; 28912695Sralph } 29012695Sralph putc(c, tfp); 29112695Sralph *cp++ = c; 29212695Sralph if (cp >= buf+sizeof(buf)-1 || c == '\n') 29312695Sralph break; 29412695Sralph } 29512695Sralph *cp = '\0'; 29612695Sralph if ((cp = index(buf, ':')) == NULL) 29712695Sralph continue; 29812695Sralph *cp++ = '\0'; 29912695Sralph hp = findheader(buf, state); 30012695Sralph } 30112695Sralph 30212695Sralph /* 30312695Sralph * Don't save the info if the header wasn't found, we don't 30412695Sralph * care about the info, or the header is repeated. 30512695Sralph */ 30612695Sralph if (hp == NULL || !(hp->h_flags & H_SAV) || hp->h_info) 30712375Sralph continue; 30812375Sralph while (isspace(*cp)) 30912375Sralph cp++; 31012375Sralph if (*cp) { 31112375Sralph info = cp; 31212375Sralph while (*cp++); 31312375Sralph cp--; 31412375Sralph while (isspace(cp[-1])) 31512375Sralph *--cp = '\0'; 31612375Sralph hp->h_info = (char *) malloc(strlen(info) + 1); 31712695Sralph if (hp->h_info == NULL) { 31812695Sralph fprintf(stderr, "ran out of memory\n"); 31912375Sralph continue; 32012695Sralph } 32112375Sralph strcpy(hp->h_info, info); 32212375Sralph if (hp == INDEX) 32312375Sralph chkindex(hp); 32412375Sralph } 32512375Sralph } 32612695Sralph fclose(tfp); 32712375Sralph /* 32812375Sralph * Verify all the required pieces of information 32912375Sralph * are present. 33012375Sralph */ 33112695Sralph for (hp = headers; hp->h_tag; hp++) { 33212375Sralph /* 33312375Sralph * Mail the bug report back to the sender with a note 33412375Sralph * explaining they must conform to the specification. 33512375Sralph */ 33612695Sralph if ((hp->h_flags & H_REQ) && !(hp->h_flags & H_FND)) { 33712695Sralph if (debug) 33812695Sralph printf("Missing %s\n", hp->h_tag); 33912695Sralph badfmt: 34012695Sralph reply(FROM_I, errfile, tmpname); 34112695Sralph file(tmpname, "errors"); 34212695Sralph return(state == EOM); 34312695Sralph } 34412375Sralph } 34512375Sralph /* 34612695Sralph * Acknowledge receipt. 34712695Sralph */ 34812695Sralph reply(FROM_I, ackfile, (char *)0); 34912695Sralph file(tmpname, folder); 35012695Sralph /* 35112375Sralph * Append information about the new bug report 35212375Sralph * to the summary file. 35312375Sralph */ 35412695Sralph if ((fs = fopen(sumfile, "a")) == NULL) 35512375Sralph fprintf(stderr, "Can't open %s\n", sumfile); 35612695Sralph else { 35712695Sralph fprintf(fs, "%14.14s/%-3d ", folder, num); 35812695Sralph fprintf(fs, "%-51.51s Recv\n", INDEX_I); 35912695Sralph fprintf(fs, "\t\t %-51.51s\n", SUBJECT_I); 36012375Sralph } 36112375Sralph fclose(fs); 362*14809Ssam /* 363*14809Ssam * Check redistribution list and, if members, 364*14809Ssam * mail a copy of the bug report to these people. 365*14809Ssam */ 366*14809Ssam redistribute(folder, num); 36712695Sralph return(state == EOM); 36812375Sralph } 36912375Sralph 37012375Sralph /* 37112695Sralph * Lookup the string in the list of headers and return a pointer 37212695Sralph * to the entry or NULL. 37312695Sralph */ 37412695Sralph 37512695Sralph struct header * 37612695Sralph findheader(name, state) 37712695Sralph char *name; 37812695Sralph int state; 37912695Sralph { 38012695Sralph register struct header *hp; 38112695Sralph 38212695Sralph if (debug) 38312695Sralph printf("findheader(%s, %d)\n", name, state); 38412695Sralph 38512695Sralph for (hp = headers; hp->h_tag; hp++) { 38612695Sralph if (!streq(hp->h_tag, buf)) 38712695Sralph continue; 38812695Sralph if ((hp->h_flags & H_HDR) && state != FLD) 38912695Sralph continue; 39012695Sralph hp->h_flags |= H_FND; 39112695Sralph return(hp); 39212695Sralph } 39312695Sralph return(NULL); 39412695Sralph } 39512695Sralph 39612695Sralph /* 39712375Sralph * Check the format of the Index information. 39812375Sralph * A side effect is to set the name of the folder if all is well. 39912375Sralph */ 40012375Sralph 40112375Sralph chkindex(hp) 40212375Sralph struct header *hp; 40312375Sralph { 40412695Sralph register char *cp1, *cp2; 40512375Sralph register char c; 40612375Sralph struct stat stbuf; 40712375Sralph 40812375Sralph if (debug) 40912695Sralph printf("chkindex(%s)\n", hp->h_info); 41012375Sralph /* 41112695Sralph * Strip of leading "/", "usr/", "src/" or "sys/". 41212695Sralph */ 41312695Sralph cp1 = hp->h_info; 41412695Sralph while (*cp1 == '/') 41512695Sralph cp1++; 41612695Sralph while (substr(cp1, "usr/") || substr(cp1, "src/") || substr(cp1, "sys/")) 41712695Sralph cp1 += 4; 418*14809Ssam /* 419*14809Ssam * Don't toss "sys/" if nothing else is given for 420*14809Ssam * a folder name, this is a valid folder as well. 421*14809Ssam */ 422*14809Ssam if (index(cp1, '/') == NULL && substr(cp1 - 4, "sys/")) 423*14809Ssam cp1 -= 4; 42412695Sralph /* 42512375Sralph * Read the folder name and remove it from the index line. 42612375Sralph */ 42712695Sralph for (cp2 = folder; ;) { 42812695Sralph switch (c = *cp1++) { 42912695Sralph case '/': 43012695Sralph if (cp2 == folder) 43112695Sralph continue; 43212375Sralph break; 43312695Sralph case '\0': 43412695Sralph cp1--; 43512695Sralph break; 43612695Sralph case ' ': 43712695Sralph case '\t': 43812695Sralph while (isspace(*cp1)) 43912695Sralph cp1++; 44012695Sralph break; 44112695Sralph default: 44212695Sralph if (cp2 < folder+sizeof(folder)-1) 44312695Sralph *cp2++ = c; 44412695Sralph continue; 44512375Sralph } 44612695Sralph *cp2 = '\0'; 44712695Sralph for (cp2 = hp->h_info; *cp2++ = *cp1++; ) 44812695Sralph ; 44912695Sralph break; 45012375Sralph } 45112695Sralph if (debug) 45212695Sralph printf("folder = %s\n", folder); 45312375Sralph /* 45412375Sralph * Check to make sure we have a valid folder name 45512375Sralph */ 45612375Sralph if (stat(folder, &stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR) 45712375Sralph return; 45812375Sralph /* 45912375Sralph * The Index line is not in the correct format so clear 46012695Sralph * the H_FND flag to mail back the correct format. 46112375Sralph */ 46212695Sralph hp->h_flags &= ~H_FND; 46312375Sralph } 46412375Sralph 46512375Sralph /* 46612375Sralph * Move or copy the file msg to the folder (directory). 467*14809Ssam * As a side effect, num is set to the number under which 468*14809Ssam * the message is filed in folder. 46912375Sralph */ 47012375Sralph 47112375Sralph file(fname, folder) 47212375Sralph char *fname, *folder; 47312375Sralph { 47412375Sralph register char *cp, n; 47512375Sralph char msgname[MAXNAMLEN*2+2]; 47612375Sralph struct stat stbuf; 47712375Sralph DIR *dirp; 47812375Sralph struct direct *d; 47912375Sralph 48012375Sralph if (debug) 48112695Sralph printf("file(%s, %s)\n", fname, folder); 48212375Sralph /* 48312375Sralph * Get the next number to use by finding the last message number 48412375Sralph * in folder and adding one. 48512375Sralph */ 48612375Sralph if ((dirp = opendir(folder)) == NULL) { 48712375Sralph fprintf(stderr, "Cannot open %s/%s\n", maildir, folder); 48812375Sralph return; 48912375Sralph } 49012375Sralph num = 0; 49112375Sralph while ((d = readdir(dirp)) != NULL) { 49212375Sralph cp = d->d_name; 49312375Sralph n = 0; 49412375Sralph while (isdigit(*cp)) 49512375Sralph n = n * 10 + (*cp++ - '0'); 49612375Sralph if (*cp == '\0' && n > num) 49712375Sralph num = n; 49812375Sralph } 49912375Sralph closedir(dirp); 50012375Sralph num++; 50112375Sralph /* 50212375Sralph * Create the destination file "folder/num" and copy fname to it. 50312375Sralph */ 50412375Sralph sprintf(msgname, "%s/%d", folder, num); 50512375Sralph if (link(fname, msgname) < 0) { 50612375Sralph int fin, fout; 50712375Sralph 50812695Sralph if ((fin = open(fname, 0)) < 0) { 50912695Sralph fprintf(stderr, "cannot open %s\n", fname); 51012375Sralph return; 51112695Sralph } 51212695Sralph if ((fout = creat(msgname, msg_prot)) < 0) { 51312695Sralph fprintf(stderr, "cannot create %s\n", msgname); 51412375Sralph return; 51512695Sralph } 51612695Sralph while ((n = read(fin, buf, sizeof(buf))) > 0) 51712695Sralph write(fout, buf, n); 51812375Sralph close(fin); 51912375Sralph close(fout); 52012375Sralph } 52112375Sralph unlink(fname); 52212375Sralph } 52312375Sralph 52412375Sralph /* 525*14809Ssam * Redistribute a bug report to those people indicated 526*14809Ssam * in the redistribution list file. Perhaps should also 527*14809Ssam * annotate bug report with this information for future 528*14809Ssam * reference? 529*14809Ssam */ 530*14809Ssam redistribute(folder, num) 531*14809Ssam char *folder; 532*14809Ssam int num; 533*14809Ssam { 534*14809Ssam FILE *fredist, *fbug, *ftemp; 535*14809Ssam char line[BUFSIZ], bug[2 * MAXNAMLEN + 1]; 536*14809Ssam register char *cp; 537*14809Ssam int redistcnt, continuation, first; 538*14809Ssam 539*14809Ssam fredist = fopen(redistfile, "r"); 540*14809Ssam if (fredist == NULL) { 541*14809Ssam if (debug) 542*14809Ssam printf("redistribute(%s, %d), no distribution list\n", 543*14809Ssam folder, num); 544*14809Ssam return; 545*14809Ssam } 546*14809Ssam continuation = 0; 547*14809Ssam first = 1; 548*14809Ssam redistcnt = 0; 549*14809Ssam while (fgets(line, sizeof (line) - 1, fredist) != NULL) { 550*14809Ssam if (debug) 551*14809Ssam printf("%s: %s", redistfile, line); 552*14809Ssam if (continuation && index(line, '\\')) 553*14809Ssam continue; 554*14809Ssam continuation = 0; 555*14809Ssam cp = any(line, " \t"); 556*14809Ssam if (cp == NULL) 557*14809Ssam continue; 558*14809Ssam *cp++ = '\0'; 559*14809Ssam if (strcmp(folder, line) == 0) 560*14809Ssam goto found; 561*14809Ssam if (index(cp, '\\')) 562*14809Ssam continuation = 1; 563*14809Ssam } 564*14809Ssam if (debug) 565*14809Ssam printf("no redistribution list found\n"); 566*14809Ssam fclose(fredist); 567*14809Ssam return; 568*14809Ssam found: 569*14809Ssam mktemp(disttmp); 570*14809Ssam ftemp = fopen(disttmp, "w+r"); 571*14809Ssam if (ftemp == NULL) { 572*14809Ssam if (debug) 573*14809Ssam printf("%s: couldn't create\n", disttmp); 574*14809Ssam return; 575*14809Ssam } 576*14809Ssam again: 577*14809Ssam if (debug) 578*14809Ssam printf("redistribution list %s", cp); 579*14809Ssam while (cp) { 580*14809Ssam char *user, terminator; 581*14809Ssam 582*14809Ssam while (*cp && (*cp == ' ' || *cp == '\t' || *cp == ',')) 583*14809Ssam cp++; 584*14809Ssam user = cp, cp = any(cp, ", \t\n\\"); 585*14809Ssam if (cp) { 586*14809Ssam terminator = *cp; 587*14809Ssam *cp++ = '\0'; 588*14809Ssam if (terminator == '\n') 589*14809Ssam cp = 0; 590*14809Ssam if (terminator == '\\') 591*14809Ssam continuation++; 592*14809Ssam } 593*14809Ssam if (*user == '\0') 594*14809Ssam continue; 595*14809Ssam if (debug) 596*14809Ssam printf("copy to %s\n", user); 597*14809Ssam if (first) { 598*14809Ssam fprintf(ftemp, "To: %s", user); 599*14809Ssam first = 0; 600*14809Ssam } else 601*14809Ssam fprintf(ftemp, ", %s", user); 602*14809Ssam redistcnt++; 603*14809Ssam } 604*14809Ssam if (!first) 605*14809Ssam putc('\n', ftemp); 606*14809Ssam if (continuation) { 607*14809Ssam first = 1; 608*14809Ssam continuation = 0; 609*14809Ssam cp = line; 610*14809Ssam if (fgets(line, sizeof (line) - 1, fredist)) 611*14809Ssam goto again; 612*14809Ssam } 613*14809Ssam fclose(fredist); 614*14809Ssam if (redistcnt == 0) 615*14809Ssam goto cleanup; 616*14809Ssam fprintf(ftemp, "Subject: "); 617*14809Ssam if (SUBJECT_I) 618*14809Ssam fprintf(ftemp, "%s\n", SUBJECT_I); 619*14809Ssam else 620*14809Ssam fprintf(ftemp, "Untitled bug report\n"); 621*14809Ssam fprintf(ftemp, "\nRedistributed-by: %s%s\n", BUGS_NAME, BUGS_HOME); 622*14809Ssam /* 623*14809Ssam * Create copy of bug report. Perhaps we should 624*14809Ssam * truncate large messages and just give people 625*14809Ssam * a pointer to the original? 626*14809Ssam */ 627*14809Ssam sprintf(bug, "%s/%d", folder, num); 628*14809Ssam fbug = fopen(bug, "r"); 629*14809Ssam if (fbug == NULL) { 630*14809Ssam if (debug) 631*14809Ssam printf("%s: disappeared?\n", bug); 632*14809Ssam goto cleanup; 633*14809Ssam } 634*14809Ssam first = 1; 635*14809Ssam while (fgets(line, sizeof (line) - 1, fbug)) { 636*14809Ssam /* first blank line indicates start of mesg */ 637*14809Ssam if (first && line[0] == '\n') { 638*14809Ssam first = 0; 639*14809Ssam continue; 640*14809Ssam } 641*14809Ssam fputs(line, ftemp); 642*14809Ssam } 643*14809Ssam fclose(fbug); 644*14809Ssam if (first) { 645*14809Ssam if (debug) 646*14809Ssam printf("empty bug report?\n"); 647*14809Ssam goto cleanup; 648*14809Ssam } 649*14809Ssam if (dodeliver(ftemp)) 650*14809Ssam unlink(disttmp); 651*14809Ssam fclose(ftemp); 652*14809Ssam return; 653*14809Ssam cleanup: 654*14809Ssam fclose(ftemp); 655*14809Ssam unlink(disttmp); 656*14809Ssam } 657*14809Ssam 658*14809Ssam dodeliver(fd) 659*14809Ssam FILE *fd; 660*14809Ssam { 661*14809Ssam char buf[BUFSIZ], cmd[BUFSIZ]; 662*14809Ssam FILE *pf, *popen(); 663*14809Ssam 664*14809Ssam strcpy(cmd, MAILCMD); 665*14809Ssam if (debug) { 666*14809Ssam strcat(cmd, " -v"); 667*14809Ssam printf("dodeliver \"%s\"\n", cmd); 668*14809Ssam } 669*14809Ssam pf = popen(cmd, "w"); 670*14809Ssam if (pf == NULL) { 671*14809Ssam if (debug) 672*14809Ssam printf("dodeliver, \"%s\" failed\n", cmd); 673*14809Ssam return (0); 674*14809Ssam } 675*14809Ssam rewind(fd); 676*14809Ssam while (fgets(buf, sizeof (buf) - 1, fd)) { 677*14809Ssam if (debug) 678*14809Ssam printf("%s", buf); 679*14809Ssam (void) fputs(buf, pf); 680*14809Ssam } 681*14809Ssam if (debug) 682*14809Ssam printf("EOF\n"); 683*14809Ssam (void) pclose(pf); 684*14809Ssam return (1); 685*14809Ssam } 686*14809Ssam 687*14809Ssam /* 68812375Sralph * Mail file1 and file2 back to the sender. 68912375Sralph */ 69012375Sralph 69112375Sralph reply(to, file1, file2) 69212375Sralph char *to, *file1, *file2; 69312375Sralph { 694*14809Ssam int pfd[2], in, w; 69512375Sralph FILE *fout; 69612375Sralph 69712375Sralph if (debug) 69812695Sralph printf("reply(%s, %s, %s)\n", to, file1, file2); 69912695Sralph 70012375Sralph /* 70112375Sralph * Create a temporary file to put the message in. 70212375Sralph */ 70312375Sralph mktemp(draft); 704*14809Ssam if ((fout = fopen(draft, "w+r")) == NULL) { 70512375Sralph fprintf(stderr, "Can't create %s\n", draft); 70612375Sralph return; 70712375Sralph } 70812375Sralph /* 70912375Sralph * Output the proper header information. 71012375Sralph */ 711*14809Ssam fprintf(fout, "Reply-To: %s%s\n", BUGS_NAME, BUGS_HOME); 71212375Sralph if (RETURNPATH_I != NULL) 71312375Sralph to = RETURNPATH_I; 71412375Sralph if (REPLYTO_I != NULL) 71512375Sralph to = REPLYTO_I; 71612375Sralph if ((to = fixaddr(to)) == 0) { 71712375Sralph fprintf(stderr, "No one to reply to\n"); 71812375Sralph return; 71912375Sralph } 72012375Sralph fprintf(fout, "To: %s\n", to); 72112375Sralph if (SUBJECT_I) { 72212375Sralph fprintf(fout, "Subject: "); 72312375Sralph if ((SUBJECT_I[0] != 'R' && SUBJECT_I[0] != 'r') || 72412375Sralph (SUBJECT_I[1] != 'E' && SUBJECT_I[1] != 'e') || 72512375Sralph SUBJECT_I[2] != ':') 72612375Sralph fprintf(fout, "Re: "); 72712375Sralph fprintf(fout, "%s\n", SUBJECT_I); 72812375Sralph } 72912375Sralph if (DATE_I) { 73012375Sralph fprintf(fout, "In-Acknowledgement-Of: Your message of "); 73112375Sralph fprintf(fout, "%s.\n", DATE_I); 73212375Sralph if (MSGID_I) 73312375Sralph fprintf(fout, " %s\n", MSGID_I); 73412375Sralph } 735*14809Ssam fprintf(fout, "\n"); 73612375Sralph if ((in = open(file1, 0)) >= 0) { 73712695Sralph while ((w = read(in, buf, sizeof(buf))) > 0) 73812695Sralph fwrite(buf, 1, w, fout); 73912375Sralph close(in); 74012375Sralph } 74112375Sralph if (file2 && (in = open(file2, 0)) >= 0) { 74212695Sralph while ((w = read(in, buf, sizeof(buf))) > 0) 74312695Sralph fwrite(buf, 1, w, fout); 74412375Sralph close(in); 74512375Sralph } 746*14809Ssam if (dodeliver(fout)) 747*14809Ssam unlink(draft); 74812375Sralph fclose(fout); 74912375Sralph } 75012375Sralph 75112375Sralph /* 75212375Sralph * fix names like "xxx (something)" to "xxx" and 75312375Sralph * "xxx <something>" to "something". 75412375Sralph */ 75512375Sralph 75612375Sralph char * 75712375Sralph fixaddr(text) 75812375Sralph char *text; 75912375Sralph { 76012375Sralph register char *cp, *lp, c; 76112375Sralph char *tp; 76212375Sralph 76312375Sralph if (!text) 76412375Sralph return(0); 76512375Sralph for (lp = cp = text; ; ) { 76612375Sralph switch (c = *cp++) { 76712375Sralph case '(': 76812375Sralph while (*cp && *cp++ != ')'); 76912375Sralph continue; 77012375Sralph case '<': 77112375Sralph lp = text; 77212375Sralph case '>': 77312375Sralph continue; 77412375Sralph case '\0': 77512375Sralph while (lp != text && (*lp == ' ' || *lp == '\t')) 77612375Sralph lp--; 77712375Sralph *lp = c; 77812375Sralph return(text); 77912375Sralph } 78012375Sralph *lp++ = c; 78112375Sralph } 78212375Sralph } 78312375Sralph 78412375Sralph /* 78512375Sralph * Compare two strings and convert any upper case letters to lower case. 78612375Sralph */ 78712375Sralph 78812695Sralph streq(s1, s2) 78912695Sralph register char *s1, *s2; 79012375Sralph { 79112375Sralph register int c; 79212375Sralph 79312695Sralph while (c = *s1++) 79412695Sralph if ((c | 040) != (*s2++ | 040)) 79512375Sralph return(0); 79612695Sralph return(*s2 == '\0'); 79712375Sralph } 79812695Sralph 79912695Sralph /* 80012695Sralph * Return true if string s2 matches the first part of s1. 80112695Sralph */ 80212695Sralph 80312695Sralph substr(s1, s2) 80412695Sralph register char *s1, *s2; 80512695Sralph { 80612695Sralph register int c; 80712695Sralph 80812695Sralph while (c = *s2++) 80912695Sralph if (c != *s1++) 81012695Sralph return(0); 81112695Sralph return(1); 81212695Sralph } 81312695Sralph 814*14809Ssam char * 815*14809Ssam any(cp, set) 816*14809Ssam register char *cp; 817*14809Ssam char *set; 818*14809Ssam { 819*14809Ssam register char *sp; 820*14809Ssam 821*14809Ssam if (cp == 0 || set == 0) 822*14809Ssam return (0); 823*14809Ssam while (*cp) { 824*14809Ssam for (sp = set; *sp; sp++) 825*14809Ssam if (*cp == *sp) 826*14809Ssam return (cp); 827*14809Ssam cp++; 828*14809Ssam } 829*14809Ssam return ((char *)0); 830*14809Ssam } 831*14809Ssam 83212695Sralph peekc(fp) 83312695Sralph FILE *fp; 83412695Sralph { 83512695Sralph register c; 83612695Sralph 83712695Sralph c = getc(fp); 83812695Sralph ungetc(c, fp); 83912695Sralph return(c); 84012695Sralph } 841