?? delphi中怎樣監視pop3信箱 (2000年11月24日).txt
字號:
Delphi中怎樣監視POP3信箱 (2000年11月24日)
本站更新 分類: 作者:劉明華 推薦: 閱讀次數:652
(http://www.codesky.net)
--------------------------------------------------------------------------------
---- 本 文 將 向 大 家 介 紹 怎 樣 編 寫自 己 的 信 箱 監 視 程 序, 程 序 將 直 接 調 用
WinSock 函 數 來 進 行網 絡 通 信。 除 了 具 備WinSock 編 程 知 識 之 外, 還 必 須 了 解
POP3 協 議。 下 面 是 對POP3 的 一 個 粗 略 的 介 紹, 讀 者 可 以 參 看RFC 1225 更 為 詳
細 地 了 解 該 協 議。 一、 關 于POP3 協 議
POP3 服 務 器 程 序 通 常 在TCP 端 口110 提 供 服 務。 當 客 戶 想 要 使 用 服 務 時,
它 便 與 服 務 器 建 立 一個TCP 連 接。 一 旦 連 接 建 立,POP3 服 務 器 就 向 客 戶 發 送
一 條歡 迎 消 息。 然 后 客 戶 開 始 給 服 務 器 發 送 命 令, 服 務 器 則 給出 相 應 的 回
答。POP3 的 命 令 由 一 個 關 鍵 詞 或 者 關 鍵 詞 加 參數 組 成。 每 個 命 令 以 回 車 換 行
(0xD0xA) 作 為 結 束 標 志。 對于 所 有 的 命 令,POP3 服 務 器 都 會 提 供 一 個 回 答。
服 務 器 的回 答 由 一 個 狀 態 標 志 加 一 些 附 加 信 息 組 成。 目 前 使 用 的兩 個 標 志
是“ +OK” 和“ -ERR”, 分 別 表 示 客 戶 的 命 令 是 否合 法。 所 有 的 回 答 也 是 以
回 車 換 行 結 束。 與 本 文 討 論 的 話 題 相 關 的 四 個POP3 命 令 是USER、PASS、LIST
和QUIT。
USER 命 令
格 式USER name
其 中name 是 用 戶 在 該POP3 服 務器 上 的 用 戶 標 識。 客 戶 應 該 在 接 到 服 務 器
的 歡 迎 消 息 后或 者 在 上 一 個 USER 或 者PASS 失 敗 之 后 可 以 發 送 此 命 令。
PASS 命 令
格 式PASS string
其 中string 為 該 用 戶 的 密 碼。客 戶 在 發 送 了USER 命 令 并 且 收 到 了 +OK 的 回
答 之 后 方 可 發送 此 命 令。 如 果 用 戶 名 和 密 碼 都 正 確, 服 務 器 回 答 +OK,否
則 -ERR。
LIST 命 令
格 式LIST
如 果 該 用 戶 有 郵 件, 則LIST 命令 會 回 答 +OK, 并 列 出 所 有 郵 件 的 標 識 符
和 大 小( 每 個 郵件 一 行), 最 后 一 個 僅 包 含 一 個 句 點 的 行(0xD0xA0x2E) 表 示整
個 回 答 的 結 束。 如 果 該 用 戶 沒 有 郵 件, 有 些 服 務 器 會 返回 -ERR, 有 些 在 可
能 返 回 一 個 +OK 和 一 個 僅 包 含 一 個 句 點的 行。 當 然, 客 戶 必 須 在PASS 命 令 通
過 之 后 客 戶 程 序 才 能給 服 務 器 發 送LIST 命 令。
QUIT 命 令
從POP3 服 務 器 上 退 出 登 錄。
二、 實 現 相 關 函 數
接 下 來 我 們 按 照POP3 協 議 所 定 義的 通 信 規 則 來 實 現 一 個 名 叫POP3CheckMail
的 函 數, 只 要 調 用此 函 數, 我 們 就 可 以 檢 測 信 箱 了。
下 面 的 代 碼 是 用 與Delphi 4 兼 容的Pascal 語 言 實 現 的, 我 們 必 須 包 含WinSock
單 元, 并 且 在 調用 下 列 函 數 之 前 初 始 化 好WinSock 動 態 連 接 庫。 初 始 化WinSock
動 態 連 接 庫 的 代 碼 如 下:
if WSAStartup( $002, wsadata)<>0 then Halt;
POP3CheckMail 的 原 型 如 下:
function POP3CheckMail(Email,Password:String;var MailList:TStringList;var
ErrorMsg:String):Bool;
參 數 說 明:
Email 和Password 分 別 為 用 戶 的email 信 箱 名 和 口 令。
變 量 參 數MailList 用 于 返 回 郵件 的 標 識 和 大 小,MailList.Count 表 示 郵 件 的
封 數。
變 量 參 數ErrorMsg 返 回 出 錯 消息。
以 下 是POP3CheckMail 及 其 它 所 用到 的 函 數 的 實 現 代 碼。
Connect_Server 函 數
功 能: 與 指 定 的 主 機 建 立 一個TCP 連 接, 返 回 一 個Socket 描 述 符。 參 數host
指 定 主 機 的 名字,Port 指 定 端 口 號。
function Connect_Server(host:string;Port:integer):integer;
var i:integer;
p:^LongInt;
phe:pHostEnt;
sin:sockaddr_in;
begin
sin.sin_family:=AF_INET;
sin.sin_port:=htons(Port);
//Get the IP for host, allowing for dotted decimal
phe:=gethostbyname(pchar(host));
if phe<>nil
then begin
p:=Pointer(phe^.h_addr_list^);
sin.sin_addr.s_addr:=p^;
end
else begin
i:=inet_addr(PChar(Host));
if i<> -1 then sin.sin_addr.S_addr:=i
end;
//create a socket
Result:=socket(PF_INET,SOCK_STREAM,0);
if (Result=INVALID_SOCKET) then Exit;
//connect to server
if Connect(Result,sin,sizeof(sin))=SOCKET_ERROR
then begin {Error handling} end;
end;
Write_Socket 函 數
功 能: 向Socket 寫 入 一 個 字 符串。
function Write_Socket(sockfd:Integer; const s:string):Integer;
begin
result:=Winsock.Send(sockfd,pointer(s)^,Length(s),0)
end;
Socket_Readline 函 數
功 能: 從Socket 上 讀 取 一 行。
function Socket_Readline(sockfd:Integer):String;
//Read until #10
var S:String; buf:array[0..1]of Char;
n:Cardinal;
begin
buf[0]:= #0;buf[1]:= #0; S:=‘';
n:=recv(sockfd,Buf,1,0);
while n>0 do begin
buf[1]:= #0;
S:=S +buf;
if (buf[0]= #10) then Break;
n:=recv(sockfd, buf, 1, 0);
end;
Result:=Trim(S);
end;
Pop3Response 函 數
功 能: 讀 取POP3 服 務 器 的 一 行返 回 信 息, 如 果 是“ +OK” 則 函 數 返 回TURE,
如 果 是“ -ERR” 則 返 回FALSE。
function Pop3Response(Sockfd:Integer):Bool;
var S: string;
begin
S:=socket_readline(sockfd);
if copy(s,1,3)=‘ +OK' then Result:=True
else {if copy(s,1,4)=‘ -ERR' then }Result:=False;
end;
POP3CheckMail 函 數
功 能: 檢 測 名 字 為email 的 信 箱,如 果 有 新 郵 件, 則 通 過 變 量 參 數MailList
將 每 一 封 郵 件 的 大小 返 回。
function POP3CheckMail
(Email,Password:String;var MailList:
TStringList;var ErrorMsg:String):Bool;
var sockfd,i:integer;
S, Host, User:String;
begin
Result:=False; ErrorMsg:=‘';
if MailList=nil then Exit;
S:=Trim(Email);
i:=Pos(‘@',Email);
User:=Trim(Copy(S,1,i -1));
Host:=Trim(Copy(S,i +1,Length(Email) -i));
MailList.Clear;
if (user=‘')or(host=‘') then begin
ErrorMsg:=‘Invalid email address.';exit; end;
if (Host[1]=‘[')and (Host[Length(host)]=‘]')
then begin Host[1]:=‘ ';Host[Length(host)]:= #0;end;
Host:=Trim(host);
sockfd:=Connect_Server(Host,110);
if not Pop3Response(sockfd)then begin ErrorMsg:=
‘Cannot connect to server';exit; end;
Write_Socket(sockfd,‘USER ' +User + #13 #10);
IF NOT POP3Response(sockfd) then begin ErrorMsg:=
‘USER failed'; Exit;end;
Write_Socket(sockfd,‘PASS ' +Password + #13 #10);
IF NOT POP3Response(sockfd) then begin ErrorMsg:=
‘PASS failed'; Exit;end;
Write_Socket(sockfd,‘LIST' #13 #10);
POP3Response(sockfd);
while true do begin
s:=Socket_readline(sockfd);
if s=‘.' then BREAK;
MailList.Add(S);
end;
Write_Socket(sockfd,‘QUIT' #13 #10);
Closesocket(sockfd);
Result:=True;
end;
三、 郵 件 的 檢 測
下 面 我 們 來 看 一 個 使 用POP3CheckMail 函 數 的 簡 單 示 例。
var MailList:TstringList;
ErrorMsg:String;
...
MailList:=TstringList.Create;
POP3CheckMail(‘simon_liu@263.net',
‘mypassword', MailList, ErrorMsg);
If MailList.Count>0 then
MessageBox(0, Pchar(‘You have ' +IntToStr
(MailList.Count) + ‘ new messages!'),
‘New Message!', MB_ICONINFORMATION)
Else if ErrorMsg=‘' then MessageBox
(0, ‘No message!', ‘',0)
Else MessageBox(0, Pchar(ErrorMsg), ‘Error', 0);
MailList.Free;
如 果 你 仔 細 閱 讀 了POP3CheckMail 函數 的 實 現 代 碼, 你 會 發 現 此 函 數 除 了 可
以 獲 取 郵 件 的 封數 之 外, 還 可 以 獲 得 每 一 封 郵 件 的 大 小。 你 可 以 通 過
POP3CheckMail 函 數 的 變 量 參 數MailList 的Strings 數 組 來 獲 取 郵 件 的 大 小。
實 現 了POP3CheckMail 函 數, 再 在此 基 礎 上 編 寫 一 個POP3 信 箱 的 監 視 程 序 就
變 得 很 簡 單 了。你 可 以 通 過 一 個 定 時 器 來 定 期 地 調 用POP3CheckMail 函 數, 這樣
你 就 可 以 監 視 某 個email 信 箱 了。 假 若 你 想 要 同 時 監 視 多個email 信 箱, 只 要
為 每 一 個 信 箱 創 建 一 個 線 程 并 且 在 線 程中 定 期 調 用POP3CheckMail 函 數 即 可。
你 的 程 序 中 如 果 沒 有 使用Delphi 的 控 件, 那 么 一 個 完 整 的 信 箱 監 視 程 序 可
能 只 有60K 左 右。
■ 作者:劉明華
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -