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