📄 savemail.c
字号:
}
/* Final-Recipient: -- the name from the RCPT command */
p = e->e_parent->e_from.q_mailer->m_addrtype;
if (p == NULL)
p = "rfc822";
for (r = q; r->q_alias != NULL; r = r->q_alias)
continue;
if (strcasecmp(p, "rfc822") != 0)
{
(void) snprintf(buf, sizeof buf,
"Final-Recipient: %s; %.800s",
r->q_mailer->m_addrtype,
r->q_user);
}
else if (strchr(r->q_user, '@') != NULL)
{
(void) snprintf(buf, sizeof buf,
"Final-Recipient: %s; %.800s",
p, r->q_user);
}
else if (strchr(r->q_paddr, '@') != NULL)
{
char *qp;
bool b;
qp = r->q_paddr;
/* strip brackets from address */
b = FALSE;
if (*qp == '<')
{
b = qp[strlen(qp) - 1] == '>';
if (b)
qp[strlen(qp) - 1] = '\0';
qp++;
}
(void) snprintf(buf, sizeof buf,
"Final-Recipient: %s; %.800s",
p, qp);
/* undo damage */
if (b)
qp[strlen(qp)] = '>';
}
else
{
(void) snprintf(buf, sizeof buf,
"Final-Recipient: %s; %.700s@%.100s",
p, r->q_user, MyHostName);
}
putline(buf, mci);
/* X-Actual-Recipient: -- the real problem address */
if (r != q && q->q_user[0] != '\0')
{
if (q->q_mailer != NULL &&
q->q_mailer->m_addrtype != NULL)
p = q->q_mailer->m_addrtype;
else
p = "rfc822";
if (strcasecmp(p, "rfc822") == 0 &&
strchr(q->q_user, '@') == NULL)
{
(void) snprintf(buf, sizeof buf,
"X-Actual-Recipient: %s; %.700s@%.100s",
p, q->q_user,
MyHostName);
}
else
{
(void) snprintf(buf, sizeof buf,
"X-Actual-Recipient: %s; %.800s",
p, q->q_user);
}
putline(buf, mci);
}
/* Action: -- what happened? */
snprintf(buf, sizeof buf, "Action: %s", action);
putline(buf, mci);
/* Status: -- what _really_ happened? */
if (q->q_status != NULL)
p = q->q_status;
else if (QS_IS_BADADDR(q->q_state))
p = "5.0.0";
else if (QS_IS_QUEUEUP(q->q_state))
p = "4.0.0";
else
p = "2.0.0";
snprintf(buf, sizeof buf, "Status: %s", p);
putline(buf, mci);
/* Remote-MTA: -- who was I talking to? */
if (q->q_statmta != NULL)
{
if (q->q_mailer == NULL ||
(p = q->q_mailer->m_mtatype) == NULL)
p = "dns";
(void) snprintf(buf, sizeof buf,
"Remote-MTA: %s; %.800s",
p, q->q_statmta);
p = &buf[strlen(buf) - 1];
if (*p == '.')
*p = '\0';
putline(buf, mci);
}
/* Diagnostic-Code: -- actual result from other end */
if (q->q_rstatus != NULL)
{
p = q->q_mailer->m_diagtype;
if (p == NULL)
p = "smtp";
(void) snprintf(buf, sizeof buf,
"Diagnostic-Code: %s; %.800s",
p, q->q_rstatus);
putline(buf, mci);
}
/* Last-Attempt-Date: -- fine granularity */
if (q->q_statdate == (time_t) 0L)
q->q_statdate = curtime();
(void) snprintf(buf, sizeof buf,
"Last-Attempt-Date: %s",
arpadate(ctime(&q->q_statdate)));
putline(buf, mci);
/* Will-Retry-Until: -- for delayed messages only */
if (QS_IS_QUEUEUP(q->q_state))
{
time_t xdate;
xdate = e->e_parent->e_ctime +
TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
snprintf(buf, sizeof buf,
"Will-Retry-Until: %s",
arpadate(ctime(&xdate)));
putline(buf, mci);
}
}
}
#endif /* DSN */
/*
** Output text of original message
*/
putline("", mci);
if (bitset(EF_HAS_DF, e->e_parent->e_flags))
{
sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
!bitset(EF_NO_BODY_RETN, e->e_flags);
if (e->e_msgboundary == NULL)
{
if (sendbody)
putline(" ----- Original message follows -----\n", mci);
else
putline(" ----- Message header follows -----\n", mci);
}
else
{
(void) snprintf(buf, sizeof buf, "--%s",
e->e_msgboundary);
putline(buf, mci);
(void) snprintf(buf, sizeof buf, "Content-Type: %s",
sendbody ? "message/rfc822"
: "text/rfc822-headers");
putline(buf, mci);
p = hvalue("Content-Transfer-Encoding",
e->e_parent->e_header);
if (p != NULL && strcasecmp(p, "binary") != 0)
p = NULL;
if (p == NULL &&
bitset(EF_HAS8BIT, e->e_parent->e_flags))
p = "8bit";
if (p != NULL)
{
(void) snprintf(buf, sizeof buf,
"Content-Transfer-Encoding: %s",
p);
putline(buf, mci);
}
}
putline("", mci);
save_errno = errno;
putheader(mci, e->e_parent->e_header, e->e_parent, M87F_OUTER);
errno = save_errno;
if (sendbody)
putbody(mci, e->e_parent, e->e_msgboundary);
else if (e->e_msgboundary == NULL)
{
putline("", mci);
putline(" ----- Message body suppressed -----", mci);
}
}
else if (e->e_msgboundary == NULL)
{
putline(" ----- No message was collected -----\n", mci);
}
if (e->e_msgboundary != NULL)
{
putline("", mci);
(void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary);
putline(buf, mci);
}
putline("", mci);
(void) fflush(mci->mci_out);
/*
** Cleanup and exit
*/
if (errno != 0)
syserr("errbody: I/O error");
}
/*
** SMTPTODSN -- convert SMTP to DSN status code
**
** Parameters:
** smtpstat -- the smtp status code (e.g., 550).
**
** Returns:
** The DSN version of the status code.
*/
char *
smtptodsn(smtpstat)
int smtpstat;
{
if (smtpstat < 0)
return "4.4.2";
switch (smtpstat)
{
case 450: /* Req mail action not taken: mailbox unavailable */
return "4.2.0";
case 451: /* Req action aborted: local error in processing */
return "4.3.0";
case 452: /* Req action not taken: insufficient sys storage */
return "4.3.1";
case 500: /* Syntax error, command unrecognized */
return "5.5.2";
case 501: /* Syntax error in parameters or arguments */
return "5.5.4";
case 502: /* Command not implemented */
return "5.5.1";
case 503: /* Bad sequence of commands */
return "5.5.1";
case 504: /* Command parameter not implemented */
return "5.5.4";
case 550: /* Req mail action not taken: mailbox unavailable */
return "5.2.0";
case 551: /* User not local; please try <...> */
return "5.1.6";
case 552: /* Req mail action aborted: exceeded storage alloc */
return "5.2.2";
case 553: /* Req action not taken: mailbox name not allowed */
return "5.1.0";
case 554: /* Transaction failed */
return "5.0.0";
}
if ((smtpstat / 100) == 2)
return "2.0.0";
if ((smtpstat / 100) == 4)
return "4.0.0";
return "5.0.0";
}
/*
** XTEXTIFY -- take regular text and turn it into DSN-style xtext
**
** Parameters:
** t -- the text to convert.
** taboo -- additional characters that must be encoded.
**
** Returns:
** The xtext-ified version of the same string.
*/
char *
xtextify(t, taboo)
register char *t;
char *taboo;
{
register char *p;
int l;
int nbogus;
static char *bp = NULL;
static int bplen = 0;
if (taboo == NULL)
taboo = "";
/* figure out how long this xtext will have to be */
nbogus = l = 0;
for (p = t; *p != '\0'; p++)
{
register int c = (*p & 0xff);
/* ASCII dependence here -- this is the way the spec words it */
if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
strchr(taboo, c) != NULL)
nbogus++;
l++;
}
if (nbogus == 0)
return t;
l += nbogus * 2 + 1;
/* now allocate space if necessary for the new string */
if (l > bplen)
{
if (bp != NULL)
free(bp);
bp = xalloc(l);
bplen = l;
}
/* ok, copy the text with byte expansion */
for (p = bp; *t != '\0'; )
{
register int c = (*t++ & 0xff);
/* ASCII dependence here -- this is the way the spec words it */
if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
strchr(taboo, c) != NULL)
{
*p++ = '+';
*p++ = "0123456789ABCDEF"[c >> 4];
*p++ = "0123456789ABCDEF"[c & 0xf];
}
else
*p++ = c;
}
*p = '\0';
return bp;
}
/*
** XUNTEXTIFY -- take xtext and turn it into plain text
**
** Parameters:
** t -- the xtextified text.
**
** Returns:
** The decoded text. No attempt is made to deal with
** null strings in the resulting text.
*/
char *
xuntextify(t)
register char *t;
{
register char *p;
int l;
static char *bp = NULL;
static int bplen = 0;
/* heuristic -- if no plus sign, just return the input */
if (strchr(t, '+') == NULL)
return t;
/* xtext is always longer than decoded text */
l = strlen(t);
if (l > bplen)
{
if (bp != NULL)
free(bp);
bp = xalloc(l);
bplen = l;
}
/* ok, copy the text with byte compression */
for (p = bp; *t != '\0'; t++)
{
register int c = *t & 0xff;
if (c != '+')
{
*p++ = c;
continue;
}
c = *++t & 0xff;
if (!isascii(c) || !isxdigit(c))
{
/* error -- first digit is not hex */
usrerr("bogus xtext: +%c", c);
t--;
continue;
}
if (isdigit(c))
c -= '0';
else if (isupper(c))
c -= 'A' - 10;
else
c -= 'a' - 10;
*p = c << 4;
c = *++t & 0xff;
if (!isascii(c) || !isxdigit(c))
{
/* error -- second digit is not hex */
usrerr("bogus xtext: +%x%c", *p >> 4, c);
t--;
continue;
}
if (isdigit(c))
c -= '0';
else if (isupper(c))
c -= 'A' - 10;
else
c -= 'a' - 10;
*p++ |= c;
}
*p = '\0';
return bp;
}
/*
** XTEXTOK -- check if a string is legal xtext
**
** Xtext is used in Delivery Status Notifications. The spec was
** taken from RFC 1891, ``SMTP Service Extension for Delivery
** Status Notifications''.
**
** Parameters:
** s -- the string to check.
**
** Returns:
** TRUE -- if 's' is legal xtext.
** FALSE -- if it has any illegal characters in it.
*/
bool
xtextok(s)
char *s;
{
int c;
while ((c = *s++) != '\0')
{
if (c == '+')
{
c = *s++;
if (!isascii(c) || !isxdigit(c))
return FALSE;
c = *s++;
if (!isascii(c) || !isxdigit(c))
return FALSE;
}
else if (c < '!' || c > '~' || c == '=')
return FALSE;
}
return TRUE;
}
/*
** PRUNEROUTE -- prune an RFC-822 source route
**
** Trims down a source route to the last internet-registered hop.
** This is encouraged by RFC 1123 section 5.3.3.
**
** Parameters:
** addr -- the address
**
** Returns:
** TRUE -- address was modified
** FALSE -- address could not be pruned
**
** Side Effects:
** modifies addr in-place
*/
static bool
pruneroute(addr)
char *addr;
{
#if NAMED_BIND
char *start, *at, *comma;
char c;
int rcode;
int i;
char hostbuf[BUFSIZ];
char *mxhosts[MAXMXHOSTS + 1];
/* check to see if this is really a route-addr */
if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
return FALSE;
start = strchr(addr, ':');
at = strrchr(addr, '@');
if (start == NULL || at == NULL || at < start)
return FALSE;
/* slice off the angle brackets */
i = strlen(at + 1);
if (i >= (SIZE_T) sizeof hostbuf)
return FALSE;
(void) strlcpy(hostbuf, at + 1, sizeof hostbuf);
hostbuf[i - 1] = '\0';
while (start)
{
if (getmxrr(hostbuf, mxhosts, NULL, FALSE, &rcode) > 0)
{
(void) strlcpy(addr + 1, start + 1, strlen(addr) - 1);
return TRUE;
}
c = *start;
*start = '\0';
comma = strrchr(addr, ',');
if (comma != NULL && comma[1] == '@' &&
strlen(comma + 2) < (SIZE_T) sizeof hostbuf)
(void) strlcpy(hostbuf, comma + 2, sizeof hostbuf);
else
comma = NULL;
*start = c;
start = comma;
}
#endif /* NAMED_BIND */
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -