程序员眼中的qmail(qmail源代码分析)代码: struct prioq_elt { datetime_sec dt;//时间戳,优先级 unsigned long id;//邮件唯一id,你可以把它同qmail-queue分析中介绍中pid文件inode联系起来 } ; prioq在prioq.h中prioq是这样定义的 GEN_ALLOC_typedef(prioq,struct prioq_elt,p,len,a) 展开后实际上定义为 typedef struct prioq { struct prioq_elt *p; // 指针 unsigned int len; //队列的长度 unsigned int a; }prioq; 消息块: --> message 我把它叫作消息块是因为他并不包含消息内容,也许这样称呼它并不确切 代码: struct message { int flagdeleted; //删除标记,在qmail-pop3d程式退出时进行实际删除动作 unsigned long size; //消息文件大小 char *fn; //消息文件名 } *m; 主要功能: qmail-pop3d是则vchkpw或checkpassword之类的程式启动的。这些程式(vchkpw)会更改环境变量USER, HOME,SHELL等等,并在启动qmail-pop3d前将工作目录改变到$HOME下. qmail-pop3d在启动时首先检查./Maildir/tmp(./Maildir是在argv中指定的)下最后访问时间超过36小 时的文件,如果存在就将其删除。也正是由于qmail-pop3d在启动时就有chdir的动作,所以qmail-pop3d 不支持mailbox形式的pop. 扫描Maildir/cur及Maildir/new目录构造一个消息块数组 m(首先是构造一个临时队列pq,然后根据这个队列 来构造消息块数组),输出+OK,进入命令循环,等待用户输入pop命令进行相应的处理.具体见代码分析. 代码: void die() { _exit(0); } //超时读,超时时间为20分钟,正常返回读到的字节数,否则程式失败die() 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; } //超时写,超时时间为20分钟,正常返回写的字节数,否则程式失败die() 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; } /*定义ssout为向fd1写,超时时间为20分钟 定义ssin为从fd0读,超时时间为20分钟 由于tcpserver或inetd已经重定向了fd1,fd0到网络,所以这就 等同于向网络读写*/ char ssoutbuf[1024]; substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); char ssinbuf[128]; substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); void put(buf,len) char *buf; int len; { substdio_put(&ssout,buf,len);//将buf缓存中的内容向网络写 } void puts(s) char *s; { substdio_puts(&ssout,s);//将s的内容向网络写,这个函数实际上是调用的substdio_put } void flush() //确保输出缓存中已经没有内容。 { substdio_flush(&ssout); } void err(s) char *s; { puts("-ERR "); puts(s); puts("\r\n"); flush(); } //错误处理函数 void die_nomem() { err("out of memory"); die(); } void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); } void die_scan() { err("unable to scan $HOME/Maildir"); die(); } void err_syntax() { err("syntax error"); } void err_unimpl() { err("unimplemented"); } void err_deleted() { err("already deleted"); } void err_nozero() { err("messages are counted from 1"); } void err_toobig() { err("not that many messages"); } void err_nosuch() { err("unable to open that message"); } void err_nounlink() { err("unable to unlink all deleted messages"); } void okay() { puts("+OK \r\n"); flush(); } void printfn(fn) char *fn; { fn += 4; put(fn,str_chr(fn,':')); } char strnum[FMT_ULONG]; stralloc line = {0}; void blast(ssfrom,limit)//从ssfrom读数据输出到fd1,一次一行(用全局缓存line) substdio *ssfrom; unsigned long limit;//除开消息头部信息,最多读limit行,limit为0将全部读完 { int match; int inheaders = 1; for (;;) { if (getln(ssfrom,&line,&match,'\n') != 0) die(); if (!match && !line.len) break; if (match) --line.len; /* no way to pass this info over POP */ if (limit) if (!inheaders) if (!--limit) break; if (!line.len) inheaders = 0; else if (line.s[0] == '.') put(".",1); put(line.s,line.len); put("\r\n",2); if (!match) break; } put("\r\n.\r\n",5); flush(); 上一篇:使用 Flex 和 Bison 更好地进行错误处理 下一篇:GNU 线性编程工具包(线性优化简介) 更多相关文章
|
推荐文章
精彩文章
|