Commit | Line | Data |
---|---|---|
b3cbe40f EA |
1 | # include <stdio.h> |
2 | # include <pwd.h> | |
3 | # include <signal.h> | |
4 | # include "dlvrmail.h" | |
5 | # ifdef LOG | |
6 | # include <log.h> | |
7 | # endif LOG | |
8 | ||
a16e99bc | 9 | static char SccsId[] = "@(#)deliver.c 1.9 %G%"; |
916b3375 | 10 | |
b3cbe40f EA |
11 | /* |
12 | ** DELIVER -- Deliver a message to a particular address. | |
13 | ** | |
14 | ** Algorithm: | |
15 | ** Compute receiving network (i.e., mailer), host, & user. | |
16 | ** If local, see if this is really a program name. | |
17 | ** Build argument for the mailer. | |
18 | ** Create pipe through edit fcn if appropriate. | |
19 | ** Fork. | |
20 | ** Child: call mailer | |
21 | ** Parent: call editfcn if specified. | |
22 | ** Wait for mailer to finish. | |
23 | ** Interpret exit status. | |
24 | ** | |
25 | ** Parameters: | |
26 | ** to -- the address to deliver the message to. | |
27 | ** editfcn -- if non-NULL, we want to call this function | |
28 | ** to output the letter (instead of just out- | |
29 | ** putting it raw). | |
30 | ** | |
31 | ** Returns: | |
32 | ** zero -- successfully delivered. | |
33 | ** else -- some failure, see ExitStat for more info. | |
34 | ** | |
35 | ** Side Effects: | |
36 | ** The standard input is passed off to someone. | |
37 | ** | |
38 | ** WARNING: | |
39 | ** The standard input is shared amongst all children, | |
40 | ** including the file pointer. It is critical that the | |
41 | ** parent waits for the child to finish before forking | |
42 | ** another child. | |
43 | ** | |
b3cbe40f EA |
44 | ** Called By: |
45 | ** main | |
46 | ** savemail | |
47 | ** | |
48 | ** Files: | |
f895a45d | 49 | ** standard input -- must be opened to the message to |
b3cbe40f | 50 | ** deliver. |
b3cbe40f EA |
51 | */ |
52 | ||
53 | deliver(to, editfcn) | |
54 | addrq *to; | |
55 | int (*editfcn)(); | |
56 | { | |
57 | register struct mailer *m; | |
58 | char *host; | |
59 | char *user; | |
60 | extern struct passwd *getpwnam(); | |
61 | char **pvp; | |
62 | extern char **buildargv(); | |
63 | auto int st; | |
64 | register int i; | |
65 | register char *p; | |
66 | int pid; | |
67 | int pvect[2]; | |
68 | extern FILE *fdopen(); | |
69 | extern int errno; | |
70 | FILE *mfile; | |
71 | extern putheader(); | |
72 | extern pipesig(); | |
73 | ||
74 | /* | |
75 | ** Compute receiving mailer, host, and to addreses. | |
76 | ** Do some initialization first. To is the to address | |
77 | ** for error messages. | |
78 | */ | |
79 | ||
80 | To = to->q_paddr; | |
81 | m = to->q_mailer; | |
82 | user = to->q_user; | |
83 | host = to->q_host; | |
d916f0ca | 84 | Errors = 0; |
b3cbe40f EA |
85 | errno = 0; |
86 | # ifdef DEBUG | |
87 | if (Debug) | |
88 | printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user); | |
89 | # endif DEBUG | |
90 | ||
91 | /* | |
92 | ** Remove quote bits from user/host. | |
93 | */ | |
94 | ||
95 | for (p = user; (*p++ &= 0177) != '\0'; ) | |
96 | continue; | |
97 | if (host != NULL) | |
98 | for (p = host; (*p++ &= 0177) != '\0'; ) | |
99 | continue; | |
100 | ||
101 | /* | |
102 | ** Strip quote bits from names if the mailer wants it. | |
103 | */ | |
104 | ||
105 | if (flagset(M_STRIPQ, m->m_flags)) | |
106 | { | |
107 | stripquotes(user); | |
108 | stripquotes(host); | |
109 | } | |
110 | ||
111 | /* | |
112 | ** See if this user name is "special". | |
113 | ** If the user is a program, diddle with the mailer spec. | |
114 | ** If the user name has a slash in it, assume that this | |
115 | ** is a file -- send it off without further ado. | |
116 | ** Note that this means that editfcn's will not | |
117 | ** be applied to the message. | |
118 | */ | |
119 | ||
120 | if (m == &Mailer[0]) | |
121 | { | |
122 | if (*user == '|') | |
123 | { | |
124 | user++; | |
125 | m = &Mailer[1]; | |
126 | } | |
127 | else | |
128 | { | |
129 | if (index(user, '/') != NULL) | |
130 | { | |
131 | i = mailfile(user); | |
132 | giveresponse(i, TRUE, m); | |
133 | return (i); | |
134 | } | |
135 | } | |
136 | } | |
137 | ||
b3cbe40f | 138 | /* |
cb590f52 EA |
139 | ** See if the user exists. |
140 | ** Strictly, this is only needed to print a pretty | |
141 | ** error message. | |
142 | ** | |
143 | ** >>>>>>>>>> This clause assumes that the local mailer | |
144 | ** >> NOTE >> cannot do any further aliasing; that | |
145 | ** >>>>>>>>>> function is subsumed by delivermail. | |
b3cbe40f EA |
146 | */ |
147 | ||
148 | if (m == &Mailer[0]) | |
149 | { | |
150 | if (getpwnam(user) == NULL) | |
151 | { | |
152 | giveresponse(EX_NOUSER, TRUE, m); | |
153 | return (EX_NOUSER); | |
154 | } | |
155 | } | |
b3cbe40f EA |
156 | |
157 | /* | |
158 | ** If the mailer wants a From line, insert a new editfcn. | |
159 | */ | |
160 | ||
161 | if (flagset(M_HDR, m->m_flags) && editfcn == NULL) | |
162 | editfcn = putheader; | |
163 | ||
164 | /* | |
165 | ** Call the mailer. | |
166 | ** The argument vector gets built, pipes through 'editfcn' | |
167 | ** are created as necessary, and we fork & exec as | |
168 | ** appropriate. In the parent, we call 'editfcn'. | |
169 | */ | |
170 | ||
171 | pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr); | |
172 | if (pvp == NULL) | |
173 | { | |
174 | usrerr("name too long"); | |
175 | return (-1); | |
176 | } | |
177 | rewind(stdin); | |
178 | ||
179 | /* create a pipe if we will need one */ | |
180 | if (editfcn != NULL && pipe(pvect) < 0) | |
181 | { | |
182 | syserr("pipe"); | |
183 | return (-1); | |
184 | } | |
c9b9c7a2 MH |
185 | # ifdef VFORK |
186 | pid = vfork(); | |
187 | # else | |
b3cbe40f | 188 | pid = fork(); |
c9b9c7a2 | 189 | # endif |
b3cbe40f EA |
190 | if (pid < 0) |
191 | { | |
192 | syserr("Cannot fork"); | |
193 | if (editfcn != NULL) | |
194 | { | |
195 | close(pvect[0]); | |
196 | close(pvect[1]); | |
197 | } | |
198 | return (-1); | |
199 | } | |
200 | else if (pid == 0) | |
201 | { | |
202 | /* child -- set up input & exec mailer */ | |
203 | signal(SIGINT, SIG_IGN); | |
204 | if (editfcn != NULL) | |
205 | { | |
206 | close(0); | |
207 | if (dup(pvect[0]) < 0) | |
208 | { | |
209 | syserr("Cannot dup to zero!"); | |
a16e99bc | 210 | _exit(EX_OSERR); |
b3cbe40f EA |
211 | } |
212 | close(pvect[0]); | |
213 | close(pvect[1]); | |
214 | } | |
215 | if (!flagset(M_RESTR, m->m_flags)) | |
216 | setuid(getuid()); | |
217 | # ifdef LOG | |
218 | initlog(NULL, 0, LOG_CLOSE); | |
219 | # endif LOG | |
c9b9c7a2 MH |
220 | # ifndef VFORK |
221 | /* | |
222 | * We have to be careful with vfork - we can't mung up the | |
223 | * memory but we don't want the mailer to inherit any extra | |
224 | * open files. Chances are the mailer won't | |
225 | * care about an extra file, but then again you never know. | |
226 | * Actually, we would like to close(fileno(pwf)), but it's | |
227 | * declared static so we can't. But if we fclose(pwf), which | |
228 | * is what endpwent does, it closes it in the parent too and | |
229 | * the next getpwnam will be slower. If you have a weird mailer | |
230 | * that chokes on the extra file you should do the endpwent(). | |
231 | */ | |
b3cbe40f | 232 | endpwent(); |
c9b9c7a2 | 233 | # endif |
b3cbe40f EA |
234 | execv(m->m_mailer, pvp); |
235 | /* syserr fails because log is closed */ | |
236 | /* syserr("Cannot exec %s", m->m_mailer); */ | |
a16e99bc | 237 | _exit(EX_UNAVAILABLE); |
b3cbe40f EA |
238 | } |
239 | ||
240 | /* arrange to write out header message if error */ | |
241 | if (editfcn != NULL) | |
242 | { | |
243 | close(pvect[0]); | |
244 | signal(SIGPIPE, pipesig); | |
245 | mfile = fdopen(pvect[1], "w"); | |
246 | (*editfcn)(mfile); | |
247 | fclose(mfile); | |
248 | } | |
249 | ||
250 | /* | |
251 | ** Wait for child to die and report status. | |
252 | ** We should never get fatal errors (e.g., segmentation | |
253 | ** violation), so we report those specially. For other | |
254 | ** errors, we choose a status message (into statmsg), | |
255 | ** and if it represents an error, we print it. | |
256 | */ | |
257 | ||
258 | while ((i = wait(&st)) > 0 && i != pid) | |
259 | continue; | |
260 | if (i < 0) | |
261 | { | |
262 | syserr("wait"); | |
263 | return (-1); | |
264 | } | |
265 | if ((st & 0377) != 0) | |
266 | { | |
267 | syserr("%s: stat %o", pvp[0], st); | |
21ec078e | 268 | ExitStat = EX_UNAVAILABLE; |
b3cbe40f EA |
269 | return (-1); |
270 | } | |
271 | i = (st >> 8) & 0377; | |
272 | giveresponse(i, FALSE, m); | |
273 | return (i); | |
274 | } | |
275 | \f/* | |
276 | ** GIVERESPONSE -- Interpret an error response from a mailer | |
277 | ** | |
278 | ** Parameters: | |
279 | ** stat -- the status code from the mailer (high byte | |
280 | ** only; core dumps must have been taken care of | |
281 | ** already). | |
282 | ** force -- if set, force an error message output, even | |
283 | ** if the mailer seems to like to print its own | |
284 | ** messages. | |
285 | ** m -- the mailer descriptor for this mailer. | |
286 | ** | |
287 | ** Returns: | |
288 | ** none. | |
289 | ** | |
290 | ** Side Effects: | |
d916f0ca | 291 | ** Errors may be incremented. |
b3cbe40f EA |
292 | ** ExitStat may be set. |
293 | ** | |
b3cbe40f EA |
294 | ** Called By: |
295 | ** deliver | |
b3cbe40f EA |
296 | */ |
297 | ||
298 | giveresponse(stat, force, m) | |
299 | int stat; | |
300 | int force; | |
301 | register struct mailer *m; | |
302 | { | |
303 | register char *statmsg; | |
304 | extern char *SysExMsg[]; | |
305 | register int i; | |
306 | extern int N_SysEx; | |
307 | ||
308 | i = stat - EX__BASE; | |
309 | if (i < 0 || i > N_SysEx) | |
310 | statmsg = NULL; | |
311 | else | |
312 | statmsg = SysExMsg[i]; | |
313 | if (stat == 0) | |
314 | statmsg = "ok"; | |
315 | else | |
316 | { | |
d916f0ca | 317 | Errors++; |
b3cbe40f EA |
318 | if (statmsg == NULL && m->m_badstat != 0) |
319 | { | |
320 | stat = m->m_badstat; | |
321 | i = stat - EX__BASE; | |
322 | # ifdef DEBUG | |
323 | if (i < 0 || i >= N_SysEx) | |
324 | syserr("Bad m_badstat %d", stat); | |
325 | else | |
326 | # endif DEBUG | |
327 | statmsg = SysExMsg[i]; | |
328 | } | |
329 | if (statmsg == NULL) | |
330 | usrerr("unknown mailer response %d", stat); | |
331 | else if (force || !flagset(M_QUIET, m->m_flags)) | |
332 | usrerr("%s", statmsg); | |
333 | } | |
334 | ||
335 | /* | |
336 | ** Final cleanup. | |
337 | ** Log a record of the transaction. Compute the new | |
338 | ** ExitStat -- if we already had an error, stick with | |
339 | ** that. | |
340 | */ | |
341 | ||
342 | # ifdef LOG | |
343 | if (statmsg == NULL) | |
344 | logmsg(LOG_INFO, "%s->%s: error %d", From.q_paddr, To, stat); | |
345 | else | |
346 | logmsg(LOG_INFO, "%s->%s: %s", From.q_paddr, To, statmsg); | |
347 | # endif LOG | |
cb590f52 | 348 | setstat(stat); |
b3cbe40f EA |
349 | return (stat); |
350 | } | |
351 | \f/* | |
352 | ** PUTHEADER -- insert the From header into some mail | |
353 | ** | |
354 | ** For mailers such as 'msgs' that want the header inserted | |
355 | ** into the mail, this edit filter inserts the From line and | |
356 | ** then passes the rest of the message through. | |
357 | ** | |
358 | ** Parameters: | |
359 | ** fp -- the file pointer for the output. | |
360 | ** | |
361 | ** Returns: | |
362 | ** none | |
363 | ** | |
364 | ** Side Effects: | |
365 | ** Puts a "From" line in UNIX format, and then | |
366 | ** outputs the rest of the message. | |
367 | ** | |
b3cbe40f EA |
368 | ** Called By: |
369 | ** deliver | |
b3cbe40f EA |
370 | */ |
371 | ||
372 | putheader(fp) | |
373 | register FILE *fp; | |
374 | { | |
375 | char buf[MAXLINE + 1]; | |
376 | long tim; | |
377 | extern char *ctime(); | |
378 | ||
379 | time(&tim); | |
380 | fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim)); | |
381 | while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp)) | |
382 | fputs(buf, fp); | |
383 | if (ferror(fp)) | |
384 | { | |
385 | syserr("putheader: write error"); | |
386 | setstat(EX_IOERR); | |
387 | } | |
388 | } | |
389 | \f/* | |
390 | ** PIPESIG -- Handle broken pipe signals | |
391 | ** | |
392 | ** This just logs an error. | |
393 | ** | |
394 | ** Parameters: | |
395 | ** none | |
396 | ** | |
397 | ** Returns: | |
398 | ** none | |
399 | ** | |
400 | ** Side Effects: | |
401 | ** logs an error message. | |
b3cbe40f EA |
402 | */ |
403 | ||
404 | pipesig() | |
405 | { | |
406 | syserr("Broken pipe"); | |
407 | } | |
408 | \f/* | |
409 | ** SENDTO -- Designate a send list. | |
410 | ** | |
411 | ** The parameter is a comma-separated list of people to send to. | |
412 | ** This routine arranges to send to all of them. | |
413 | ** | |
414 | ** Parameters: | |
415 | ** list -- the send list. | |
416 | ** copyf -- the copy flag; passed to parse. | |
417 | ** | |
418 | ** Returns: | |
419 | ** none | |
420 | ** | |
421 | ** Side Effects: | |
422 | ** none. | |
423 | ** | |
b3cbe40f EA |
424 | ** Called By: |
425 | ** main | |
426 | ** alias | |
b3cbe40f EA |
427 | */ |
428 | ||
429 | sendto(list, copyf) | |
430 | char *list; | |
431 | int copyf; | |
432 | { | |
433 | register char *p; | |
434 | register char *q; | |
435 | register char c; | |
436 | addrq *a; | |
437 | extern addrq *parse(); | |
438 | bool more; | |
439 | ||
440 | /* more keeps track of what the previous delimiter was */ | |
441 | more = TRUE; | |
442 | for (p = list; more; ) | |
443 | { | |
444 | /* find the end of this address */ | |
445 | q = p; | |
446 | while ((c = *p++) != '\0' && c != ',' && c != '\n') | |
447 | continue; | |
448 | more = c != '\0'; | |
449 | *--p = '\0'; | |
450 | if (more) | |
451 | p++; | |
452 | ||
453 | /* parse the address */ | |
454 | if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) | |
455 | continue; | |
456 | ||
457 | /* arrange to send to this person */ | |
458 | recipient(a, &SendQ); | |
459 | } | |
460 | To = NULL; | |
461 | } | |
462 | \f/* | |
463 | ** RECIPIENT -- Designate a message recipient | |
464 | ** | |
465 | ** Saves the named person for future mailing. | |
466 | ** | |
467 | ** Designates a person as a recipient. This routine | |
468 | ** does the initial parsing, and checks to see if | |
469 | ** this person has already received the mail. | |
470 | ** It also supresses local network names and turns them into | |
471 | ** local names. | |
472 | ** | |
473 | ** Parameters: | |
474 | ** a -- the (preparsed) address header for the recipient. | |
475 | ** targetq -- the queue to add the name to. | |
476 | ** | |
477 | ** Returns: | |
478 | ** none. | |
479 | ** | |
480 | ** Side Effects: | |
481 | ** none. | |
482 | ** | |
b3cbe40f EA |
483 | ** Called By: |
484 | ** sendto | |
485 | ** main | |
b3cbe40f EA |
486 | */ |
487 | ||
488 | recipient(a, targetq) | |
489 | register addrq *a; | |
490 | addrq *targetq; | |
491 | { | |
492 | register addrq *q; | |
493 | register struct mailer *m; | |
494 | register char **pvp; | |
495 | extern char *xalloc(); | |
496 | extern bool forward(); | |
497 | extern int errno; | |
498 | extern bool sameaddr(); | |
499 | ||
500 | To = a->q_paddr; | |
501 | m = a->q_mailer; | |
502 | errno = 0; | |
503 | # ifdef DEBUG | |
504 | if (Debug) | |
505 | printf("recipient(%s)\n", To); | |
506 | # endif DEBUG | |
507 | ||
b3cbe40f EA |
508 | /* |
509 | ** Look up this person in the recipient list. If they | |
510 | ** are there already, return, otherwise continue. | |
511 | */ | |
512 | ||
513 | if (!ForceMail) | |
514 | { | |
515 | for (q = &SendQ; (q = nxtinq(q)) != NULL; ) | |
516 | if (sameaddr(q, a, FALSE)) | |
517 | { | |
518 | # ifdef DEBUG | |
519 | if (Debug) | |
520 | printf("(%s in SendQ)\n", a->q_paddr); | |
521 | # endif DEBUG | |
522 | return; | |
523 | } | |
524 | for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) | |
525 | if (sameaddr(q, a, FALSE)) | |
526 | { | |
527 | # ifdef DEBUG | |
528 | if (Debug) | |
529 | printf("(%s in AliasQ)\n", a->q_paddr); | |
530 | # endif DEBUG | |
531 | return; | |
532 | } | |
533 | } | |
534 | ||
535 | /* | |
536 | ** See if the user wants hir mail forwarded. | |
537 | ** `Forward' must do the forwarding recursively. | |
538 | */ | |
539 | ||
540 | if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) | |
541 | return; | |
542 | ||
543 | /* | |
544 | ** Put the user onto the target queue. | |
545 | */ | |
546 | ||
547 | if (targetq != NULL) | |
548 | { | |
549 | putonq(a, targetq); | |
550 | } | |
551 | ||
552 | return; | |
553 | } | |
554 | \f/* | |
555 | ** BUILDARGV -- Build an argument vector for a mail server. | |
556 | ** | |
557 | ** Using a template defined in config.c, an argv is built. | |
558 | ** The format of the template is already a vector. The | |
559 | ** items of this vector are copied, unless a dollar sign | |
560 | ** is encountered. In this case, the next character | |
561 | ** specifies something else to copy in. These can be | |
562 | ** $f The from address. | |
563 | ** $h The host. | |
564 | ** $u The user. | |
565 | ** $c The hop count. | |
566 | ** The vector is built in a local buffer. A pointer to | |
567 | ** the static argv is returned. | |
568 | ** | |
569 | ** Parameters: | |
570 | ** tmplt -- a template for an argument vector. | |
571 | ** flags -- the flags for this server. | |
572 | ** host -- the host name to send to. | |
573 | ** user -- the user name to send to. | |
574 | ** from -- the person this mail is from. | |
575 | ** | |
576 | ** Returns: | |
577 | ** A pointer to an argv. | |
578 | ** | |
579 | ** Side Effects: | |
580 | ** none | |
581 | ** | |
582 | ** WARNING: | |
583 | ** Since the argv is staticly allocated, any subsequent | |
584 | ** calls will clobber the old argv. | |
585 | ** | |
b3cbe40f EA |
586 | ** Called By: |
587 | ** deliver | |
b3cbe40f EA |
588 | */ |
589 | ||
590 | char ** | |
591 | buildargv(tmplt, flags, host, user, from) | |
592 | char **tmplt; | |
593 | int flags; | |
594 | char *host; | |
595 | char *user; | |
596 | char *from; | |
597 | { | |
598 | register char *p; | |
599 | register char *q; | |
600 | static char *pv[MAXPV+1]; | |
601 | char **pvp; | |
602 | char **mvp; | |
603 | static char buf[512]; | |
604 | register char *bp; | |
605 | char pbuf[30]; | |
606 | ||
607 | /* | |
608 | ** Do initial argv setup. | |
609 | ** Insert the mailer name. Notice that $x expansion is | |
610 | ** NOT done on the mailer name. Then, if the mailer has | |
611 | ** a picky -f flag, we insert it as appropriate. This | |
612 | ** code does not check for 'pv' overflow; this places a | |
613 | ** manifest lower limit of 4 for MAXPV. | |
614 | */ | |
615 | ||
616 | pvp = pv; | |
617 | bp = buf; | |
618 | ||
619 | *pvp++ = tmplt[0]; | |
620 | ||
621 | /* insert -f or -r flag as appropriate */ | |
622 | if (flagset(M_FOPT|M_ROPT, flags) && FromFlag) | |
623 | { | |
624 | if (flagset(M_FOPT, flags)) | |
625 | *pvp++ = "-f"; | |
626 | else | |
627 | *pvp++ = "-r"; | |
628 | *pvp++ = From.q_paddr; | |
629 | } | |
630 | ||
631 | /* | |
632 | ** Build the rest of argv. | |
633 | ** For each prototype parameter, the prototype is | |
634 | ** scanned character at a time. If a dollar-sign is | |
635 | ** found, 'q' is set to the appropriate expansion, | |
636 | ** otherwise it is null. Then either the string | |
637 | ** pointed to by q, or the original character, is | |
638 | ** interpolated into the buffer. Buffer overflow is | |
639 | ** checked. | |
640 | */ | |
641 | ||
642 | for (mvp = tmplt; (p = *++mvp) != NULL; ) | |
643 | { | |
644 | if (pvp >= &pv[MAXPV]) | |
645 | { | |
646 | syserr("Too many parameters to %s", pv[0]); | |
647 | return (NULL); | |
648 | } | |
649 | *pvp++ = bp; | |
650 | for (; *p != '\0'; p++) | |
651 | { | |
652 | /* q will be the interpolated quantity */ | |
653 | q = NULL; | |
654 | if (*p == '$') | |
655 | { | |
656 | switch (*++p) | |
657 | { | |
658 | case 'f': /* from person */ | |
659 | q = from; | |
660 | break; | |
661 | ||
662 | case 'u': /* user */ | |
663 | q = user; | |
664 | break; | |
665 | ||
666 | case 'h': /* host */ | |
667 | q = host; | |
668 | break; | |
669 | ||
670 | case 'c': /* hop count */ | |
671 | sprintf(pbuf, "%d", HopCount); | |
672 | q = pbuf; | |
673 | break; | |
674 | } | |
675 | } | |
676 | ||
677 | /* | |
678 | ** Interpolate q or output one character | |
679 | ** Strip quote bits as we proceed..... | |
680 | */ | |
681 | ||
682 | if (q != NULL) | |
683 | { | |
684 | while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') | |
685 | continue; | |
686 | bp--; | |
b3cbe40f EA |
687 | } |
688 | else if (bp < &buf[sizeof buf - 1]) | |
689 | *bp++ = *p; | |
690 | } | |
691 | *bp++ = '\0'; | |
692 | if (bp >= &buf[sizeof buf - 1]) | |
693 | return (NULL); | |
694 | } | |
695 | *pvp = NULL; | |
696 | ||
697 | # ifdef DEBUG | |
698 | if (Debug) | |
699 | { | |
700 | printf("Interpolated argv is:\n"); | |
701 | for (mvp = pv; *mvp != NULL; mvp++) | |
702 | printf("\t%s\n", *mvp); | |
703 | } | |
704 | # endif DEBUG | |
705 | ||
706 | return (pv); | |
707 | } | |
708 | \f/* | |
709 | ** MAILFILE -- Send a message to a file. | |
710 | ** | |
711 | ** Parameters: | |
712 | ** filename -- the name of the file to send to. | |
713 | ** | |
714 | ** Returns: | |
715 | ** The exit code associated with the operation. | |
716 | ** | |
717 | ** Side Effects: | |
718 | ** none. | |
719 | ** | |
b3cbe40f EA |
720 | ** Called By: |
721 | ** deliver | |
b3cbe40f EA |
722 | */ |
723 | ||
724 | mailfile(filename) | |
725 | char *filename; | |
726 | { | |
727 | char buf[MAXLINE]; | |
728 | register FILE *f; | |
729 | auto long tim; | |
730 | extern char *ctime(); | |
731 | ||
732 | f = fopen(filename, "a"); | |
733 | if (f == NULL) | |
734 | return (EX_CANTCREAT); | |
735 | ||
736 | /* output the timestamp */ | |
737 | time(&tim); | |
738 | fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); | |
739 | rewind(stdin); | |
740 | while (fgets(buf, sizeof buf, stdin) != NULL) | |
741 | { | |
742 | fputs(buf, f); | |
743 | if (ferror(f)) | |
744 | { | |
745 | fclose(f); | |
746 | return (EX_IOERR); | |
747 | } | |
748 | } | |
749 | fputs("\n", f); | |
750 | fclose(f); | |
751 | return (EX_OK); | |
752 | } |