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

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

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

  //FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */

  char unique[FMT_ULONG + FMT_ULONG + 3];

  char *hostname;

  stralloc username = {0};

  int seenuser = 0;

  char **childargs;

  substdio ssup;

  char upbuf[128];

  void doanddie(user,userlen,pass)

  char *user;

  unsigned int userlen; /* including 0 byte */

  char *pass;

  {

  int child;

  int wstat;

  int pi[2];

  if (fd_copy(2,1) == -1) die_pipe();//关闭出错(fd2),将标准输出(fd1),定向到标准出错(fd2)

  close(3);

  if (pipe(pi) == -1) die_pipe();

  if (pi[0] != 3) die_pipe(); //确保向子进程能够读到硬编码的fd 3

  switch(child = fork()) { //建立子进程执行subprogram给出的程式,一般是一个检验用户名和密码的程式

  case -1:

  die_fork();

  case 0:

  close(pi[1]);

  sig_pipedefault();//子进程执行checkpassword或vchkpw之类的程式,检验密码,如果认证通过

  execvp(*childargs,childargs);//这些再调用qmail-pop3d

  _exit(1);

  }

  //父进程向子进程的fd3传送用户名及密码,这是一个约定。如果你要写自已的检验密码的程式,记得

  //从fd3读密码哦。

  close(pi[0]);

  substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);

  if (substdio_put(&ssup,user,userlen) == -1) die_write();

  if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write();

  //父进程向子进程传送<进程ID.当前时间@主机名>

  if (substdio_puts(&ssup,"<") == -1) die_write();

  if (substdio_puts(&ssup,unique) == -1) die_write();

  if (substdio_puts(&ssup,hostname) == -1) die_write();

  if (substdio_put(&ssup,">",2) == -1) die_write();

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

  close(pi[1]);

  //清除密码及用户名缓冲区

  byte_zero(pass,str_len(pass));

  byte_zero(upbuf,sizeof upbuf);

  if (wait_pid(&wstat,child) == -1) die();//等待子进程结束

  if (wait_crashed(wstat)) die_childcrashed();

  if (wait_exitcode(wstat)) die_badauth();

  //完成一次pop3对话退出

  die();

  }

  //显示欢迎信息

  void pop3_greet()

  {

  char *s;

  s = unique;

  s += fmt_uint(s,getpid());

  *s++ = '.';

  s += fmt_ulong(s,(unsigned long) now());

  *s++ = '@';

  *s++ = 0;

  puts("+OK <");

  puts(unique);

  puts(hostname);

  puts(">\r\n");

  flush();

  }

  //设置标志,初始化用户名变量

  void pop3_user(arg) char *arg;

  {

  if (!*arg) { err_syntax(); return; }

  okay();

  seenuser = 1; //user命令已经执行的标志

  if (!stralloc_copys(&username,arg)) die_nomem(); //将参数存入username

  if (!stralloc_0(&username)) die_nomem();

  }

  void pop3_pass(arg) char *arg;

  {

  if (!seenuser) { err_wantuser(); return; }//如果没有执行user命令,返回

  if (!*arg) { err_syntax(); return; }

  doanddie(username.s,username.len,arg);//调用子进程验正密码并等待它完成

  }

  void pop3_apop(arg) char *arg;//用户名及密码在一个命令中给出的情况,见user,pass

  {

  char *space;

  space = arg + str_chr(arg,' ');

  if (!*space) { err_syntax(); return; }

  *space++ = 0;

  doanddie(arg,space - arg,space);

  }

  struct commands pop3commands[] = {//命令及相应的处理函数表

  { "user", pop3_user, 0 }

  , { "pass", pop3_pass, 0 }

  , { "apop", pop3_apop, 0 }

  , { "quit", pop3_quit, 0 }

  , { "noop", okay, 0 }

  , { 0, err_authoriz, 0 }

  } ;

  void main(argc,argv)

  int argc;

  char **argv;

  {

  sig_alarmcatch(die);//捕获sigalrm信号

  sig_pipeignore();//忽略pipe信号

  hostname = argv[1]; //hostname 指向 程式的第一个参数

  if (!hostname) die_usage();

  childargs = argv + 2;

  if (!*childargs) die_usage();

  pop3_greet();//显示欢迎信息后进入命令循环,等待用户命令

  commands(&ssin,pop3commands);

  die();

  }

  qmail-start.c 分析

  Programmer:夜未眠

  Comefrom:ChongQing Gearbox co.,ltd

  qmail-start 是很简单的一个程式,他完成qmail-send,qmail-clean,qmail-lspawn,qmail-rspawn,splogger的启动,并通过管道将他们联系在一起,当然不是网状连接.具体如下

  代码:

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



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



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

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