⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smtpserv.c

📁 uCLinux下的一个TCP/IP协议栈源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* SMTP Server state machine - see RFC 821
 */
#include <stdio.h>
#include <time.h>
#ifdef UNIX
#include <sys/types.h>
#endif
#if	defined(__STDC__) || defined(__TURBOC__)
#include <stdarg.h>
#endif
#include <ctype.h>
#include <setjmp.h>
#include "global.h"
#include "mbuf.h"
#include "cmdparse.h"
#include "socket.h"
#include "iface.h"
#include "proc.h"
#include "smtp.h"
#include "commands.h"
#include "dirutil.h"
#include "mailbox.h"
#include "bm.h"
#include "domain.h"

char *Days[7] = {  "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
char *Months[12] = { "Jan","Feb","Mar","Apr","May","Jun",
		"Jul","Aug","Sep","Oct","Nov","Dec" };



static struct list *expandalias(struct list **head,char *user);
static int  getmsgtxt(struct smtpsv *mp);
static struct smtpsv *mail_create(void);
static void mail_clean(struct smtpsv *mp);
static int mailit(FILE *data,char *from,struct list *tolist);
static int router_queue(FILE *data,char *from,struct list *to);
static void smtplog(char *fmt,...);
static void smtpserv(int s,void *unused,void *p);
static int mailuser(FILE *data,char *from,char *to);

/* Command table */
static char *commands[] = {
	"helo",
	"noop",
	"mail from:",
	"quit",
	"rcpt to:",
	"help",
	"data",
	"rset",
	"expn",
	NULL
};
enum smtp_cmd {
	HELO_CMD,
	NOOP_CMD,
	MAIL_CMD,
	QUIT_CMD,
	RCPT_CMD,
	HELP_CMD,
	DATA_CMD,
	RSET_CMD,
	EXPN_CMD
};

/* Reply messages */
static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
static char Banner[] = "220 %s SMTP ready\n";
static char Closing[] = "221 Closing\n";
static char Ok[] = "250 Ok\n";
static char Reset[] = "250 Reset state\n";
static char Sent[] = "250 Sent\n";
static char Ourname[] = "250 %s, Share and Enjoy!\n";
static char Enter[] = "354 Enter mail, end with .\n";
static char Ioerr[] = "452 Temp file write error\n";
static char Badcmd[] = "500 Command unrecognized\n";
static char Lowmem[] = "421 System overloaded, try again later\n";
static char Syntax[] = "501 Syntax error\n";
static char Needrcpt[] = "503 Need RCPT (recipient)\n";
static char Unknown[] = "550 <%s> address unknown\n";
static char Noalias[] = "550 No alias for <%s>\n";

static int Ssmtp = -1; /* prototype socket for service */

/* Start up SMTP receiver service */
int
smtp1(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	struct sockaddr_in lsocket;
	int s;
	FILE *network;

	if(Ssmtp != -1){
		return 0;
	}
	ksignal(Curproc,0);	/* Don't keep the parser waiting */
	chname(Curproc,"SMTP listener");

	lsocket.sin_family = AF_INET;
	lsocket.sin_addr.s_addr = INADDR_ANY;
	if(argc < 2)
		lsocket.sin_port = IPPORT_SMTP;
	else
		lsocket.sin_port = atoi(argv[1]);

	Ssmtp = socket(AF_INET,SOCK_STREAM,0);
	bind(Ssmtp,(struct sockaddr *)&lsocket,sizeof(lsocket));
	listen(Ssmtp,1);
	for(;;){
		if((s = accept(Ssmtp,NULL,(int *)NULL)) == -1)
			break;	/* Service is shutting down */

		network = fdopen(s,"r+t");
		if(availmem() != 0){
			fprintf(network,Lowmem);
			fclose(network);
		} else {
			/* Spawn a server */
			newproc("SMTP server",2048,smtpserv,s,(void *)network,NULL,0);
		}
	}
	return 0;
}

/* Shutdown SMTP service (existing connections are allowed to finish) */
int
smtp0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	close_s(Ssmtp);
	Ssmtp = -1;
	return 0;
}

static void
smtpserv(s,n,p)
int s;
void *n;
void *p;
{
	struct smtpsv *mp;
	char **cmdp,buf[LINELEN],*arg,*cp,*cmd,*newaddr;
	struct list *ap,*list;
	int cnt;
	char address_type;
	FILE *network;

	network = (FILE *)n;
	sockowner(fileno(network),Curproc);		/* We own it now */
	logmsg(fileno(network),"open SMTP");

	if((mp = mail_create()) == NULL){
		printf(Nospace);
		logmsg(fileno(network),"close SMTP - no space");
		fclose(network);
		return;
	}
	mp->network = network;

	(void) fprintf(network,Banner,Hostname);

loop:	if (fgets(buf,sizeof(buf),network) == NULL) {
		/* He closed on us */
		goto quit;
	}
	cnt = strlen(buf);
	if(cnt < 4){
		/* Can't be a legal command */
		fprintf(network,Badcmd);
		goto loop;
	}	
	rip(buf);
	cmd = buf;

	/* Translate entire buffer to lower case */
	for(cp = cmd;*cp != '\0';cp++)
		*cp = tolower(*cp);

	/* Find command in table; if not present, return syntax error */
	for(cmdp = commands;*cmdp != NULL;cmdp++)
		if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
			break;
	if(*cmdp == NULL){
		(void) fprintf(network,Badcmd);
		goto loop;
	}
	arg = &cmd[strlen(*cmdp)];
	/* Skip spaces after command */
	while(*arg == ' ')
		arg++;
	/* Execute specific command */
	switch(cmdp-commands) {
	case HELO_CMD:
		free(mp->system);
		mp->system = strdup(arg);
		(void) fprintf(network,Ourname,Hostname);
		break;
	case NOOP_CMD:
		(void) fprintf(network,Ok);
		break;
	case MAIL_CMD:
		if((cp = getname(arg)) == NULL){
			(void) fprintf(network,Syntax);
			break;
		}
		free(mp->from);
		mp->from = strdup(cp);
		(void) fprintf(network,Ok);
		break;
	case QUIT_CMD:
		(void) fprintf(network,Closing);
		goto quit;
	case RCPT_CMD:	/* Specify recipient */
		if((cp = getname(arg)) == NULL){
			(void) fprintf(network,Syntax);
			break;
		}

		/* rewrite address if possible */
		if((newaddr = rewrite_address(cp)) != NULL) {
			strcpy(buf,newaddr);
			cp = buf;
			free(newaddr);
		}

		/* check if address is ok */
		if ((address_type = validate_address(cp)) == BADADDR) {
			(void) fprintf(network,Unknown,cp);
			break;
		}
		/* if a local address check for an alias */
		if (address_type == LOCAL)
			expandalias(&mp->to, cp);
		else
			/* a remote address is added to the list */
			addlist(&mp->to, cp, address_type);

		(void) fprintf(network,Ok);
		break;
	case HELP_CMD:
		(void) fprintf(network,Help);
		break;
	case DATA_CMD:
		if(mp->to == NULL)
			(void) fprintf(network,Needrcpt);
		else if ((mp->data = tmpfile()) == NULL)
			(void) fprintf(network,Ioerr);
		 else
			getmsgtxt(mp);
		break;
	case RSET_CMD:
		del_list(mp->to);
		mp->to = NULL;
		(void) fprintf(network,Reset);
		break;
	case EXPN_CMD:
		if (*arg == '\0') {
			(void) fprintf(network,Syntax);
			break;
		}

		list = NULL;
		/* rewrite address if possible */
		if((newaddr = rewrite_address(arg)) != NULL)
			if(strcmp(newaddr,arg) == 0) {
				free(newaddr);
				newaddr = NULL;
			}
			else {
				strcpy(buf,newaddr);
				arg = buf;
			}
		list = NULL;
		expandalias(&list,arg);
		if (strcmp(list->val,arg) == 0 && list->next == NULL)
			if(newaddr == NULL) {
				(void) fprintf(network,Noalias,arg);
				del_list(list);
				break;
			}
		ap = list;
		while (ap->next != NULL) {
			(void) fprintf(network,"250-%s\n",ap->val);
			ap = ap->next;
		}
		fprintf(network,"250 %s\n",ap->val);
		del_list(list);
		free(newaddr);
		break;
	}
	goto loop;

quit:
	logmsg(fileno(network),"close SMTP");
	fclose(network);
	mail_clean(mp);
	smtptick(0L);			/* start SMTP daemon immediately */
}

/* read the message text */
static int
getmsgtxt(mp)
struct smtpsv *mp;
{
	char buf[LINELEN];
	register char *p = buf;
	long t;
	FILE *network;
	FILE *data;
	char *cp;

	network = mp->network;
	data = mp->data;
	/* Add timestamp; ptime adds newline */
	time(&t);
	fprintf(data,"Received: ");
	if(mp->system != NULL)
		fprintf(data,"from %s ",mp->system);
	fprintf(data,"by %s with SMTP\n\tid AA%ld ; %s",
			Hostname, get_msgid(), ptime(&t));
	if(ferror(data)){
		(void) fprintf(network,Ioerr);
		return 1;
	} else {
		(void) fprintf(network,Enter);
	}
	while(1) {
		if(fgets(p,sizeof(buf),network) == NULL){
			return 1;
		}
		rip(p);
		/* check for end of message ie a . or escaped .. */
		if (*p == '.') {
			if (*++p == '\0') {
				/* Also sends appropriate response */
				if (mailit(data,mp->from,mp->to) != 0)
					(void) fprintf(network,Ioerr);
				else
					(void) fprintf(network,Sent);
				fclose(data);
				data = NULL;
				del_list(mp->to);
				mp->to = NULL;
				return 0;
			} else if (!(*p == '.' && *(p+1) == '\0'))
				p--;
		}
#ifdef	MSDOS
		while((cp = strchr(p,CTLZ)) != NULL)
			*cp = '\n';
#endif
		/* for UNIX mail compatiblity */
		if (strncmp(p,"From ",5) == 0)
			(void) putc('>',data);
		/* Append to data file */
		if(fprintf(data,"%s\n",p) < 0) {
			(void) fprintf(network,Ioerr);
			return 1;
		}
	}
	return 0;
}

/* Create control block, initialize */
static struct smtpsv *
mail_create()
{
	register struct smtpsv *mp;

	mp = (struct smtpsv *)callocw(1,sizeof(struct smtpsv));
	mp->from = strdup("");	/* Default to null From address */
	return mp;
}

/* Free resources, delete control block */
static void
mail_clean(mp)
register struct smtpsv *mp;
{
	if (mp == NULL)
		return;
	free(mp->system);
	free(mp->from);
	if(mp->data != NULL)
		fclose(mp->data);
	del_list(mp->to);
	free(mp);
}


/* Given a string of the form <user@host>, extract the part inside the
 * brackets and return a pointer to it.
 */
char *
getname(cp)
register char *cp;
{
	register char *cp1;

	if ((cp = strchr(cp,'<')) == NULL)
		return NULL;
	cp++;	/* cp -> first char of name */
	if ((cp1 = strchr(cp,'>')) == NULL)
		return NULL;
	*cp1 = '\0';
	return cp;
}

		
/* General mailit function. It takes a list of addresses which have already
** been verified and expanded for aliases. Base on the current mode the message
** is place in an mbox, the outbound smtp queue or the rqueue interface
*/
static int
mailit(data,from,tolist)
FILE *data;
char *from;
struct list *tolist;
{
	struct list *ap, *dlist = NULL;
	register FILE *fp;
	char	mailbox[50], *cp, *host, *qhost;
	int	c, fail = 0;
	time_t	t;

	if ((Smtpmode & QUEUE) != 0)
		return(router_queue(data,from,tolist));

	do {
		qhost = NULL;
		for(ap = tolist;ap != NULL;ap = ap->next)
			if (ap->type == DOMAIN) {
				if ((host = strrchr(ap->val,'@')) != NULL)
					host++;
				else
					host = Hostname;
				if(qhost == NULL)
			     		qhost = host;
				if(stricmp(qhost,host) == 0) {
					ap->type = BADADDR;
					addlist(&dlist,ap->val,0);
				}
			}
		if(qhost != NULL) {
			rewind(data);
			queuejob(data,qhost,dlist,from);
			del_list(dlist);
			dlist = NULL;
		}
	} while(qhost != NULL);

	for(ap = tolist;ap != NULL;ap = ap->next) {
		if(ap->type != LOCAL) {
			ap->type = DOMAIN;
			continue;
		}
		rewind(data);
		/* strip off host name of LOCAL addresses */
		if ((cp = strchr(ap->val,'@')) != NULL)
			*cp = '\0';

		/* truncate long user names */
		if (strlen(ap->val) > MBOXLEN)
			ap->val[MBOXLEN] = '\0';

		/* if mail file is busy save it in our smtp queue
		 * and let the smtp daemon try later.
		 */
		if (mlock(Mailspool,ap->val)) {
			addlist(&dlist,ap->val,0);
			fail = queuejob(data,Hostname,dlist,from);
			del_list(dlist);
			dlist = NULL;
		}
		else {
			char buf[LINELEN];
			int tocnt = 0;
			sprintf(mailbox,"%s/%s.txt",Mailspool,ap->val);
#ifndef	AMIGA
			if((fp = fopen(mailbox,APPEND_TEXT)) != NULL) {
#else
			if((fp = fopen(mailbox,"r+")) != NULL) {
				(void) fseek(fp, 0L, 2);
#endif
				time(&t);
				fprintf(fp,"From %s %s",from,ctime(&t));
				host = NULL;
				while(fgets(buf,sizeof(buf),data) != NULL){
					if(buf[0] == '\n'){
						if(tocnt == 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -