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

📄 qmail-smtpd.c

📁 linux下qmail的源码 本人加了一些注释
💻 C
📖 第 1 页 / 共 2 页
字号:
  r = rcpthosts(addr.s,str_len(addr.s));  if (r == -1) die_control();  return r;}int seenmail = 0;int flagbarf; /* defined if seenmail */stralloc mailfrom = {0};stralloc rcptto = {0};void smtp_helo(arg) char *arg;{  smtp_greet("250 "); out("\r\n");  seenmail = 0; dohelo(arg);}void smtp_ehlo(arg) char *arg;{  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");  seenmail = 0; dohelo(arg);}

//重新初始化,调用helo或ehlo命令都会完成相同的功能void smtp_rset(){  seenmail = 0;  out("250 flushed\r\n");}

//mail命令解释程序,重要变量:[mailfrom/全局]
//该函数完成检查mailfrom是否在badmailfrom中定义,设置标志指明mail命令已经执行void smtp_mail(arg) char *arg;{  if (!addrparse(arg)) { err_syntax(); return; }

  //检查是否badmailfrom,如果是设置相应标志,这个标志在rcpt命令的处理程序中才起作用  flagbarf = bmfcheck();  seenmail = 1;		//指示已经执行过mail命令。  if (!stralloc_copys(&rcptto,"")) die_nomem();		//分配rcptto缓冲区  if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();	//复制mail命令中指定的地址到mailfrom  if (!stralloc_0(&mailfrom)) die_nomem();  out("250 ok\r\n");}

//rcpt命令解释程序,重要变量:[rcptto/全局]void smtp_rcpt(arg) char *arg; {  if (!seenmail) { err_wantmail(); return; }	//买了命令是否已经执行?  if (!addrparse(arg)) { err_syntax(); return; }	//分离邮件地址参数存入全局缓存addr  
  //如果mail命令中的地址在control/badmailfrom中有定义,返回
  if (flagbarf) { err_bmf(); return; }
  //至此addr缓存中包含了rcpt命令指定的email地址
  //如果rcpt命令,则有addr="email@eg.org"。这个变量是在addrparse函数中赋值的
  //如果RELAYCLIENT环境变量设置将不进行rcpthosts,morercpthosts.cdb的比较
  //足以,大国smtp认证补丁,如果通过认证后会设置relayclient=""  if (relayclient) {    --addr.len;    if (!stralloc_cats(&addr,relayclient)) die_nomem();    if (!stralloc_0(&addr)) die_nomem();  }  else		//如果没有指定RELAYCLIENT变量,则有control/rcpthosts决定是否进行转发    if (!addrallowed()) { err_nogateway(); return; }

	//生成头连接到全局缓存rcptto:
	//例如地址"rcpt test@eg.org"命令将产生rcptto="Temail@eg.org"
	//多次执行rcpt命令效果会是rcptto=“Ttest@eg.orgTtwo@eg.org”  if (!stralloc_cats(&rcptto,"T")) die_nomem();  if (!stralloc_cats(&rcptto,addr.s)) die_nomem();  if (!stralloc_0(&rcptto)) die_nomem();  out("250 ok\r\n");}
//saferead,从网络读len个字节到buf缓冲区
//返回实际读到的字节数.
//超时值为control/timeoutsmtpd文件中指定的值.见setup()函数,(默认值1200秒)int saferead(fd,buf,len) int fd; char *buf; int len;{  int r;  flush();  r = timeoutread(timeout,fd,buf,len);  if (r == -1) if (errno == error_timeout) die_alarm();  if (r <= 0) die_read();  return r;}char ssinbuf[1024];substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);struct qmail qqt;unsigned int bytestooverflow = 0;void put(ch)char *ch;{  if (bytestooverflow)    if (!--bytestooverflow)      qmail_fail(&qqt);  qmail_put(&qqt,ch,1);}void blast(hops)int *hops;{  char ch;  int state;  int flaginheader;  int pos; /* number of bytes since most recent \n, if fih */  int flagmaybex; /* 1 if this line might match RECEIVED, if fih */  int flagmaybey; /* 1 if this line might match \r\n, if fih */  int flagmaybez; /* 1 if this line might match DELIVERED, if fih */   state = 1;  *hops = 0;  flaginheader = 1;  pos = 0; flagmaybex = flagmaybey = flagmaybez = 1;  for (;;) {

	//从标准输入(也就是网络)读邮件内容直到独到仅有一个点的行.    substdio_get(&ssin,&ch,1);    if (flaginheader) {      if (pos < 9) {        if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0;        if (flagmaybez) if (pos == 8) ++*hops;        if (pos < 8)          if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0;        if (flagmaybex) if (pos == 7) ++*hops;        if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0;        if (flagmaybey) if (pos == 1) flaginheader = 0;      }      ++pos;      if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; }    }    switch(state) {      case 0:        if (ch == '\n') straynewline();        if (ch == '\r') { state = 4; continue; }        break;      case 1: /* \r\n */        if (ch == '\n') straynewline();        if (ch == '.') { state = 2; continue; }        if (ch == '\r') { state = 4; continue; }        state = 0;        break;      case 2: /* \r\n + . */        if (ch == '\n') straynewline();        if (ch == '\r') { state = 3; continue; }        state = 0;        break;      case 3: /* \r\n + .\r */        if (ch == '\n') return;        put(".");        put("\r");        if (ch == '\r') { state = 4; continue; }        state = 0;        break;      case 4: /* + \r */        if (ch == '\n') { state = 1; break; }        if (ch != '\r') { put("\r"); state = 0; }    }    put(&ch);  }}char accept_buf[FMT_ULONG];void acceptmessage(qp) unsigned long qp;{  datetime_sec when;  when = now();  out("250 ok ");  accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;  out(accept_buf);  out(" qp ");  accept_buf[fmt_ulong(accept_buf,qp)] = 0;  out(accept_buf);  out("\r\n");}
//data命令解释程序
//完成向qmail-queue投递邮件void smtp_data() {  int hops;  unsigned long qp;  char *qqx;   if (!seenmail) { err_wantmail(); return; }	//如果没有执行过mail命令,出错返回  if (!rcptto.len) { err_wantrcpt(); return; }	//如果没有执行rcpt命令,出错返回  seenmail = 0;		//将mail命令标志失效

  //databytes邮件最大长度,如果没有指定那么值是0,代表无限  if (databytes) bytestooverflow = databytes + 1;  if (qmail_open(&qqt) == -1) { err_qqt(); return; }	//建立子进程执行qmail-queue  qp = qmail_qp(&qqt);		//qp为qmail-queue process缩写,it's a process id。  out("354 go ahead\r\n"); 
  //向新建立的进程传送邮件头  received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);  blast(&hops);  hops = (hops >= MAXHOPS);  if (hops) qmail_fail(&qqt);

  //向qmail-queue传送邮件头信息,如果hong@hg.org向lyx@hg.org发送邮件,那么向qmail-queue
  //传送的字符串将是 Fhong@hg.orgTlyx@hg.org  qmail_from(&qqt,mailfrom.s);  qmail_put(&qqt,rcptto.s,rcptto.len);   qqx = qmail_close(&qqt);  if (!*qqx) { acceptmessage(qp); return; }		//如果接受成功  if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }  if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }  if (*qqx == 'D') out("554 "); else out("451 ");  out(qqx + 1);  out("\r\n");}

//smtp命令处理函数表struct commands smtpcommands[] = {  { "rcpt", smtp_rcpt, 0 }, { "mail", smtp_mail, 0 }, { "data", smtp_data, flush }		//建立子进程执行qmail-queue,并向其传送邮件., { "quit", smtp_quit, flush }, { "helo", smtp_helo, flush }, { "ehlo", smtp_ehlo, flush }, { "rset", smtp_rset, 0 }, { "help", smtp_help, flush }, { "noop", err_noop, flush }		//实际上未实现的命令, { "vrfy", err_vrfy, flush }		//实际上未实现的命令, { 0, err_unimpl, flush }			//命令错误} ;

/*
  qmail-smtpd 是由tcp-env程序启动
  tcp-env将来自网络的连接重定向到qmail-smtpd的标准输入及标准输出.
	这些程式建立一些环境变量(如TCPREMOTEHOST,TCPREMOTEIP)将由setup()函数使用
*/
void main(){  sig_pipeignore();		//忽略信号  if (chdir(auto_qmail) == -1) die_control();	//改变当前目录到/var/qmail  setup();		//读控制文件及相应的环境变量  if (ipme_init() != 1) die_ipme();		//取本地接口的ip地址  smtp_greet("220 ");		//显示欢迎信息  out(" ESMTP\r\n");

  //从标准读入(网络连接)读入smtp命令  if (commands(&ssin,&smtpcommands) == 0) die_read();  die_nomem();}

⌨️ 快捷键说明

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