]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/slocal.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / docs / historical / mh-6.8.5 / uip / slocal.c
1 /* slocal.c - MH style mailer to write to a local user's mailbox */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: slocal.c,v 1.25 1995/12/07 00:01:25 jromine Exp shettich $";
4 #endif /* lint */
5
6 /* This program implements mail delivery in the MH/MMDF style.
7
8 Under SendMail, users should add the line
9
10 "| /usr/local/lib/mh/slocal"
11
12 to their $HOME/.forward file.
13
14 Under MMDF-I, users should (symbolically) link /usr/local/lib/mh/slocal
15 to $HOME/bin/rcvmail.
16
17 Under stand-alone MH, post will automatically run this during local
18 delivery.
19
20 This program should be used ONLY if you have "mts sendmail" or "mts mh"
21 or "mts mmdf1" set in your MH configuration.
22 */
23
24 /* \f */
25
26 #include "../h/mh.h"
27 #include "../h/dropsbr.h"
28 #include "../h/rcvmail.h"
29 #include "../zotnet/tws.h"
30 #include "../zotnet/mts.h"
31 #include <pwd.h>
32 #include <signal.h>
33 #ifndef V7
34 #ifndef NOIOCTLH
35 #include <sys/ioctl.h>
36 #endif /* NOIOCTLH */
37 #endif /* not V7 */
38 #include <sys/stat.h>
39 #include <utmp.h>
40 #ifdef LOCALE
41 #include <locale.h>
42 #endif
43
44
45 #ifdef MSGID
46
47 #undef DBM /* used by ndbm.h */
48 #include <ndbm.h>
49 #include <stdio.h>
50 #include <sys/types.h>
51 #include <sys/file.h>
52 #ifdef SYS5
53 #include <fcntl.h>
54 #endif
55 #ifdef UNISTD
56 #include <unistd.h>
57 #endif
58 #if defined(LOCKF) && !defined(F_ULOCK)
59 #include <sys/fcntl.h>
60 #endif /* LOCKF */
61
62 #endif
63
64
65 #define NVEC 100
66
67 /* \f */
68
69 static struct swit switches[] = {
70 #define ADDRSW 0
71 "addr address", 0,
72 #define USERSW 1
73 "user name", 0,
74 #define FILESW 2
75 "file file", 0,
76 #define SENDSW 3
77 "sender address", 0,
78 #define MBOXSW 4
79 "mailbox file", 0,
80 #define HOMESW 5
81 "home directory", -4,
82 #define INFOSW 6
83 "info data", 0,
84
85 #define MAILSW 7
86 "maildelivery file", 0,
87
88 #define VERBSW 8
89 "verbose", 0,
90 #define NVERBSW 9
91 "noverbose", 0,
92
93 #define DEBUGSW 10
94 "debug", 0,
95
96 #define HELPSW 11
97 "help", 4,
98
99 NULL, 0
100 };
101
102 /* \f */
103
104 static int debug = 0;
105 static int globbed = 0;
106 static int parsed = 0;
107 static int utmped = 0;
108 static int verbose = 0;
109
110 static char *addr = NULLCP;
111 static char *user = NULLCP;
112 static char *info = NULLCP;
113 static char *file = NULLCP;
114 static char *sender = NULLCP;
115 static char *unixfrom = NULLCP;
116 static char *mbox = NULLCP;
117 static char *home = NULLCP;
118
119
120 static struct passwd *pw;
121
122
123 static char ddate[BUFSIZ];
124
125 struct tws *now;
126
127
128 static jmp_buf myctx;
129
130 /* \f */
131
132 struct pair {
133 char *p_name;
134 char *p_value;
135
136 char p_flags;
137 #define P_NIL 0x00
138 #define P_ADR 0x01
139 #define P_HID 0x02
140 #define P_CHK 0x04
141 };
142
143 static struct pair *lookup ();
144
145
146 static struct pair hdrs[NVEC + 1] = {
147 "source", NULL, P_HID,
148 "addr", NULL, P_HID,
149
150 "Return-Path", NULL, P_ADR,
151 "Reply-To", NULL, P_ADR,
152 "From", NULL, P_ADR,
153 "Sender", NULL, P_ADR,
154 "To", NULL, P_ADR,
155 "cc", NULL, P_ADR,
156 "Resent-Reply-To", NULL, P_ADR,
157 "Resent-From", NULL, P_ADR,
158 "Resent-Sender", NULL, P_ADR,
159 "Resent-To", NULL, P_ADR,
160 "Resent-cc", NULL, P_ADR,
161
162 NULL
163 };
164
165
166 static struct pair vars[] = {
167 "sender", NULL, P_NIL,
168 "address", NULL, P_NIL,
169 "size", NULL, P_NIL,
170 "reply-to", NULL, P_CHK,
171 "info", NULL, P_NIL,
172
173 NULL
174 };
175
176 /* \f */
177
178 extern char **environ;
179
180 static void adorn ();
181 static TYPESIG alrmser ();
182
183
184 off_t lseek ();
185 #ifndef __STDC__
186 #ifdef SYS5
187 struct passwd *getpwnam ();
188 #endif /* SYS5 */
189 #endif
190 static int localmail(), usr_delivery(), split(), parse(), logged_in();
191 static int timely(), usr_file(), usr_pipe(), copyfile();
192 static expand(), glob(), copyinfo();
193
194 /* \f */
195
196 /* ARGSUSED */
197
198 main (argc, argv, envp)
199 int argc;
200 char **argv,
201 **envp;
202 {
203 int fd;
204 FILE *fp = stdin;
205 char *cp,
206 *mdlvr = NULL,
207 buf[100],
208 from[BUFSIZ],
209 mailbox[BUFSIZ],
210 tmpfil[BUFSIZ],
211 **argp = argv + 1;
212
213 #ifdef LOCALE
214 setlocale(LC_ALL, "");
215 #endif
216 invo_name = r1bindex (*argv, '/');
217 m_foil (NULLCP);
218 mts_init (invo_name);
219
220 /* \f */
221
222 while (cp = *argp++) {
223 if (*cp == '-')
224 switch (smatch (++cp, switches)) {
225 case AMBIGSW:
226 ambigsw (cp, switches);
227 done (1);
228 case UNKWNSW:
229 adios (NULLCP, "-%s unknown", cp);
230 case HELPSW:
231 (void) sprintf (buf, "%s [switches] [address info sender]",
232 invo_name);
233 help (buf, switches);
234 done (1);
235
236 case ADDRSW:
237 if (!(addr = *argp++))/* allow -xyz arguments */
238 adios (NULLCP, "missing argument to %s", argp[-2]);
239 continue;
240 case INFOSW:
241 if (!(info = *argp++))/* allow -xyz arguments */
242 adios (NULLCP, "missing argument to %s", argp[-2]);
243 continue;
244 case USERSW:
245 if (!(user = *argp++))/* allow -xyz arguments */
246 adios (NULLCP, "missing argument to %s", argp[-2]);
247 continue;
248 case FILESW:
249 if (!(file = *argp++) || *file == '-')
250 adios (NULLCP, "missing argument to %s", argp[-2]);
251 continue;
252 case SENDSW:
253 if (!(sender = *argp++))/* allow -xyz arguments */
254 adios (NULLCP, "missing argument to %s", argp[-2]);
255 continue;
256 case MBOXSW:
257 if (!(mbox = *argp++) || *mbox == '-')
258 adios (NULLCP, "missing argument to %s", argp[-2]);
259 continue;
260 case HOMESW:
261 if (!(home = *argp++) || *home == '-')
262 adios (NULLCP, "missing argument to %s", argp[-2]);
263 continue;
264
265 case MAILSW:
266 if (!(cp = *argp++) || *cp == '-')
267 adios (NULLCP, "missing argument to %s", argp[-2]);
268 if (mdlvr)
269 adios (NULLCP, "only one maildelivery file at a time!");
270 mdlvr = cp;
271 continue;
272
273 case VERBSW:
274 verbose++;
275 continue;
276 case NVERBSW:
277 verbose = 0;
278 continue;
279
280 case DEBUGSW:
281 debug++;
282 continue;
283 }
284
285 switch (argp - (argv + 1)) {
286 case 1:
287 addr = cp;
288 break;
289
290 case 2:
291 info = cp;
292 break;
293
294 case 3:
295 sender = cp;
296 break;
297 }
298 }
299
300 /* \f */
301
302 if (addr == NULL)
303 addr = getusr ();
304 if (user == NULL)
305 user = (cp = index (addr, '.')) ? ++cp : addr;
306 if ((pw = getpwnam (user)) == NULL)
307 adios (NULLCP, "no such local user as %s", user);
308
309 if (chdir (pw -> pw_dir) == NOTOK)
310 (void) chdir ("/");
311 (void) umask (0077);
312
313 if (geteuid () == 0) {
314 #ifdef BSD41A
315 (void) inigrp (pw -> pw_name, pw -> pw_gid);
316 #endif /* BSD41A */
317 (void) setgid (pw -> pw_gid);
318 #ifdef BSD42
319 (void) initgroups (pw -> pw_name, pw -> pw_gid);
320 #endif /* BSD42 */
321 (void) setuid (pw -> pw_uid);
322 }
323
324 if (info == NULL)
325 info = "";
326
327 setbuf (stdin, NULLCP);
328
329 if (file == NULL) {
330 if ((fd = copyfile (fileno (stdin), file = tmpfil, 1)) == NOTOK)
331 adios (NULLCP, "unable to create temporary file");
332 if (debug)
333 fprintf (stderr, "temporary file \"%s\" selected\n", tmpfil);
334 else
335 (void) unlink (tmpfil);
336 if ((fp = fdopen (fd, "r+")) == NULL)
337 adios (NULLCP, "unable to access temporary file");
338 }
339 else
340 fd = fileno (stdin);
341
342 from[0] = 0;
343 if (sender == NULL)
344 copyinfo (fp, from);
345
346
347 if (mbox == NULL) {
348 (void) sprintf (mailbox, "%s/%s",
349 mmdfldir[0] ? mmdfldir : pw -> pw_dir,
350 mmdflfil[0] ? mmdflfil : pw -> pw_name);
351 mbox = mailbox;
352 }
353 if (home == NULL)
354 home = pw -> pw_dir;
355
356 if ((now = dtwstime ()) == NULL)
357 adios (NULLCP, "unable to ascertain local time");
358 (void) sprintf (ddate, "Delivery-Date: %s\n", dtimenow ());
359
360 if (debug) {
361 fprintf (stderr, "addr=\"%s\" user=\"%s\" info=\"%s\" file=\"%s\"\n",
362 addr, user, info, file);
363 fprintf (stderr, "sender=\"%s\" mbox=\"%s\" home=\"%s\" from=\"%s\"\n",
364 sender ? sender : "", mbox, home, from);
365 fprintf (stderr, "ddate=\"%s\" now=%02d:%02d\n",
366 ddate, now -> tw_hour, now -> tw_min);
367 }
368
369 done (localmail (fd, from, mdlvr) != NOTOK ? RCV_MOK : RCV_MBX);
370 }
371
372 /* \f */
373
374 static int localmail (fd, from, mdlvr)
375 int fd;
376 char *from,
377 *mdlvr;
378 {
379 #ifdef MSGID
380 struct stat st;
381
382 if (stat (".maildelivery.pag", &st) != NOTOK
383 && check_msgid (fd, ".maildelivery") == DONE)
384 return OK;
385 #endif
386
387 if (usr_delivery (fd, mdlvr ? mdlvr : ".maildelivery", 0, from) != NOTOK)
388 return OK;
389
390 if (usr_delivery (fd, maildelivery, 1, from) != NOTOK)
391 return OK;
392
393 #ifdef notdef
394 if (verbose)
395 printf ("(invoking hook)\n");
396 if (usr_hook (fd, mbox) != NOTOK)
397 return OK;
398 #endif /* notdef */
399
400 if (verbose)
401 printf ("(trying normal delivery)\n");
402 return usr_file (fd, mbox, from);
403 }
404
405 /* \f */
406
407 #define matches(a,b) (stringdex (b, a) >= 0)
408
409 static int usr_delivery (fd, delivery, su, from)
410 int fd,
411 su;
412 char *delivery,
413 *from;
414 {
415 int i,
416 accept,
417 status,
418 won,
419 vecp,
420 next;
421 register char *cp,
422 *action,
423 *field,
424 *pattern,
425 *string;
426 char buffer[BUFSIZ],
427 tmpbuf[BUFSIZ],
428 *vec[NVEC];
429 struct stat st;
430 register struct pair *p;
431 register FILE *fp;
432
433 if ((fp = fopen (delivery, "r")) == NULL)
434 return NOTOK;
435 if (fstat (fileno (fp), &st) == NOTOK
436 || (st.st_uid != 0 && (su || st.st_uid != pw -> pw_uid))
437 || st.st_mode & 0022) {
438 if (verbose) {
439 printf ("%s: ownership/modes bad (%d, %d,%d,0%o)\n",
440 delivery, su, pw -> pw_uid, st.st_uid, st.st_mode);
441 (void) fflush (stdout);
442 }
443 return NOTOK;
444 }
445
446 won = 0;
447 next = 1;
448 while (fgets (buffer, sizeof buffer, fp) != NULL) {
449 if (*buffer == '#')
450 continue;
451 if (cp = index (buffer, '\n'))
452 *cp = 0;
453 if ((vecp = split (buffer, vec)) < 5)
454 continue;
455 if (debug)
456 for (i = 0; vec[i]; i++)
457 fprintf (stderr, "vec[%d]: \"%s\"\n", i, vec[i]);
458
459 field = vec[0];
460 pattern = vec[1];
461 action = vec[2];
462
463 switch (vec[3][0]) {
464 case 'N':
465 case 'n':
466 if (! next)
467 continue; /* if previous condition failed, don't
468 do this - else fall through */
469
470 case '?':
471 if (won)
472 continue; /* else fall */
473 case 'A':
474 case 'a':
475 accept = 1;
476 break;
477
478 case 'R':
479 case 'r':
480 default:
481 accept = 0;
482 break;
483 }
484
485 string = vec[4];
486
487 if (vecp > 5) {
488 if (uleq (vec[5], "select")) {
489 if (logged_in () != NOTOK)
490 continue;
491 if (vecp > 7 && timely (vec[6], vec[7]) == NOTOK)
492 continue;
493 }
494 }
495
496 switch (*field) {
497 case '*':
498 break;
499
500 case 'd':
501 if (uleq (field, "default")) {
502 if (won)
503 continue;
504 break;
505 } /* else fall */
506
507 default:
508 if (!parsed && parse (fd) == NOTOK) {
509 (void) fclose (fp);
510 return NOTOK;
511 }
512 if ((p = lookup (hdrs, field)) == NULL
513 || (p->p_value == NULL) /* XXX */
514 || !matches (p -> p_value, pattern)) {
515 next = 0;
516 continue;
517 }
518 else
519 next = 1;
520 break;
521 }
522
523 switch (*action) {
524 case 'q':
525 if (!uleq (action, "qpipe"))
526 continue; /* else fall */
527 case '^':
528 expand (tmpbuf, string, fd);
529 if (split (tmpbuf, vec) < 1)
530 continue;
531 status = usr_pipe (fd, tmpbuf, vec[0], vec);
532 break;
533
534 case 'p':
535 if (!uleq (action, "pipe"))
536 continue; /* else fall */
537 case '|':
538 vec[2] = "sh";
539 vec[3] = "-c";
540 expand (tmpbuf, string, fd);
541 vec[4] = tmpbuf;
542 vec[5] = NULL;
543 status = usr_pipe (fd, tmpbuf, "/bin/sh", vec + 2);
544 break;
545
546 case 'f':
547 if (!uleq (action, "file"))
548 continue; /* else fall */
549 case '>':
550 #ifdef RPATHS
551 status = usr_file (fd, string, from); /* UUCP format? */
552 #else
553 status = usr_file (fd, string, NULLCP);
554 #endif
555 break;
556
557 case 'm':
558 if (!uleq (action, "mbox"))
559 continue;
560 status = usr_file (fd, string, NULLCP);
561 break;
562
563 case 'd':
564 if (!uleq (action, "destroy"))
565 continue;
566 status = OK;
567 break;
568 }
569
570 if (accept && status == OK)
571 won++;
572 }
573
574 (void) fclose (fp);
575 return (won ? OK : NOTOK);
576 }
577
578 /* \f */
579
580 #define QUOTE '\\'
581
582 static int split (cp, vec)
583 char *cp,
584 **vec;
585 {
586 register int i;
587 register char *s;
588
589 for (i = 0, s = cp; i <= NVEC;) {
590 vec[i] = NULL;
591 while (isspace (*s) || *s == ',')
592 *s++ = 0;
593 if (*s == 0)
594 break;
595
596 if (*s == '"') {
597 for (vec[i++] = ++s; *s != 0 && *s != '"'; s++)
598 if (*s == QUOTE) {
599 if (*++s == '"')
600 (void) strcpy (s - 1, s);
601 s--;
602 }
603 if (*s == '"')
604 *s++ = 0;
605 continue;
606 }
607 if (*s == QUOTE && *++s != '"')
608 s--;
609 vec[i++] = s++;
610
611 while (*s != 0 && !isspace (*s) && *s != ',')
612 s++;
613 }
614 vec[i] = NULL;
615
616 return i;
617 }
618
619 /* \f */
620
621 static int parse (fd)
622 register int fd;
623 {
624 register int i,
625 state;
626 int fd1;
627 register char *cp,
628 *dp,
629 *lp;
630 char name[NAMESZ],
631 field[BUFSIZ];
632 register struct pair *p,
633 *q;
634 register FILE *in;
635
636 if (parsed++)
637 return OK;
638
639 if ((fd1 = dup (fd)) == NOTOK)
640 return NOTOK;
641 if ((in = fdopen (fd1, "r")) == NULL) {
642 (void) close (fd1);
643 return NOTOK;
644 }
645 rewind (in);
646
647 if (p = lookup (hdrs, "source"))
648 p -> p_value = getcpy (sender);
649 if (p = lookup (hdrs, "addr"))
650 p -> p_value = getcpy (addr);
651
652 for (i = 0, state = FLD;;) {
653 switch (state = m_getfld (state, name, field, sizeof field, in)) {
654 case FLD:
655 case FLDEOF:
656 case FLDPLUS:
657 lp = add (field, NULLCP);
658 while (state == FLDPLUS) {
659 state = m_getfld (state, name, field, sizeof field, in);
660 lp = add (field, lp);
661 }
662 for (p = hdrs; p -> p_name; p++)
663 if (uleq (p -> p_name, name)) {
664 if (!(p -> p_flags & P_HID)) {
665 if (cp = p -> p_value)
666 if (p -> p_flags & P_ADR) {
667 dp = cp + strlen (cp) - 1;
668 if (*dp == '\n')
669 *dp = 0;
670 cp = add (",\n\t", cp);
671 }
672 else
673 cp = add ("\t", cp);
674 p -> p_value = add (lp, cp);
675 }
676 free (lp);
677 break;
678 }
679 if (p -> p_name == NULL && i < NVEC) {
680 p -> p_name = getcpy (name);
681 p -> p_value = lp;
682 p -> p_flags = P_NIL;
683 p++, i++;
684 p -> p_name = NULL;
685 }
686 if (state != FLDEOF)
687 continue;
688 break;
689
690 case BODY:
691 case BODYEOF:
692 case FILEEOF:
693 break;
694
695 case LENERR:
696 case FMTERR:
697 advise (NULLCP, "format error in message");
698 break;
699
700 default:
701 advise (NULLCP, "internal error");
702 (void) fclose (in);
703 return NOTOK;
704 }
705 break;
706 }
707 (void) fclose (in);
708
709 if (p = lookup (vars, "reply-to")) {
710 if ((q = lookup (hdrs, "reply-to")) == NULL || q -> p_value == NULL)
711 q = lookup (hdrs, "from");
712 p -> p_value = getcpy (q ? q -> p_value : "");
713 p -> p_flags &= ~P_CHK;
714 if (debug)
715 fprintf (stderr, "vars[%d]: name=\"%s\" value=\"%s\"\n",
716 p - vars, p -> p_name, p -> p_value);
717 }
718 #define empty(s) ((s) ? (s) : "")
719 if (debug)
720 for (p = hdrs; p -> p_name; p++)
721 fprintf (stderr, "hdrs[%d]: name=\"%s\" value=\"%s\"\n",
722 p - hdrs, p -> p_name, empty(p -> p_value));
723 #undef empty
724
725 return OK;
726 }
727
728 /* \f */
729
730 #define LPAREN '('
731 #define RPAREN ')'
732
733 static expand (s1, s2, fd)
734 register char *s1,
735 *s2;
736 int fd;
737 {
738 register char c,
739 *cp;
740 register struct pair *p;
741
742 if (!globbed)
743 glob (fd);
744
745 while (c = *s2++)
746 if (c != '$' || *s2 != LPAREN)
747 *s1++ = c;
748 else {
749 for (cp = ++s2; *s2 && *s2 != RPAREN; s2++)
750 continue;
751 if (*s2 != RPAREN) {
752 s2 = --cp;
753 continue;
754 }
755 *s2++ = 0;
756 if (p = lookup (vars, cp)) {
757 if (!parsed && (p -> p_flags & P_CHK))
758 (void) parse (fd);
759
760 (void) strcpy (s1, p -> p_value);
761 s1 += strlen (s1);
762 }
763 }
764 *s1 = 0;
765 }
766
767 /* \f */
768
769 static glob (fd)
770 register int fd;
771 {
772 char buffer[BUFSIZ];
773 struct stat st;
774 register struct pair *p;
775
776 if (globbed++)
777 return;
778
779 if (p = lookup (vars, "sender"))
780 p -> p_value = getcpy (sender);
781 if (p = lookup (vars, "address"))
782 p -> p_value = getcpy (addr);
783 if (p = lookup (vars, "size")) {
784 (void) sprintf (buffer, "%d",
785 fstat (fd, &st) != NOTOK ? (int) st.st_size : 0);
786 p -> p_value = getcpy (buffer);
787 }
788 if (p = lookup (vars, "info"))
789 p -> p_value = getcpy (info);
790
791 if (debug)
792 for (p = vars; p -> p_name; p++)
793 fprintf (stderr, "vars[%d]: name=\"%s\" value=\"%s\"\n",
794 p - vars, p -> p_name, p -> p_value);
795 }
796
797 /* \f */
798
799 static struct pair *lookup (pairs, key)
800 register struct pair *pairs;
801 register char *key;
802 {
803 register char *cp;
804
805 for (; cp = pairs -> p_name; pairs++)
806 if (uleq (cp, key))
807 return pairs;
808
809 return NULL;
810 }
811
812 /* \f */
813
814 static int logged_in () {
815 struct utmp ut;
816 register FILE *uf;
817
818 if (utmped)
819 return utmped;
820
821 if ((uf = fopen ("/etc/utmp", "r")) == NULL)
822 return NOTOK;
823
824 while (fread ((char *) &ut, sizeof ut, 1, uf) == 1)
825 if (ut.ut_name[0] != 0
826 && strncmp (user, ut.ut_name, sizeof ut.ut_name) == 0) {
827 if (debug)
828 continue;
829 (void) fclose (uf);
830 return (utmped = DONE);
831 }
832
833 (void) fclose (uf);
834 return (utmped = NOTOK);
835 }
836
837
838 static int timely (t1, t2)
839 char *t1,
840 *t2;
841 {
842 #define check(t,a,b) if (t < a || t > b) return NOTOK
843 #define cmpar(h1,m1,h2,m2) if (h1 < h2 || (h1 == h2 && m1 < m2)) return OK
844
845 int t1hours,
846 t1mins,
847 t2hours,
848 t2mins;
849
850 if (sscanf (t1, "%d:%d", &t1hours, &t1mins) != 2)
851 return NOTOK;
852 check (t1hours, 0, 23);
853 check (t1mins, 0, 59);
854
855 if (sscanf (t2, "%d:%d", &t2hours, &t2mins) != 2)
856 return NOTOK;
857 check (t2hours, 0, 23);
858 check (t2mins, 0, 59);
859
860 cmpar (now -> tw_hour, now -> tw_min, t1hours, t1mins);
861 cmpar (t2hours, t2mins, now -> tw_hour, now -> tw_min);
862
863 return NOTOK;
864 }
865
866 /* \f */
867
868 static int usr_file (fd, mailbox, from)
869 int fd;
870 char *mailbox,
871 *from;
872 {
873 int md,
874 mapping;
875 register char *bp;
876 char buffer[BUFSIZ];
877
878 if (verbose)
879 printf ("\tdelivering to file \"%s\"", mailbox);
880 if (from && *from) {
881 (void) mbx_uucp ();
882 if (verbose)
883 printf (" (uucp style)");
884 (void) sprintf (buffer, "%s%s", from, ddate);
885 bp = buffer;
886 mapping = 0;
887 }
888 else {
889 bp = ddate;
890 mapping = 1;
891 }
892 if (verbose)
893 (void) fflush (stdout);
894
895 if ((md = mbx_open (mailbox, pw -> pw_uid, pw -> pw_gid, m_gmprot ()))
896 == NOTOK) {
897 adorn ("", "unable to open:");
898 return NOTOK;
899 }
900
901 (void) lseek (fd, (off_t)0, 0);
902 if (mbx_copy (mailbox, md, fd, mapping, bp, verbose) == NOTOK) {
903 adorn ("", "error writing to:");
904 return NOTOK;
905 }
906
907 (void) mbx_close (mailbox, md);
908 if (verbose) {
909 printf (", done.\n");
910 (void) fflush (stdout);
911 }
912 return OK;
913 }
914
915 /* \f */
916
917 #ifdef notdef
918 static int usr_hook (fd, mailbox)
919 int fd;
920 char *mailbox;
921 {
922 int i,
923 vecp;
924 char receive[BUFSIZ],
925 tmpfil[BUFSIZ],
926 *vec[NVEC];
927
928 if ((fd = copyfile (fd, tmpfil, 0)) == NOTOK) {
929 if (verbose)
930 adorn ("unable to copy message; skipping hook\n");
931 return NOTOK;
932 }
933 (void) chown (tmpfil, pw -> pw_uid, pw -> pw_gid);
934
935 vecp = 1;
936 (void) sprintf (receive, "%s/.mh_receive", pw -> pw_dir);
937 switch (access (receive, 01)) {
938 case NOTOK:
939 (void) sprintf (receive, "%s/bin/rcvmail", pw -> pw_dir);
940 if (access (receive, 01) == NOTOK) {
941 (void) unlink (tmpfil);
942 if (verbose) {
943 printf ("\tnot present\n");
944 (void) fflush (stdout);
945 }
946 return NOTOK;
947 }
948 vec[vecp++] = addr;
949 vec[vecp++] = tmpfil;
950 vec[vecp++] = sender;
951 break;
952
953 default:
954 vec[vecp++] = tmpfil;
955 vec[vecp++] = mailbox;
956 vec[vecp++] = home;
957 vec[vecp++] = addr;
958 vec[vecp++] = sender;
959 break;
960 }
961 vec[0] = r1bindex (receive, '/');
962 vec[vecp] = NULL;
963
964 i = usr_pipe (fd, "rcvmail", receive, vec);
965 (void) unlink (tmpfil);
966
967 return i;
968 }
969 #endif /* notdef */
970
971 /* \f */
972
973 static int usr_pipe (fd, cmd, pgm, vec)
974 int fd;
975 char *cmd,
976 *pgm,
977 **vec;
978 {
979 int bytes,
980 i,
981 child_id,
982 status;
983 struct stat st;
984
985 if (verbose) {
986 printf ("\tdelivering to pipe \"%s\"", cmd);
987 (void) fflush (stdout);
988 }
989 (void) lseek (fd, (off_t)0, 0);
990
991 for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
992 sleep (5);
993 switch (child_id) {
994 case NOTOK:
995 adorn ("fork", "unable to");
996 return NOTOK;
997
998 case OK:
999 if (fd != 0)
1000 (void) dup2 (fd, 0);
1001 (void) freopen ("/dev/null", "w", stdout);
1002 (void) freopen ("/dev/null", "w", stderr);
1003 if (fd != 3)
1004 (void) dup2 (fd, 3);
1005 closefds (4);
1006 #ifdef TIOCNOTTY
1007 if ((fd = open ("/dev/tty", 2)) != NOTOK) {
1008 (void) ioctl (fd, TIOCNOTTY, NULLCP);
1009 (void) close (fd);
1010 }
1011 #endif /* TIOCNOTTY */
1012 #ifdef BSD42
1013 (void) setpgrp (0, getpid ());
1014 #endif /* BSD42 */
1015
1016 *environ = NULL;
1017 (void) m_putenv ("USER", pw -> pw_name);
1018 (void) m_putenv ("HOME", pw -> pw_dir);
1019 (void) m_putenv ("SHELL", pw -> pw_shell);
1020
1021 execvp (pgm, vec);
1022 _exit (-1);
1023
1024 default:
1025 switch (setjmp (myctx)) {
1026 case OK:
1027 (void) signal (SIGALRM, alrmser);
1028 bytes = fstat (fd, &st) != NOTOK ? (int) st.st_size : 100;
1029 if (bytes <= 0)
1030 bytes = 100;
1031 (void) alarm ((unsigned) (bytes * 60 + 300));
1032
1033 status = pidwait (child_id, OK);
1034
1035 (void) alarm (0);
1036 #ifdef MMDFI
1037 if (status == RP_MOK || status == RP_OK)
1038 status = 0;
1039 #endif /* MMDFI */
1040 if (verbose) {
1041 if (status == 0)
1042 printf (", wins.\n");
1043 else
1044 if ((status & 0xff00) == 0xff00)
1045 printf (", system error\n");
1046 else
1047 (void) pidstatus (status, stdout, ", loses");
1048 (void) fflush (stdout);
1049 }
1050 return (status == 0 ? OK : NOTOK);
1051
1052 default:
1053 #ifndef BSD42
1054 (void) kill (child_id, SIGKILL);
1055 #else /* BSD42 */
1056 (void) killpg (child_id, SIGKILL);
1057 #endif /* BSD42 */
1058 if (verbose) {
1059 printf (", timed-out; terminated\n");
1060 (void) fflush (stdout);
1061 }
1062 return NOTOK;
1063 }
1064 }
1065 }
1066
1067 /* \f */
1068
1069 /* ARGSUSED */
1070
1071 static TYPESIG alrmser (i)
1072 int i;
1073 {
1074 longjmp (myctx, DONE);
1075 }
1076
1077 /* \f */
1078
1079 static copyinfo (fp, from)
1080 register FILE *fp;
1081 char *from;
1082 {
1083 int i;
1084 register char *cp;
1085 static char buffer[BUFSIZ];
1086
1087 if (unixfrom) /* interface from copyfile */
1088 strcpy (from, unixfrom);
1089 else if (fgets (from, BUFSIZ, fp) == NULL)
1090 adios (NULLCP, "no message");
1091
1092 if (strncmp (from, "From ", i = strlen ("From "))) {
1093 rewind (fp);
1094 *from = 0;
1095 return;
1096 }
1097
1098 (void) strcpy (buffer, from + i);
1099 if (cp = index (buffer, '\n')) {
1100 *cp = 0;
1101 cp -= 24;
1102 if (cp < buffer)
1103 cp = buffer;
1104 }
1105 else
1106 cp = buffer;
1107 *cp = 0;
1108
1109 for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--)
1110 if (isspace (*cp))
1111 *cp = 0;
1112 else
1113 break;
1114 sender = buffer;
1115 rewind (fp);
1116 }
1117
1118 /* \f */
1119
1120 static int copyfile (qd, tmpfil, fold)
1121 int qd,
1122 fold;
1123 register char *tmpfil;
1124 {
1125 register int i,
1126 first = 0,
1127 fd1,
1128 fd2;
1129 char buffer[BUFSIZ];
1130 register FILE *qfp,
1131 *ffp;
1132
1133 (void) strcpy (tmpfil, m_tmpfil (invo_name));
1134 if ((fd1 = creat (tmpfil, 0600)) == NOTOK)
1135 return NOTOK;
1136 (void) close (fd1);
1137 if ((fd1 = open (tmpfil, 2)) == NOTOK)
1138 return NOTOK;
1139
1140 if (!fold) {
1141 while ((i = read (qd, buffer, sizeof buffer)) > 0)
1142 if (write (fd1, buffer, i) != i) {
1143 you_lose: ;
1144 (void) close (fd1);
1145 (void) unlink (tmpfil);
1146 return NOTOK;
1147 }
1148 if (i == NOTOK)
1149 goto you_lose;
1150 (void) lseek (fd1, (off_t)0, 0);
1151 return fd1;
1152 }
1153
1154 if ((fd2 = dup (qd)) == NOTOK) {
1155 (void) close (fd1);
1156 return NOTOK;
1157 }
1158 if ((qfp = fdopen (fd2, "r")) == NULL) {
1159 (void) close (fd1);
1160 (void) close (fd2);
1161 return NOTOK;
1162 }
1163
1164 if ((fd2 = dup (fd1)) == NOTOK) {
1165 (void) close (fd1);
1166 (void) fclose (qfp);
1167 return NOTOK;
1168 }
1169 if ((ffp = fdopen (fd2, "r+")) == NULL) {
1170 (void) close (fd1);
1171 (void) close (fd2);
1172 (void) fclose (qfp);
1173 return NOTOK;
1174 }
1175
1176 i = strlen ("From ");
1177 while (fgets (buffer, sizeof buffer, qfp)) {
1178 if (!strncmp (buffer, "From ", i))
1179 if (first == 0) {
1180 #ifdef RPATHS
1181 register char *fp, *cp, *hp, *ep;
1182 #endif
1183 unixfrom = getcpy (buffer); /* save for later */
1184 #ifndef RPATHS
1185 continue; /* but don't put in file */
1186 #else
1187 hp = cp = index (fp = unixfrom + i, ' ');
1188 while (hp = index (++hp, 'r'))
1189 if (uprf (hp, "remote from")) {
1190 hp = rindex (hp, ' ');
1191 break;
1192 }
1193 if (hp) {
1194 ep = rindex (++hp, '\n');
1195 sprintf (buffer, "Return-Path: %.*s!%.*s\n",
1196 ep - hp, hp,
1197 cp - fp, fp);
1198 }
1199 else
1200 sprintf (buffer, "Return-Path: %.*s\n",
1201 cp - fp, fp);
1202 #endif
1203 }
1204 #ifdef notdef /* mbx_copy does this */
1205 else
1206 putc ('>', ffp);
1207 #endif /* notdef */
1208 first++;
1209 fputs (buffer, ffp);
1210 if (ferror (ffp)) {
1211 (void) close (fd1);
1212 (void) fclose (ffp);
1213 (void) fclose (qfp);
1214 return NOTOK;
1215 }
1216 }
1217
1218 (void) fclose (ffp);
1219 if (ferror (qfp)) {
1220 (void) close (fd1);
1221 (void) fclose (qfp);
1222 return NOTOK;
1223 }
1224 (void) fclose (qfp);
1225
1226 (void) lseek (fd1, (off_t)0, 0);
1227
1228 return fd1;
1229 }
1230
1231 /* \f */
1232
1233 /* VARARGS2 */
1234
1235 static void adorn (what, fmt, a, b, c, d, e, f)
1236 char *what,
1237 *fmt,
1238 *a,
1239 *b,
1240 *c,
1241 *d,
1242 *e,
1243 *f;
1244 {
1245 char *cp = invo_name;
1246
1247 if (!verbose)
1248 return;
1249 printf (", ");
1250
1251 invo_name = NULL;
1252 advise (what, fmt, a, b, c, d, e, f);
1253 invo_name = cp;
1254 }
1255
1256 /* \f */
1257
1258 #ifdef MSGID
1259
1260 static int check_msgid (fd, file)
1261 int fd;
1262 char *file;
1263 {
1264 int fd1,
1265 state;
1266 char *cp,
1267 buf[BUFSIZ],
1268 name[NAMESZ];
1269 datum key,
1270 value;
1271 DBM *db;
1272 FILE *in;
1273
1274 if ((fd1 = dup (fd)) == NOTOK)
1275 return NOTOK;
1276 if ((in = fdopen (fd1, "r")) == NULL) {
1277 (void) close (fd1);
1278 return NOTOK;
1279 }
1280 rewind (in);
1281
1282 for (state = FLD;;) {
1283 switch (state = m_getfld (state, name, buf, sizeof buf, in)) {
1284 case FLD:
1285 case FLDPLUS:
1286 case FLDEOF:
1287 if (!uleq (name, "Message-ID")) {
1288 while (state == FLDPLUS)
1289 state = m_getfld (state, name, buf, sizeof buf, in);
1290 continue;
1291 }
1292
1293 cp = add (buf, NULLCP);
1294 while (state == FLDPLUS) {
1295 state = m_getfld (state, name, buf, sizeof buf, in);
1296 cp = add (buf, cp);
1297 }
1298 key.dsize = strlen (key.dptr = trimcpy (cp)) + 1;
1299 free (cp);
1300 cp = key.dptr;
1301
1302 if ((db = dbm_open (file, O_RDWR | O_CREAT, 0600)) == NULL) {
1303 advise (file, "unable to perform dbm_open on");
1304 out: ;
1305 free (cp);
1306 (void) fclose (in);
1307 return NOTOK;
1308 }
1309 #ifdef FCNTL
1310 {
1311 struct flock fl;
1312
1313 fl.l_type = F_WRLCK;
1314 fl.l_whence = 0;
1315 fl.l_start = 0;
1316 fl.l_len = 0;
1317 if (fcntl (dbm_pagfno (db), F_SETLK, &fl) == -1) {
1318 advise (file, "unable to perform flock on");
1319 goto out;
1320 }
1321 }
1322 #else
1323 #ifdef LOCKF
1324 if (lockf (dbm_pagfno (db), F_LOCK) == NOTOK) {
1325 advise (file, "unable to perform lockf on");
1326 goto out;
1327 }
1328 #else
1329 if (flock (dbm_pagfno (db), LOCK_EX) == NOTOK) {
1330 advise (file, "unable to perform flock on");
1331 goto out;
1332 }
1333 #endif
1334 #endif
1335
1336 value = dbm_fetch (db, key);
1337 if (value.dptr != NULL) {
1338 if (debug)
1339 advise (NULLCP,
1340 "Message-ID: %s already received on\n\tDate: %s",
1341 cp, value.dptr);
1342 free (cp);
1343 (void) fclose (in);
1344 return DONE;
1345 }
1346
1347 value.dsize = strlen (value.dptr =
1348 ddate + sizeof "Delivery-Date:") + 1;
1349
1350 if (dbm_store (db, key, value, DBM_INSERT))
1351 advise (file, "possibly corrupt file");
1352
1353 dbm_close (db);
1354
1355 free (cp);
1356 break;
1357
1358 case BODY:
1359 case BODYEOF:
1360 case FILEEOF:
1361 break;
1362
1363 case LENERR:
1364 case FMTERR:
1365 default:
1366 break;
1367 }
1368
1369 break;
1370 }
1371
1372 (void) fclose (in);
1373 return OK;
1374 }
1375 #endif