if (maildir_scan(&pq,&2006830231942.htms,1,1) == -1) die_scan(); numm = pq.p ? pq.len : 0; //记录下队列长度
//通过队列pq构造消息块数组,构建结束后队列pq删除
m = (struct message *) alloc(numm * sizeof(struct message));//分配消息块
if (!m) die_nomem();
for (i = 0;i < numm;++i) {
if (!prioq_min(&pq,&pe)) { numm = i; break; }
prioq_delmin(&pq);
m.fn = 2006830231942.htms.s + pe.id;
m.flagdeleted = 0;
if (stat(m.fn,&st) == -1)
m.size = 0;
else
m.size = st.st_size;
}
}
void pop3_stat() //打印类似 +OK <消息数量><删除标记未设置的消息所占空间>
{ //如 +OK 3 3555表示总共有3条消息,占用空间3555(通过stat取得的)
int i;
unsigned long total;
total = 0;
for (i = 0;i < numm;++i) if (!m.flagdeleted) total += m.size;
puts("+OK ");
put(strnum,fmt_uint(strnum,numm));
puts(" ");
put(strnum,fmt_ulong(strnum,total));
puts("\r\n");
flush();
}
void pop3_rset()//重置pop对话,清除所有删除标记
{
int i;
for (i = 0;i < numm;++i) m.flagdeleted = 0;
last = 0;
okay();
}
void pop3_last()//显示最后一个消息块
{
puts("+OK ");
put(strnum,fmt_uint(strnum,last));
puts("\r\n");
flush();
}
void pop3_quit()//结束一次pop对话,删除所有删除标记设置的消息,将new下的消息移到cur下
{
int i;
for (i = 0;i < numm;++i)
if (m.flagdeleted) {
if (unlink(m.fn) == -1) err_nounlink();
}
else
if (str_start(m.fn,"new/")) {
if (!stralloc_copys(&line,"cur/")) die_nomem();
if (!stralloc_cats(&line,m.fn + 4)) die_nomem();
if (!stralloc_cats(&line,":2,")) die_nomem();
if (!stralloc_0(&line)) die_nomem();
rename(m.fn,line.s); /* if it fails, bummer */
}
okay();
die();
}
//检查消息块是否存在。或消息块的删除标记是否已经设置了
//成功返回消息块的位置int型
//失败返回-1
int msgno(arg) char *arg;
{
unsigned long u;
if (!scan_ulong(arg,&u)) { err_syntax(); return -1; }
if (!u) { err_nozero(); return -1; }
--u;
if (u >= numm) { err_toobig(); return -1; }
if (m.flagdeleted) { err_deleted(); return -1; }
return u;
}
void pop3_dele(arg) char *arg;//将arg指定消息块设置删除标记,实际删除动作将在pop3退出时进行
{
int i;
i = msgno(arg);
if (i == -1) return;
m.flagdeleted = 1;
if (i + 1 > last) last = i + 1;
okay();
}
void list(i,flaguidl)
int i;
int flaguidl;
{//显示消息块的内容,如果flaguidl设置,输出消息文件名,否则消息大小
put(strnum,fmt_uint(strnum,i + 1));
puts(" ");
if (flaguidl) printfn(m.fn);
else put(strnum,fmt_ulong(strnum,m.size));
puts("\r\n");
}
//如果指定了参数arg那么列出arg指定的消息块的内容,否则列出全部消息
void dolisting(arg,flaguidl) char *arg; int flaguidl;
{
unsigned int i;
if (*arg) {
i = msgno(arg);
if (i == -1) return;
puts("+OK ");
list(i,flaguidl);
}
else {
okay();
for (i = 0;i < numm;++i)
if (!m.flagdeleted)
list(i,flaguidl);
puts(".\r\n");
}
flush();
}
void pop3_uidl(arg) char *arg; { dolisting(arg,1); }
void pop3_list(arg) char *arg; { dolisting(arg,0); }
substdio ssmsg; char ssmsgbuf[1024];
void pop3_top(arg) char *arg;//显示指定消息的内容
{
int i;
unsigned long limit;
int fd;
i = msgno(arg);//邮件号
if (i == -1) return;
arg += scan_ulong(arg,&limit);//显示几行,如果未指定那么limit为0(balst函数打印全部内容)
while (*arg == ' ') ++arg;
if (scan_ulong(arg,&limit)) ++limit; else limit = 0;
fd = open_read(m.fn);
if (fd == -1) { err_nosuch(); return; }
okay();
//关系ssmsg为从指定的消息文件中读
substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf));
//从ssmsg中读到fd1,如果limit大于0将只读取除消息头外的limit行,如果等于0读全部邮件
blast(&ssmsg,limit);
close(fd);
}
struct commands pop3commands[] = { //pop3命令及处理函数表
{ "quit", pop3_quit, 0 }
, { "stat", pop3_stat, 0 }
, { "list", pop3_list, 0 }//显示消息大小, { "uidl", pop3_uidl, 0 }//显示消息文件名, { "dele", pop3_dele, 0 }
, { "retr", pop3_top, 0 }//取一条消息的内容,与top实现是一样的, { "rset", pop3_rset, 0 }//重置pop对话,清除所有删除标记, { "last", pop3_last, 0 }
, { "top", pop3_top, 0 }
, { "noop", okay, 0 }
, { 0, err_unimpl, 0 }
} ;
/*qmail-pop3d由vchkpw或checkpassword之类的程式起动,只有认证通过后才能
执行本程式提供各种pop3命令
*/
void main(argc,argv)
int argc;
char **argv;
{
sig_alarmcatch(die);
sig_pipeignore();
if (!argv[1]) die_nomaildir();
//由于vchkpw或checkpassword之类的程式在启动pop3之前已经将工作目录改变到HOME下了.
//所以这里直接进入arg指定的Maildir目录.也是由于这个改变目录原因。qamil-pop3d不支持Mailbox.
if (chdir(argv[1]) == -1) die_nomaildir();
getlist(); //这里构造了我们前面提到了消息块数组*m
okay();
//进入命令循环
commands(&ssin,pop3commands);
die();
}
==自此qmail的pop3部分分析基本结束==
小结
Maildir/cur 只要用户进行了一次连接,qmail-pop3d就会将new下所有邮件移动这个目录下来(quit命令解释程式中有体现.)
Maildir/new 用户还没看过新邮件
可见qmail的pop3部分只与Maildir有联系,与smtp基本无关。也许有人会问怎么pop3代码都完了,怎么没看见有使用 Maildir/tmp目录的地方呢?(只见删除)其实这个tmp目录是qmail-local用来保证可靠的转发所用的临时文件目录。如果你想知道具体怎么可靠法可以看qmail-local的源代码分析或者man maildir 的HOW A MESSAGE IS DELIVERED节.
原文链接:http://www.5dmail.net/html/2006-8-30/2006830231942.htm |