📄 smtpcli.c
字号:
/* Say HELO */
sendcmd(cb,"HELO %s\n",Hostname);
if(!Smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
do { /* For each message... */
/* if this file open fails, skip it */
if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULL)
continue;
/* Send MAIL and RCPT commands */
sendcmd(cb,"MAIL FROM:<%s>\n",cb->jobq->from);
if(!Smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
rcpts = 0;
goodrcpt = 0;
for (tp = cb->jobq->to; tp != NULL; tp = tp->next){
sendcmd(cb,"RCPT TO:<%s>\n",tp->val);
if(!Smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1)
goto quit;
if(rcode < 400)
goodrcpt = 1; /* At least one good */
}
rcpts++;
}
/* Send DATA command */
sendcmd(cb,"DATA\n");
if(!Smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
if(Smtpbatch){
/* Now wait for the responses to come back. The first time
* we do this, we wait first for the start banner and
* HELO response. In any case, we wait for the response to
* the MAIL command here.
*/
for(i= init ? 3 : 1;i > 0;i--){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
init = 0;
/* Now process the responses to the RCPT commands */
for(i=rcpts;i!=0;i--){
rcode = getresp(cb,200);
if(rcode == -1)
goto quit;
if(rcode < 400)
goodrcpt = 1; /* At least one good */
}
/* And finally get the response to the DATA command.
* Some servers will return failure here if no recipients
* are valid, some won't.
*/
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
/* check for no good rcpt on the list */
if (goodrcpt == 0){
sendcmd(cb,".\n"); /* Get out of data mode */
goto quit;
}
}
/* Send the file. This also closes it */
smtpsendfile(cb);
/* Wait for the OK response */
rcode = getresp(cb,200);
if(rcode == -1)
goto quit;
if((rcode >= 200 && rcode < 300) || rcode >= 500){
/* if a good transfer or permanent failure remove job */
if (cb->errlog != NULL)
retmail(cb);
/* Unlink the textfile */
(void) unlink(cb->tname);
(void) unlink(cb->wname); /* unlink workfile */
logmsg(s,"SMTP sent job %s To: %s From: %s",
cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
}
} while(next_job(cb));
quit:
sendcmd(cb,"QUIT\n");
if (cb->errlog != NULL){
retmail(cb);
(void) unlink(cb->wname); /* unlink workfile */
(void) unlink(cb->tname); /* unlink text */
}
(void) fclose(cb->network);
if(cb->tfile != NULL)
fclose(cb->tfile);
cb->lock = 0;
del_session(cb);
}
/* create mail lockfile */
int
mlock(dir,id)
char *dir,*id;
{
char lockname[LINELEN];
int fd;
struct stat statbuf;
#ifdef MSDOS
if(strlen(id) > 8) { /* truncate long filenames */
id[8] = '\0';
if(id[7] == '/')
id[7] = '\0';
}
#endif
/* Try to create the lock file in an atomic operation */
sprintf(lockname,"%s/%s.lck",dir,id);
#ifdef AMIGA
/* don't ask, really, just don't ask... I'd do file locking on
* an Amiga much more differently than this.
*/
if(access(lockname, 0) == 0)
return -1;
#endif
fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600);
if(fd != -1){
/* Lock succeeded */
close(fd);
return 0;
}
/* See if the dir doesn't exist */
if(stat(dir,&statbuf) == -1 || (statbuf.st_mode & S_IFMT) != S_IFDIR){
printf("Lock directory %s missing\n",dir);
fflush(stdout);
return 0;
}
return -1; /* lock failed */
}
/* remove mail lockfile */
int
rmlock(dir,id)
char *dir,*id;
{
char lockname[LINELEN];
#ifdef MSDOS
if(strlen(id) > 8) { /* truncate long filenames */
id[8] = '\0';
if(id[7] == '/')
id[7] = '\0';
}
#endif
sprintf(lockname,"%s/%s.lck",dir,id);
return(unlink(lockname));
}
/* free the message struct and data */
static void
del_session(cb)
register struct smtpcli *cb;
{
register struct smtp_job *jp,*tp;
register int i;
if (cb == NULL)
return;
for(i=0; i<MAXSESSIONS; i++)
if(cli_session[i] == cb) {
cli_session[i] = NULL;
break;
}
free(cb->wname);
free(cb->tname);
free(cb->destname);
for (jp = cb->jobq; jp != NULL;jp = tp) {
tp = jp->next;
del_job(jp);
}
del_list(cb->errlog);
free(cb);
Smtpsessions--; /* number of connections active */
}
static void
del_job(jp)
register struct smtp_job *jp;
{
if ( *jp->jobname != '\0')
(void) rmlock(Mailqdir,jp->jobname);
free(jp->from);
del_list(jp->to);
free(jp);
}
/* delete a list of list structs */
void
del_list(lp)
struct list *lp;
{
register struct list *tp, *tp1;
for (tp = lp; tp != NULL; tp = tp1) {
tp1 = tp->next;
free(tp->val);
free(tp);
}
}
/* stub for calling mdaemon to return message to sender */
static void
retmail(cb)
struct smtpcli *cb;
{
FILE *infile;
#ifdef SMTPTRACE
if (Smtptrace > 5) {
printf("smtp job %s returned to sender\n",cb->wname);
}
#endif
if ((infile = fopen(cb->tname,READ_TEXT)) == NULL)
return;
mdaemon(infile,cb->jobq->from,cb->errlog,1);
fclose(infile);
}
/* look to see if a smtp control block exists for this ipdest */
static struct smtpcli *
lookup(destaddr)
int32 destaddr;
{
register int i;
for(i=0; i<MAXSESSIONS; i++) {
if (cli_session[i] == NULL)
continue;
if(cli_session[i]->ipdest == destaddr)
return cli_session[i];
}
return NULL;
}
/* create a new smtp control block */
static struct smtpcli *
newcb()
{
register int i;
register struct smtpcli *cb;
for(i=0; i<MAXSESSIONS; i++) {
if(cli_session[i] == NULL) {
cb = (struct smtpcli *)callocw(1,sizeof(struct smtpcli));
cb->wname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
cb->tname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
cli_session[i] = cb;
Smtpsessions++; /* number of connections active */
return(cb);
}
}
return NULL;
}
static void
execjobs()
{
register struct smtpcli *cb;
register int i;
for(i=0; i<MAXSESSIONS; i++) {
cb = cli_session[i];
if (cb == NULL)
continue;
if(cb->lock)
continue;
sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
newproc("smtp_send", 1024, smtp_send, 0, cb,NULL,0);
#ifdef SMTPTRACE
if (Smtptrace)
printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
#endif
}
}
/* add this job to control block queue */
static struct smtp_job *
setupjob(cb,id,from)
struct smtpcli *cb;
char *id,*from;
{
register struct smtp_job *p1,*p2;
p1 = (struct smtp_job *)callocw(1,sizeof(struct smtp_job));
p1->from = strdup(from);
strcpy(p1->jobname,id);
/* now add to end of jobq */
if ((p2 = cb->jobq) == NULL)
cb->jobq = p1;
else {
while(p2->next != NULL)
p2 = p2->next;
p2->next = p1;
}
return p1;
}
/* called to advance to the next job */
static int
next_job(cb)
register struct smtpcli *cb;
{
register struct smtp_job *jp;
jp = cb->jobq->next;
del_job(cb->jobq);
/* remove the error log of previous message */
del_list(cb->errlog);
cb->errlog = NULL;
cb->jobq = jp;
if (jp == NULL)
return 0;
sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
#ifdef SMTPTRACE
if (Smtptrace > 5) {
printf("sending job %s\n",jp->jobname);
}
#endif
return 1;
}
/* Mail routing function. For now just use the hosts file */
int32
mailroute(dest)
char *dest;
{
int32 destaddr;
/* look up address or use the gateway */
destaddr = resolve_mx(dest);
if (destaddr == 0 && (destaddr = resolve(dest)) == 0)
if (Gateway != 0)
destaddr = Gateway; /* Use the gateway */
return destaddr;
}
/* save line in error list */
static void
logerr(cb,line)
struct smtpcli *cb;
char *line;
{
register struct list *lp,*tp;
tp = (struct list *)callocw(1,sizeof(struct list));
tp->val = strdup(line);
/* find end of list */
if ((lp = cb->errlog) == NULL)
cb->errlog = tp;
else {
while(lp->next != NULL)
lp = lp->next;
lp->next = tp;
}
}
static int
smtpsendfile(cb)
register struct smtpcli *cb;
{
int error = 0;
strcpy(cb->buf,"\n");
while(fgets(cb->buf,sizeof(cb->buf),cb->tfile) != NULL) {
/* Escape a single '.' character at the beginning of a line */
if(strcmp(cb->buf,".\n") == 0)
putc('.',cb->network);
fputs(cb->buf,cb->network);
}
fclose(cb->tfile);
cb->tfile = NULL;
/* Send the end-of-message command */
if(cb->buf[strlen(cb->buf)-1] == '\n')
sendcmd(cb,".\n");
else
sendcmd(cb,"\n.\n");
return error;
}
/* do a printf() on the network stream with optional local tracing */
static void
sendcmd(struct smtpcli *cb,char *fmt, ...)
{
va_list args;
va_start(args,fmt);
#ifdef SMTPTRACE
if(Smtptrace){
printf("smtp sent: ");
vprintf(fmt,args);
}
#endif
vsprintf(cb->buf,fmt,args);
fputs(cb->buf,cb->network);
va_end(args);
}
/* Wait for, read and display response from server. Return the result code. */
static int
getresp(cb,mincode)
struct smtpcli *cb;
int mincode; /* Keep reading until at least this code comes back */
{
int rval;
char line[LINELEN];
fflush(cb->network);
for(;;){
/* Get line */
if(fgets(line,LINELEN,cb->network) == NULL){
rval = -1;
break;
}
rip(line); /* Remove cr/lf */
rval = atoi(line);
#ifdef SMTPTRACE
if(Smtptrace)
printf("smtp recv: %s\n",line);/* Display to user */
#endif
if(rval >= 500) { /* Save permanent error replies */
char tmp[LINELEN];
if(cb->errlog == NULL) {
sprintf(tmp,"While talking to %s:",
cb->destname);
logerr(cb,tmp);
}
if(cb->buf[0] != '\0') { /* Save offending command */
rip(cb->buf);
sprintf(tmp,">>> %s",cb->buf);
logerr(cb,tmp);
cb->buf[0] = '\0';
}
sprintf(tmp,"<<< %s",line);
logerr(cb,tmp); /* save the error reply */
}
/* Messages with dashes are continued */
if(line[3] != '-' && rval >= mincode)
break;
}
return rval;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -