verify that we are checking the root file system (from conrad@cgl.ucsf.edu)
[unix-history] / usr / src / libexec / bugfiler / bugfiler.c
CommitLineData
7172eb74
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
524aa063 13#ifndef lint
3b28bda3 14static char sccsid[] = "@(#)bugfiler.c 5.5 (Berkeley) 86/05/20";
7172eb74 15#endif not lint
524aa063 16
b7520dd0
RC
17/*
18 * Bug report processing program.
ae422d11
SL
19 * It is designed to be invoked by alias(5)
20 * and to be compatible with mh.
b7520dd0
RC
21 */
22
23#include <stdio.h>
24#include <ctype.h>
25#include <signal.h>
ae422d11
SL
26#include <pwd.h>
27
b7520dd0
RC
28#include <sys/types.h>
29#include <sys/stat.h>
80765673 30#include <sys/dir.h>
b7520dd0 31
b57c7a41 32#ifndef BUGS_NAME
ae422d11 33#define BUGS_NAME "4bsd-bugs"
b57c7a41
RE
34#endif
35#ifndef BUGS_HOME
f25bd20a 36#define BUGS_HOME "@ucbvax.BERKELEY.EDU"
b57c7a41 37#endif
ae422d11
SL
38#define MAILCMD "/usr/lib/sendmail -i -t"
39
f25bd20a
JB
40#ifndef UNIXTOMH
41#define UNIXTOMH "/usr/lib/unixtomh"
42#endif
ae422d11
SL
43char *bugperson = "bugs";
44char *maildir = "mail";
b7520dd0
RC
45char ackfile[] = ".ack";
46char errfile[] = ".format";
47char sumfile[] = "summary";
48char logfile[] = "errors/log";
ae422d11 49char redistfile[] = ".redist";
b7520dd0
RC
50char tmpname[] = "BfXXXXXX";
51char draft[] = "RpXXXXXX";
ae422d11 52char disttmp[] = "RcXXXXXX";
b7520dd0 53
80765673 54char buf[8192];
b7520dd0
RC
55char folder[MAXNAMLEN];
56int num;
3b28bda3
MK
57int msg_prot = 0640;
58int folder_prot = 0750;
b7520dd0
RC
59
60int debug;
61
62char *index();
63char *rindex();
64char *fixaddr();
ae422d11 65char *any();
b7520dd0
RC
66
67main(argc, argv)
68 char *argv[];
69{
70 register char *cp;
80765673
RC
71 register int n;
72 int pfd[2];
b7520dd0 73
354f1223 74 if (argc > 4) {
b7520dd0 75 usage:
80765673 76 fprintf(stderr, "Usage: bugfiler [-d] [-mmsg_mode] [maildir]\n");
b7520dd0
RC
77 exit(1);
78 }
79 while (--argc > 0) {
80 cp = *++argv;
80765673
RC
81 if (*cp == '-')
82 switch (cp[1]) {
b7520dd0
RC
83 case 'd':
84 debug++;
85 break;
80765673
RC
86
87 case 'm': /* set message protection */
88 n = 0;
89 for (cp += 2; *cp >= '0' && *cp <= '7'; )
90 n = (n << 3) + (*cp++ - '0');
91 msg_prot = n & 0777;
92 break;
93
b7520dd0
RC
94 default:
95 goto usage;
96 }
97 else
98 maildir = cp;
99 }
80765673
RC
100 if (!debug)
101 freopen(logfile, "a", stderr);
102
ae422d11
SL
103 if (bugperson) {
104 struct passwd *pwd = getpwnam(bugperson);
105
106 if (pwd == NULL) {
107 fprintf(stderr, "%s: bugs person is unknown\n",
108 bugperson);
109 exit(1);
110 }
111 if (chdir(pwd->pw_dir) < 0) {
112 fprintf(stderr, "can't chdir to %s\n", pwd->pw_dir);
113 exit(1);
114 }
354f1223 115 setuid(pwd->pw_uid);
ae422d11 116 }
b7520dd0
RC
117 if (chdir(maildir) < 0) {
118 fprintf(stderr, "can't chdir to %s\n", maildir);
119 exit(1);
120 }
80765673
RC
121 umask(0);
122
123#ifdef UNIXCOMP
124 /*
125 * Convert UNIX style mail to mh style by filtering stdin through
126 * unixtomh.
127 */
128 if (pipe(pfd) >= 0) {
129 while ((n = fork()) == -1)
130 sleep(5);
131 if (n == 0) {
132 close(pfd[0]);
133 dup2(pfd[1], 1);
134 close(pfd[1]);
f25bd20a 135 execl(UNIXTOMH, "unixtomh", 0);
80765673
RC
136 _exit(127);
137 }
138 close(pfd[1]);
139 dup2(pfd[0], 0);
140 close(pfd[0]);
141 }
142#endif
143 while (process())
144 ;
145 exit(0);
b7520dd0
RC
146}
147
80765673
RC
148/* states */
149
150#define EOM 0 /* End of message seen */
151#define FLD 1 /* Looking for header lines */
152#define BODY 2 /* Looking for message body lines */
153
b7520dd0
RC
154/* defines used for tag attributes */
155
156#define H_REQ 01
80765673
RC
157#define H_SAV 02
158#define H_HDR 04
159#define H_FND 010
b7520dd0 160
d93ebe7f 161#define FROM &headers[0]
b7520dd0
RC
162#define FROM_I headers[0].h_info
163#define SUBJECT_I headers[1].h_info
164#define INDEX &headers[2]
165#define INDEX_I headers[2].h_info
166#define DATE_I headers[3].h_info
167#define MSGID_I headers[4].h_info
168#define REPLYTO_I headers[5].h_info
982f965a
RC
169#define TO_I headers[6].h_info
170#define CC_I headers[7].h_info
171#define FIX headers[10]
b7520dd0
RC
172
173struct header {
174 char *h_tag;
175 int h_flags;
176 char *h_info;
177} headers[] = {
80765673 178 "From", H_REQ|H_SAV|H_HDR, 0,
982f965a 179 "Subject", H_REQ|H_SAV, 0,
b7520dd0 180 "Index", H_REQ|H_SAV, 0,
80765673
RC
181 "Date", H_SAV|H_HDR, 0,
182 "Message-Id", H_SAV|H_HDR, 0,
183 "Reply-To", H_SAV|H_HDR, 0,
80765673
RC
184 "To", H_SAV|H_HDR, 0,
185 "Cc", H_SAV|H_HDR, 0,
b7520dd0 186 "Description", H_REQ, 0,
4c01e0cf 187 "Repeat-By", 0, 0,
80765673 188 "Fix", 0, 0,
b7520dd0
RC
189 0, 0, 0,
190};
191
80765673
RC
192struct header *findheader();
193
b7520dd0
RC
194process()
195{
196 register struct header *hp;
197 register char *cp;
80765673 198 register int c;
b7520dd0 199 char *info;
d93ebe7f 200 int state, tmp, no_reply = 0;
80765673 201 FILE *tfp, *fs;
b7520dd0
RC
202
203 /*
204 * Insure all headers are in a consistent
205 * state. Anything left there is free'd.
206 */
207 for (hp = headers; hp->h_tag; hp++) {
80765673 208 hp->h_flags &= ~H_FND;
b7520dd0 209 if (hp->h_info) {
80765673 210 free(hp->h_info);
b7520dd0
RC
211 hp->h_info = 0;
212 }
213 }
b7520dd0
RC
214 /*
215 * Read the report and make a copy. Must conform to RFC822 and
216 * be of the form... <tag>: <info>
80765673
RC
217 * Note that the input is expected to be in mh mail format
218 * (i.e., messages are separated by lines of ^A's).
b7520dd0 219 */
80765673
RC
220 while ((c = getchar()) == '\001' && peekc(stdin) == '\001')
221 while (getchar() != '\n')
222 ;
223 if (c == EOF)
224 return(0); /* all done */
225
b7520dd0 226 mktemp(tmpname);
80765673 227 if ((tmp = creat(tmpname, msg_prot)) < 0) {
3b28bda3 228 fprintf(stderr, "cannot create %s\n", tmpname);
80765673
RC
229 exit(1);
230 }
231 if ((tfp = fdopen(tmp, "w")) == NULL) {
232 fprintf(stderr, "cannot fdopen temp file\n");
233 exit(1);
234 }
235
236 for (state = FLD; state != EOF && state != EOM; c = getchar()) {
237 switch (state) {
238 case FLD:
239 if (c == '\n' || c == '-')
240 goto body;
241 for (cp = buf; c != ':'; c = getchar()) {
242 if (cp < buf+sizeof(buf)-1 && c != '\n' && c != EOF) {
243 *cp++ = c;
244 continue;
245 }
246 *cp = '\0';
247 fputs(buf, tfp);
248 state = EOF;
249 while (c != EOF) {
250 if (c == '\n')
251 if ((tmp = peekc(stdin)) == EOF)
252 break;
253 else if (tmp == '\001') {
254 state = EOM;
255 break;
256 }
257 putc(c, tfp);
258 c = getchar();
259 }
260 fclose(tfp);
261 goto badfmt;
262 }
263 *cp = '\0';
264 fprintf(tfp, "%s:", buf);
265 hp = findheader(buf, state);
266
267 for (cp = buf; ; ) {
268 if (cp >= buf+sizeof(buf)-1) {
269 fprintf(stderr, "field truncated\n");
270 while ((c = getchar()) != EOF && c != '\n')
271 putc(c, tfp);
272 }
273 if ((c = getchar()) == EOF) {
274 state = EOF;
275 break;
276 }
277 putc(c, tfp);
278 *cp++ = c;
279 if (c == '\n')
280 if ((c = peekc(stdin)) != ' ' && c != '\t') {
281 if (c == EOF)
282 state = EOF;
283 else if (c == '\001')
284 state = EOM;
285 break;
286 }
287 }
288 *cp = '\0';
289 cp = buf;
290 break;
291
292 body:
293 state = BODY;
294 case BODY:
295 for (cp = buf; ; c = getchar()) {
296 if (c == EOF) {
297 state = EOF;
298 break;
299 }
300 if (c == '\001' && peekc(stdin) == '\001') {
301 state = EOM;
302 break;
303 }
304 putc(c, tfp);
305 *cp++ = c;
306 if (cp >= buf+sizeof(buf)-1 || c == '\n')
307 break;
308 }
309 *cp = '\0';
310 if ((cp = index(buf, ':')) == NULL)
311 continue;
312 *cp++ = '\0';
313 hp = findheader(buf, state);
b7520dd0 314 }
80765673
RC
315
316 /*
317 * Don't save the info if the header wasn't found, we don't
318 * care about the info, or the header is repeated.
319 */
320 if (hp == NULL || !(hp->h_flags & H_SAV) || hp->h_info)
321 continue;
b7520dd0
RC
322 while (isspace(*cp))
323 cp++;
324 if (*cp) {
325 info = cp;
326 while (*cp++);
327 cp--;
328 while (isspace(cp[-1]))
329 *--cp = '\0';
330 hp->h_info = (char *) malloc(strlen(info) + 1);
80765673
RC
331 if (hp->h_info == NULL) {
332 fprintf(stderr, "ran out of memory\n");
b7520dd0 333 continue;
80765673 334 }
b7520dd0 335 strcpy(hp->h_info, info);
d93ebe7f
RC
336 if (hp == FROM && chkfrom(hp) < 0)
337 no_reply = 1;
b7520dd0
RC
338 if (hp == INDEX)
339 chkindex(hp);
340 }
341 }
80765673 342 fclose(tfp);
d93ebe7f
RC
343 if (no_reply) {
344 unlink(tmpname);
345 exit(0);
346 }
b7520dd0
RC
347 /*
348 * Verify all the required pieces of information
349 * are present.
350 */
80765673 351 for (hp = headers; hp->h_tag; hp++) {
b7520dd0
RC
352 /*
353 * Mail the bug report back to the sender with a note
354 * explaining they must conform to the specification.
355 */
80765673
RC
356 if ((hp->h_flags & H_REQ) && !(hp->h_flags & H_FND)) {
357 if (debug)
358 printf("Missing %s\n", hp->h_tag);
359 badfmt:
360 reply(FROM_I, errfile, tmpname);
361 file(tmpname, "errors");
3b28bda3 362 redistribute("errors", num);
80765673
RC
363 return(state == EOM);
364 }
b7520dd0 365 }
80765673
RC
366 /*
367 * Acknowledge receipt.
368 */
369 reply(FROM_I, ackfile, (char *)0);
370 file(tmpname, folder);
b7520dd0
RC
371 /*
372 * Append information about the new bug report
373 * to the summary file.
374 */
80765673 375 if ((fs = fopen(sumfile, "a")) == NULL)
b7520dd0 376 fprintf(stderr, "Can't open %s\n", sumfile);
80765673
RC
377 else {
378 fprintf(fs, "%14.14s/%-3d ", folder, num);
379 fprintf(fs, "%-51.51s Recv\n", INDEX_I);
380 fprintf(fs, "\t\t %-51.51s\n", SUBJECT_I);
b7520dd0 381 }
b7520dd0 382 fclose(fs);
ae422d11
SL
383 /*
384 * Check redistribution list and, if members,
385 * mail a copy of the bug report to these people.
386 */
387 redistribute(folder, num);
80765673
RC
388 return(state == EOM);
389}
390
391/*
392 * Lookup the string in the list of headers and return a pointer
393 * to the entry or NULL.
394 */
395
396struct header *
397findheader(name, state)
398 char *name;
399 int state;
400{
401 register struct header *hp;
402
403 if (debug)
404 printf("findheader(%s, %d)\n", name, state);
405
406 for (hp = headers; hp->h_tag; hp++) {
407 if (!streq(hp->h_tag, buf))
408 continue;
409 if ((hp->h_flags & H_HDR) && state != FLD)
410 continue;
411 hp->h_flags |= H_FND;
412 return(hp);
413 }
414 return(NULL);
b7520dd0
RC
415}
416
d93ebe7f
RC
417/*
418 * Check the FROM line to eliminate loops.
419 */
420
421chkfrom(hp)
422 struct header *hp;
423{
424 register char *cp1, *cp2;
425 register char c;
426
427 if (debug)
c8308884 428 printf("chkfrom(%s)\n", hp->h_info);
d93ebe7f 429
c8308884
JB
430 if (substr(hp->h_info, BUGS_NAME))
431 return(-1);
d93ebe7f
RC
432 if (substr(hp->h_info, "MAILER-DAEMON"))
433 return(-1);
434 return(0);
435}
436
b7520dd0
RC
437/*
438 * Check the format of the Index information.
439 * A side effect is to set the name of the folder if all is well.
440 */
441
442chkindex(hp)
443 struct header *hp;
444{
80765673 445 register char *cp1, *cp2;
b7520dd0
RC
446 register char c;
447 struct stat stbuf;
448
449 if (debug)
80765673
RC
450 printf("chkindex(%s)\n", hp->h_info);
451 /*
a06e3027 452 * Strip of leading "/", ".", "usr/", or "src/".
80765673
RC
453 */
454 cp1 = hp->h_info;
a06e3027 455 while (*cp1 == '/' || *cp1 == '.')
80765673 456 cp1++;
647e1291 457 while (substr(cp1, "usr/") || substr(cp1, "src/"))
80765673 458 cp1 += 4;
b7520dd0
RC
459 /*
460 * Read the folder name and remove it from the index line.
461 */
80765673
RC
462 for (cp2 = folder; ;) {
463 switch (c = *cp1++) {
464 case '/':
465 if (cp2 == folder)
466 continue;
b7520dd0 467 break;
80765673
RC
468 case '\0':
469 cp1--;
470 break;
471 case ' ':
472 case '\t':
473 while (isspace(*cp1))
474 cp1++;
475 break;
476 default:
477 if (cp2 < folder+sizeof(folder)-1)
478 *cp2++ = c;
479 continue;
b7520dd0 480 }
80765673
RC
481 *cp2 = '\0';
482 for (cp2 = hp->h_info; *cp2++ = *cp1++; )
483 ;
484 break;
b7520dd0 485 }
80765673
RC
486 if (debug)
487 printf("folder = %s\n", folder);
b7520dd0
RC
488 /*
489 * Check to make sure we have a valid folder name
490 */
491 if (stat(folder, &stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR)
492 return;
493 /*
494 * The Index line is not in the correct format so clear
80765673 495 * the H_FND flag to mail back the correct format.
b7520dd0 496 */
80765673 497 hp->h_flags &= ~H_FND;
b7520dd0
RC
498}
499
500/*
501 * Move or copy the file msg to the folder (directory).
ae422d11
SL
502 * As a side effect, num is set to the number under which
503 * the message is filed in folder.
b7520dd0
RC
504 */
505
506file(fname, folder)
507 char *fname, *folder;
508{
d72100a5
RC
509 register char *cp;
510 register int n;
b7520dd0
RC
511 char msgname[MAXNAMLEN*2+2];
512 struct stat stbuf;
513 DIR *dirp;
514 struct direct *d;
515
516 if (debug)
80765673 517 printf("file(%s, %s)\n", fname, folder);
b7520dd0
RC
518 /*
519 * Get the next number to use by finding the last message number
520 * in folder and adding one.
521 */
522 if ((dirp = opendir(folder)) == NULL) {
3b28bda3
MK
523 (void) mkdir(folder, folder_prot);
524 if ((dirp = opendir(folder)) == NULL) {
525 fprintf(stderr, "Cannot open %s/%s\n", maildir, folder);
526 return;
527 }
b7520dd0
RC
528 }
529 num = 0;
530 while ((d = readdir(dirp)) != NULL) {
531 cp = d->d_name;
532 n = 0;
533 while (isdigit(*cp))
534 n = n * 10 + (*cp++ - '0');
535 if (*cp == '\0' && n > num)
536 num = n;
537 }
538 closedir(dirp);
539 num++;
540 /*
541 * Create the destination file "folder/num" and copy fname to it.
542 */
543 sprintf(msgname, "%s/%d", folder, num);
544 if (link(fname, msgname) < 0) {
545 int fin, fout;
546
80765673
RC
547 if ((fin = open(fname, 0)) < 0) {
548 fprintf(stderr, "cannot open %s\n", fname);
b7520dd0 549 return;
80765673
RC
550 }
551 if ((fout = creat(msgname, msg_prot)) < 0) {
552 fprintf(stderr, "cannot create %s\n", msgname);
b7520dd0 553 return;
80765673
RC
554 }
555 while ((n = read(fin, buf, sizeof(buf))) > 0)
556 write(fout, buf, n);
b7520dd0
RC
557 close(fin);
558 close(fout);
559 }
560 unlink(fname);
561}
562
ae422d11
SL
563/*
564 * Redistribute a bug report to those people indicated
565 * in the redistribution list file. Perhaps should also
566 * annotate bug report with this information for future
567 * reference?
568 */
569redistribute(folder, num)
570 char *folder;
571 int num;
572{
573 FILE *fredist, *fbug, *ftemp;
574 char line[BUFSIZ], bug[2 * MAXNAMLEN + 1];
575 register char *cp;
576 int redistcnt, continuation, first;
577
578 fredist = fopen(redistfile, "r");
579 if (fredist == NULL) {
580 if (debug)
581 printf("redistribute(%s, %d), no distribution list\n",
582 folder, num);
583 return;
584 }
585 continuation = 0;
586 first = 1;
587 redistcnt = 0;
588 while (fgets(line, sizeof (line) - 1, fredist) != NULL) {
589 if (debug)
590 printf("%s: %s", redistfile, line);
591 if (continuation && index(line, '\\'))
592 continue;
593 continuation = 0;
594 cp = any(line, " \t");
595 if (cp == NULL)
596 continue;
597 *cp++ = '\0';
598 if (strcmp(folder, line) == 0)
599 goto found;
600 if (index(cp, '\\'))
601 continuation = 1;
602 }
603 if (debug)
604 printf("no redistribution list found\n");
605 fclose(fredist);
606 return;
607found:
608 mktemp(disttmp);
609 ftemp = fopen(disttmp, "w+r");
610 if (ftemp == NULL) {
611 if (debug)
612 printf("%s: couldn't create\n", disttmp);
613 return;
614 }
615again:
616 if (debug)
617 printf("redistribution list %s", cp);
618 while (cp) {
619 char *user, terminator;
620
621 while (*cp && (*cp == ' ' || *cp == '\t' || *cp == ','))
622 cp++;
623 user = cp, cp = any(cp, ", \t\n\\");
624 if (cp) {
625 terminator = *cp;
626 *cp++ = '\0';
627 if (terminator == '\n')
628 cp = 0;
629 if (terminator == '\\')
630 continuation++;
631 }
632 if (*user == '\0')
633 continue;
634 if (debug)
635 printf("copy to %s\n", user);
636 if (first) {
c8308884 637 fprintf(ftemp, "Resent-To: %s", user);
ae422d11
SL
638 first = 0;
639 } else
640 fprintf(ftemp, ", %s", user);
641 redistcnt++;
642 }
643 if (!first)
644 putc('\n', ftemp);
645 if (continuation) {
646 first = 1;
647 continuation = 0;
648 cp = line;
649 if (fgets(line, sizeof (line) - 1, fredist))
650 goto again;
651 }
652 fclose(fredist);
653 if (redistcnt == 0)
654 goto cleanup;
c8308884
JB
655 if (! SUBJECT_I) {
656 fprintf(ftemp, "Subject: ");
ae422d11 657 fprintf(ftemp, "Untitled bug report\n");
c8308884 658 }
3b28bda3 659 fprintf(ftemp, "Folder: %s/%d\n", folder, num);
ae422d11
SL
660 /*
661 * Create copy of bug report. Perhaps we should
662 * truncate large messages and just give people
663 * a pointer to the original?
664 */
665 sprintf(bug, "%s/%d", folder, num);
666 fbug = fopen(bug, "r");
667 if (fbug == NULL) {
668 if (debug)
669 printf("%s: disappeared?\n", bug);
670 goto cleanup;
671 }
672 first = 1;
673 while (fgets(line, sizeof (line) - 1, fbug)) {
674 /* first blank line indicates start of mesg */
675 if (first && line[0] == '\n') {
676 first = 0;
ae422d11
SL
677 }
678 fputs(line, ftemp);
679 }
680 fclose(fbug);
681 if (first) {
682 if (debug)
683 printf("empty bug report?\n");
684 goto cleanup;
685 }
686 if (dodeliver(ftemp))
687 unlink(disttmp);
688 fclose(ftemp);
689 return;
690cleanup:
691 fclose(ftemp);
692 unlink(disttmp);
693}
694
695dodeliver(fd)
696 FILE *fd;
697{
698 char buf[BUFSIZ], cmd[BUFSIZ];
699 FILE *pf, *popen();
700
701 strcpy(cmd, MAILCMD);
702 if (debug) {
703 strcat(cmd, " -v");
704 printf("dodeliver \"%s\"\n", cmd);
705 }
706 pf = popen(cmd, "w");
707 if (pf == NULL) {
708 if (debug)
709 printf("dodeliver, \"%s\" failed\n", cmd);
710 return (0);
711 }
712 rewind(fd);
713 while (fgets(buf, sizeof (buf) - 1, fd)) {
714 if (debug)
715 printf("%s", buf);
716 (void) fputs(buf, pf);
717 }
718 if (debug)
719 printf("EOF\n");
720 (void) pclose(pf);
721 return (1);
722}
723
b7520dd0
RC
724/*
725 * Mail file1 and file2 back to the sender.
726 */
727
728reply(to, file1, file2)
729 char *to, *file1, *file2;
730{
ae422d11 731 int pfd[2], in, w;
b7520dd0
RC
732 FILE *fout;
733
734 if (debug)
80765673
RC
735 printf("reply(%s, %s, %s)\n", to, file1, file2);
736
b7520dd0
RC
737 /*
738 * Create a temporary file to put the message in.
739 */
740 mktemp(draft);
ae422d11 741 if ((fout = fopen(draft, "w+r")) == NULL) {
b7520dd0
RC
742 fprintf(stderr, "Can't create %s\n", draft);
743 return;
744 }
745 /*
746 * Output the proper header information.
747 */
ae422d11 748 fprintf(fout, "Reply-To: %s%s\n", BUGS_NAME, BUGS_HOME);
aef45c03 749 fprintf(fout, "From: %s%s (Bugs Bunny)\n", BUGS_NAME, BUGS_HOME);
b7520dd0
RC
750 if (REPLYTO_I != NULL)
751 to = REPLYTO_I;
752 if ((to = fixaddr(to)) == 0) {
753 fprintf(stderr, "No one to reply to\n");
754 return;
755 }
756 fprintf(fout, "To: %s\n", to);
757 if (SUBJECT_I) {
758 fprintf(fout, "Subject: ");
759 if ((SUBJECT_I[0] != 'R' && SUBJECT_I[0] != 'r') ||
760 (SUBJECT_I[1] != 'E' && SUBJECT_I[1] != 'e') ||
761 SUBJECT_I[2] != ':')
762 fprintf(fout, "Re: ");
763 fprintf(fout, "%s\n", SUBJECT_I);
764 }
765 if (DATE_I) {
766 fprintf(fout, "In-Acknowledgement-Of: Your message of ");
767 fprintf(fout, "%s.\n", DATE_I);
768 if (MSGID_I)
769 fprintf(fout, " %s\n", MSGID_I);
770 }
ae422d11 771 fprintf(fout, "\n");
b7520dd0 772 if ((in = open(file1, 0)) >= 0) {
80765673
RC
773 while ((w = read(in, buf, sizeof(buf))) > 0)
774 fwrite(buf, 1, w, fout);
b7520dd0
RC
775 close(in);
776 }
777 if (file2 && (in = open(file2, 0)) >= 0) {
80765673
RC
778 while ((w = read(in, buf, sizeof(buf))) > 0)
779 fwrite(buf, 1, w, fout);
b7520dd0
RC
780 close(in);
781 }
ae422d11 782 if (dodeliver(fout))
b7520dd0 783 unlink(draft);
ae422d11 784 fclose(fout);
b7520dd0
RC
785}
786
787/*
788 * fix names like "xxx (something)" to "xxx" and
789 * "xxx <something>" to "something".
790 */
791
792char *
793fixaddr(text)
794 char *text;
795{
796 register char *cp, *lp, c;
797 char *tp;
798
799 if (!text)
800 return(0);
801 for (lp = cp = text; ; ) {
802 switch (c = *cp++) {
803 case '(':
804 while (*cp && *cp++ != ')');
805 continue;
806 case '<':
807 lp = text;
808 case '>':
809 continue;
810 case '\0':
811 while (lp != text && (*lp == ' ' || *lp == '\t'))
812 lp--;
813 *lp = c;
814 return(text);
815 }
816 *lp++ = c;
817 }
818}
819
820/*
821 * Compare two strings and convert any upper case letters to lower case.
822 */
823
80765673
RC
824streq(s1, s2)
825 register char *s1, *s2;
b7520dd0
RC
826{
827 register int c;
828
80765673
RC
829 while (c = *s1++)
830 if ((c | 040) != (*s2++ | 040))
b7520dd0 831 return(0);
80765673
RC
832 return(*s2 == '\0');
833}
834
835/*
836 * Return true if string s2 matches the first part of s1.
837 */
838
839substr(s1, s2)
840 register char *s1, *s2;
841{
842 register int c;
843
844 while (c = *s2++)
845 if (c != *s1++)
846 return(0);
847 return(1);
848}
849
ae422d11
SL
850char *
851any(cp, set)
852 register char *cp;
853 char *set;
854{
855 register char *sp;
856
857 if (cp == 0 || set == 0)
858 return (0);
859 while (*cp) {
860 for (sp = set; *sp; sp++)
861 if (*cp == *sp)
862 return (cp);
863 cp++;
864 }
865 return ((char *)0);
866}
867
80765673
RC
868peekc(fp)
869FILE *fp;
870{
871 register c;
872
873 c = getc(fp);
874 ungetc(c, fp);
875 return(c);
b7520dd0 876}