?? qmail-queue.c
字號(hào):
//程序主要完成的功能是:
//1.生成自己的郵件首部,也就是你在郵件頭中見到的類似下面的東西
//Recevied (qmail 855 invoked by uid 0); 2 May 2003 12:18:09 -0000
//2.建立3個(gè)文件
// queue/mess 郵件正文
// queue/intd 用戶id,進(jìn)程id,mailform,rcptto
// queue/todo 是intd目錄下文件的復(fù)本
//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;
// 錯(cuò)誤清理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中
//這個(gè)字符串實(shí)際上就是/var/qmail/queue/pid目錄下一個(gè)文件名,指示當(dāng)前進(jìn)程的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之類的進(jìn)程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); //將起始時(shí)間轉(zhuǎn)換為可讀年月日時(shí)分秒的形式
//生成自己的郵件頭存入緩存reseived中
//例如:received="Received:(qmail 3434 invoked by 34434); Apr 27 2003 14:55:34" received_setup(); sig_pipeignore(); sig_miscignore(); sig_alarmcatch(sigalrm); //捕捉alarm信號(hào),控制超時(shí) sig_bugcatch(sigbug); alarm(DEATH); //超時(shí)秒數(shù),缺省值是86400(24小時(shí))后錯(cuò)誤返回52 pidopen(); //建立進(jìn)程id文件 if (fstat(messfd,&pidst) == -1) die(63); messnum = pidst.st_ino; //進(jìn)程id文件的inode節(jié)點(diǎn)號(hào)
/*生成將要建立的文件的文件名
幾個(gè)文件都是根據(jù)剛才建立的pid文件的inode節(jié)點(diǎn)號(hào)命名的.inode不可能被兩個(gè)文件同時(shí)
占用,這保證了郵件唯一性。其中mess目錄下的文件放置有一個(gè)%23的問題,
tips: 因?yàn)槭?23所以該目錄名最大的可能只有22,明白queue/mess目錄下目錄為什么
最大只22了吧 ,比如說inode節(jié)點(diǎn)號(hào)為3455,那么3455%23=5,
那么將生成/var/qmail/queue/mess/5/3455 這樣一個(gè)文件來存放郵件。
/var/qmail/queue/todo/3455與/var/qmail/queue/intd/3455是相同的,
都是保存用戶id,進(jìn)程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);
//進(jìn)程id文件使命很快結(jié)束,死掉了
//所以你不應(yīng)該想在queue/pid目錄中找到進(jìn)程id文件
//另外,qmail-clean也將第七清理queue/pid目錄下的pid文件,說定期其實(shí)也不是,
//qmail-clean會(huì)在每收到30個(gè)清理郵件的請(qǐng)求后清理pid目錄一次,這在分析qmail-clean
//時(shí)我們將會(huì)看到 flagmademess = 1;
//fd1關(guān)聯(lián)寫mess/下新建的文件,通過管道連接<------qmail-smtp的qqt->fde
//也就是說qmail-smtpd進(jìn)程寫它的qqt-fde,那就相當(dāng)于寫mess/下新建立的郵件
//注意是關(guān)聯(lián)不是正式寫 substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));
//fd0關(guān)聯(lián)到讀標(biāo)準(zhǔn)輸入到緩存區(qū)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設(shè)置的郵件首部 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關(guān)聯(lián)到寫intd/下新建立的文件 fd0關(guān)聯(lián)到讀inbuff緩沖區(qū) substdio_fdbuf(&ssout,write,intdfd,outbuf,sizeof(outbuf)); substdio_fdbuf(&ssin,read,1,inbuf,sizeof(inbuf));
/*
向intd下新建立的文件寫如下格式內(nèi)容
這些內(nèi)容來自于qmail-smtpd.c中的data命令的解釋函數(shù)。
u[uid]p[pid]F[mailfrom]T[rcptto1][rcptto2][rcptton]
例如:lyx@hg.org向hong@hg.org和beggar@hg.org發(fā)郵件可能會(huì)有如下內(nèi)容
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; }
//如有多個(gè)郵件接收人時(shí),這些接收人的地址總長(zhǎng)度不能超過1023字節(jié),如果每個(gè)
//郵件地址約為15個(gè)字節(jié)的話,大約可能指定65個(gè) 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();
//復(fù)制intdfn到todofn 由此可見這兩個(gè)是相同的文件 if (link(intdfn,todofn) == -1) die(66);
//向命名管道/var/qmail/queue/lock/trigger寫一個(gè)字節(jié)(寫的是0),通知有新的郵件 triggerpull(); die(0); //退出}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -