📄 deliver.c
字号:
** q -- the address to mark.** rcode -- the code signifying the particular failure.**** Returns:** none.**** Side Effects:** marks the address (and possibly the envelope) with the** failure so that an error will be returned or** the message will be queued, as appropriate.*/markfailure(e, q, rcode) register ENVELOPE *e; register ADDRESS *q; int rcode;{ if (rcode == EX_OK) return; else if (rcode != EX_TEMPFAIL) q->q_flags |= QBADADDR; else if (curtime() > e->e_ctime + TimeOut) { extern char *pintvl(); char buf[MAXLINE]; if (!bitset(EF_TIMEOUT, e->e_flags)) { (void) sprintf(buf, "Cannot send message for %s", pintvl(TimeOut, FALSE)); if (e->e_message != NULL) free(e->e_message); e->e_message = newstr(buf); message(Arpa_Info, buf); } q->q_flags |= QBADADDR; e->e_flags |= EF_TIMEOUT; } else q->q_flags |= QQUEUEUP;}/*** DOFORK -- do a fork, retrying a couple of times on failure.**** This MUST be a macro, since after a vfork we are running** two processes on the same stack!!!**** Parameters:** none.**** Returns:** From a macro??? You've got to be kidding!**** Side Effects:** Modifies the ==> LOCAL <== variable 'pid', leaving:** pid of child in parent, zero in child.** -1 on unrecoverable error.**** Notes:** I'm awfully sorry this looks so awful. That's** vfork for you.....*/# define NFORKTRIES 5# ifdef VMUNIX# define XFORK vfork# else VMUNIX# define XFORK fork# endif VMUNIX# define DOFORK(fORKfN) \{\ register int i;\\ for (i = NFORKTRIES; --i >= 0; )\ {\ pid = fORKfN();\ if (pid >= 0)\ break;\ if (i > 0)\ sleep((unsigned) NFORKTRIES - i);\ }\}/*** DOFORK -- simple fork interface to DOFORK.**** Parameters:** none.**** Returns:** pid of child in parent.** zero in child.** -1 on error.**** Side Effects:** returns twice, once in parent and once in child.*/dofork(){ register int pid; DOFORK(fork); return (pid);}/*** SENDOFF -- send off call to mailer & collect response.**** Parameters:** e -- the envelope to mail.** m -- mailer descriptor.** pvp -- parameter vector to send to it.** ctladdr -- an address pointer controlling the** user/groupid etc. of the mailer.**** Returns:** exit status of mailer.**** Side Effects:** none.*/sendoff(e, m, pvp, ctladdr) register ENVELOPE *e; MAILER *m; char **pvp; ADDRESS *ctladdr;{ auto FILE *mfile; auto FILE *rfile; register int i; int pid; /* ** Create connection to mailer. */ pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); if (pid < 0) return (-1); /* ** Format and send message. */ putfromline(mfile, m); (*e->e_puthdr)(mfile, m, e); putline("\n", mfile, m); (*e->e_putbody)(mfile, m, e); (void) fclose(mfile); i = endmailer(pid, pvp[0]); /* arrange a return receipt if requested */ if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) { e->e_flags |= EF_SENDRECEIPT; /* do we want to send back more info? */ } return (i);}/*** ENDMAILER -- Wait for mailer to terminate.**** We should never get fatal errors (e.g., segmentation** violation), so we report those specially. For other** errors, we choose a status message (into statmsg),** and if it represents an error, we print it.**** Parameters:** pid -- pid of mailer.** name -- name of mailer (for error messages).**** Returns:** exit code of mailer.**** Side Effects:** none.*/endmailer(pid, name) int pid; char *name;{ int st; /* in the IPC case there is nothing to wait for */ if (pid == 0) return (EX_OK); /* wait for the mailer process to die and collect status */ st = waitfor(pid); if (st == -1) { syserr("endmailer %s: wait", name); return (EX_SOFTWARE); } /* see if it died a horrid death */ if ((st & 0377) != 0) { syserr("mailer %s died with signal %o", name, st); ExitStat = EX_TEMPFAIL; return (EX_TEMPFAIL); } /* normal death -- return status */ st = (st >> 8) & 0377; return (st);}/*** OPENMAILER -- open connection to mailer.**** Parameters:** m -- mailer descriptor.** pvp -- parameter vector to pass to mailer.** ctladdr -- controlling address for user.** clever -- create a full duplex connection.** pmfile -- pointer to mfile (to mailer) connection.** prfile -- pointer to rfile (from mailer) connection.**** Returns:** pid of mailer ( > 0 ).** -1 on error.** zero on an IPC connection.**** Side Effects:** creates a mailer in a subprocess.*/openmailer(m, pvp, ctladdr, clever, pmfile, prfile) MAILER *m; char **pvp; ADDRESS *ctladdr; bool clever; FILE **pmfile; FILE **prfile;{ int pid; int mpvect[2]; int rpvect[2]; FILE *mfile; FILE *rfile; extern FILE *fdopen();# ifdef DEBUG if (tTd(11, 1)) { printf("openmailer:"); printav(pvp); }# endif DEBUG errno = 0; CurHostName = m->m_mailer; /* ** Deal with the special case of mail handled through an IPC ** connection. ** In this case we don't actually fork. We must be ** running SMTP for this to work. We will return a ** zero pid to indicate that we are running IPC. ** We also handle a debug version that just talks to stdin/out. */#ifdef DEBUG /* check for Local Person Communication -- not for mortals!!! */ if (strcmp(m->m_mailer, "[LPC]") == 0) { *pmfile = stdout; *prfile = stdin; return (0); }#endif DEBUG if (strcmp(m->m_mailer, "[IPC]") == 0) {#ifdef HOSTINFO register STAB *st; extern STAB *stab();#endif HOSTINFO#ifdef DAEMON register int i, j; register u_short port; CurHostName = pvp[1]; if (!clever) syserr("non-clever IPC"); if (pvp[2] != NULL) port = atoi(pvp[2]); else port = 0; for (j = 0; j < nmx; j++) { CurHostName = mxhosts[j];#ifdef HOSTINFO /* see if we have already determined that this host is fried */ st = stab(mxhosts[j], ST_HOST, ST_FIND); if (st == NULL || st->s_host.ho_exitstat == EX_OK) i = makeconnection(mxhosts[j], port, pmfile, prfile); else { i = st->s_host.ho_exitstat; errno = st->s_host.ho_errno; }#else HOSTINFO i = makeconnection(mxhosts[j], port, pmfile, prfile);#endif HOSTINFO if (i != EX_OK) { /* * Consider the case of multiple MX entries * for a given host where the last entry refers * to non-existent host. On occasions when * none of the hosts are reachable, the mail * will bounce if the last ExitStat is * EX_NOHOST. Handle this by resetting i to * EX_TEMPFAIL if it's not the primary MX entry * and it's the last MX entry. -pbp */#ifdef LOG if (i == EX_NOHOST) syslog(LOG_WARNING, "Found non-existent host %s in MX records for %s", CurHostName, pvp[1]);#endif LOG if (j != 0 && j == (nmx - 1)) i = EX_TEMPFAIL;#ifdef HOSTINFO /* enter status of this host */ if (st == NULL) st = stab(mxhosts[j], ST_HOST, ST_ENTER); st->s_host.ho_exitstat = i; st->s_host.ho_errno = errno;#endif HOSTINFO ExitStat = i; continue; } else return (0); } return (-1);#else DAEMON syserr("openmailer: no IPC"); return (-1);#endif DAEMON } /* create a pipe to shove the mail through */ if (pipe(mpvect) < 0) { syserr("openmailer: pipe (to mailer)"); return (-1); }#ifdef SMTP /* if this mailer speaks smtp, create a return pipe */ if (clever && pipe(rpvect) < 0) { syserr("openmailer: pipe (from mailer)"); (void) close(mpvect[0]); (void) close(mpvect[1]); return (-1); }#endif SMTP /* ** Actually fork the mailer process. ** DOFORK is clever about retrying. ** ** Dispose of SIGCHLD signal catchers that may be laying ** around so that endmail will get it. */ if (CurEnv->e_xfp != NULL) (void) fflush(CurEnv->e_xfp); /* for debugging */ (void) fflush(stdout);# ifdef SIGCHLD (void) signal(SIGCHLD, SIG_DFL);# endif SIGCHLD DOFORK(XFORK); /* pid is set by DOFORK */ if (pid < 0) { /* failure */ syserr("openmailer: cannot fork"); (void) close(mpvect[0]); (void) close(mpvect[1]);#ifdef SMTP if (clever) { (void) close(rpvect[0]); (void) close(rpvect[1]); }#endif SMTP return (-1); } else if (pid == 0) { int i; extern int DtableSize; /* child -- set up input & exec mailer */ /* make diagnostic output be standard output */ (void) signal(SIGINT, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGTERM, SIG_DFL); /* arrange to filter standard & diag output of command */ if (clever) { (void) close(rpvect[0]); (void) close(1); (void) dup(rpvect[1]); (void) close(rpvect[1]); } else if (OpMode == MD_SMTP || HoldErrs) { /* put mailer output in transcript */ (void) close(1); (void) dup(fileno(CurEnv->e_xfp)); } (void) close(2); (void) dup(1); /* arrange to get standard input */ (void) close(mpvect[1]); (void) close(0); if (dup(mpvect[0]) < 0) { syserr("Cannot dup to zero!"); _exit(EX_OSERR); } (void) close(mpvect[0]); if (!bitnset(M_RESTR, m->m_flags)) { if (ctladdr == NULL || ctladdr->q_uid == 0) { (void) setgid(DefGid); (void) initgroups(DefUser, DefGid); (void) setuid(DefUid); } else { (void) setgid(ctladdr->q_gid); (void) initgroups(ctladdr->q_ruser ? ctladdr->q_ruser : ctladdr->q_user, ctladdr->q_gid); (void) setuid(ctladdr->q_uid); } } /* arrange for all the files to be closed */ for (i = 3; i < DtableSize; i++)#ifdef FIOCLEX (void) ioctl(i, FIOCLEX, 0);#else FIOCLEX (void) close(i);#endif FIOCLEX /* try to execute the mailer */ execve(m->m_mailer, pvp, UserEnviron);#ifdef FIOCLEX if (errno == ENOENT) { printf("554 Cannot exec %s\n", m->m_mailer); fflush(stdout); _exit(EX_UNAVAILABLE); } syserr("Cannot exec %s", m->m_mailer);#else FIOCLEX printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); (void) fflush(stdout);#endif FIOCLEX if (m == LocalMailer || errno == EIO || errno == EAGAIN || errno == ENOMEM || errno == EPROCLIM) _exit(EX_TEMPFAIL); else _exit(EX_UNAVAILABLE); } /* ** Set up return value. */ (void) close(mpvect[0]); mfile = fdopen(mpvect[1], "w"); if (clever) { (void) close(rpvect[1]); rfile = fdopen(rpvect[0], "r"); } *pmfile = mfile; *prfile = rfile; return (pid);}/*** GIVERESPONSE -- Interpret an error response from a mailer**** Parameters:** stat -- the status code from the mailer (high byte** only; core dumps must have been taken care of** already).** m -- the mailer descriptor for this mailer.**** Returns:** none.**** Side Effects:** Errors may be incremented.** ExitStat may be set.*/giveresponse(stat, m, e) int stat; register MAILER *m; ENVELOPE *e;{ register char *statmsg; extern char *SysExMsg[]; register int i; extern int N_SysEx; char buf[MAXLINE];#ifdef lint if (m == NULL) return;#endif lint /* ** Compute status message from code. */ i = stat - EX__BASE; if (stat == 0) statmsg = "250 Sent"; else if (i < 0 || i > N_SysEx)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -