?? qmail-smtpd.c
字號:
r = rcpthosts(addr.s,str_len(addr.s)); if (r == -1) die_control(); return r;}int seenmail = 0;int flagbarf; /* defined if seenmail */stralloc mailfrom = {0};stralloc rcptto = {0};void smtp_helo(arg) char *arg;{ smtp_greet("250 "); out("\r\n"); seenmail = 0; dohelo(arg);}void smtp_ehlo(arg) char *arg;{ smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); seenmail = 0; dohelo(arg);}
//重新初始化,調用helo或ehlo命令都會完成相同的功能void smtp_rset(){ seenmail = 0; out("250 flushed\r\n");}
//mail命令解釋程序,重要變量:[mailfrom/全局]
//該函數完成檢查mailfrom是否在badmailfrom中定義,設置標志指明mail命令已經執行void smtp_mail(arg) char *arg;{ if (!addrparse(arg)) { err_syntax(); return; }
//檢查是否badmailfrom,如果是設置相應標志,這個標志在rcpt命令的處理程序中才起作用 flagbarf = bmfcheck(); seenmail = 1; //指示已經執行過mail命令。 if (!stralloc_copys(&rcptto,"")) die_nomem(); //分配rcptto緩沖區 if (!stralloc_copys(&mailfrom,addr.s)) die_nomem(); //復制mail命令中指定的地址到mailfrom if (!stralloc_0(&mailfrom)) die_nomem(); out("250 ok\r\n");}
//rcpt命令解釋程序,重要變量:[rcptto/全局]void smtp_rcpt(arg) char *arg; { if (!seenmail) { err_wantmail(); return; } //買了命令是否已經執行? if (!addrparse(arg)) { err_syntax(); return; } //分離郵件地址參數存入全局緩存addr
//如果mail命令中的地址在control/badmailfrom中有定義,返回
if (flagbarf) { err_bmf(); return; }
//至此addr緩存中包含了rcpt命令指定的email地址
//如果rcpt命令,則有addr="email@eg.org"。這個變量是在addrparse函數中賦值的
//如果RELAYCLIENT環境變量設置將不進行rcpthosts,morercpthosts.cdb的比較
//足以,大國smtp認證補丁,如果通過認證后會設置relayclient="" if (relayclient) { --addr.len; if (!stralloc_cats(&addr,relayclient)) die_nomem(); if (!stralloc_0(&addr)) die_nomem(); } else //如果沒有指定RELAYCLIENT變量,則有control/rcpthosts決定是否進行轉發 if (!addrallowed()) { err_nogateway(); return; }
//生成頭連接到全局緩存rcptto:
//例如地址"rcpt test@eg.org"命令將產生rcptto="Temail@eg.org"
//多次執行rcpt命令效果會是rcptto=“Ttest@eg.orgTtwo@eg.org” if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem(); out("250 ok\r\n");}
//saferead,從網絡讀len個字節到buf緩沖區
//返回實際讀到的字節數.
//超時值為control/timeoutsmtpd文件中指定的值.見setup()函數,(默認值1200秒)int saferead(fd,buf,len) int fd; char *buf; int len;{ int r; flush(); r = timeoutread(timeout,fd,buf,len); if (r == -1) if (errno == error_timeout) die_alarm(); if (r <= 0) die_read(); return r;}char ssinbuf[1024];substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);struct qmail qqt;unsigned int bytestooverflow = 0;void put(ch)char *ch;{ if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qqt); qmail_put(&qqt,ch,1);}void blast(hops)int *hops;{ char ch; int state; int flaginheader; int pos; /* number of bytes since most recent \n, if fih */ int flagmaybex; /* 1 if this line might match RECEIVED, if fih */ int flagmaybey; /* 1 if this line might match \r\n, if fih */ int flagmaybez; /* 1 if this line might match DELIVERED, if fih */ state = 1; *hops = 0; flaginheader = 1; pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; for (;;) {
//從標準輸入(也就是網絡)讀郵件內容直到獨到僅有一個點的行. substdio_get(&ssin,&ch,1); if (flaginheader) { if (pos < 9) { if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0; if (flagmaybez) if (pos == 8) ++*hops; if (pos < 8) if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0; if (flagmaybex) if (pos == 7) ++*hops; if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0; if (flagmaybey) if (pos == 1) flaginheader = 0; } ++pos; if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; } } switch(state) { case 0: if (ch == '\n') straynewline(); if (ch == '\r') { state = 4; continue; } break; case 1: /* \r\n */ if (ch == '\n') straynewline(); if (ch == '.') { state = 2; continue; } if (ch == '\r') { state = 4; continue; } state = 0; break; case 2: /* \r\n + . */ if (ch == '\n') straynewline(); if (ch == '\r') { state = 3; continue; } state = 0; break; case 3: /* \r\n + .\r */ if (ch == '\n') return; put("."); put("\r"); if (ch == '\r') { state = 4; continue; } state = 0; break; case 4: /* + \r */ if (ch == '\n') { state = 1; break; } if (ch != '\r') { put("\r"); state = 0; } } put(&ch); }}char accept_buf[FMT_ULONG];void acceptmessage(qp) unsigned long qp;{ datetime_sec when; when = now(); out("250 ok "); accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0; out(accept_buf); out(" qp "); accept_buf[fmt_ulong(accept_buf,qp)] = 0; out(accept_buf); out("\r\n");}
//data命令解釋程序
//完成向qmail-queue投遞郵件void smtp_data() { int hops; unsigned long qp; char *qqx; if (!seenmail) { err_wantmail(); return; } //如果沒有執行過mail命令,出錯返回 if (!rcptto.len) { err_wantrcpt(); return; } //如果沒有執行rcpt命令,出錯返回 seenmail = 0; //將mail命令標志失效
//databytes郵件最大長度,如果沒有指定那么值是0,代表無限 if (databytes) bytestooverflow = databytes + 1; if (qmail_open(&qqt) == -1) { err_qqt(); return; } //建立子進程執行qmail-queue qp = qmail_qp(&qqt); //qp為qmail-queue process縮寫,it's a process id。 out("354 go ahead\r\n");
//向新建立的進程傳送郵件頭 received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo); blast(&hops); hops = (hops >= MAXHOPS); if (hops) qmail_fail(&qqt);
//向qmail-queue傳送郵件頭信息,如果hong@hg.org向lyx@hg.org發送郵件,那么向qmail-queue
//傳送的字符串將是 Fhong@hg.orgTlyx@hg.org qmail_from(&qqt,mailfrom.s); qmail_put(&qqt,rcptto.s,rcptto.len); qqx = qmail_close(&qqt); if (!*qqx) { acceptmessage(qp); return; } //如果接受成功 if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; } if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; } if (*qqx == 'D') out("554 "); else out("451 "); out(qqx + 1); out("\r\n");}
//smtp命令處理函數表struct commands smtpcommands[] = { { "rcpt", smtp_rcpt, 0 }, { "mail", smtp_mail, 0 }, { "data", smtp_data, flush } //建立子進程執行qmail-queue,并向其傳送郵件., { "quit", smtp_quit, flush }, { "helo", smtp_helo, flush }, { "ehlo", smtp_ehlo, flush }, { "rset", smtp_rset, 0 }, { "help", smtp_help, flush }, { "noop", err_noop, flush } //實際上未實現的命令, { "vrfy", err_vrfy, flush } //實際上未實現的命令, { 0, err_unimpl, flush } //命令錯誤} ;
/*
qmail-smtpd 是由tcp-env程序啟動
tcp-env將來自網絡的連接重定向到qmail-smtpd的標準輸入及標準輸出.
這些程式建立一些環境變量(如TCPREMOTEHOST,TCPREMOTEIP)將由setup()函數使用
*/
void main(){ sig_pipeignore(); //忽略信號 if (chdir(auto_qmail) == -1) die_control(); //改變當前目錄到/var/qmail setup(); //讀控制文件及相應的環境變量 if (ipme_init() != 1) die_ipme(); //取本地接口的ip地址 smtp_greet("220 "); //顯示歡迎信息 out(" ESMTP\r\n");
//從標準讀入(網絡連接)讀入smtp命令 if (commands(&ssin,&smtpcommands) == 0) die_read(); die_nomem();}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -