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