Linux中国 Linux中国门户站!
设为主页 设为主页
收藏本站 收藏本站
 
当前位置 :首页 ->Linux技术 ->Linux程序设计 ->正文

程序员眼中的qmail(qmail源代码分析)

来源:5dmail.net 作者:未知  时间:2007-04-22 点击: [收藏] [投稿]

  //将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

  //拒绝转发返回0

  int addrallowed()

  {

  int r;

  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; }

  flagbarf = bmfcheck(); //检查是否badmailfrom,如果是设置相应标志,这个标志在rcpt命令的处理程式中才起作用

  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; }//mail命令是否已执行?

  if (!addrparse(arg)) { err_syntax(); return; }//分离邮件地址参数存入全局缓存addr

  if (flagbarf) { err_bmf(); return; }//如果mail命令中的地址在control/badmailfrom中有定义,返回

  //至此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;

 如果您对本文有任何疑问或者建议,请到讨论区发表您的意见: >> 论坛入口 <<



上一篇:使用 Flex 和 Bison 更好地进行错误处理   下一篇:GNU 线性编程工具包(线性优化简介)

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章
Power by linux-cn.com 粤ICP备05006655号