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

📄 qmail-smtpd.c

📁 linux下qmail的源码 本人加了一些注释
💻 C
📖 第 1 页 / 共 2 页
字号:
//	qmail-smtpd接受远程主机的邮件并转交给队列处理程序qmail-queue来处理
//	由tcp-env.c启动,完成邮件smtp命令的接收,并调用相应的处理程序
//	只接收邮件内容(mailfrom,mailto)并传送给qmail-queue,并不对邮件进行转发

#include "sig.h"#include "readwrite.h"#include "stralloc.h"#include "substdio.h"#include "alloc.h"#include "auto_qmail.h"#include "control.h"#include "received.h"#include "constmap.h"#include "error.h"#include "ipme.h"#include "ip.h"#include "qmail.h"#include "str.h"#include "fmt.h"#include "scan.h"#include "byte.h"#include "case.h"#include "env.h"#include "now.h"#include "exit.h"#include "rcpthosts.h"#include "timeoutread.h"#include "timeoutwrite.h"#include "commands.h"#define MAXHOPS 100unsigned int databytes = 0;		//邮件最大长度:0=无限int timeout = 1200;		//默认超时20分钟
//	向网络写,超时值为control/timeoutsmtpd指定的值,没有这个文件则取默认值20分钟int safewrite(fd,buf,len) int fd; char *buf; int len;{  int r;  r = timeoutwrite(timeout,fd,buf,len);  if (r <= 0) _exit(1);  return r;}char ssoutbuf[512];substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);void flush() { substdio_flush(&ssout); }

//	void out(s) char *s 相当于 void out(char* s)void out(s) char *s; { substdio_puts(&ssout,s); }
//	错误处理函数void die_read() { _exit(1); }void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }void err_noop() { out("250 ok\r\n"); }void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }stralloc greeting = {0};//end 错误处理函数
//	输出提示信息*codevoid smtp_greet(code) char *code;{  substdio_puts(&ssout,code);  substdio_put(&ssout,greeting.s,greeting.len);}void smtp_help(){  out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n");}void smtp_quit(){  smtp_greet("221 "); out("\r\n"); flush(); _exit(0);}char *remoteip;	//远端ip地址char *remotehost;	//远端主机名char *remoteinfo;	//远端信息char *local;	//本地主机char *relayclient;	//是否检查rcpthosts文件stralloc helohost = {0};char *fakehelo; /* pointer into helohost, or 0 */void dohelo(arg) char *arg; {  if (!stralloc_copys(&helohost,arg)) die_nomem();   if (!stralloc_0(&helohost)) die_nomem(); 

  //fakehelo变量,如果helo参数指定的主机名与TCPREMOTEHOST环境变量中的主机名不同则
  //fakehelo的值为helo命令的参数指定的主机名。如果两者相同则fekehelo为NULL;
  //data命令处理程式用到这个变量  fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;}int liphostok = 0;stralloc liphost = {0};int bmfok = 0;

//	badmailfrom 用来指定不喜欢的发见人的邮件地址或者是域名
//该地址给主机发送邮件时将得到code 553,告知其是不受欢迎的发件人stralloc bmf = {0};		struct constmap mapbmf;void setup(){  char *x;  unsigned long u;   if (control_init() == -1) die_control();	//control/me

  //读入欢迎信息greeting,如果不存在则从me文件复制  if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)    die_control();

  //读入localiphost,如果文件不存在则从me文件复制  liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0);  if (liphostok == -1) die_control();

  //读control/timeoutsmtpd存入timeout,用于控制超时的情况  if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();  if (timeout <= 0) timeout = 1;  if (rcpthosts_init() == -1) die_control();
  //读入badmailfrom文件存入bmf  bmfok = control_readfile(&bmf,"control/badmailfrom",0);  if (bmfok == -1) die_control();  if (bmfok)    if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem(); 
  //读入databytes文件存入databytes,如果该文件不存在,则将databytes的值设为0.  if (control_readint(&databytes,"control/databytes") == -1) die_control();  x = env_get("DATABYTES");  if (x) { scan_ulong(x,&u); databytes = u; }  if (!(databytes + 1)) --databytes; 
  //取tcp-environ环境变量,如果环境变量没有设置,将它的值设置为unknow
  //这些信息在tcp-env文件中  remoteip = env_get("TCPREMOTEIP");  if (!remoteip) remoteip = "unknown";  local = env_get("TCPLOCALHOST");  if (!local) local = env_get("TCPLOCALIP");  if (!local) local = "unknown";  remotehost = env_get("TCPREMOTEHOST");  if (!remotehost) remotehost = "unknown";  remoteinfo = env_get("TCPREMOTEINFO");

  //从环境变量RELAYCLIENT读入,如果RELAYCLIENT变量没有设置那么relayclient将会是NULL  relayclient = env_get("RELAYCLIENT");  dohelo(remotehost);}stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
//对命令参数arg进行邮件地址分析,并将分离出的email地址存入全局缓存addr,成功返回值1,
//失败返回0int addrparse(arg)char *arg;{  int i;  char ch;  char terminator;  struct ip_address ip;  int flagesc;  int flagquoted; 
  //分离出邮件地址,例如:arg="",或arg=": email@eg.org"
  //执行下面这段程序后arg="email@eg.org"  terminator = '>';  i = str_chr(arg,'<');  if (arg[i])    arg += i + 1;  else { /* partner should go read rfc 821 */    terminator = ' ';    arg += str_chr(arg,':');    if (*arg == ':') ++arg;    while (*arg == ' ') ++arg;  }  /* strip source route */  if (*arg == '@') while (*arg) if (*arg++ == ':') break;  if (!stralloc_copys(&addr,"")) die_nomem();  flagesc = 0;  flagquoted = 0;  for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */    if (flagesc) {      if (!stralloc_append(&addr,&ch)) die_nomem();      flagesc = 0;    }    else {      if (!flagquoted && (ch == terminator)) break;      switch(ch) {        case '\\': flagesc = 1; break;        case '"': flagquoted = !flagquoted; break;        default: if (!stralloc_append(&addr,&ch)) die_nomem();      }    }  }  /* could check for termination failure here, but why bother? */  if (!stralloc_append(&addr,"")) die_nomem();
  //将ip地址转换为主机名:
  //如test@[10.0.6.21]转换为test@host.mydomain.org
  //依据是control/localiphost文件中有host.mydomain.org  if (liphostok) {    i = byte_rchr(addr.s,addr.len,'@');    if (i < addr.len) /* if not, partner should go read rfc 821 */      if (addr.s[i + 1] == '[')		//比较是否是用[]括起来的ip地址        if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)])          if (ipme_is(&ip)) {            addr.len = i + 1;            if (!stralloc_cat(&addr,&liphost)) die_nomem();            if (!stralloc_0(&addr)) die_nomem();          }  }  if (addr.len > 900) return 0;		//地址太长,出错返回  return 1;		//成功返回}
//简单的垃圾邮件检查,检查全局缓冲区addr中的地址是否有在badmailfrom中定义,如果
//有则返回1,否则返回0.int bmfcheck(){  int j;  if (!bmfok) return 0;  if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;  j = byte_rchr(addr.s,addr.len,'@');  if (j < addr.len)    if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;  return 0;}
//检查全局缓存addr中的邮件地址是否要进行转发(依据control/rcpthosts文件)
//可以进行转发返回1,拒绝转发返回0int addrallowed(){  int r;

⌨️ 快捷键说明

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