程序员眼中的qmail(qmail源代码分析)//将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 //如果 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.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 线性编程工具包(线性优化简介) 更多相关文章
|
推荐文章
精彩文章
|