uCheckEmailThread.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:9k
源码类别:

Email服务器

开发平台:

Delphi

  1. //
  2. //检查新邮件
  3. //
  4. unit uCheckEmailThread;
  5. interface
  6. uses Classes,IniFiles,WinSock,Windows,SysUtils;
  7. const
  8.   RESPONSE_OK='+OK';
  9.   RESPONSE_ERR='-ERR';
  10.   DATA_END=#$D#$A'.'#$D#$A;
  11.   CRLF=#$D#$A;
  12.   
  13. type
  14.   TAccount=record
  15.     Pop3ServerAddr:string[120];
  16.     SeverPort:Integer;
  17.     EmailAccount:string[120];
  18.     EmailPwd:string[20];
  19.   end;
  20.   TAccounts=array of TAccount;
  21.   TCheckEmailSocket=class
  22.   private
  23.     FSocketTalk:TSocket;
  24.     FTimeOut:Integer; //以秒记
  25.     FWaitServer:Boolean;
  26.     FBuffer:TStringStream;
  27.     procedure SetTimeOut(const Value: Integer);
  28.   protected
  29.     function SendCmd(CMD:string):Boolean;
  30.     function RecvBuffer(EndStr:string=DATA_END):Boolean;
  31.     procedure WaitServer;
  32.   public
  33.     function Login(UserName,Password:string):Boolean;
  34.     function Connect(Server:string;Port:Word):Boolean;
  35.     function Quit:Boolean;
  36.     function GetUIDLS(List:TStrings):Boolean;
  37.     constructor Create;
  38.     destructor Destroy;override;
  39.     property  TimeOut:Integer  read FTimeOut write SetTimeOut;
  40.   end;
  41.   TNewEmailArrive=procedure (Sender:TObject;NewEmailUIDLs:TStrings) of object;
  42.   TCheckEmailThread=class(TThread)
  43.   private
  44.     FCheckEmailSocket:TCheckEmailSocket;
  45.     FAccounts:TAccounts; //保存需要检查新邮件的邮箱的信息
  46.     //FBlackList,
  47.     //FWhiteList:TStrings;    //保存黑白名单
  48.     FOldEmailUIDLS, //保存已经下载了的email的uidl
  49.     FUILDsOnServer,
  50.     FNewEmailUIDLs:TStrings;
  51.     FNewEmailArrive:TNewEmailArrive;
  52.     procedure DoOnNewEmail;
  53.     procedure SetOldEmailUIDLS(const Value: TStrings);
  54.   protected
  55.     procedure Execute;override;
  56.   public
  57.     constructor Create(AAccount:TAccounts;AOldEmailUIDLS:TStrings);
  58.     destructor Destroy;override;
  59.     property  OnNewEmailArrive:TNewEmailArrive  read FNewEmailArrive write FNewEmailArrive;
  60.     property  OldEmailUIDLS:TStrings  read FOldEmailUIDLS write SetOldEmailUIDLS;
  61.   end;
  62. implementation
  63. uses uCommon;
  64. { TCheckEmailThread }
  65. constructor TCheckEmailThread.Create(AAccount: TAccounts;
  66.   AOldEmailUIDLS: TStrings);
  67. var
  68.   I:Integer;
  69. begin
  70.   inherited Create(True);
  71.   SetLength(FAccounts,Length(AAccount));
  72.   for I:=0 to Length(AAccount)-1 do FAccounts[I]:=AAccount[I];
  73.   FOldEmailUIDLS:=THashedStringList.Create;
  74.   FNewEmailUIDLs:=THashedStringList.Create;
  75.   FUILDsOnServer:=THashedStringList.Create;
  76.   FOldEmailUIDLS.Assign(AOldEmailUIDLS);
  77.   Self.Priority:=tpLower;
  78.   
  79.   FreeOnTerminate:=True;
  80. //  Resume;
  81. end;
  82. destructor TCheckEmailThread.Destroy;
  83. begin
  84.   FOldEmailUIDLS.Free;
  85.   FNewEmailUIDLs.Free;
  86.   FUILDsOnServer.Free;
  87.   inherited;
  88. end;
  89. procedure TCheckEmailThread.DoOnNewEmail;
  90. begin
  91.   WriteLog('TCheckEmailThread.DoOnNewEmail_FNewEmailUIDLs.Text:'+FNewEmailUIDLs.Text);
  92.   if Assigned(FNewEmailArrive) then FNewEmailArrive(Self,FNewEmailUIDLs);
  93. end;
  94. procedure TCheckEmailThread.Execute;
  95. var
  96.   I,J:Integer;
  97.   info:PPop3LoginInfo;
  98. begin
  99.   WriteLog(#$D#$A'----------------CheckEmail Begin--------------------');
  100.   for I:=0 to Length(FAccounts)-1 do
  101.   begin
  102.     if Self.Terminated then Exit;
  103.     FUILDsOnServer.Clear;
  104.     FCheckEmailSocket:=TCheckEmailSocket.Create;
  105.     FCheckEmailSocket.TimeOut:=6;
  106.     try
  107.       if FCheckEmailSocket.Connect(FAccounts[I].Pop3ServerAddr,FAccounts[I].SeverPort) then
  108.       begin
  109.         try
  110.           if Self.Terminated then Exit;
  111.           if   FCheckEmailSocket.Login(FAccounts[I].EmailAccount,FAccounts[I].EmailPwd) then
  112.           begin
  113.             if Self.Terminated then Exit;
  114.             if FCheckEmailSocket.GetUIDLS(FUILDsOnServer) then
  115.             begin
  116.               if Self.Terminated then Exit;
  117.               FNewEmailUIDLs.Clear;
  118.               for J:=0 to FUILDsOnServer.Count-1 do
  119.               begin
  120.                 WriteLog('FUILDsOnServer:'+FUILDsOnServer.Text);
  121.                 WriteLog('FOldEmailUIDLS:'+FOldEmailUIDLS.Text);
  122.                 if FOldEmailUIDLS.IndexOf(PartStr(FUILDsOnServer[J],#32,True))=-1 then
  123.                 begin
  124.                   New(info);
  125.                   FillChar(info^,SizeOf(TPop3LoginInfo),0);
  126.                   info.FPopServer:=FAccounts[I].Pop3ServerAddr;
  127.                   info.FPort:=FAccounts[I].SeverPort;
  128.                   info.FUserName:=FAccounts[I].EmailAccount;
  129.                   info.FPwd:=FAccounts[I].EmailPwd;
  130.                   FNewEmailUIDLs.AddObject(FUILDsOnServer[J],TObject(info));  //these Objects MUST dispose !!!
  131.                 end;
  132.               end;
  133.               if FNewEmailUIDLs.Count>0 then
  134.                 Synchronize(DoOnNewEmail);
  135.               if Self.Terminated then Exit;
  136.             end;
  137.           end;
  138.         finally
  139.           FCheckEmailSocket.Quit;
  140.         end;
  141.       end;
  142.     finally
  143.       FCheckEmailSocket.Free;
  144.     end;
  145.   end;
  146.   WriteLog('----------------CheckEmail END--------------------'#$D#$A);
  147. end;
  148. procedure TCheckEmailThread.SetOldEmailUIDLS(const Value: TStrings);
  149. begin
  150.   FOldEmailUIDLS.Assign(Value);
  151. end;
  152. { TCheckEmailSocket }
  153. function TCheckEmailSocket.Connect(Server: string; Port: Word): Boolean;
  154. var
  155.   Addr:sockaddr_in;
  156.   PHost:PHostEnt;
  157.   P:^LongInt;
  158. begin
  159.   PHost:=gethostbyname(PAnsiChar(Server));
  160.   if PHost=nil then
  161.     raise Exception.Create(SysErrorMessage(WSAGetLastError));
  162.   Addr.sin_port:=htons(Port);
  163.   Addr.sin_family:=AF_INET;
  164.   P:=Pointer(PHost.h_addr_list^);
  165.   Addr.sin_addr.S_addr:=P^;
  166.   Result:= WinSock.connect(FSocketTalk,Addr, SizeOf(Addr))=0;
  167. end;
  168. constructor TCheckEmailSocket.Create;
  169. var
  170.   data:TWSAData;
  171.   timeout:Integer;
  172.   opt:LongBool;
  173. begin
  174.   if WSAStartup(MakeWord(2,0),data)<>0 then
  175.     raise Exception.Create('Couldn''t find a usable  WinSock DLL');
  176.   FBuffer:=TStringStream.Create('');
  177.   FSocketTalk:=socket(AF_INET,SOCK_STREAM,0);
  178.   if FSocketTalk=INVALID_SOCKET then raise Exception.Create('Couldn''t Allocate Socket Handle');
  179.   FTimeOut:=6;
  180.   opt:=True;
  181.   setsockopt(FSocketTalk,SOL_SOCKET,SO_KEEPALIVE,@opt,SizeOf(LongBool));
  182.   timeout:=2048;
  183.   setsockopt(FSocketTalk,SOL_SOCKET,SO_RCVBUF,@timeout,SizeOf(timeout))
  184. end;
  185. destructor TCheckEmailSocket.Destroy;
  186. begin
  187.   FBuffer.Free;
  188.   closesocket(FSocketTalk);
  189.   WSACleanup;
  190.   inherited;
  191. end;
  192. function TCheckEmailSocket.GetUIDLS(List: TStrings): Boolean;
  193. begin
  194.   List.Clear;
  195.   Result:= SendCmd('UIDL '#$D#$A);
  196.   if Result then
  197.   begin
  198.     Result:=RecvBuffer(DATA_END);
  199.     if not Result then Exit;
  200.     Result:=StrBeginWith(RESPONSE_OK,FBuffer.DataString);
  201.     if Result then
  202.     begin
  203.       Split(#$D#$A,FBuffer.DataString,List);
  204.       WriteLog('Split:'+List.Text);
  205.       if List.Count>=2 then
  206.       begin
  207.         List.Delete(0);  //delte +OK
  208.         List.Delete(List.Count-1); //delete .
  209.       end;
  210.       
  211.       if List.Count>0 then
  212.         if StrBeginWith(RESPONSE_OK+#32,List.Strings[0]) then List.Delete(0);
  213.         
  214.       Result:=List.Count>0;
  215.       WriteLog('List.Text:'+List.Text);
  216.     end;
  217.   end;
  218. end;
  219. function TCheckEmailSocket.Login(UserName, Password: string): Boolean;
  220. begin
  221.    Result:= SendCmd('USER '+UserName+#$D#$A);
  222.    if Result then
  223.    begin
  224.      Result:=RecvBuffer(#$D#$A);
  225.      if not Result then Exit;
  226.      Result:=StrBeginWith(RESPONSE_OK,FBuffer.DataString);
  227.      if Result and SendCmd('PASS '+trim(password)+#$D#$A) then
  228.      begin
  229.        Result:=RecvBuffer(#$D#$A);
  230.        if Result then Result := StrBeginWith(RESPONSE_OK,FBuffer.DataString);
  231.      end;
  232.   end;
  233. end;
  234. function TCheckEmailSocket.Quit: Boolean;
  235. begin
  236.   Result:= SendCmd('QUIT '#$D#$A);
  237.   if Result then
  238.     Result:=RecvBuffer(#$D#$A);
  239. end;
  240. function TCheckEmailSocket.RecvBuffer(EndStr:string): Boolean;
  241. var
  242.   ret:Integer;
  243.   fdRead:TFDSet;
  244.   t:timeval;
  245.   TempBuf:PAnsiChar;
  246. begin
  247.   t.tv_sec:=FTimeOut;
  248.   t.tv_usec:=0;
  249.   Result:=False;
  250.   FBuffer.Position:=0;
  251.   FBuffer.Size:=0;
  252.   GetMem(TempBuf,1024);
  253.   try
  254.     while True do
  255.     begin
  256.       FillChar(TempBuf^,1024,0);
  257.       FD_ZERO(fdRead);
  258.       FD_SET(FSocketTalk,fdRead);
  259.       ret:= select(0,@fdRead,nil,nil,@t);
  260.             
  261.       IF FD_ISSET(FSocketTalk,fdRead) THEN
  262.         FD_CLR(FSocketTalk,fdRead);
  263.       if (ret=SOCKET_ERROR) or (ret=0) then  Break; {发生错误或超时}
  264.       ret:=recv(FSocketTalk,TempBuf^,1024,0);
  265.       if (ret=SOCKET_ERROR) OR (ret=0) then Break; {发生错误或服务器关闭连接}
  266.       if ret >0 then
  267.       begin
  268.         FBuffer.WriteBuffer(TempBuf^,ret);
  269.         if FBuffer.Size> Length(EndStr) then
  270.         begin
  271.           if StrEndWith(EndStr,FBuffer.DataString) then
  272.           begin
  273.             Result:=True;
  274.             Break; //服务器发送完毕
  275.           end;
  276.         end;
  277.       end;
  278.     end;
  279.   finally
  280.     FreeMem(TempBuf);
  281.   end;
  282. end;
  283. function TCheckEmailSocket.SendCmd(CMD: string): Boolean;
  284. begin
  285.   Result:= send(FSocketTalk,CMD[1],Length(CMD),0)<>SOCKET_ERROR;
  286.   if Result and FWaitServer then WaitServer;
  287. end;
  288. procedure TCheckEmailSocket.SetTimeOut(const Value: Integer);
  289. begin
  290.   if FTimeOut<>Value then
  291.   begin
  292.     FTimeOut := Value;
  293.     timeout:=FTimeOut*1000;
  294.     setsockopt(FSocketTalk,IPPROTO_TCP,SO_SNDTIMEO,@timeout,SizeOf(Integer)); //if setsockopt's return<>0 then error;
  295.   end;
  296. end;
  297. procedure TCheckEmailSocket.WaitServer;
  298. begin
  299. end;
  300. end.