|
|
researchv10 Norman
/*
* smtp -- client, send mail to remote smtp server
* TODO:
* allow partial delivery to multiple recipients when only some
* fail (maybe)
* send stuff from cmds.h instead of hard-coded here
*/
#define USAGE "usage: %s [-u] [-H helohost] [-d domain] [-a addr] [-f] [-D] [-L loglevel] sender targethost recip1 recip2 ...\n"
#include <stdio.h>
#include <ctype.h>
#include <sysexits.h>
#include "addrformat.h"
#include "smtp.h"
#include "string.h"
#include "aux.h"
#include "sys.h"
#ifndef DIALER
#define DIALER "tcp"
#endif
#ifndef SERVNAME
#define SERVNAME "smtp" /* service we wanna talk to */
#endif
char *progname;
int debug;
char *helohost;
int kludgepause = 0;
char *strcat(), *strcpy();
extern char *convertaddr();
extern int ipcdebug;
extern char *ipcpath();
static int errno;
static char errstr[128];
char *convertto();
/*
* main - parse arguments and handle options
*/
main(argc, argv)
int argc;
char *argv[];
{
register int c;
int errflg = 0;
int unixformat = 0;
int filter = 0;
char *domain = 0;
char *sender = 0;
char *host = 0;
char *addr = 0;
namelist *recips, *newname(), *appendname();
FILE *sfi, *sfo;
string *replyaddr=s_new();
string *hh;
extern int optind;
extern char *optarg;
umask(2);
progname = argv[0];
Openlog("smtp", LOG_PID, LOG_SMTP);
setlogmask(LOG_UPTO(DEFAULT_LOG_LEVEL));
while ((c = getopt(argc, argv, "ga:uDd:H:fL:K")) != EOF)
switch (c) {
case 'a': addr = optarg; break;
case 'u': unixformat++; break;
case 'D': debug++; ipcdebug++; break;
case 'd': domain = optarg; break;
case 'H': helohost = optarg; break;
case 'f': filter++; break;
case 'K': kludgepause++; break;
case 'L': setloglevel(optarg); break;
case '?':
default:
errflg++;
break;
}
if (errflg || (argc - optind) < 3) {
(void) fprintf(stderr, USAGE, progname);
Syslog(LOG_WARNING, "SMTP illegal usage.");
bomb(EX_USAGE);
}
/*
* figure out what to call ourselves
*/
if (helohost==NULL)
helohost=s_to_c(s_copy(sysname_read()));
/*
* if there is no domain in the helo host name
* and we the -d option is specified, domainify
* the helo host
*/
if(strchr(helohost, '.')==0 && domain){
hh = s_copy(helohost);
s_append(hh, domain);
helohost = s_to_c(hh);
}
/*
* put our address onto the reply address
*/
if(strchr(argv[optind], '!')==0 || !domain){
s_append(replyaddr, helohost);
s_append(replyaddr, "!");
s_append(replyaddr, argv[optind]);
} else {
s_append(replyaddr, argv[optind]);
}
optind++;
/*
* convert the arguments to 822 form
*/
sender = convertaddr(s_to_c(replyaddr), domain, SOURCEROUTE);
host = argv[optind++];
recips = newname(convertto(argv[optind++], unixformat, host));
for (; optind < argc; optind++)
recips = appendname(recips, convertto(argv[optind], unixformat, host));
/*
* run as a filter
*/
if ( filter ) {
do_data(unixformat, stdin, stdout, sender, recips, domain);
exit(0);
}
/*
* open connection
*/
setup(addr ? addr : host, &sfi, &sfo);
/*
* hold the conversation
*/
converse(unixformat, sender, recips, domain, sfi, sfo, stdin);
/* converse terminates with the appropriate exit code */
}
namelist *
newname(s)
char *s;
{
namelist *np;
np = (namelist *)malloc(sizeof(namelist));
if (np == NULL) {
Syslog(LOG_WARNING, "could not alloc (newname)");
bomb(1);
}
np->name = s;
np->next = NULL;
return np;
}
/* could add at beginning, but let's maintain original order */
namelist *
appendname(nl, s)
char *s;
namelist *nl;
{
register namelist *tl;
if (nl == NULL)
bomb(1); /* shouldn't happen */
for (tl=nl; tl->next!=NULL; tl=tl->next)
;
tl->next = newname(s);
return nl;
}
/*
* convert a destination address to outgoing format
*
* if unixformat, just leave it alone
*
* if not add the destination host name.
*/
char *
convertto(recip, unixformat, desthost)
char *recip;
char *desthost;
{
static string *buf;
if(unixformat)
return recip;
buf = s_reset(buf);
s_append(buf, desthost);
s_append(buf, "!");
s_append(buf, recip);
return convertaddr(s_to_c(buf), 0, SOURCEROUTE);
}
/*
* setup -- setup tcp/ip connection to/from server
*/
setup(host, sfip, sfop)
char *host;
FILE **sfip, **sfop;
{
int s;
char *path;
int localerr;
path = ipcpath(host, DIALER, SERVNAME);
Syslog(LOG_DEBUG, "Opening connection to %s\n", path);
if ((s = ipcopen(path, "")) < 0) {
extern int ipcerrno;
extern char syserrstr[];
char errbuf[256];
sprintf(errbuf, "SMTP connect error to %s", host);
ipcperror(errbuf);
Syslog(LOG_INFO, "%s: %s\n", errbuf, syserrstr);
bomb(ipcerrno);
}
if (((*sfip = fdopen(s, "r")) == (FILE *) NULL) ||
((*sfop = fdopen(s, "w")) == (FILE *) NULL)) {
perror("setup - fdopen");
Syslog(LOG_INFO, "setup - fdopen");
bomb(EX_IOERR);
}
}
/*
* bomb(code) - exit program, map smtp error code into mailsystem code
* Codes with EX_ are from <sysexits.h>
* Lines with FOO are placeholders until we decrypt more appropriate codes.
*/
bomb(code)
int code;
{
switch(code) {
case 451: /* some temporary error */
exit(EX_TEMPFAIL); /* try later */
/*NOTREACHED*/
case 554: /* syntax error in address */
case 552: /* message too long */
case 501: /* data format error */
exit(EX_DATAERR);
/*NOTREACHED*/
case 550: /* no such user */
exit(EX_NOUSER);
/*NOTREACHED*/
case EX_USAGE:
case EX_DATAERR:
case EX_NOINPUT:
case EX_NOUSER:
case EX_NOHOST:
case EX_UNAVAILABLE:
case EX_SOFTWARE:
case EX_OSERR:
case EX_OSFILE:
case EX_CANTCREAT:
case EX_IOERR:
case EX_TEMPFAIL:
case EX_PROTOCOL:
case EX_NOPERM:
exit(code);
/*NOTREACHED*/
default: /* can't happen? */
if ((code >= 400) && (code <= 499))
exit(EX_TEMPFAIL);
else {
Syslog(LOG_WARNING, "SMTP protocol error %d\n", code);
exit(EX_PROTOCOL); /* unknown error */
}
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.