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

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

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

  例如:lyx@hg.org向hong@hg.org和beggar@hg.org发邮件可能会有如下内容

  u6027p34234Flyx@hg.orgThong@hg.orgTbeggar@hg.org

  */

  if (substdio_bput(&ssout,"u",1) == -1) die_write();

  if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,uid)) == -1) die_write();

  if (substdio_bput(&ssout,"",1) == -1) die_write();

  if (substdio_bput(&ssout,"p",1) == -1) die_write();

  if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,mypid)) == -1) die_write();

  if (substdio_bput(&ssout,"",1) == -1) die_write();

  if (substdio_get(&ssin,&ch,1) < 1) die_read();

  if (ch != 'F') die(91);

  if (substdio_bput(&ssout,&ch,1) == -1) die_write();

  for (len = 0;len < ADDR;++len)

  {

  if (substdio_get(&ssin,&ch,1) < 1) die_read();

  if (substdio_put(&ssout,&ch,1) == -1) die_write();

  if (!ch) break;

  }

  //如有多个邮件接收人时,这些接收人的地址总不长度不能超过1023字节,如果每个邮件地址约为15个字节的话,

  //大约可能指定65个

  if (len >= ADDR) die(11);

  if (substdio_bput(&ssout,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write();

  for (;;)

  {

  if (substdio_get(&ssin,&ch,1) < 1) die_read();

  if (!ch) break;

  if (ch != 'T') die(91);

  if (substdio_bput(&ssout,&ch,1) == -1) die_write();

  for (len = 0;len < ADDR;++len)

  {

  if (substdio_get(&ssin,&ch,1) < 1) die_read();

  if (substdio_bput(&ssout,&ch,1) == -1) die_write();

  if (!ch) break;

  }

  if (len >= ADDR) die(11);

  }

  if (substdio_flush(&ssout) == -1) die_write();

  if (fsync(intdfd) == -1) die_write();

  //复制intdfn到todofn 由此可见这两个是相同的文件

  if (link(intdfn,todofn) == -1) die(66);

  triggerpull(); //向命名管道 /var/qmail/queue/lock/trigger写一个字节(写的是0),通知有新的邮件

  die(0); //退出

  }

  ==完==

  qmail-popup.c分析

  Programmer:夜未眠

  Come from:ChongQing Gearbox co.,ltd

  qmail -popup也是由tcpserver或tcp-env之类的程式启动。这些程式是通过管道与qmail-popup通信的。这也是qmail 的美妙之处,总观整个qmail源代码,除少量dns代码外。基本上没有使用网络编程。各个进程间大部分都是通管道通信。把监听,读写网络部分交给 inetd或tcpserver来作。使得qmail代码相当容易阅读理解。

  主要功能:

  1.从网络读pop3命令,进行相应处理。

  2.调用子进程(vchkpw或checkpassword,具体是哪一个由你在运行参数中指定,当然,仔细分析完doanddie函数后你也许就能编写自己的checkpw了,呵呵)完成检验密码,启动qmail-pop3d的工作

  重要的函数是doanddie. 理解这个函数基本上就能理解qmail pop密码的检验流程。

  几个程式间的关系是:

  代码:

  tcpserver---->qmail-popup---->vchkpw----认证成功--->qmail-pop3d

  | |

  | |

  <---------- 认证失败-----------+

  ==========================

  代码:

  void die() { _exit(1); }

  int saferead(fd,buf,len) int fd; char *buf; int len;

  {

  int r;

  r = timeoutread(1200,fd,buf,len);

  if (r <= 0) die();

  return r;

  }

  int safewrite(fd,buf,len) int fd; char *buf; int len;

  {

  int r;

  r = timeoutwrite(1200,fd,buf,len);

  if (r <= 0) die();

  return r;

  }

  char ssoutbuf[128];

  substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);

  char ssinbuf[128];

  substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);

  void puts(s) char *s;

  {

  substdio_puts(&ssout,s);

  }

  void flush()

  {

  substdio_flush(&ssout);

  }

  void err(s) char *s;

  {

  puts("-ERR ");

  puts(s);

  puts("\r\n");

  flush();

  }

  void die_usage() { err("usage: popup hostname subprogram"); die(); }

  void die_nomem() { err("out of memory"); die(); }

  void die_pipe() { err("unable to open pipe"); die(); }

  void die_write() { err("unable to write pipe"); die(); }

  void die_fork() { err("unable to fork"); die(); }

  void die_childcrashed() { err("aack, child crashed"); }

  void die_badauth() { err("authorization failed"); }

  void err_syntax() { err("syntax error"); }

  void err_wantuser() { err("USER first"); }

  void err_authoriz() { err("authorization first"); }

  void okay() { puts("+OK \r\n"); flush(); }

  void pop3_quit() { okay(); die(); }

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



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

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