Mercurial > hg > Applications > mh
view uip/slocal.c @ 4:6bc439d68ff9 utf-8-support
*** empty log message ***
author | kono |
---|---|
date | Wed, 20 Apr 2005 14:39:40 +0900 |
parents | bce86c4163a3 |
children | 441a2190cfae |
line wrap: on
line source
/* slocal.c - MH style mailer to write to a local user's mailbox */ #ifndef lint static char ident[] = "@(#)$Id$"; #endif /* lint */ /* This program implements mail delivery in the MH/MMDF style. Under SendMail, users should add the line "| /usr/local/lib/mh/slocal" to their $HOME/.forward file. Under MMDF-I, users should (symbolically) link /usr/local/lib/mh/slocal to $HOME/bin/rcvmail. Under stand-alone MH, post will automatically run this during local delivery. This program should be used ONLY if you have "mts sendmail" or "mts mh" or "mts mmdf1" set in your MH configuration. */ /* */ #include "../h/mh.h" #include "../h/dropsbr.h" #include "../h/rcvmail.h" #include "../zotnet/tws.h" #include "../zotnet/mts.h" #include <pwd.h> #include <signal.h> #ifndef V7 #ifndef NOIOCTLH #include <sys/ioctl.h> #endif /* NOIOCTLH */ #endif /* not V7 */ #include <sys/stat.h> #include <utmp.h> #ifndef UTMP_FILENAME #ifdef UTMP_FILE #define UTMP_FILENAME UTMP_FILE #else #ifdef _PATH_UTMP #define UTMP_FILENAME _PATH_UTMP #else #define UTMP_FILENAME "/etc/utmp" #endif #endif #endif /* UTMP_FILENAME */ #ifdef LOCALE #include <locale.h> #endif #ifdef MSGID static int check_msgid (int, char *); #undef DBM /* used by ndbm.h */ #include <ndbm.h> #ifdef DBM_SUFFIX #undef dbm_pagfno #define dbm_pagfno dbm_dirfno #endif /* DBM_SUFFIX */ #include <stdio.h> #include <sys/types.h> #include <sys/file.h> #ifdef SYS5 #include <fcntl.h> #endif #ifdef UNISTD #include <unistd.h> #endif #if defined(LOCKF) && !defined(F_ULOCK) #include <sys/fcntl.h> #endif /* LOCKF */ #endif #define NVEC 100 /* */ static struct swit switches[] = { #define ADDRSW 0 "addr address", 0, #define USERSW 1 "user name", 0, #define FILESW 2 "file file", 0, #define SENDSW 3 "sender address", 0, #define MBOXSW 4 "mailbox file", 0, #define HOMESW 5 "home directory", -4, #define INFOSW 6 "info data", 0, #define MAILSW 7 "maildelivery file", 0, #define VERBSW 8 "verbose", 0, #define NVERBSW 9 "noverbose", 0, #define DEBUGSW 10 "debug", 0, #define HELPSW 11 "help", 4, NULL, 0 }; /* */ static int debug = 0; static int globbed = 0; static int parsed = 0; static int utmped = 0; static int verbose = 0; #ifdef SETMG static gid_t mailgroup; #endif /* SETMG */ static char *addr = NULLCP; static char *user = NULLCP; static char *info = NULLCP; static char *file = NULLCP; static char *sender = NULLCP; static char *unixfrom = NULLCP; static char *mbox = NULLCP; static char *home = NULLCP; static struct passwd *pw; static char ddate[BUFSIZ]; struct tws *now; static jmp_buf myctx; /* */ struct pair { char *p_name; char *p_value; char p_flags; #define P_NIL 0x00 #define P_ADR 0x01 #define P_HID 0x02 #define P_CHK 0x04 }; static struct pair *lookup (); static struct pair hdrs[NVEC + 1] = { "source", NULL, P_HID, "addr", NULL, P_HID, "Return-Path", NULL, P_ADR, "Reply-To", NULL, P_ADR, "From", NULL, P_ADR, "Sender", NULL, P_ADR, "To", NULL, P_ADR, "cc", NULL, P_ADR, "Resent-Reply-To", NULL, P_ADR, "Resent-From", NULL, P_ADR, "Resent-Sender", NULL, P_ADR, "Resent-To", NULL, P_ADR, "Resent-cc", NULL, P_ADR, NULL }; static struct pair vars[] = { "sender", NULL, P_NIL, "address", NULL, P_NIL, "size", NULL, P_NIL, "reply-to", NULL, P_CHK, "info", NULL, P_NIL, NULL }; static char *rcvstore; /* */ extern char **environ; static void adorn (); static TYPESIG alrmser (); off_t lseek (); #ifndef __STDC__ #ifdef SYS5 struct passwd *getpwnam (); #endif /* SYS5 */ #endif static int localmail(), usr_delivery(), split(), parse(), logged_in(); static int timely(), usr_file(), usr_pipe(), copyfile(); static expand(), glob(), copyinfo(); /* */ /* ARGSUSED */ main (argc, argv, envp) int argc; char **argv, **envp; { int fd; FILE *fp = stdin; char *cp, *mdlvr = NULL, buf[100], from[BUFSIZ], mailbox[BUFSIZ], tmpfil[BUFSIZ], **argp = argv + 1; #ifdef LOCALE setlocale(LC_ALL, ""); #endif #ifdef JAPAN ml_init(); #endif invo_name = r1bindex (*argv, '/'); m_foil (NULLCP); mts_init (invo_name); /* */ while (cp = *argp++) { if (*cp == '-') switch (smatch (++cp, switches)) { case AMBIGSW: ambigsw (cp, switches); done (1); case UNKWNSW: adios (NULLCP, "-%s unknown", cp); case HELPSW: (void) sprintf (buf, "%s [switches] [address info sender]", invo_name); help (buf, switches); done (1); case ADDRSW: if (!(addr = *argp++))/* allow -xyz arguments */ adios (NULLCP, "missing argument to %s", argp[-2]); continue; case INFOSW: if (!(info = *argp++))/* allow -xyz arguments */ adios (NULLCP, "missing argument to %s", argp[-2]); continue; case USERSW: if (!(user = *argp++))/* allow -xyz arguments */ adios (NULLCP, "missing argument to %s", argp[-2]); continue; case FILESW: if (!(file = *argp++) || *file == '-') adios (NULLCP, "missing argument to %s", argp[-2]); continue; case SENDSW: if (!(sender = *argp++))/* allow -xyz arguments */ adios (NULLCP, "missing argument to %s", argp[-2]); continue; case MBOXSW: if (!(mbox = *argp++) || *mbox == '-') adios (NULLCP, "missing argument to %s", argp[-2]); continue; case HOMESW: if (!(home = *argp++) || *home == '-') adios (NULLCP, "missing argument to %s", argp[-2]); continue; case MAILSW: if (!(cp = *argp++) || *cp == '-') adios (NULLCP, "missing argument to %s", argp[-2]); if (mdlvr) adios (NULLCP, "only one maildelivery file at a time!"); mdlvr = cp; continue; case VERBSW: verbose++; continue; case NVERBSW: verbose = 0; continue; case DEBUGSW: debug++; continue; } switch (argp - (argv + 1)) { case 1: addr = cp; break; case 2: info = cp; break; case 3: sender = cp; break; } } /* */ rcvstore = getcpy(libpath("rcvstore")); if (addr == NULL) addr = getusr (); if (user == NULL) user = (cp = index (addr, '.')) ? ++cp : addr; if ((pw = getpwnam (user)) == NULL) adios (NULLCP, "no such local user as %s", user); if (chdir (pw -> pw_dir) == NOTOK) (void) chdir ("/"); (void) umask (0077); if (geteuid () == 0) { #ifdef BSD41A (void) inigrp (pw -> pw_name, pw -> pw_gid); #endif /* BSD41A */ (void) setgid (pw -> pw_gid); #if defined(BSD42) || defined(SVR4) (void) initgroups (pw -> pw_name, pw -> pw_gid); #endif /* BSD42 || SVR4 */ (void) setuid (pw -> pw_uid); } #ifdef SETMG mailgroup = getegid(); setgid(getgid()); #endif /* SETMG */ if (info == NULL) info = ""; setbuf (stdin, NULLCP); if (file == NULL) { if (debug) fprintf (stderr, "retrieving message from stdin\n"); if ((fd = copyfile (fileno (stdin), file = tmpfil, 1)) == NOTOK) adios (NULLCP, "unable to create temporary file"); } else { int tmpfd; if ((tmpfd = open (file, 0)) == NOTOK) adios(file, "unable to open"); if (debug) fprintf (stderr, "retrieving message from file \"%s\"\n", file); if ((fd = copyfile (tmpfd, tmpfil, 1)) == NOTOK) adios (NULL, "unable to create temporary file"); close (tmpfd); } if (debug) fprintf (stderr, "temporary file \"%s\" selected\n", tmpfil); else (void) unlink (tmpfil); if ((fp = fdopen (fd, "r+")) == NULL) adios (NULLCP, "unable to access temporary file"); from[0] = 0; if (sender == NULL) { sender = ""; copyinfo (fp, from); } if (mbox == NULL) { (void) sprintf (mailbox, "%s/%s", mmdfldir[0] ? mmdfldir : pw -> pw_dir, mmdflfil[0] ? mmdflfil : pw -> pw_name); mbox = mailbox; } if (home == NULL) home = pw -> pw_dir; if ((now = dtwstime ()) == NULL) adios (NULLCP, "unable to ascertain local time"); (void) sprintf (ddate, "Delivery-Date: %s\n", dtimenow ()); if (debug) { fprintf (stderr, "addr=\"%s\" user=\"%s\" info=\"%s\" file=\"%s\"\n", addr, user, info, file); fprintf (stderr, "sender=\"%s\" mbox=\"%s\" home=\"%s\" from=\"%s\"\n", sender, mbox, home, from); fprintf (stderr, "ddate=\"%s\" now=%02d:%02d\n", ddate, now -> tw_hour, now -> tw_min); } done (localmail (fd, from, mdlvr) != NOTOK ? RCV_MOK : RCV_MBX); } /* */ static int localmail (fd, from, mdlvr) int fd; char *from, *mdlvr; { #ifdef MSGID struct stat st; static int first = 1; #ifdef DBM_SUFFIX char buf[32]; (void) sprintf(buf, ".maildelivery%s", DBM_SUFFIX); if (stat (buf, &st) != NOTOK) { #else /* DBM_SUFFIX */ if (stat (".maildelivery.pag", &st) != NOTOK) { #endif /* DBM_SUFFIX */ /* * Allow a user to trigger the database by creating an * empty database file. That gets us here, now we need * to remove it so DBM will create and initialize it properly. */ if (st.st_size == 0 && first) { first = 0; #ifdef DBM_SUFFIX (void) unlink(buf); #else /* DBM_SUFFIX */ (void) unlink(".maildelivery.pag"); #endif /* DBM_SUFFIX */ } if (check_msgid (fd, ".maildelivery") == DONE) return OK; } #endif if (usr_delivery (fd, mdlvr ? mdlvr : ".maildelivery", 0, from) != NOTOK) return OK; if (usr_delivery (fd, maildelivery, 1, from) != NOTOK) return OK; #ifdef notdef if (verbose) printf ("(invoking hook)\n"); if (usr_hook (fd, mbox) != NOTOK) return OK; #endif /* notdef */ if (verbose) printf ("(trying normal delivery)\n"); return usr_file (fd, mbox, from); } /* */ #ifdef JAPAN int matches (p1, p2) register char *p1, *p2; { register char *p; if (p1 == 0 || p2 == 0) return 0; /* XXX */ for (p = p1; *p; p++) { if (uprf (p, p2)) return 1; if (ml_ismlptr (p)) p++; } return 0; } #else /* JAPAN */ #define matches(a,b) (stringdex (b, a) >= 0) #endif /* JAPAN */ static int usr_delivery (fd, delivery, su, from) int fd, su; char *delivery, *from; { int i, accept, status, won, vecp, next; register char *cp, *action, *field, *pattern, *string; char buffer[BUFSIZ], tmpbuf[BUFSIZ], *vec[NVEC]; struct stat st; register struct pair *p; register FILE *fp; if ((fp = fopen (delivery, "r")) == NULL) return NOTOK; if (fstat (fileno (fp), &st) == NOTOK || (st.st_uid != 0 && (su || st.st_uid != pw -> pw_uid)) || st.st_mode & 0022) { if (verbose) { printf ("%s: ownership/modes bad (%d, %d,%d,0%o)\n", delivery, su, pw -> pw_uid, st.st_uid, st.st_mode); (void) fflush (stdout); } return NOTOK; } won = 0; next = 1; while (fgets (buffer, sizeof buffer, fp) != NULL) { if (*buffer == '#' || *buffer == '\n') continue; if (cp = index (buffer, '\n')) *cp = 0; #ifdef JAPAN ml_conv(buffer); #endif /* JAPAN */ if ((vecp = split (buffer, vec)) < 5) { if (debug) fprintf(stderr, "WARNING: entry with only %d fields, skipping ...\n", vecp); continue; } if (debug) for (i = 0; vec[i]; i++) fprintf (stderr, "vec[%d]: \"%s\"\n", i, vec[i]); field = vec[0]; pattern = vec[1]; action = vec[2]; switch (vec[3][0]) { case 'N': case 'n': if (! next) continue; /* if previous condition failed, don't do this - else fall through */ case '?': if (won) continue; /* else fall */ case 'A': case 'a': accept = 1; break; case 'R': case 'r': default: accept = 0; break; } string = vec[4]; if (vecp > 5) { if (uleq (vec[5], "select")) { if (logged_in () != NOTOK) continue; if (vecp > 7 && timely (vec[6], vec[7]) == NOTOK) continue; } } switch (*field) { case '*': break; case 'd': if (uleq (field, "default")) { if (won) continue; break; } /* else fall */ default: if (!parsed && parse (fd) == NOTOK) { (void) fclose (fp); return NOTOK; } if ((p = lookup (hdrs, field)) == NULL || (p->p_value == NULL) /* XXX */ || !matches (p -> p_value, pattern)) { next = 0; continue; } else next = 1; break; } switch (*action) { case 'q': if (!uleq (action, "qpipe")) continue; /* else fall */ case '^': expand (tmpbuf, string, fd); if (split (tmpbuf, vec) < 1) continue; status = usr_pipe (fd, tmpbuf, vec[0], vec); break; case 'p': if (!uleq (action, "pipe")) continue; /* else fall */ case '|': vec[2] = "sh"; vec[3] = "-c"; expand (tmpbuf, string, fd); vec[4] = tmpbuf; vec[5] = NULL; status = usr_pipe (fd, tmpbuf, "/bin/sh", vec + 2); break; case '+': dofolder: if (*string == '+') strcpy(tmpbuf, string); else sprintf(tmpbuf, "+%s", string); vec[2] = "rcvstore"; vec[3] = tmpbuf; vec[4] = NULL; if (verbose) printf("rcvstore %s", vec[3]); status = usr_pipe(fd, "rcvstore", rcvstore, vec + 2); break; case 'f': if (uleq(action, "folder")) goto dofolder; if (!uleq (action, "file")) continue; /* else fall */ case '>': #ifdef RPATHS status = usr_file (fd, string, from); /* UUCP format? */ #else status = usr_file (fd, string, NULLCP); #endif break; case 'm': if (!uleq (action, "mbox")) continue; status = usr_file (fd, string, NULLCP); break; case 'd': if (!uleq (action, "destroy")) continue; status = OK; #ifdef REALLY_DESTROY if (verbose) printf ("\tdestroying message\n"); if (accept) won++; goto finish; #endif /* REALLY_DESTROY */ break; } if (status == OK) { /* next is already 1. */ if (accept) won++; } else { /* overload the next variable */ next = 0; /* to indicate that action failed */ } } finish: (void) fclose (fp); return (won ? OK : NOTOK); } /* */ #define QUOTE '\\' static int split (cp, vec) char *cp, **vec; { register int i; register char *s; for (i = 0, s = cp; i <= NVEC;) { vec[i] = NULL; while (isspace (*s) || *s == ',') *s++ = 0; if (*s == 0) break; if (*s == '"') { for (vec[i++] = ++s; *s != 0 && *s != '"'; s++) if (*s == QUOTE) { if (*++s == '"') (void) strcpy (s - 1, s); s--; } if (*s == '"') *s++ = 0; continue; } if (*s == QUOTE && *++s != '"') s--; vec[i++] = s++; while (*s != 0 && !isspace (*s) && *s != ',') s++; } vec[i] = NULL; return i; } /* */ static int parse (fd) register int fd; { register int i, state; int fd1; register char *cp, *dp, *lp; char name[NAMESZ], field[BUFSIZ]; register struct pair *p, *q; register FILE *in; if (parsed++) return OK; if ((fd1 = dup (fd)) == NOTOK) return NOTOK; if ((in = fdopen (fd1, "r")) == NULL) { (void) close (fd1); return NOTOK; } rewind (in); if (p = lookup (hdrs, "source")) p -> p_value = getcpy (sender); if (p = lookup (hdrs, "addr")) p -> p_value = getcpy (addr); for (i = 0, state = FLD;;) { switch (state = m_getfld (state, name, field, sizeof field, in)) { case FLD: case FLDEOF: case FLDPLUS: lp = add (field, NULLCP); while (state == FLDPLUS) { state = m_getfld (state, name, field, sizeof field, in); lp = add (field, lp); } for (p = hdrs; p -> p_name; p++) if (uleq (p -> p_name, name)) { if (!(p -> p_flags & P_HID)) { if (cp = p -> p_value) if (p -> p_flags & P_ADR) { dp = cp + strlen (cp) - 1; if (*dp == '\n') *dp = 0; cp = add (",\n\t", cp); } else cp = add ("\t", cp); p -> p_value = add (lp, cp); } free (lp); break; } if (p -> p_name == NULL && i < NVEC) { p -> p_name = getcpy (name); p -> p_value = lp; p -> p_flags = P_NIL; p++, i++; p -> p_name = NULL; } if (state != FLDEOF) continue; break; case BODY: case BODYEOF: case FILEEOF: break; case LENERR: case FMTERR: advise (NULLCP, "format error in message"); break; default: advise (NULLCP, "internal error"); (void) fclose (in); return NOTOK; } break; } (void) fclose (in); if (p = lookup (vars, "reply-to")) { if ((q = lookup (hdrs, "reply-to")) == NULL || q -> p_value == NULL) q = lookup (hdrs, "from"); p -> p_value = getcpy (q ? q -> p_value : ""); p -> p_flags &= ~P_CHK; if (debug) fprintf (stderr, "vars[%d]: name=\"%s\" value=\"%s\"\n", p - vars, p -> p_name, p -> p_value); } #define empty(s) ((s) ? (s) : "") if (debug) for (p = hdrs; p -> p_name; p++) fprintf (stderr, "hdrs[%d]: name=\"%s\" value=\"%s\"\n", p - hdrs, p -> p_name, empty(p -> p_value)); #undef empty #ifdef MIME_HEADERS for (p = hdrs; p -> p_name; p++) { char *tmpbuf; if (! p -> p_value) continue; tmpbuf = getcpy(p -> p_value); exthdr_decode(tmpbuf, p -> p_value); free(tmpbuf); } #endif /* MIME_HEADERS */ return OK; } /* */ #define LPAREN '(' #define RPAREN ')' static expand (s1, s2, fd) register char *s1, *s2; int fd; { register char c, *cp; register struct pair *p; if (!globbed) glob (fd); while (c = *s2++) if (c != '$' || *s2 != LPAREN) *s1++ = c; else { for (cp = ++s2; *s2 && *s2 != RPAREN; s2++) continue; if (*s2 != RPAREN) { s2 = --cp; continue; } *s2++ = 0; if (p = lookup (vars, cp)) { if (!parsed && (p -> p_flags & P_CHK)) (void) parse (fd); (void) strcpy (s1, p -> p_value); s1 += strlen (s1); } } *s1 = 0; } /* */ static glob (fd) register int fd; { char buffer[BUFSIZ]; struct stat st; register struct pair *p; if (globbed++) return; if (p = lookup (vars, "sender")) p -> p_value = getcpy (sender); if (p = lookup (vars, "address")) p -> p_value = getcpy (addr); if (p = lookup (vars, "size")) { (void) sprintf (buffer, "%d", fstat (fd, &st) != NOTOK ? (int) st.st_size : 0); p -> p_value = getcpy (buffer); } if (p = lookup (vars, "info")) p -> p_value = getcpy (info); if (debug) for (p = vars; p -> p_name; p++) fprintf (stderr, "vars[%d]: name=\"%s\" value=\"%s\"\n", p - vars, p -> p_name, p -> p_value); } /* */ static struct pair *lookup (pairs, key) register struct pair *pairs; register char *key; { register char *cp; for (; cp = pairs -> p_name; pairs++) if (uleq (cp, key)) return pairs; return NULL; } /* */ static int logged_in () { struct utmp ut; register FILE *uf; if (utmped) return utmped; if ((uf = fopen (UTMP_FILENAME, "r")) == NULL) return NOTOK; while (fread ((char *) &ut, sizeof ut, 1, uf) == 1) if (ut.ut_name[0] != 0 #ifdef UTMAXTYPE && ut.ut_type == USER_PROCESS #endif && strncmp (user, ut.ut_name, sizeof ut.ut_name) == 0) { if (debug) continue; (void) fclose (uf); return (utmped = DONE); } (void) fclose (uf); return (utmped = NOTOK); } static int timely (t1, t2) char *t1, *t2; { #define check(t,a,b) if (t < a || t > b) return NOTOK #define cmpar(h1,m1,h2,m2) if (h1 < h2 || (h1 == h2 && m1 < m2)) return OK int t1hours, t1mins, t2hours, t2mins; if (sscanf (t1, "%d:%d", &t1hours, &t1mins) != 2) return NOTOK; check (t1hours, 0, 23); check (t1mins, 0, 59); if (sscanf (t2, "%d:%d", &t2hours, &t2mins) != 2) return NOTOK; check (t2hours, 0, 23); check (t2mins, 0, 59); cmpar (now -> tw_hour, now -> tw_min, t1hours, t1mins); cmpar (t2hours, t2mins, now -> tw_hour, now -> tw_min); return NOTOK; } /* */ static int usr_file (fd, mailbox, from) int fd; char *mailbox, *from; { int md, mapping; register char *bp; char buffer[BUFSIZ]; gid_t mail_gid; int file_mode; if (verbose) printf ("\tdelivering to file \"%s\"", mailbox); if (from && *from) { (void) mbx_uucp (); if (verbose) printf (" (uucp style)"); (void) sprintf (buffer, "%s%s", from, ddate); bp = buffer; mapping = 0; } else { bp = ddate; mapping = 1; } if (verbose) (void) fflush (stdout); /* * for SYS5 systems * (maildrop: gid = mail (660)) * Attention!! This routine may open a security hole... * by hayashi@kuic.kyoto-u.ac.jp */ #ifdef SETMG if (strcmp(mailbox, mbox) == 0) { mail_gid = mailgroup; file_mode = 0660; setgid(mailgroup); } else { mail_gid = pw -> pw_gid; file_mode = m_gmprot(); } #else /* SETMG */ mail_gid = pw -> pw_gid; file_mode = m_gmprot(); #endif /* SETMG */ if ((md = mbx_open (mailbox, pw -> pw_uid, mail_gid, file_mode)) == NOTOK) { #ifdef SETMG setgid(getgid()); #endif /* SETMG */ adorn ("", "unable to open:"); return NOTOK; } (void) lseek (fd, (off_t)0, 0); if (mbx_copy (mailbox, md, fd, mapping, bp, verbose) == NOTOK) { #ifdef SETMG setgid(getgid()); #endif /* SETMG */ adorn ("", "error writing to:"); return NOTOK; } (void) mbx_close (mailbox, md); #ifdef SETMG setgid(getgid()); #endif /* SETMG */ if (verbose) { printf (", done.\n"); (void) fflush (stdout); } return OK; } /* */ #ifdef notdef static int usr_hook (fd, mailbox) int fd; char *mailbox; { int i, vecp; char receive[BUFSIZ], tmpfil[BUFSIZ], *vec[NVEC]; if ((fd = copyfile (fd, tmpfil, 0)) == NOTOK) { if (verbose) adorn ("unable to copy message; skipping hook\n"); return NOTOK; } (void) chown (tmpfil, pw -> pw_uid, pw -> pw_gid); vecp = 1; (void) sprintf (receive, "%s/.mh_receive", pw -> pw_dir); switch (access (receive, 01)) { case NOTOK: (void) sprintf (receive, "%s/bin/rcvmail", pw -> pw_dir); if (access (receive, 01) == NOTOK) { (void) unlink (tmpfil); if (verbose) { printf ("\tnot present\n"); (void) fflush (stdout); } return NOTOK; } vec[vecp++] = addr; vec[vecp++] = tmpfil; vec[vecp++] = sender; break; default: vec[vecp++] = tmpfil; vec[vecp++] = mailbox; vec[vecp++] = home; vec[vecp++] = addr; vec[vecp++] = sender; break; } vec[0] = r1bindex (receive, '/'); vec[vecp] = NULL; i = usr_pipe (fd, "rcvmail", receive, vec); (void) unlink (tmpfil); return i; } #endif /* notdef */ /* */ static int usr_pipe (fd, cmd, pgm, vec) int fd; char *cmd, *pgm, **vec; { int bytes, i, child_id, status; struct stat st; if (verbose) { printf ("\tdelivering to pipe \"%s\"", cmd); (void) fflush (stdout); } (void) lseek (fd, (off_t)0, 0); for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++) sleep (5); switch (child_id) { case NOTOK: adorn ("fork", "unable to"); return NOTOK; case OK: if (fd != 0) (void) dup2 (fd, 0); (void) freopen ("/dev/null", "w", stdout); (void) freopen ("/dev/null", "w", stderr); if (fd != 3) (void) dup2 (fd, 3); closefds (4); #ifdef TIOCNOTTY if ((fd = open ("/dev/tty", 2)) != NOTOK) { (void) ioctl (fd, TIOCNOTTY, NULLCP); (void) close (fd); } #endif /* TIOCNOTTY */ #ifdef BSD42 (void) setpgrp (0, getpid ()); #endif /* BSD42 */ *environ = NULL; (void) m_putenv ("USER", pw -> pw_name); (void) m_putenv ("HOME", pw -> pw_dir); (void) m_putenv ("SHELL", pw -> pw_shell); execvp (pgm, vec); _exit (-1); default: switch (setjmp (myctx)) { case OK: (void) signal (SIGALRM, alrmser); bytes = fstat (fd, &st) != NOTOK ? (int) st.st_size : 100; if (bytes <= 0) bytes = 100; (void) alarm ((unsigned) (bytes * 60 + 300)); status = pidwait (child_id, OK); (void) alarm (0); #ifdef MMDFI if (status == RP_MOK || status == RP_OK) status = 0; #endif /* MMDFI */ if (verbose) { if (status == 0) printf (", wins.\n"); else if ((status & 0xff00) == 0xff00) printf (", system error\n"); else (void) pidstatus (status, stdout, ", loses"); (void) fflush (stdout); } return (status == 0 ? OK : NOTOK); default: #ifndef BSD42 (void) kill (child_id, SIGKILL); #else /* BSD42 */ (void) killpg (child_id, SIGKILL); #endif /* BSD42 */ if (verbose) { printf (", timed-out; terminated\n"); (void) fflush (stdout); } return NOTOK; } } } /* */ /* ARGSUSED */ static TYPESIG alrmser (i) int i; { longjmp (myctx, DONE); } /* */ static copyinfo (fp, from) register FILE *fp; char *from; { int i; register char *cp; static char buffer[BUFSIZ]; if (unixfrom) /* interface from copyfile */ strcpy (from, unixfrom); else if (fgets (from, BUFSIZ, fp) == NULL) adios (NULLCP, "no message"); if (strncmp (from, "From ", i = strlen ("From "))) { rewind (fp); *from = 0; return; } (void) strcpy (buffer, from + i); if (cp = index (buffer, '\n')) { *cp = 0; cp -= 24; if (cp < buffer) cp = buffer; } else cp = buffer; *cp = 0; for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) if (isspace (*cp)) *cp = 0; else break; sender = buffer; rewind (fp); } /* */ static int copyfile (qd, tmpfil, fold) int qd, fold; register char *tmpfil; { register int i, first = 0, fd1, fd2; char buffer[BUFSIZ]; register FILE *qfp, *ffp; (void) strcpy (tmpfil, m_tmpfil (invo_name)); if ((fd1 = creat (tmpfil, 0600)) == NOTOK) return NOTOK; (void) close (fd1); if ((fd1 = open (tmpfil, 2)) == NOTOK) return NOTOK; if (!fold) { while ((i = read (qd, buffer, sizeof buffer)) > 0) if (write (fd1, buffer, i) != i) { you_lose: ; (void) close (fd1); (void) unlink (tmpfil); return NOTOK; } if (i == NOTOK) goto you_lose; (void) lseek (fd1, (off_t)0, 0); return fd1; } if ((fd2 = dup (qd)) == NOTOK) { (void) close (fd1); return NOTOK; } if ((qfp = fdopen (fd2, "r")) == NULL) { (void) close (fd1); (void) close (fd2); return NOTOK; } if ((fd2 = dup (fd1)) == NOTOK) { (void) close (fd1); (void) fclose (qfp); return NOTOK; } if ((ffp = fdopen (fd2, "r+")) == NULL) { (void) close (fd1); (void) close (fd2); (void) fclose (qfp); return NOTOK; } i = strlen ("From "); while (fgets (buffer, sizeof buffer, qfp)) { if (!strncmp (buffer, "From ", i)) if (first == 0) { #ifdef RPATHS register char *fp, *cp, *hp, *ep; #endif unixfrom = getcpy (buffer); /* save for later */ #ifndef RPATHS continue; /* but don't put in file */ #else hp = cp = index (fp = unixfrom + i, ' '); while (hp = index (++hp, 'r')) if (uprf (hp, "remote from")) { hp = rindex (hp, ' '); break; } if (hp) { ep = rindex (++hp, '\n'); sprintf (buffer, "Return-Path: %.*s!%.*s\n", ep - hp, hp, cp - fp, fp); } else sprintf (buffer, "Return-Path: %.*s\n", cp - fp, fp); #endif } #ifdef notdef /* mbx_copy does this */ else putc ('>', ffp); #endif /* notdef */ first++; fputs (buffer, ffp); if (ferror (ffp)) { (void) close (fd1); (void) fclose (ffp); (void) fclose (qfp); return NOTOK; } } (void) fclose (ffp); if (ferror (qfp)) { (void) close (fd1); (void) fclose (qfp); return NOTOK; } (void) fclose (qfp); (void) lseek (fd1, (off_t)0, 0); return fd1; } /* */ /* VARARGS2 */ static void adorn (what, fmt, a, b, c, d, e, f) char *what, *fmt, *a, *b, *c, *d, *e, *f; { char *cp = invo_name; if (!verbose) return; printf (", "); invo_name = NULL; advise (what, fmt, a, b, c, d, e, f); invo_name = cp; } /* */ #ifdef MSGID static int check_msgid (fd, file) int fd; char *file; { int fd1, state; char *cp, buf[BUFSIZ], name[NAMESZ]; datum key, value; DBM *db; FILE *in; if ((fd1 = dup (fd)) == NOTOK) return NOTOK; if ((in = fdopen (fd1, "r")) == NULL) { (void) close (fd1); return NOTOK; } rewind (in); for (state = FLD;;) { switch (state = m_getfld (state, name, buf, sizeof buf, in)) { case FLD: case FLDPLUS: case FLDEOF: if (!uleq (name, "Message-ID")) { while (state == FLDPLUS) state = m_getfld (state, name, buf, sizeof buf, in); continue; } cp = add (buf, NULLCP); while (state == FLDPLUS) { state = m_getfld (state, name, buf, sizeof buf, in); cp = add (buf, cp); } key.dsize = strlen (key.dptr = trimcpy (cp)) + 1; free (cp); cp = key.dptr; if ((db = dbm_open (file, O_RDWR | O_CREAT, 0600)) == NULL) { advise (file, "unable to perform dbm_open on"); out: ; free (cp); (void) fclose (in); return NOTOK; } #ifdef LOCKF if (lockf (dbm_pagfno (db), F_LOCK, 0) == NOTOK) { advise (file, "unable to perform lockf on"); goto out; } #else #ifdef FCNTL { struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = 0; fl.l_start = 0; fl.l_len = 0; if (fcntl (dbm_pagfno (db), F_SETLK, &fl) == -1) { advise (file, "unable to perform flock on"); goto out; } } #else if (flock (dbm_pagfno (db), LOCK_EX) == NOTOK) { advise (file, "unable to perform flock on"); goto out; } #endif #endif value = dbm_fetch (db, key); if (value.dptr != NULL) { if (debug) advise (NULLCP, "Message-ID: %s already received on\n\tDate: %s", cp, value.dptr); free (cp); (void) fclose (in); return DONE; } value.dsize = strlen (value.dptr = ddate + sizeof "Delivery-Date:") + 1; if (dbm_store (db, key, value, DBM_INSERT)) advise (file, "possibly corrupt file"); dbm_close (db); free (cp); break; case BODY: case BODYEOF: case FILEEOF: break; case LENERR: case FMTERR: default: break; } break; } (void) fclose (in); return OK; } #endif