Commit | Line | Data |
---|---|---|
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 | |
8 | char 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 | 14 | static 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 |
43 | char *bugperson = "bugs"; |
44 | char *maildir = "mail"; | |
b7520dd0 RC |
45 | char ackfile[] = ".ack"; |
46 | char errfile[] = ".format"; | |
47 | char sumfile[] = "summary"; | |
48 | char logfile[] = "errors/log"; | |
ae422d11 | 49 | char redistfile[] = ".redist"; |
b7520dd0 RC |
50 | char tmpname[] = "BfXXXXXX"; |
51 | char draft[] = "RpXXXXXX"; | |
ae422d11 | 52 | char disttmp[] = "RcXXXXXX"; |
b7520dd0 | 53 | |
80765673 | 54 | char buf[8192]; |
b7520dd0 RC |
55 | char folder[MAXNAMLEN]; |
56 | int num; | |
3b28bda3 MK |
57 | int msg_prot = 0640; |
58 | int folder_prot = 0750; | |
b7520dd0 RC |
59 | |
60 | int debug; | |
61 | ||
62 | char *index(); | |
63 | char *rindex(); | |
64 | char *fixaddr(); | |
ae422d11 | 65 | char *any(); |
b7520dd0 RC |
66 | |
67 | main(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 | |
173 | struct 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 |
192 | struct header *findheader(); |
193 | ||
b7520dd0 RC |
194 | process() |
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 | ||
396 | struct header * | |
397 | findheader(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 | ||
421 | chkfrom(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 | ||
442 | chkindex(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 | ||
506 | file(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 | */ | |
569 | redistribute(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; | |
607 | found: | |
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 | } | |
615 | again: | |
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; | |
690 | cleanup: | |
691 | fclose(ftemp); | |
692 | unlink(disttmp); | |
693 | } | |
694 | ||
695 | dodeliver(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 | ||
728 | reply(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 | ||
792 | char * | |
793 | fixaddr(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 |
824 | streq(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 | ||
839 | substr(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 |
850 | char * |
851 | any(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 |
868 | peekc(fp) |
869 | FILE *fp; | |
870 | { | |
871 | register c; | |
872 | ||
873 | c = getc(fp); | |
874 | ungetc(c, fp); | |
875 | return(c); | |
b7520dd0 | 876 | } |