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