⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qmail-queue.c

📁 linux下qmail的源码 本人加了一些注释
💻 C
字号:
//程序主要完成的功能是:
//1.生成自己的邮件首部,也就是你在邮件头中见到的类似下面的东西
//Recevied (qmail 855 invoked by uid 0); 2 May 2003 12:18:09 -0000
//2.建立3个文件	
//	queue/mess		邮件正文
//	queue/intd		用户id,进程id,mailform,rcptto
//	queue/todo		是intd目录下文件的复本
//3.写命名管道lock/trigger通知新邮件

#include <sys/types.h>#include <sys/stat.h>#include "readwrite.h"#include "sig.h"#include "exit.h"#include "open.h"#include "seek.h"#include "fmt.h"#include "alloc.h"#include "substdio.h"#include "datetime.h"#include "now.h"#include "triggerpull.h"#include "extra.h"#include "auto_qmail.h"#include "auto_uids.h"#include "date822fmt.h"#include "fmtqfn.h"#define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */#define ADDR 1003char inbuf[2048];struct substdio ssin;char outbuf[256];struct substdio ssout;datetime_sec starttime;struct datetime dt;unsigned long mypid;unsigned long uid;char *pidfn;struct stat pidst;unsigned long messnum;char *messfn;char *todofn;char *intdfn;int messfd;int intdfd;int flagmademess = 0;int flagmadeintd = 0;
//	错误清理void cleanup(){ if (flagmadeintd)  {   seek_trunc(intdfd,0);   if (unlink(intdfn) == -1) return;  } if (flagmademess)  {   seek_trunc(messfd,0);   if (unlink(messfn) == -1) return;  }}void die(e) int e; { _exit(e); }void die_write() { cleanup(); die(53); }void die_read() { cleanup(); die(54); }void sigalrm() { /* thou shalt not clean up here */ die(52); }void sigbug() { die(81); }unsigned int receivedlen;char *received;/* "Received: (qmail-queue invoked by alias); 26 Sep 1995 04:46:54 -0000\n" */static unsigned int receivedfmt(s)char *s;{ unsigned int i; unsigned int len; len = 0;

 //生成		26 Sep 1995 04:46:54 -0000	的形式 i = fmt_str(s,"Received: (qmail "); len += i; if (s) s += i; i = fmt_ulong(s,mypid); len += i; if (s) s += i; i = fmt_str(s," invoked "); len += i; if (s) s += i; if (uid == auto_uida)  { i = fmt_str(s,"by alias"); len += i; if (s) s += i; } else if (uid == auto_uidd)  { i = fmt_str(s,"from network"); len += i; if (s) s += i; } else if (uid == auto_uids)  { i = fmt_str(s,"for bounce"); len += i; if (s) s += i; } else  {   i = fmt_str(s,"by uid "); len += i; if (s) s += i;   i = fmt_ulong(s,uid); len += i; if (s) s += i;  } i = fmt_str(s,"); "); len += i; if (s) s += i; i = date822fmt(s,&dt); len += i; if (s) s += i; return len;}void received_setup(){ receivedlen = receivedfmt((char *) 0); received = alloc(receivedlen + 1); if (!received) die(51); receivedfmt(received);}unsigned int pidfmt(s,seq)char *s;unsigned long seq;{ unsigned int i; unsigned int len;
 //生成类型pid/3434.34242424.1的字符串到s中
 //这个字符串实际上就是/var/qmail/queue/pid目录下一个文件名,指示当前进程的pid len = 0; i = fmt_str(s,"pid/"); len += i; if (s) s += i; i = fmt_ulong(s,mypid); len += i; if (s) s += i; i = fmt_str(s,"."); len += i; if (s) s += i; i = fmt_ulong(s,starttime); len += i; if (s) s += i; i = fmt_str(s,"."); len += i; if (s) s += i; i = fmt_ulong(s,seq); len += i; if (s) s += i; ++len; if (s) *s++ = 0; return len;}char *fnnum(dirslash,flagsplit)char *dirslash;int flagsplit;{ char *s; s = alloc(fmtqfn((char *) 0,dirslash,messnum,flagsplit)); if (!s) die(51); fmtqfn(s,dirslash,messnum,flagsplit); return s;}
//建立类似/var/run/inet.pid之类的进程id文件void pidopen(){ unsigned int len; unsigned long seq; seq = 1; len = pidfmt((char *) 0,seq); pidfn = alloc(len); if (!pidfn) die(51); for (seq = 1;seq < 10;++seq)  {   if (pidfmt((char *) 0,seq) > len) die(81); /* paranoia */   pidfmt(pidfn,seq);   messfd = open_excl(pidfn);   if (messfd != -1) return;  } die(63);}char tmp[FMT_ULONG];void main(){ unsigned int len; char ch; sig_blocknone(); umask(033); if (chdir(auto_qmail) == -1) die(61); if (chdir("queue") == -1) die(62);		//改变工作目录到/var/qmail/queue mypid = getpid(); uid = getuid(); starttime = now();
 datetime_tai(&dt,starttime);	 //将起始时间转换为可读年月日时分秒的形式
 //生成自己的邮件头存入缓存reseived中
 //例如:received="Received:(qmail 3434 invoked by 34434); Apr 27 2003 14:55:34" received_setup(); sig_pipeignore(); sig_miscignore(); sig_alarmcatch(sigalrm);	//捕捉alarm信号,控制超时 sig_bugcatch(sigbug); alarm(DEATH);		//超时秒数,缺省值是86400(24小时)后错误返回52 pidopen();		//建立进程id文件 if (fstat(messfd,&pidst) == -1) die(63); messnum = pidst.st_ino;	//进程id文件的inode节点号

 /*生成将要建立的文件的文件名
	几个文件都是根据刚才建立的pid文件的inode节点号命名的.inode不可能被两个文件同时
	占用,这保证了邮件唯一性。其中mess目录下的文件放置有一个%23的问题,
  tips: 因为是%23所以该目录名最大的可能只有22,明白queue/mess目录下目录为什么
	最大只22了吧 ,比如说inode节点号为3455,那么3455%23=5,
	那么将生成/var/qmail/queue/mess/5/3455 这样一个文件来存放邮件。
 	/var/qmail/queue/todo/3455与/var/qmail/queue/intd/3455是相同的,
	都是保存用户id,进程id,mailfrom,rcptto的。
 */ messfn = fnnum("mess/",1); todofn = fnnum("todo/",0); intdfn = fnnum("intd/",0); if (link(pidfn,messfn) == -1) die(64); if (unlink(pidfn) == -1) die(63);

 //进程id文件使命很快结束,死掉了
 //所以你不应该想在queue/pid目录中找到进程id文件
 //另外,qmail-clean也将第七清理queue/pid目录下的pid文件,说定期其实也不是,
 //qmail-clean会在每收到30个清理邮件的请求后清理pid目录一次,这在分析qmail-clean
 //时我们将会看到 flagmademess = 1;
 //fd1关联写mess/下新建的文件,通过管道连接<------qmail-smtp的qqt->fde
 //也就是说qmail-smtpd进程写它的qqt-fde,那就相当于写mess/下新建立的邮件
 //注意是关联不是正式写 substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));

 //fd0关联到读标准输入到缓存区inbuf通过管道连接<-----qmail-smtp的qqt->fdm
 //也就是说读ssin将从qmail-smtpd的qqt->fdm端读 substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
 //向mess/下的邮件文件写qmail-queue的头部信息 if (substdio_bput(&ssout,received,receivedlen) == -1) die_write();
 //从fd1读smtpd设置的邮件首部 switch(substdio_copy(&ssout,&ssin))  {   case -2: die_read();   case -3: die_write();  } if (substdio_flush(&ssout) == -1) die_write(); if (fsync(messfd) == -1) die_write(); intdfd = open_excl(intdfn); if (intdfd == -1) die(65); flagmadeintd = 1;
 //fd1关联到写intd/下新建立的文件 fd0关联到读inbuff缓冲区 substdio_fdbuf(&ssout,write,intdfd,outbuf,sizeof(outbuf)); substdio_fdbuf(&ssin,read,1,inbuf,sizeof(inbuf));
 /*
  向intd下新建立的文件写如下格式内容
  这些内容来自于qmail-smtpd.c中的data命令的解释函数。
  u[uid]p[pid]F[mailfrom]T[rcptto1][rcptto2][rcptton]
  例如: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);
 //向命名管道/var/qmail/queue/lock/trigger写一个字节(写的是0),通知有新的邮件 triggerpull(); die(0);		//退出}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -