一、 关 于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_.net;
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:=.net_addr(pchar(host));
if i<> -1 then sin.sin_addr.s_addr:=i
end;
//create a socket
result:=socket(pf_.net,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 左 右。
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器