荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: georgehill (佐治·希尔【多情网虫无情网】), 信区: Program
标  题: 监视POP3信箱
发信站: BBS 荔园晨风站 (Sun Mar 12 02:11:43 2000), 转信

资料整理·中国程序员网站


监视POP3信箱


----本文将向大家介绍怎样编写自己的信箱监视程序,程序将直接调用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的函
数,只要调用此函数,我们就可以检测信箱了。
----下面的代码是用与Delphi4兼容的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左右。

--
        那你可不可以教我,
        有什么办法可以不去喜欢一个人呢?

                -- Bye 赤明莉香 --
 我是来自大富翁的小美!^_^

※ 来源:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.1.115]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店