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 | ||
31cef89c | 9 | static char SccsId[] = "@(#)deliver.c 1.11 10/27/80"; |
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 */ | |
902c5f15 EA |
203 | /* make diagnostic output be standard output */ |
204 | close(2); | |
205 | dup(1); | |
b3cbe40f EA |
206 | signal(SIGINT, SIG_IGN); |
207 | if (editfcn != NULL) | |
208 | { | |
209 | close(0); | |
210 | if (dup(pvect[0]) < 0) | |
211 | { | |
212 | syserr("Cannot dup to zero!"); | |
a16e99bc | 213 | _exit(EX_OSERR); |
b3cbe40f EA |
214 | } |
215 | close(pvect[0]); | |
216 | close(pvect[1]); | |
217 | } | |
218 | if (!flagset(M_RESTR, m->m_flags)) | |
219 | setuid(getuid()); | |
220 | # ifdef LOG | |
221 | initlog(NULL, 0, LOG_CLOSE); | |
222 | # endif LOG | |
c9b9c7a2 MH |
223 | # ifndef VFORK |
224 | /* | |
225 | * We have to be careful with vfork - we can't mung up the | |
226 | * memory but we don't want the mailer to inherit any extra | |
227 | * open files. Chances are the mailer won't | |
228 | * care about an extra file, but then again you never know. | |
229 | * Actually, we would like to close(fileno(pwf)), but it's | |
230 | * declared static so we can't. But if we fclose(pwf), which | |
231 | * is what endpwent does, it closes it in the parent too and | |
232 | * the next getpwnam will be slower. If you have a weird mailer | |
233 | * that chokes on the extra file you should do the endpwent(). | |
234 | */ | |
b3cbe40f | 235 | endpwent(); |
c9b9c7a2 | 236 | # endif |
b3cbe40f EA |
237 | execv(m->m_mailer, pvp); |
238 | /* syserr fails because log is closed */ | |
239 | /* syserr("Cannot exec %s", m->m_mailer); */ | |
a16e99bc | 240 | _exit(EX_UNAVAILABLE); |
b3cbe40f EA |
241 | } |
242 | ||
243 | /* arrange to write out header message if error */ | |
244 | if (editfcn != NULL) | |
245 | { | |
246 | close(pvect[0]); | |
247 | signal(SIGPIPE, pipesig); | |
248 | mfile = fdopen(pvect[1], "w"); | |
249 | (*editfcn)(mfile); | |
250 | fclose(mfile); | |
251 | } | |
252 | ||
253 | /* | |
254 | ** Wait for child to die and report status. | |
255 | ** We should never get fatal errors (e.g., segmentation | |
256 | ** violation), so we report those specially. For other | |
257 | ** errors, we choose a status message (into statmsg), | |
258 | ** and if it represents an error, we print it. | |
259 | */ | |
260 | ||
261 | while ((i = wait(&st)) > 0 && i != pid) | |
262 | continue; | |
263 | if (i < 0) | |
264 | { | |
265 | syserr("wait"); | |
266 | return (-1); | |
267 | } | |
268 | if ((st & 0377) != 0) | |
269 | { | |
270 | syserr("%s: stat %o", pvp[0], st); | |
21ec078e | 271 | ExitStat = EX_UNAVAILABLE; |
b3cbe40f EA |
272 | return (-1); |
273 | } | |
274 | i = (st >> 8) & 0377; | |
275 | giveresponse(i, FALSE, m); | |
276 | return (i); | |
277 | } | |
278 | \f/* | |
279 | ** GIVERESPONSE -- Interpret an error response from a mailer | |
280 | ** | |
281 | ** Parameters: | |
282 | ** stat -- the status code from the mailer (high byte | |
283 | ** only; core dumps must have been taken care of | |
284 | ** already). | |
285 | ** force -- if set, force an error message output, even | |
286 | ** if the mailer seems to like to print its own | |
287 | ** messages. | |
288 | ** m -- the mailer descriptor for this mailer. | |
289 | ** | |
290 | ** Returns: | |
291 | ** none. | |
292 | ** | |
293 | ** Side Effects: | |
d916f0ca | 294 | ** Errors may be incremented. |
b3cbe40f EA |
295 | ** ExitStat may be set. |
296 | ** | |
b3cbe40f EA |
297 | ** Called By: |
298 | ** deliver | |
b3cbe40f EA |
299 | */ |
300 | ||
301 | giveresponse(stat, force, m) | |
302 | int stat; | |
303 | int force; | |
304 | register struct mailer *m; | |
305 | { | |
306 | register char *statmsg; | |
307 | extern char *SysExMsg[]; | |
308 | register int i; | |
309 | extern int N_SysEx; | |
afcbcc6e EA |
310 | extern long MsgSize; |
311 | char buf[30]; | |
b3cbe40f EA |
312 | |
313 | i = stat - EX__BASE; | |
314 | if (i < 0 || i > N_SysEx) | |
315 | statmsg = NULL; | |
316 | else | |
317 | statmsg = SysExMsg[i]; | |
318 | if (stat == 0) | |
319 | statmsg = "ok"; | |
320 | else | |
321 | { | |
d916f0ca | 322 | Errors++; |
b3cbe40f EA |
323 | if (statmsg == NULL && m->m_badstat != 0) |
324 | { | |
325 | stat = m->m_badstat; | |
326 | i = stat - EX__BASE; | |
327 | # ifdef DEBUG | |
328 | if (i < 0 || i >= N_SysEx) | |
329 | syserr("Bad m_badstat %d", stat); | |
330 | else | |
331 | # endif DEBUG | |
332 | statmsg = SysExMsg[i]; | |
333 | } | |
334 | if (statmsg == NULL) | |
335 | usrerr("unknown mailer response %d", stat); | |
336 | else if (force || !flagset(M_QUIET, m->m_flags)) | |
337 | usrerr("%s", statmsg); | |
338 | } | |
339 | ||
340 | /* | |
341 | ** Final cleanup. | |
342 | ** Log a record of the transaction. Compute the new | |
343 | ** ExitStat -- if we already had an error, stick with | |
344 | ** that. | |
345 | */ | |
346 | ||
b3cbe40f | 347 | if (statmsg == NULL) |
afcbcc6e EA |
348 | { |
349 | sprintf(buf, "error %d", stat); | |
350 | statmsg = buf; | |
351 | } | |
352 | ||
353 | # ifdef LOG | |
354 | logmsg(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); | |
b3cbe40f | 355 | # endif LOG |
cb590f52 | 356 | setstat(stat); |
b3cbe40f EA |
357 | return (stat); |
358 | } | |
359 | \f/* | |
360 | ** PUTHEADER -- insert the From header into some mail | |
361 | ** | |
362 | ** For mailers such as 'msgs' that want the header inserted | |
363 | ** into the mail, this edit filter inserts the From line and | |
364 | ** then passes the rest of the message through. | |
365 | ** | |
366 | ** Parameters: | |
367 | ** fp -- the file pointer for the output. | |
368 | ** | |
369 | ** Returns: | |
370 | ** none | |
371 | ** | |
372 | ** Side Effects: | |
373 | ** Puts a "From" line in UNIX format, and then | |
374 | ** outputs the rest of the message. | |
375 | ** | |
b3cbe40f EA |
376 | ** Called By: |
377 | ** deliver | |
b3cbe40f EA |
378 | */ |
379 | ||
380 | putheader(fp) | |
381 | register FILE *fp; | |
382 | { | |
383 | char buf[MAXLINE + 1]; | |
384 | long tim; | |
385 | extern char *ctime(); | |
386 | ||
387 | time(&tim); | |
388 | fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim)); | |
389 | while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp)) | |
390 | fputs(buf, fp); | |
391 | if (ferror(fp)) | |
392 | { | |
393 | syserr("putheader: write error"); | |
394 | setstat(EX_IOERR); | |
395 | } | |
396 | } | |
397 | \f/* | |
398 | ** PIPESIG -- Handle broken pipe signals | |
399 | ** | |
400 | ** This just logs an error. | |
401 | ** | |
402 | ** Parameters: | |
403 | ** none | |
404 | ** | |
405 | ** Returns: | |
406 | ** none | |
407 | ** | |
408 | ** Side Effects: | |
409 | ** logs an error message. | |
b3cbe40f EA |
410 | */ |
411 | ||
412 | pipesig() | |
413 | { | |
414 | syserr("Broken pipe"); | |
902c5f15 | 415 | signal(SIGPIPE, SIG_IGN); |
b3cbe40f EA |
416 | } |
417 | \f/* | |
418 | ** SENDTO -- Designate a send list. | |
419 | ** | |
420 | ** The parameter is a comma-separated list of people to send to. | |
421 | ** This routine arranges to send to all of them. | |
422 | ** | |
423 | ** Parameters: | |
424 | ** list -- the send list. | |
425 | ** copyf -- the copy flag; passed to parse. | |
426 | ** | |
427 | ** Returns: | |
428 | ** none | |
429 | ** | |
430 | ** Side Effects: | |
431 | ** none. | |
432 | ** | |
b3cbe40f EA |
433 | ** Called By: |
434 | ** main | |
435 | ** alias | |
b3cbe40f EA |
436 | */ |
437 | ||
438 | sendto(list, copyf) | |
439 | char *list; | |
440 | int copyf; | |
441 | { | |
442 | register char *p; | |
443 | register char *q; | |
444 | register char c; | |
445 | addrq *a; | |
446 | extern addrq *parse(); | |
447 | bool more; | |
448 | ||
449 | /* more keeps track of what the previous delimiter was */ | |
450 | more = TRUE; | |
451 | for (p = list; more; ) | |
452 | { | |
453 | /* find the end of this address */ | |
454 | q = p; | |
455 | while ((c = *p++) != '\0' && c != ',' && c != '\n') | |
456 | continue; | |
457 | more = c != '\0'; | |
458 | *--p = '\0'; | |
459 | if (more) | |
460 | p++; | |
461 | ||
462 | /* parse the address */ | |
463 | if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) | |
464 | continue; | |
465 | ||
466 | /* arrange to send to this person */ | |
467 | recipient(a, &SendQ); | |
468 | } | |
469 | To = NULL; | |
470 | } | |
471 | \f/* | |
472 | ** RECIPIENT -- Designate a message recipient | |
473 | ** | |
474 | ** Saves the named person for future mailing. | |
475 | ** | |
476 | ** Designates a person as a recipient. This routine | |
477 | ** does the initial parsing, and checks to see if | |
478 | ** this person has already received the mail. | |
479 | ** It also supresses local network names and turns them into | |
480 | ** local names. | |
481 | ** | |
482 | ** Parameters: | |
483 | ** a -- the (preparsed) address header for the recipient. | |
484 | ** targetq -- the queue to add the name to. | |
485 | ** | |
486 | ** Returns: | |
487 | ** none. | |
488 | ** | |
489 | ** Side Effects: | |
490 | ** none. | |
491 | ** | |
b3cbe40f EA |
492 | ** Called By: |
493 | ** sendto | |
494 | ** main | |
b3cbe40f EA |
495 | */ |
496 | ||
497 | recipient(a, targetq) | |
498 | register addrq *a; | |
499 | addrq *targetq; | |
500 | { | |
501 | register addrq *q; | |
502 | register struct mailer *m; | |
503 | register char **pvp; | |
504 | extern char *xalloc(); | |
505 | extern bool forward(); | |
506 | extern int errno; | |
507 | extern bool sameaddr(); | |
508 | ||
509 | To = a->q_paddr; | |
510 | m = a->q_mailer; | |
511 | errno = 0; | |
512 | # ifdef DEBUG | |
513 | if (Debug) | |
514 | printf("recipient(%s)\n", To); | |
515 | # endif DEBUG | |
516 | ||
b3cbe40f EA |
517 | /* |
518 | ** Look up this person in the recipient list. If they | |
519 | ** are there already, return, otherwise continue. | |
520 | */ | |
521 | ||
522 | if (!ForceMail) | |
523 | { | |
524 | for (q = &SendQ; (q = nxtinq(q)) != NULL; ) | |
525 | if (sameaddr(q, a, FALSE)) | |
526 | { | |
527 | # ifdef DEBUG | |
528 | if (Debug) | |
529 | printf("(%s in SendQ)\n", a->q_paddr); | |
530 | # endif DEBUG | |
531 | return; | |
532 | } | |
533 | for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) | |
534 | if (sameaddr(q, a, FALSE)) | |
535 | { | |
536 | # ifdef DEBUG | |
537 | if (Debug) | |
538 | printf("(%s in AliasQ)\n", a->q_paddr); | |
539 | # endif DEBUG | |
540 | return; | |
541 | } | |
542 | } | |
543 | ||
544 | /* | |
545 | ** See if the user wants hir mail forwarded. | |
546 | ** `Forward' must do the forwarding recursively. | |
547 | */ | |
548 | ||
549 | if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) | |
550 | return; | |
551 | ||
552 | /* | |
553 | ** Put the user onto the target queue. | |
554 | */ | |
555 | ||
556 | if (targetq != NULL) | |
557 | { | |
558 | putonq(a, targetq); | |
559 | } | |
560 | ||
561 | return; | |
562 | } | |
563 | \f/* | |
564 | ** BUILDARGV -- Build an argument vector for a mail server. | |
565 | ** | |
566 | ** Using a template defined in config.c, an argv is built. | |
567 | ** The format of the template is already a vector. The | |
568 | ** items of this vector are copied, unless a dollar sign | |
569 | ** is encountered. In this case, the next character | |
570 | ** specifies something else to copy in. These can be | |
571 | ** $f The from address. | |
572 | ** $h The host. | |
573 | ** $u The user. | |
574 | ** $c The hop count. | |
575 | ** The vector is built in a local buffer. A pointer to | |
576 | ** the static argv is returned. | |
577 | ** | |
578 | ** Parameters: | |
579 | ** tmplt -- a template for an argument vector. | |
580 | ** flags -- the flags for this server. | |
581 | ** host -- the host name to send to. | |
582 | ** user -- the user name to send to. | |
583 | ** from -- the person this mail is from. | |
584 | ** | |
585 | ** Returns: | |
586 | ** A pointer to an argv. | |
587 | ** | |
588 | ** Side Effects: | |
589 | ** none | |
590 | ** | |
591 | ** WARNING: | |
592 | ** Since the argv is staticly allocated, any subsequent | |
593 | ** calls will clobber the old argv. | |
594 | ** | |
b3cbe40f EA |
595 | ** Called By: |
596 | ** deliver | |
b3cbe40f EA |
597 | */ |
598 | ||
599 | char ** | |
600 | buildargv(tmplt, flags, host, user, from) | |
601 | char **tmplt; | |
602 | int flags; | |
603 | char *host; | |
604 | char *user; | |
605 | char *from; | |
606 | { | |
607 | register char *p; | |
608 | register char *q; | |
609 | static char *pv[MAXPV+1]; | |
610 | char **pvp; | |
611 | char **mvp; | |
612 | static char buf[512]; | |
613 | register char *bp; | |
614 | char pbuf[30]; | |
615 | ||
616 | /* | |
617 | ** Do initial argv setup. | |
618 | ** Insert the mailer name. Notice that $x expansion is | |
619 | ** NOT done on the mailer name. Then, if the mailer has | |
620 | ** a picky -f flag, we insert it as appropriate. This | |
621 | ** code does not check for 'pv' overflow; this places a | |
622 | ** manifest lower limit of 4 for MAXPV. | |
623 | */ | |
624 | ||
625 | pvp = pv; | |
626 | bp = buf; | |
627 | ||
628 | *pvp++ = tmplt[0]; | |
629 | ||
630 | /* insert -f or -r flag as appropriate */ | |
631 | if (flagset(M_FOPT|M_ROPT, flags) && FromFlag) | |
632 | { | |
633 | if (flagset(M_FOPT, flags)) | |
634 | *pvp++ = "-f"; | |
635 | else | |
636 | *pvp++ = "-r"; | |
637 | *pvp++ = From.q_paddr; | |
638 | } | |
639 | ||
640 | /* | |
641 | ** Build the rest of argv. | |
642 | ** For each prototype parameter, the prototype is | |
643 | ** scanned character at a time. If a dollar-sign is | |
644 | ** found, 'q' is set to the appropriate expansion, | |
645 | ** otherwise it is null. Then either the string | |
646 | ** pointed to by q, or the original character, is | |
647 | ** interpolated into the buffer. Buffer overflow is | |
648 | ** checked. | |
649 | */ | |
650 | ||
651 | for (mvp = tmplt; (p = *++mvp) != NULL; ) | |
652 | { | |
653 | if (pvp >= &pv[MAXPV]) | |
654 | { | |
655 | syserr("Too many parameters to %s", pv[0]); | |
656 | return (NULL); | |
657 | } | |
658 | *pvp++ = bp; | |
659 | for (; *p != '\0'; p++) | |
660 | { | |
661 | /* q will be the interpolated quantity */ | |
662 | q = NULL; | |
663 | if (*p == '$') | |
664 | { | |
665 | switch (*++p) | |
666 | { | |
667 | case 'f': /* from person */ | |
668 | q = from; | |
669 | break; | |
670 | ||
671 | case 'u': /* user */ | |
672 | q = user; | |
673 | break; | |
674 | ||
675 | case 'h': /* host */ | |
676 | q = host; | |
677 | break; | |
678 | ||
679 | case 'c': /* hop count */ | |
680 | sprintf(pbuf, "%d", HopCount); | |
681 | q = pbuf; | |
682 | break; | |
683 | } | |
684 | } | |
685 | ||
686 | /* | |
687 | ** Interpolate q or output one character | |
688 | ** Strip quote bits as we proceed..... | |
689 | */ | |
690 | ||
691 | if (q != NULL) | |
692 | { | |
693 | while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') | |
694 | continue; | |
695 | bp--; | |
b3cbe40f EA |
696 | } |
697 | else if (bp < &buf[sizeof buf - 1]) | |
698 | *bp++ = *p; | |
699 | } | |
700 | *bp++ = '\0'; | |
701 | if (bp >= &buf[sizeof buf - 1]) | |
702 | return (NULL); | |
703 | } | |
704 | *pvp = NULL; | |
705 | ||
706 | # ifdef DEBUG | |
707 | if (Debug) | |
708 | { | |
709 | printf("Interpolated argv is:\n"); | |
710 | for (mvp = pv; *mvp != NULL; mvp++) | |
711 | printf("\t%s\n", *mvp); | |
712 | } | |
713 | # endif DEBUG | |
714 | ||
715 | return (pv); | |
716 | } | |
717 | \f/* | |
718 | ** MAILFILE -- Send a message to a file. | |
719 | ** | |
720 | ** Parameters: | |
721 | ** filename -- the name of the file to send to. | |
722 | ** | |
723 | ** Returns: | |
724 | ** The exit code associated with the operation. | |
725 | ** | |
726 | ** Side Effects: | |
727 | ** none. | |
728 | ** | |
b3cbe40f EA |
729 | ** Called By: |
730 | ** deliver | |
b3cbe40f EA |
731 | */ |
732 | ||
733 | mailfile(filename) | |
734 | char *filename; | |
735 | { | |
736 | char buf[MAXLINE]; | |
737 | register FILE *f; | |
738 | auto long tim; | |
739 | extern char *ctime(); | |
740 | ||
741 | f = fopen(filename, "a"); | |
742 | if (f == NULL) | |
743 | return (EX_CANTCREAT); | |
744 | ||
745 | /* output the timestamp */ | |
746 | time(&tim); | |
747 | fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); | |
748 | rewind(stdin); | |
749 | while (fgets(buf, sizeof buf, stdin) != NULL) | |
750 | { | |
751 | fputs(buf, f); | |
752 | if (ferror(f)) | |
753 | { | |
754 | fclose(f); | |
755 | return (EX_IOERR); | |
756 | } | |
757 | } | |
758 | fputs("\n", f); | |
759 | fclose(f); | |
760 | return (EX_OK); | |
761 | } |