监督POP3信箱
副标题#e#
本文将向各人先容奈何编写本身的信箱监督措施,措施将直接挪用WinSock函数来举办网络通信。除了具备WinSock编程常识之外,还必需相识POP3协议。下面是对POP3的一个大致的先容,读者可以参看RFC1225更为具体地相识该协议。
一、关于POP3协议
POP3处事器措施凡是在TCP端口110提供处事。当客户想要利用处事时,它便与处事器成立一个TCP毗连。一旦毗连成立,POP3处事器就向客户发送一条接待动静。然后客户开始给处事器发送呼吁,处事器则给出相应的答复。POP3的呼吁由一个要害词可能要害词加参数构成。每个呼吁以回车换行(0xD0xA)作为竣事符号。对付所有的呼吁,POP3处事器城市提供一个答复。处事器的答复由一个状态符号加一些附加信息构成。今朝利用的两个符号是“+OK”和“-ERR”,别离暗示客户的呼吁是否正当。所有的答复也是以回车换行竣事。
与本文接头的话题相关的四个POP3呼吁是USER、PASS、LIST和QUIT。
USER呼吁
名目USERname
个中name是用户在该POP3处事器上的用户标识。客户应该在接随处事器的接待动静后可能在上一个USER可能PASS失败之后可以发送此呼吁。
PASS呼吁
名目PASSstring
个中string为该用户的暗码。客户在发送了USER呼吁而且收到了+OK的答复之后方可发送此呼吁。假如用户名和暗码都正确,处事器答复+OK,不然-ERR。
LIST呼吁
名目LIST
假如该用户有邮件,则LIST呼吁会答复+OK,并列出所有邮件的标识符和巨细(每个邮件一行),最后一个仅包括一个句点的行(0xD0xA0x2E)暗示整个答复的竣事。假如该用户没有邮件,有些处事器会返回-ERR,有些在大概返回一个+OK和一个仅包括一个句点的行。虽然,客户必需在PASS呼吁通过之后客户措施才气给处事器发送LIST呼吁。
QUIT呼吁
从POP3处事器上退出登录。
二、实现相关函数
接下来我们凭据POP3协议所界说的通信法则来实现一个名叫POP3CheckMail的函数,只要挪用此函数,我们就可以检测信箱了。
下面的代码是用与Delphi4兼容的Pascal语言实现的,我们必需包括WinSock单位,而且在挪用下列函数之前初始化好WinSock动态毗连库。初始化WinSock动态毗连库的代码如下:
ifWSAStartup($002,wsadata)<>0thenHalt;
POP3CheckMail的原型如下:
functionPOP3CheckMail(Email,Password:String;varMailList:TStringList;varErrorMsg:String):Bool;
参数说明:
Email和Password别离为用户的email信箱名和口令。
变量参数MailList用于返回邮件的标识和巨细,MailList.Count暗示邮件的封数。
变量参数ErrorMsg返回堕落动静。
#p#副标题#e#
以下是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将每一封邮件的巨细返回。
#p#分页标题#e#
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(‘[email protected]',
‘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阁下。