📄 smtpcli.c
字号:
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <setjmp.h>
#ifdef UNIX
#include <sys/types.h>
#endif
#ifdef AMIGA
#include <stat.h>
#else
#include <sys/stat.h>
#endif
#ifdef __TURBOC__
#include <dir.h>
#include <io.h>
#endif
#include "global.h"
#include <stdarg.h>
#include "mbuf.h"
#include "cmdparse.h"
#include "proc.h"
#include "socket.h"
#include "timer.h"
#include "netuser.h"
#include "smtp.h"
#include "dirutil.h"
#include "commands.h"
#include "session.h"
static struct timer Smtpcli_t;
static int32 Gateway;
#ifdef SMTPTRACE
static unsigned short Smtptrace = 0; /* used for trace level */
static int dosmtptrace(int argc,char *argv[],void *p);
#endif
static unsigned short Smtpmaxcli = MAXSESSIONS; /* the max client connections allowed */
static int Smtpsessions = 0; /* number of client connections
* currently open */
static int Smtpbatch;
int Smtpmode = 0;
static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions */
static void del_job(struct smtp_job *jp);
static void del_session(struct smtpcli *cb);
static int dogateway(int argc,char *argv[],void *p);
static int dosmtpmaxcli(int argc,char *argv[],void *p);
static int dotimer(int argc,char *argv[],void *p);
static int dosmtpkill(int argc,char *argv[],void *p);
static int dosmtplist(int argc,char *argv[],void *p);
static int dobatch(int argc,char *argv[],void *p);
static void execjobs(void);
static int getresp(struct smtpcli *ftp,int mincode);
static void logerr(struct smtpcli *cb,char *line);
static struct smtpcli *lookup(int32 destaddr);
static struct smtpcli *newcb(void);
static int next_job(struct smtpcli *cb);
static void retmail(struct smtpcli *cb);
static void sendcmd(struct smtpcli *cb,char *fmt,...);
static int smtpsendfile(struct smtpcli *cb);
static int setsmtpmode(int argc,char *argv[],void *p);
static struct smtp_job *setupjob(struct smtpcli *cb,char *id,char *from);
static void smtp_send(int unused,void *cb1,void *p);
static int smtpkick(int argc,char *argv[],void *p);
static struct cmds Smtpcmds[] = {
"batch", dobatch, 0, 0, NULL,
"gateway", dogateway, 0, 0, NULL,
"mode", setsmtpmode, 0, 0, NULL,
"kick", smtpkick, 0, 0, NULL,
"kill", dosmtpkill, 0, 2, "kill <jobnumber>",
"list", dosmtplist, 0, 0, NULL,
"maxclients", dosmtpmaxcli, 0, 0, NULL,
"timer", dotimer, 0, 0, NULL,
#ifdef SMTPTRACE
"trace", dosmtptrace, 0, 0, NULL,
#endif
NULL,
};
int
dosmtp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Smtpcmds,argc,argv,p);
}
static int
dobatch(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Smtpbatch,"SMTP batching",argc,argv);
}
static int
dosmtpmaxcli(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setshort(&Smtpmaxcli,"Max clients",argc,argv);
}
static int
setsmtpmode(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if (argc < 2) {
printf("smtp mode: %s\n",
(Smtpmode & QUEUE) ? "queue" : "route");
} else {
switch(*argv[1]) {
case 'q':
Smtpmode |= QUEUE;
break;
case 'r':
Smtpmode &= ~QUEUE;
break;
default:
printf("Usage: smtp mode [queue | route]\n");
break;
}
}
return 0;
}
static int
dogateway(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int32 n;
if(argc < 2){
printf("%s\n",inet_ntoa(Gateway));
} else if((n = resolve(argv[1])) == 0){
printf(Badhost,argv[1]);
return 1;
} else
Gateway = n;
return 0;
}
#ifdef SMTPTRACE
static int
dosmtptrace(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setshort(&Smtptrace,"SMTP tracing",argc,argv);
}
#endif
/* list jobs wating to be sent in the mqueue */
static int
dosmtplist(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char tstring[80];
char line[20];
char host[LINELEN];
char to[LINELEN];
char from[LINELEN];
char *cp;
char status;
struct stat stbuf;
struct tm *tminfo, *localtime();
FILE *fp;
printf("S Job Size Date Time Host From\n");
filedir(Mailqueue,0,line);
while(line[0] != '\0') {
sprintf(tstring,"%s/%s",Mailqdir,line);
if ((fp = fopen(tstring,READ_TEXT)) == NULL) {
printf("Can't open %s: %s\n",tstring,sys_errlist[errno]);
continue;
}
if ((cp = strrchr(line,'.')) != NULL)
*cp = '\0';
sprintf(tstring,"%s/%s.lck",Mailqdir,line);
if (access(tstring,0))
status = ' ';
else
status = 'L';
sprintf(tstring,"%s/%s.txt",Mailqdir,line);
stat(tstring,&stbuf);
tminfo = localtime(&stbuf.st_ctime);
fgets(host,sizeof(host),fp);
rip(host);
fgets(from,sizeof(from),fp);
rip(from);
printf("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n ",
status, line, stbuf.st_size,
tminfo->tm_mon+1,
tminfo->tm_mday,
tminfo->tm_hour,
tminfo->tm_min,
host,from);
while (fgets(to,sizeof(to),fp) != NULL) {
rip(to);
printf("%s ",to);
}
printf("\n");
(void) fclose(fp);
kwait(NULL);
filedir(Mailqueue,1,line);
}
return 0;
}
/* kill a job in the mqueue */
static int
dosmtpkill(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char s[SLINELEN];
char *cp,c;
sprintf(s,"%s/%s.lck",Mailqdir,argv[1]);
cp = strrchr(s,'.');
if (!access(s,0)) {
Current->ttystate.echo = Current->ttystate.edit = 0;
c = keywait("Warning, the job is locked by SMTP. Remove (y/n)? ",0);
Current->ttystate.echo = Current->ttystate.edit = 1;
if (c != 'y')
return 0;
(void) unlink(s);
}
strcpy(cp,".wrk");
if (unlink(s))
printf("Job id %s not found\n",argv[1]);
strcpy(cp,".txt");
(void) unlink(s);
return 0;
}
/* Set outbound spool scan interval */
static int
dotimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
printf("%lu/%lu\n",
read_timer(&Smtpcli_t) /1000L,
dur_timer(&Smtpcli_t)/ 1000L);
return 0;
}
Smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
Smtpcli_t.arg = NULL; /* dummy value */
set_timer(&Smtpcli_t,atol(argv[1])*1000L); /* set timer duration */
start_timer(&Smtpcli_t); /* and fire it up */
return 0;
}
static int
smtpkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int32 addr = 0;
if(argc > 1 && (addr = resolve(argv[1])) == 0){
printf(Badhost,argv[1]);
return 1;
}
smtptick(addr);
return 0;
}
/* This is the routine that gets called every so often to do outgoing
* mail processing. When called with a null argument, it runs the entire
* queue; if called with a specific non-zero IP address from the remote
* kick server, it only starts up sessions to that address.
*/
int
smtptick(target)
int32 target;
{
register struct smtpcli *cb;
struct smtp_job *jp;
struct list *ap;
char tmpstring[LINELEN], wfilename[13], prefix[9];
char from[LINELEN], to[LINELEN];
char *cp, *cp1;
int32 destaddr;
FILE *wfile;
#ifdef SMTPTRACE
if (Smtptrace > 5)
printf("smtp daemon entered, target = %s\n",inet_ntoa(target));
#endif
if(availmem() != 0){
/* Memory is tight, don't do anything */
/* Restart timer */
start_timer(&Smtpcli_t);
return 0;
}
for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
filedir(Mailqueue,1,wfilename)){
/* save the prefix of the file name which it job id */
cp = wfilename;
cp1 = prefix;
while (*cp && *cp != '.')
*cp1++ = *cp++;
*cp1 = '\0';
/* lock this file from the smtp daemon */
if (mlock(Mailqdir,prefix))
continue;
sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
if ((wfile = fopen(tmpstring,READ_TEXT)) == NULL) {
/* probably too many open files */
(void) rmlock(Mailqdir,prefix);
/* continue to next message. The failure
* may be temporary */
continue;
}
(void) fgets(tmpstring,LINELEN,wfile); /* read target host */
rip(tmpstring);
if ((destaddr = mailroute(tmpstring)) == 0) {
fclose(wfile);
printf("** smtp: Unknown address %s\n",tmpstring);
(void) rmlock(Mailqdir,prefix);
continue;
}
if(target != 0 && destaddr != target){
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
continue; /* Not the proper target of a kick */
}
if ((cb = lookup(destaddr)) == NULL) {
/* there are enough processes running already */
if (Smtpsessions >= Smtpmaxcli) {
#ifdef SMTPTRACE
if (Smtptrace) {
printf("smtp daemon: too many processes\n");
}
#endif
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
break;
}
if ((cb = newcb()) == NULL) {
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
break;
}
cb->ipdest = destaddr;
cb->destname = strdup(tmpstring);
} else {
if(cb->lock){
/* This system is already is sending mail lets not
* interfere with its send queue.
*/
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
continue;
}
}
(void) fgets(from,LINELEN,wfile); /* read from */
rip(from);
if ((jp = setupjob(cb,prefix,from)) == NULL) {
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
del_session(cb);
break;
}
while (fgets(to,LINELEN,wfile) != NULL) {
rip(to);
if (addlist(&jp->to,to,DOMAIN) == NULL) {
fclose(wfile);
del_session(cb);
}
}
fclose(wfile);
#ifdef SMTPTRACE
if (Smtptrace > 1) {
printf("queue job %s From: %s To:",prefix,from);
for (ap = jp->to; ap != NULL; ap = ap->next)
printf(" %s",ap->val);
printf("\n");
}
#endif
}
/* start sending that mail */
execjobs();
/* Restart timer */
start_timer(&Smtpcli_t);
return 0;
}
/* This is the master state machine that handles a single SMTP transaction.
* It is called with a queue of jobs for a particular host.
* The logic is complicated by the "Smtpbatch" variable, which controls
* the batching of SMTP commands. If Smtpbatch is true, then many of the
* SMTP commands are sent in one swell foop before waiting for any of
* the responses. Unfortunately, this breaks many brain-damaged SMTP servers
* out there, so provisions have to be made to operate SMTP in lock-step mode.
*/
static void
smtp_send(unused,cb1,p)
int unused;
void *cb1;
void *p;
{
register struct smtpcli *cb;
register struct list *tp;
struct sockaddr_in fsocket;
char *cp;
int rcode;
int rcpts;
int goodrcpt;
int i,s;
int init = 1;
cb = (struct smtpcli *)cb1;
cb->lock = 1;
fsocket.sin_family = AF_INET;
fsocket.sin_addr.s_addr = cb->ipdest;
fsocket.sin_port = IPPORT_SMTP;
s = socket(AF_INET,SOCK_STREAM,0);
#ifdef SMTPTRACE
if (Smtptrace)
printf("SMTP client Trying...\n");
#endif
if(connect(s,(struct sockaddr *)&fsocket,SOCKSIZE) == 0){
cb->network = fdopen(s,"r+t");
#ifdef SMTPTRACE
if (Smtptrace)
printf("Connected\n");
#endif
} else {
cp = sockerr(s);
#ifdef SMTPTRACE
if (Smtptrace)
printf("Connect failed: %s\n",cp != NULL ? cp : "");
#endif
logmsg(s,"SMTP %s Connect failed: %s",psocket(&fsocket),
cp != NULL ? cp : "");
}
if(!Smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -