SCCSID(@
(#)savemail.c 3.53 %G%);
** SAVEMAIL -- Save mail on error
** If mailing back errors, mail it back to the originator
** together with an error message; otherwise, just put it in
** dead.letter in the user's home directory (if he exists on
** e -- the envelope containing the message in error.
** Saves the letter, by writing or mailing it back to the
** sender, or by putting it in dead.letter in her home
register struct passwd
*pw
;
extern struct passwd
*getpwnam();
if (bitset(EF_RESPONSE
, e
->e_flags
))
message(Arpa_Info
, "Dumping junk mail");
e
->e_flags
&= ~EF_FATALERRS
;
** In the unhappy event we don't know who to return the mail
if (CurEnv
->e_returnto
== NULL
)
CurEnv
->e_returnto
= parse("root", (ADDRESS
*) NULL
, 0);
if (CurEnv
->e_returnto
== NULL
)
syserr("Cannot parse root!");
** If called from Eric Schmidt's network, do special mailback.
** Fundamentally, this is the mailback case except that
** it returns an OK exit status (assuming the return
** Also, if the from address is not local, mail it back.
if (ErrorMode
== EM_BERKNET
)
if (!bitset(M_LOCAL
, CurEnv
->e_returnto
->q_mailer
->m_flags
))
** If writing back, do it.
** If the user is still logged in on the same terminal,
** then write the error messages back to hir (sic).
** If not, mail back instead.
if (ErrorMode
== EM_WRITE
)
if (p
== NULL
|| freopen(p
, "w", stdout
) == NULL
)
expand("$n", buf
, &buf
[sizeof buf
- 1], e
);
printf("\r\nMessage from %s...\r\n", buf
);
printf("Errors occurred while sending mail.\r\n");
xfile
= fopen(queuename(e
, 'x'), "r");
syserr("Cannot open %s", queuename(e
, 'x'));
printf("Transcript of session is unavailable.\r\n");
printf("Transcript follows:\r\n");
while (fgets(buf
, sizeof buf
, xfile
) != NULL
&&
(void) syserr("savemail: stdout: write err");
** If mailing back, do it.
** Throw away all further output. Don't do aliases, since
** this could cause loops, e.g., if joe mails to x:joe,
** and for some reason the network for x: is down, then
** the response gets sent to x:joe, which gives a
** response, etc. Also force the mail to be delivered
** even if a version of it has already been sent to the
if (ErrorMode
== EM_MAIL
)
if (returntosender("Unable to deliver mail", CurEnv
->e_returnto
, TRUE
) == 0)
** Save the message in dead.letter.
** If we weren't mailing back, and the user is local, we
** should save the message in dead.letter so that the
** poor person doesn't have to type it over again --
** and we all know what poor typists programmers are.
if (CurEnv
->e_returnto
->q_mailer
== LocalMailer
)
if (CurEnv
->e_returnto
->q_home
!= NULL
)
p
= CurEnv
->e_returnto
->q_home
;
else if ((pw
= getpwnam(CurEnv
->e_returnto
->q_user
)) != NULL
)
syserr("Can't return mail to %s", CurEnv
->e_returnto
->q_paddr
);
if (p
!= NULL
&& e
->e_dfp
!= NULL
)
/* we have a home directory; open dead.letter */
expand("$z/dead.letter", buf
, &buf
[sizeof buf
- 1], e
);
message(Arpa_Info
, "Saving message in %s", buf
);
sendtolist(buf
, (ADDRESS
*) NULL
, &q
);
/* add terminator to writeback message */
if (ErrorMode
== EM_WRITE
)
** RETURNTOSENDER -- return a message to the sender with an error.
** msg -- the explanatory message.
** returnto -- the queue of people to send the message to.
** sendbody -- if TRUE, also send back the body of the
** message; otherwise just send the header.
** zero -- if everything went ok.
** Returns the current message to the sender via
#define MAXRETURNS 6 /* max depth of returning messages */
returntosender(msg
, returnto
, sendbody
)
extern putheader(), errbody();
extern ENVELOPE
*newenvelope();
printf("Return To Sender: msg=\"%s\", depth=%d, CurEnv=%x,\n",
msg
, returndepth
, CurEnv
);
printaddr(returnto
, TRUE
);
if (++returndepth
>= MAXRETURNS
)
if (returndepth
!= MAXRETURNS
)
syserr("returntosender: infinite recursion on %s", returnto
->q_paddr
);
/* don't "unrecurse" and fake a clean exit */
define('g', "$f", CurEnv
);
ee
= newenvelope(&errenvelope
);
ee
->e_puthdr
= putheader
;
ee
->e_flags
|= EF_RESPONSE
;
ee
->e_sendqueue
= returnto
;
for (q
= returnto
; q
!= NULL
; q
= q
->q_next
)
addheader("to", q
->q_paddr
, ee
);
addheader("subject", msg
, ee
);
/* fake up an address header for the from person */
expand("$n", buf
, &buf
[sizeof buf
- 1], CurEnv
);
if (parseaddr(buf
, &ee
->e_from
, -1) == NULL
)
syserr("Can't parse myself!");
/* push state into submessage */
define('x', "Mail Delivery Subsystem", ee
);
/* actually deliver the error message */
CurEnv
= CurEnv
->e_parent
;
/* should check for delivery errors here */
** ERRBODY -- output the body of an error message.
** Typically this is a copy of the transcript plus a copy of the
** original offending message.
** xfile -- the transcript file.
** fp -- the output file.
** xdot -- if set, use the SMTP hidden dot algorithm.
** e -- the envelope we are working in.
** Outputs the body of an error message.
register struct mailer
*m
;
bool fullsmtp
= bitset(M_FULLSMTP
, m
->m_flags
);
** Output transcript of errors
p
= queuename(e
->e_parent
, 'x');
if ((xfile
= fopen(p
, "r")) == NULL
)
syserr("Cannot open %s", p
);
fprintf(fp
, " ----- Transcript of session is unavailable -----\n");
fprintf(fp
, " ----- Transcript of session follows -----\n");
while (fgets(buf
, sizeof buf
, xfile
) != NULL
)
putline(buf
, fp
, fullsmtp
);
** Output text of original message
fprintf(fp
, "\n ----- Return message suppressed -----\n\n");
else if (e
->e_parent
->e_dfp
!= NULL
)
fprintf(fp
, "\n ----- Unsent message follows -----\n");
putheader(fp
, m
, e
->e_parent
);
putbody(fp
, m
, xdot
, e
->e_parent
);
fprintf(fp
, "\n ----- Message header follows -----\n");
putheader(fp
, m
, e
->e_parent
);
fprintf(fp
, "\n ----- No message was collected -----\n\n");
syserr("errbody: I/O error");