Delphi中怎样监视POP3信箱
---- 本 文 将 向 大 家 介 绍 怎 样 编 写自 己 的 信 箱 监 视 程
序, 程 序 将 直 接 调 用WinSock 函 数 来 进 行网 络 通 信。 除 了
具 备WinSock 编 程 知 识 之 外, 还 必 须 了 解POP3 协 议。 下 面 是
对POP3 的 一 个 粗 略 的 介 绍, 读 者 可 以 参 看RFC 1225 更 为 详 细
地 了 解 该 协 议。 一、 关 于POP3 协 议 USER 命 令 其 中name 是 用 户 在 该POP3 服 务器 上 的 用 户 标 识。 客 户 应 该 在 接 到 服 务 器 的 欢 迎 消 息 后或 者 在 上 一 个 USER 或 者PASS 失 败 之 后 可 以 发 送 此 命 令。 PASS 命 令 其 中string 为 该 用 户 的 密 码。客 户 在 发 送 了USER 命 令 并 且 收 到 了 +OK 的 回 答 之 后 方 可 发送 此 命 令。 如 果 用 户 名 和 密 码 都 正 确, 服 务 器 回 答 +OK,否 则 -ERR。 LIST 命 令 如 果 该 用 户 有 邮 件, 则LIST 命令 会 回 答 +OK, 并 列 出 所 有 邮 件 的 标 识 符 和 大 小( 每 个 邮件 一 行), 最 后 一 个 仅 包 含 一 个 句 点 的 行(0xD0xA0x2E) 表 示整 个 回 答 的 结 束。 如 果 该 用 户 没 有 邮 件, 有 些 服 务 器 会 返回 -ERR, 有 些 在 可 能 返 回 一 个 +OK 和 一 个 仅 包 含 一 个 句 点的 行。 当 然, 客 户 必 须 在PASS 命 令 通 过 之 后 客 户 程 序 才 能给 服 务 器 发 送LIST 命 令。 QUIT 命 令 从POP3 服 务 器 上 退 出 登 录。 二、 实 现 相 关 函 数 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; 功 能: 向Socket 写 入 一 个 字 符串。 function Write_Socket(sockfd:Integer; const s:string):Integer; begin result:=Winsock.Send(sockfd,pointer(s)^,Length(s),0) end; 功 能: 从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; 功 能: 读 取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; 功 能: 检 测 名 字 为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; 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 函 数, 再 在此 基 础 上 编 写 一 个POP3
信 箱 的 监 视 程 序 就 变 得 很 简 单 了。你 可 以 通 过 一 个 定
时 器 来 定 期 地 调 用POP3CheckMail 函 数, 这样 你 就 可 以 监 视 某
个email 信 箱 了。 假 若 你 想 要 同 时 监 视 多个email 信 箱, 只 要
为 每 一 个 信 箱 创 建 一 个 线 程 并 且 在 线 程中 定 期 调 用POP3CheckMail
函 数 即 可。 你 的 程 序 中 如 果 没 有 使用Delphi 的 控 件, 那 么
一 个 完 整 的 信 箱 监 视 程 序 可 能 只 有60K 左 右。
|