Thanks to John Cummings.
This commit is contained in:
parent
cd37451963
commit
5cdb17983a
94 changed files with 26853 additions and 0 deletions
575
src/cmd/upas/send/main.c
Normal file
575
src/cmd/upas/send/main.c
Normal file
|
|
@ -0,0 +1,575 @@
|
|||
#include "common.h"
|
||||
#include "send.h"
|
||||
|
||||
/* globals to all files */
|
||||
int rmail;
|
||||
char *thissys, *altthissys;
|
||||
int nflg;
|
||||
int xflg;
|
||||
int debug;
|
||||
int rflg;
|
||||
int iflg = 1;
|
||||
int nosummary;
|
||||
|
||||
/* global to this file */
|
||||
static String *errstring;
|
||||
static message *mp;
|
||||
static int interrupt;
|
||||
static int savemail;
|
||||
static Biobuf in;
|
||||
static int forked;
|
||||
static int add822headers = 1;
|
||||
static String *arglist;
|
||||
|
||||
/* predeclared */
|
||||
static int send(dest *, message *, int);
|
||||
static void lesstedious(void);
|
||||
static void save_mail(message *);
|
||||
static int complain_mail(dest *, message *);
|
||||
static int pipe_mail(dest *, message *);
|
||||
static void appaddr(String *, dest *);
|
||||
static void mkerrstring(String *, message *, dest *, dest *, char *, int);
|
||||
static int replymsg(String *, message *, dest *);
|
||||
static int catchint(void*, char*);
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: mail [-birtx] list-of-addresses\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
dest *dp=0;
|
||||
int checkforward;
|
||||
char *base;
|
||||
int rv;
|
||||
|
||||
/* process args */
|
||||
ARGBEGIN{
|
||||
case '#':
|
||||
nflg = 1;
|
||||
break;
|
||||
case 'b':
|
||||
add822headers = 0;
|
||||
break;
|
||||
case 'x':
|
||||
nflg = 1;
|
||||
xflg = 1;
|
||||
break;
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'i':
|
||||
iflg = 0;
|
||||
break;
|
||||
case 'r':
|
||||
rflg = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
while(*argv){
|
||||
if(shellchars(*argv)){
|
||||
fprint(2, "illegal characters in destination\n");
|
||||
exits("syntax");
|
||||
}
|
||||
d_insert(&dp, d_new(s_copy(*argv++)));
|
||||
}
|
||||
|
||||
if (dp == 0)
|
||||
usage();
|
||||
arglist = d_to(dp);
|
||||
|
||||
/*
|
||||
* get context:
|
||||
* - whether we're rmail or mail
|
||||
*/
|
||||
base = basename(argv0);
|
||||
checkforward = rmail = (strcmp(base, "rmail")==0) | rflg;
|
||||
thissys = sysname_read();
|
||||
altthissys = alt_sysname_read();
|
||||
if(rmail)
|
||||
add822headers = 0;
|
||||
|
||||
/*
|
||||
* read the mail. If an interrupt occurs while reading, save in
|
||||
* dead.letter
|
||||
*/
|
||||
if (!nflg) {
|
||||
Binit(&in, 0, OREAD);
|
||||
if(!rmail)
|
||||
atnotify(catchint, 1);
|
||||
mp = m_read(&in, rmail, !iflg);
|
||||
if (mp == 0)
|
||||
exit(0);
|
||||
if (interrupt != 0) {
|
||||
save_mail(mp);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
mp = m_new();
|
||||
if(default_from(mp) < 0){
|
||||
fprint(2, "%s: can't determine login name\n", argv0);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
errstring = s_new();
|
||||
getrules();
|
||||
|
||||
/*
|
||||
* If this is a gateway, translate the sender address into a local
|
||||
* address. This only happens if mail to the local address is
|
||||
* forwarded to the sender.
|
||||
*/
|
||||
gateway(mp);
|
||||
|
||||
/*
|
||||
* Protect against shell characters in the sender name for
|
||||
* security reasons.
|
||||
*/
|
||||
mp->sender = escapespecial(mp->sender);
|
||||
if (shellchars(s_to_c(mp->sender)))
|
||||
mp->replyaddr = s_copy("postmaster");
|
||||
else
|
||||
mp->replyaddr = s_clone(mp->sender);
|
||||
|
||||
/*
|
||||
* reject messages that have been looping for too long
|
||||
*/
|
||||
if(mp->received > 32)
|
||||
exit(refuse(dp, mp, "possible forward loop", 0, 0));
|
||||
|
||||
/*
|
||||
* reject messages that are too long. We don't do it earlier
|
||||
* in m_read since we haven't set up enough things yet.
|
||||
*/
|
||||
if(mp->size < 0)
|
||||
exit(refuse(dp, mp, "message too long", 0, 0));
|
||||
|
||||
rv = send(dp, mp, checkforward);
|
||||
if(savemail)
|
||||
save_mail(mp);
|
||||
if(mp)
|
||||
m_free(mp);
|
||||
exit(rv);
|
||||
}
|
||||
|
||||
/* send a message to a list of sites */
|
||||
static int
|
||||
send(dest *destp, message *mp, int checkforward)
|
||||
{
|
||||
dest *dp; /* destination being acted upon */
|
||||
dest *bound; /* bound destinations */
|
||||
int errors=0;
|
||||
|
||||
/* bind the destinations to actions */
|
||||
bound = up_bind(destp, mp, checkforward);
|
||||
if(add822headers && mp->haveto == 0){
|
||||
if(nosummary)
|
||||
mp->to = d_to(bound);
|
||||
else
|
||||
mp->to = arglist;
|
||||
}
|
||||
|
||||
/* loop through and execute commands */
|
||||
for (dp = d_rm(&bound); dp != 0; dp = d_rm(&bound)) {
|
||||
switch (dp->status) {
|
||||
case d_cat:
|
||||
errors += cat_mail(dp, mp);
|
||||
break;
|
||||
case d_pipeto:
|
||||
case d_pipe:
|
||||
if (!rmail && !nflg && !forked) {
|
||||
forked = 1;
|
||||
lesstedious();
|
||||
}
|
||||
errors += pipe_mail(dp, mp);
|
||||
break;
|
||||
default:
|
||||
errors += complain_mail(dp, mp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/* avoid user tedium (as Mike Lesk said in a previous version) */
|
||||
static void
|
||||
lesstedious(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(debug)
|
||||
return;
|
||||
|
||||
switch(fork()){
|
||||
case -1:
|
||||
break;
|
||||
case 0:
|
||||
sysdetach();
|
||||
for(i=0; i<3; i++)
|
||||
close(i);
|
||||
savemail = 0;
|
||||
break;
|
||||
default:
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* save the mail */
|
||||
static void
|
||||
save_mail(message *mp)
|
||||
{
|
||||
Biobuf *fp;
|
||||
String *file;
|
||||
|
||||
file = s_new();
|
||||
deadletter(file);
|
||||
fp = sysopen(s_to_c(file), "cAt", 0660);
|
||||
if (fp == 0)
|
||||
return;
|
||||
m_bprint(mp, fp);
|
||||
sysclose(fp);
|
||||
fprint(2, "saved in %s\n", s_to_c(file));
|
||||
s_free(file);
|
||||
}
|
||||
|
||||
/* remember the interrupt happened */
|
||||
|
||||
static int
|
||||
catchint(void *a, char *msg)
|
||||
{
|
||||
USED(a);
|
||||
if(strstr(msg, "interrupt") || strstr(msg, "hangup")) {
|
||||
interrupt = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dispose of incorrect addresses */
|
||||
static int
|
||||
complain_mail(dest *dp, message *mp)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
switch (dp->status) {
|
||||
case d_undefined:
|
||||
msg = "Invalid address"; /* a little different, for debugging */
|
||||
break;
|
||||
case d_syntax:
|
||||
msg = "invalid address";
|
||||
break;
|
||||
case d_unknown:
|
||||
msg = "unknown user";
|
||||
break;
|
||||
case d_eloop:
|
||||
case d_loop:
|
||||
msg = "forwarding loop";
|
||||
break;
|
||||
case d_noforward:
|
||||
if(dp->pstat && *s_to_c(dp->repl2))
|
||||
return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat, 0);
|
||||
else
|
||||
msg = "destination unknown or forwarding disallowed";
|
||||
break;
|
||||
case d_pipe:
|
||||
msg = "broken pipe";
|
||||
break;
|
||||
case d_cat:
|
||||
msg = "broken cat";
|
||||
break;
|
||||
case d_translate:
|
||||
if(dp->pstat && *s_to_c(dp->repl2))
|
||||
return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat, 0);
|
||||
else
|
||||
msg = "name translation failed";
|
||||
break;
|
||||
case d_alias:
|
||||
msg = "broken alias";
|
||||
break;
|
||||
case d_badmbox:
|
||||
msg = "corrupted mailbox";
|
||||
break;
|
||||
case d_resource:
|
||||
return refuse(dp, mp, "out of some resource. Try again later.", 0, 1);
|
||||
default:
|
||||
msg = "unknown d_";
|
||||
break;
|
||||
}
|
||||
if (nflg) {
|
||||
print("%s: %s\n", msg, s_to_c(dp->addr));
|
||||
return 0;
|
||||
}
|
||||
return refuse(dp, mp, msg, 0, 0);
|
||||
}
|
||||
|
||||
/* dispose of remote addresses */
|
||||
static int
|
||||
pipe_mail(dest *dp, message *mp)
|
||||
{
|
||||
dest *next, *list=0;
|
||||
String *cmd;
|
||||
process *pp;
|
||||
int status;
|
||||
char *none;
|
||||
String *errstring=s_new();
|
||||
|
||||
if (dp->status == d_pipeto)
|
||||
none = "none";
|
||||
else
|
||||
none = 0;
|
||||
/*
|
||||
* collect the arguments
|
||||
*/
|
||||
next = d_rm_same(&dp);
|
||||
if(xflg)
|
||||
cmd = s_new();
|
||||
else
|
||||
cmd = s_clone(next->repl1);
|
||||
for(; next != 0; next = d_rm_same(&dp)){
|
||||
if(xflg){
|
||||
s_append(cmd, s_to_c(next->addr));
|
||||
s_append(cmd, "\n");
|
||||
} else {
|
||||
if (next->repl2 != 0) {
|
||||
s_append(cmd, " ");
|
||||
s_append(cmd, s_to_c(next->repl2));
|
||||
}
|
||||
}
|
||||
d_insert(&list, next);
|
||||
}
|
||||
|
||||
if (nflg) {
|
||||
if(xflg)
|
||||
print("%s", s_to_c(cmd));
|
||||
else
|
||||
print("%s\n", s_to_c(cmd));
|
||||
s_free(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* run the process
|
||||
*/
|
||||
pp = proc_start(s_to_c(cmd), instream(), 0, outstream(), 1, none);
|
||||
if(pp==0 || pp->std[0]==0 || pp->std[2]==0)
|
||||
return refuse(list, mp, "out of processes, pipes, or memory", 0, 1);
|
||||
pipesig(0);
|
||||
m_print(mp, pp->std[0]->fp, thissys, 0);
|
||||
pipesigoff();
|
||||
stream_free(pp->std[0]);
|
||||
pp->std[0] = 0;
|
||||
while(s_read_line(pp->std[2]->fp, errstring))
|
||||
;
|
||||
status = proc_wait(pp);
|
||||
proc_free(pp);
|
||||
s_free(cmd);
|
||||
|
||||
/*
|
||||
* return status
|
||||
*/
|
||||
if (status != 0)
|
||||
return refuse(list, mp, s_to_c(errstring), status, 0);
|
||||
loglist(list, mp, "remote");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
appaddr(String *sp, dest *dp)
|
||||
{
|
||||
dest *parent;
|
||||
String *s;
|
||||
|
||||
if (dp->parent != 0) {
|
||||
for(parent=dp->parent; parent->parent!=0; parent=parent->parent)
|
||||
;
|
||||
s = unescapespecial(s_clone(parent->addr));
|
||||
s_append(sp, s_to_c(s));
|
||||
s_free(s);
|
||||
s_append(sp, "' alias `");
|
||||
}
|
||||
s = unescapespecial(s_clone(dp->addr));
|
||||
s_append(sp, s_to_c(s));
|
||||
s_free(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* reject delivery
|
||||
*
|
||||
* returns 0 - if mail has been disposed of
|
||||
* other - if mail has not been disposed
|
||||
*/
|
||||
int
|
||||
refuse(dest *list, message *mp, char *cp, int status, int outofresources)
|
||||
{
|
||||
String *errstring=s_new();
|
||||
dest *dp;
|
||||
int rv;
|
||||
|
||||
dp = d_rm(&list);
|
||||
mkerrstring(errstring, mp, dp, list, cp, status);
|
||||
|
||||
/*
|
||||
* log first in case we get into trouble
|
||||
*/
|
||||
logrefusal(dp, mp, s_to_c(errstring));
|
||||
|
||||
/*
|
||||
* bulk mail is never replied to, if we're out of resources,
|
||||
* let the sender try again
|
||||
*/
|
||||
if(rmail){
|
||||
/* accept it or request a retry */
|
||||
if(outofresources){
|
||||
fprint(2, "Mail %s\n", s_to_c(errstring));
|
||||
rv = 1; /* try again later */
|
||||
} else if(mp->bulk)
|
||||
rv = 0; /* silently discard bulk */
|
||||
else
|
||||
rv = replymsg(errstring, mp, dp); /* try later if we can't reply */
|
||||
} else {
|
||||
/* aysnchronous delivery only happens if !rmail */
|
||||
if(forked){
|
||||
/*
|
||||
* if spun off for asynchronous delivery, we own the mail now.
|
||||
* return it or dump it on the floor. rv really doesn't matter.
|
||||
*/
|
||||
rv = 0;
|
||||
if(!outofresources && !mp->bulk)
|
||||
replymsg(errstring, mp, dp);
|
||||
} else {
|
||||
fprint(2, "Mail %s\n", s_to_c(errstring));
|
||||
savemail = 1;
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
|
||||
s_free(errstring);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* make the error message */
|
||||
static void
|
||||
mkerrstring(String *errstring, message *mp, dest *dp, dest *list, char *cp, int status)
|
||||
{
|
||||
dest *next;
|
||||
char smsg[64];
|
||||
String *sender;
|
||||
|
||||
sender = unescapespecial(s_clone(mp->sender));
|
||||
|
||||
/* list all aliases */
|
||||
s_append(errstring, " from '");
|
||||
s_append(errstring, s_to_c(sender));
|
||||
s_append(errstring, "'\nto '");
|
||||
appaddr(errstring, dp);
|
||||
for(next = d_rm(&list); next != 0; next = d_rm(&list)) {
|
||||
s_append(errstring, "'\nand '");
|
||||
appaddr(errstring, next);
|
||||
d_insert(&dp, next);
|
||||
}
|
||||
s_append(errstring, "'\nfailed with error '");
|
||||
s_append(errstring, cp);
|
||||
s_append(errstring, "'.\n");
|
||||
|
||||
/* >> and | deserve different flavored messages */
|
||||
switch(dp->status) {
|
||||
case d_pipe:
|
||||
s_append(errstring, "The mailer `");
|
||||
s_append(errstring, s_to_c(dp->repl1));
|
||||
sprint(smsg, "' returned error status %x.\n\n", status);
|
||||
s_append(errstring, smsg);
|
||||
break;
|
||||
}
|
||||
|
||||
s_free(sender);
|
||||
}
|
||||
|
||||
/*
|
||||
* create a new boundary
|
||||
*/
|
||||
static String*
|
||||
mkboundary(void)
|
||||
{
|
||||
char buf[32];
|
||||
int i;
|
||||
static int already;
|
||||
|
||||
if(already == 0){
|
||||
srand((time(0)<<16)|getpid());
|
||||
already = 1;
|
||||
}
|
||||
strcpy(buf, "upas-");
|
||||
for(i = 5; i < sizeof(buf)-1; i++)
|
||||
buf[i] = 'a' + nrand(26);
|
||||
buf[i] = 0;
|
||||
return s_copy(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* reply with up to 1024 characters of the
|
||||
* original message
|
||||
*/
|
||||
static int
|
||||
replymsg(String *errstring, message *mp, dest *dp)
|
||||
{
|
||||
message *refp = m_new();
|
||||
dest *ndp;
|
||||
char *rcvr;
|
||||
int rv;
|
||||
String *boundary;
|
||||
|
||||
boundary = mkboundary();
|
||||
|
||||
refp->bulk = 1;
|
||||
refp->rfc822headers = 1;
|
||||
rcvr = dp->status==d_eloop ? "postmaster" : s_to_c(mp->replyaddr);
|
||||
ndp = d_new(s_copy(rcvr));
|
||||
s_append(refp->sender, "postmaster");
|
||||
s_append(refp->replyaddr, "/dev/null");
|
||||
s_append(refp->date, thedate());
|
||||
refp->haveto = 1;
|
||||
s_append(refp->body, "To: ");
|
||||
s_append(refp->body, rcvr);
|
||||
s_append(refp->body, "\n");
|
||||
s_append(refp->body, "Subject: bounced mail\n");
|
||||
s_append(refp->body, "MIME-Version: 1.0\n");
|
||||
s_append(refp->body, "Content-Type: multipart/mixed;\n");
|
||||
s_append(refp->body, "\tboundary=\"");
|
||||
s_append(refp->body, s_to_c(boundary));
|
||||
s_append(refp->body, "\"\n");
|
||||
s_append(refp->body, "Content-Disposition: inline\n");
|
||||
s_append(refp->body, "\n");
|
||||
s_append(refp->body, "This is a multi-part message in MIME format.\n");
|
||||
s_append(refp->body, "--");
|
||||
s_append(refp->body, s_to_c(boundary));
|
||||
s_append(refp->body, "\n");
|
||||
s_append(refp->body, "Content-Disposition: inline\n");
|
||||
s_append(refp->body, "Content-Type: text/plain; charset=\"US-ASCII\"\n");
|
||||
s_append(refp->body, "Content-Transfer-Encoding: 7bit\n");
|
||||
s_append(refp->body, "\n");
|
||||
s_append(refp->body, "The attached mail");
|
||||
s_append(refp->body, s_to_c(errstring));
|
||||
s_append(refp->body, "--");
|
||||
s_append(refp->body, s_to_c(boundary));
|
||||
s_append(refp->body, "\n");
|
||||
s_append(refp->body, "Content-Type: message/rfc822\n");
|
||||
s_append(refp->body, "Content-Disposition: inline\n\n");
|
||||
s_append(refp->body, s_to_c(mp->body));
|
||||
s_append(refp->body, "--");
|
||||
s_append(refp->body, s_to_c(boundary));
|
||||
s_append(refp->body, "--\n");
|
||||
|
||||
refp->size = s_len(refp->body);
|
||||
rv = send(ndp, refp, 0);
|
||||
m_free(refp);
|
||||
d_free(ndp);
|
||||
return rv;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue