⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 icqdirect2.pas

📁 本程序是转载的
💻 PAS
📖 第 1 页 / 共 3 页
字号:
unit ICQDirect2;
{************************************************
    For updates checkout: http://www.cobans.net
      (C) Alex Demchenko(alex@ritlabs.com)
          Gene Reeves(notgiven2k@lycos.com)
*************************************************}

{ Created on 01-2003}

{$HINTS OFF}

interface
//****************************************************************************//
// TicqDCM - Direct Connection Manager                                        //
//           Supplies interface to ICQClient for managing DCs.                //
//                                                                            //
// TicqBaseDC - Base class for direct connection                              //
//            Handles all common tasks in a DC                                //
//                                                                            //
// TicqDCxxxx - Direct Connection Handler classes                             //
//   TicqDCNormal   - Main DC class used for Msg, File Req, Chat Req, etc.    //
//   TicqDCRecvFile - DC class used to receive files.                         //
//   TicqDCSendFile - DC class used to send files                             //
//   TicqDCChat     - DC class used for chat sessions.                        //
//                                                                            //
//****************************************************************************//
// To Add New DC Type:                                                        //
//                                                                            //
//   1. Create new subclass of TicqBaseDC.                                    //
//   2. Implement Start, Stop and HandlePacket routines in new subclass.      //
//   3. Add interface routines to TicqDCM for needed functionality.           //
//                                                                            //
//****************************************************************************//


// {ToDo}
// Need to add proxy support back into DC's
//     must be done in ICQSock.pas.
// Need to finish TicqDCChat class


Uses
  Classes, Sysutils, ICQWorks, ICQSock, WinSock, Windows;

Type
  PicqDirectUser = ^TicqDirectUser;
  TicqDirectUser = record
    UIN, Cookie,
    ExtIP, IntIP: LongWord;
    Port:Word;
    IsConnected:Boolean;
    LastActivity: LongWord; // Last tickcount of activity
    DCMain,
    DCRecvFile,
    DCSendFile,
    DCChat:Integer
  End;
  TDirectUser = TicqDirectUser;
  TicqBaseDC = class;
  TicqDCnormal = Class;


  //TicqEventType = (ET_NORMAL, ET_FILE_RECV, ET_FILE_SEND, ET_CHAT);

  TicqDCEvent = Procedure(Sender: TicqBaseDC) of Object;
  TOnHandle = procedure(Sender: TObject; UIN: LongWord; Pak: PRawPkt; Len: LongWord) of object;
  TOnParseDirectPkt = procedure(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean; UIN:Cardinal) of object;

  //Direct Connection Manager
  TicqDCM = Class(TObject)
    Private
      fSrv:TSrvSocket;
      fTmpDC:TicqDCNormal;
      fPort:Word;
      fProxyType: TProxyType;
      fProxyHost: String;
      fProxyPort: Word;
      fProxyAuth: Boolean;
      fProxyPass: String;
      fUserID: String;
      fResolve: Boolean;
      fOnError: TOnError;
      fOnPktDump: TOnParseDirectPkt;
      fOnHandle:TOnHandle;
      fOnFTInit: TOnFTInit;
      fOnFTStart: TOnFTStart;
      fOnFTFileData: TOnFTFileData;
      fOnSendFileStart:TOnSendFileStart;
      fOnSendFileData:TOnSendFileData;
      fOnSendFileFinish:TOnSendFileFinish;
      fpUser:PicqDirectUser;
      fDestroying:Boolean;
      fTmrIdle:TThreadTimer;

      procedure InternalOnErrorProc(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String); virtual;
      procedure InternalOnPktDump(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean; UIN: Cardinal);
      procedure InternalOnHandle(Sender: TObject; UIN: LongWord; Pak: PRawPkt; Len: LongWord);
      procedure OnIdleTimeOut(Sender: TObject);
      procedure OnSrvSockConnect(Sender: TObject; Socket: TMySocket);
    Public
      MyUIN:LongWord;
      fDCL:TList;   // List of DC's
      fUL:TList;    // List of User DC Info.
      constructor Create(aMyUIN: LongWord);
      destructor Destroy; override;

      Function ExtIP:LongWord;
      Function IntIP:LongWord;

      procedure AddUser(aUIN, aCookie, aIPExt, aIPInt: LongWord; aPort: Word);
      Function GetUserIndex(aUIN:LongWord; Var Idx:integer):Boolean;
      Procedure HandleDCEvent(Sender: TicqBaseDC);
      Function SendData(aUIN:LongWord; pPkt: PRawPkt):Boolean;
      function SendDataFile(aUIN: LongWord; Pak: PRawPkt): Boolean;
      Procedure DeleteUser(aUIN: LongWord);
      Procedure DeleteDC(Var aIndex:Integer);
      function AddFileUser(aUIN: LongWord; var aPort: Word; FTReqRec:Pointer = nil): Boolean;
      Procedure SetFileRecord(aUIN: LongWord; aFileRec:TSendFileRec);
      Function AddSendFileUser(aUIN:LongWord; Var aPort, aSeq:Word):Boolean;
      function StopFileReceiving(aUIN: LongWord): Boolean;
      Procedure StopFileSending(aUIN: LongWOrd);
      procedure EstabilishConnection(aUIN: LongWord);
      function ConnectionEstabilished(aUIN: LongWord): Boolean;

      property BindPort: Word read FPort;
      property ProxyType: TProxyType read FProxyType write FProxyType;
      property ProxyHost: String read FProxyHost write FProxyHost;
      property ProxyPort: Word read FProxyPort write FProxyPort;
      property ProxyUserID: String read FUserID write FUserID;
      property ProxyAuth: Boolean read FProxyAuth write FProxyAuth;
      property ProxyPass: String read FProxyPass write FProxyPass;
      property UseProxyResolve: Boolean read FResolve write FResolve default False;
      Property pUser:PicqDirectUser read fpUser;

      property OnPktDump: TOnParseDirectPkt read FOnPktDump write FOnPktDump;
      property OnHandle: TOnHandle read FOnHandle write FOnHandle;
      property OnError: TOnError read FOnError write FOnError;

      property OnFTInit: TOnFTInit read FOnFTInit write FOnFTInit;
      property OnFTStart: TOnFTStart read FOnFTStart write FOnFTStart;
      property OnFTFileData: TOnFTFileData read FOnFTFileData write FOnFTFileData;
      Property OnSendFileStart:TonSendFileStart read FOnSendFileStart write FOnSendFileStart;
      Property OnSendFileData:TOnSendFileData read fOnSendFileData write fOnSendFileData;
      Property OnSendFileFinish:TOnSendFileFinish read fOnSendFileFinish write fOnSendFileFinish;
  End;
  TDirectControl = Class(TicqDCM);
  TDirectClient = TDirectControl;
  //Base Direct Connection Type
  TicqBaseDC = Class(TObject)
    Protected
      fManager:TicqDCM;
      fOnDCEvent:TicqDCEvent;
      fRemUIN:LongWord;
      FPort:Word;
      fIncoming:Boolean;
      FProxyType: TProxyType;
      FProxyHost: String;
      FProxyPort: Word;
      FProxyAuth: Boolean;
      FProxyPass: String;
      FUserID: String;
      FResolve: Boolean;
      FOnError: TOnError;
      FOnPktDump: TOnParseDirectPkt;
      fOnHandle: TOnHandle;
      fpUser: PicqDirectUser;
      CSck:TMySocket;
      SSck:TSrvSocket;
      fDPkt:TRawPkt;
      fPktLen:Integer;
      fPktSize:Integer;

      procedure SetCSck(aSock:TMySocket);
      procedure OnSockError(Sender: TObject);
      procedure OnSockConnectError(Sender: TObject);
      procedure OnConnect(Sender: TObject);
      procedure OnReceive(Sender: TObject; Socket: TSocket; Buffer: Pointer; BufLen: LongWord);
      procedure OnIntPktDump(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean; UIN: Cardinal);
      procedure OnIntError(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String); virtual;
    Public
      EventType:Integer;
      MyUIN:LongWord;

      constructor Create(aMyUIN: LongWord);
      destructor Destroy; override;

      Function Start:Boolean;Virtual;abstract;  //Used to start connection.
      Procedure Stop;Virtual;abstract;          //Used to stop connection.
      Function SendData(Pkt: PRawPkt):Boolean;Virtual; // Used to Send Data through Connection.
      Function HandlePacket(pPkt: PRawPkt; PktLen:Integer):Boolean;Virtual;

      Property Client:TMySocket Read CSck write SetCSck;

      Property RemoteUIN:LongWord read fRemUIN write fRemUIN;
      property BindPort: Word read FPort;
      property ProxyType: TProxyType read FProxyType write FProxyType;
      property ProxyHost: String read FProxyHost write FProxyHost;
      property ProxyPort: Word read FProxyPort write FProxyPort;
      property ProxyUserID: String read FUserID write FUserID;
      property ProxyAuth: Boolean read FProxyAuth write FProxyAuth;
      property ProxyPass: String read FProxyPass write FProxyPass;
      property UseProxyResolve: Boolean read FResolve write FResolve default False;

      Property OnDCEvent:TicqDCEvent read fOnDCEvent write fOnDCEvent;
      property OnPktDump: TOnParseDirectPkt read FOnPktDump write FOnPktDump;
      property OnHandle: TOnHandle read fOnHandle write fOnHandle;
      property OnError: TOnError read FOnError write FOnError;
  End;

  // DC for Main DC
  TicqDCNormal = Class(TicqBaseDC)
    Private

    Public
      Constructor Create(aMyUIN: LongWord; aClient: TMySocket; Incoming:Boolean);

      Function Start:Boolean;override;
      Procedure Stop;override;
      Function HandlePacket(pPkt: PRawPkt; PktLen:Integer):Boolean; Override;
  End;

  // DC for Recv File
  TicqDCRecvFile = Class(TicqBaseDC)
    private
      fSrvConnected:Boolean;
      Procedure OnRFSrvSockConnect(Sender: TObject; Socket: TMySocket);
    Public
      PDataPacket:PRawPkt;
      DataPacketLen:LongWord;
      IsLastPacket:Boolean;
      TotalBytes:LongWord;
      NickName:String;
      FTStartRec:TFTStartRec;
      FTRequestRec:TFTRequestRec;
      FTPos:LongWord;

      Constructor Create(MyUIN, aUIN: LongWord; aPort:Dword);

      Function Start:Boolean;override;
      Procedure Stop;override;
      Function HandlePacket(pPkt: PRawPkt; PktLen:Integer):Boolean; Override;
  End;

  // DC for Send File
  TicqDCSendFile = Class(TicqBaseDC)
    Private
      tmrSend:TThreadTimer;
      fPeerReady:Boolean;
      fRemPort:DWord;
      fSeq:Word;
      fPkt:TRawPkt;
      fConnectionFinished: Boolean;
      fTransfering:Boolean;
      fAborted:Boolean;

      procedure OnSFConnect(Sender: TObject);
      procedure OnSFDisconnect(Sender: TObject);
      procedure OnSendTimer(Sender: TObject);
      Procedure OnDataSent(Sender: TObject);
    Public
      PDataPacket:PRawPkt;
      DataPacketLen:LongWord;
      IsLastPacket:Boolean;
      SendFileRecord:TSendFileRec;

      Constructor Create(MyUIN, aUIN: LongWord; aFileRec:TSendFileRec);
      Destructor Destroy;override;

      Function Start:Boolean;override;
      Procedure Stop;override;
      Function HandlePacket(pPkt: PRawPkt; PktLen:Integer):Boolean; Override;

      Property Aborted:Boolean read fAborted;
  End;

  // DC for chat
  TicqDCChat = Class(TicqBaseDC)
    Private
    Public
  End;

Const
  // PEER Commands
  PEER_INIT        = $FF;
  PEER_INIT2       = $03;
  PEER_MSG         = $02;
  PEER_FILE_INIT   = $00;
  PEER_FILE_INITACK= $01;
  PEER_FILE_DATA   = $06;
  //Event Types
  DCEVENT_OnFTInit        = $0002;
  DCEVENT_OnFTStart       = $0004;
  DCEVENT_OnFTFileData    = $0008;
  DCEVENT_OnSendFileStart = $0020;
  DCEVENT_OnSendFileData  = $0040;
  DCEVENT_OnSendFileFinish= $0080;
  // Idle Timeout
  MAXTICKS_TIMEOUT = 18*60*60*5; { 5 min in ticks = 18 ticks per sec, 60 sec per min, 5 min}

ResourceString
  RS_ERROR_BUFFEROVERRUN          = 'Buffer Overrun Error';
  RS_ERROR_NO_DC_WRONGVER         = 'Can not estabilish direct connection due to client using an unsupported protocol version.';
  RS_ERROR_NO_DC_SECURITY         = 'Can not estabilish direct connection due to security issues.';
  RS_ERROR_NO_DC_UNSUPPORTEDPROXY = 'Can not estabilish direct connection due to client using an unsupported proxy type.';
  RS_ERROR_NO_DC_PACKETERROR      = 'Can not estabilish direct connection due to Packet Error.';

implementation

Procedure GiveUpCpuTime;
var
  Msg: TMsg;
begin
  While PeekMessage(Msg, 0, 0, 0, PM_REMOVE) Do
      begin
        TranslateMessage(Msg);
        DispatchMessage(Msg);
      end;
End;

procedure FreeAndNil(var Obj);
var
  P: TObject;
begin
  P := TObject(Obj);
  TObject(Obj) := nil;
  P.Free;
end;

Function IPToStr(aIP:LongWord):String;
Var
  HV:String;
Begin
  HV := IntToHex(aIP, 8);
  Result := '';
  Result := IntToStr(HexToInt(Copy(HV, 7, 2))) + '.';
  Result := Result + IntToStr(HexToInt(Copy(HV, 5, 2)))+ '.';
  Result := Result + IntToStr(HexToInt(Copy(HV, 3, 2))) + '.';
  Result := Result + IntToStr(HexToInt(Copy(HV, 1, 2)));
End;

//****************************************************************************//
{ TicqDCM }
constructor TicqDCM.Create(aMyUIN: LongWord);
Begin
  inherited Create;
  fDestroying := False;
  fUL   := TList.Create;
  fDCL  := TList.Create;
  MyUIN := aMyUin;
  fPort := FindBindPort;
  GetMem(fpUser, SizeOf(TicqDirectUser));
  With fpUser^ Do Begin
    UIN := MyUIN;
    Port := fPort;
    ExtIP := LongWord(GetLocalIP);
    IntIP := LongWord(GetLocalIP);
    LastActivity := GetTickCount;
    DCMain := -1;
    DCRecvFile := -1;
    DCSendFile := -1;
    DCChat     := -1;
  End;
  fSrv  := TSrvSocket.Create;
  fOnError := Nil;
  fOnPktDump := Nil;
  fOnHandle := Nil;

  // idle timeout timer (fires once a sec and checks for nonactivity for MAXTICKS_TIMEOUT)
  fTmrIdle := TThreadTimer.Create;
  fTmrIdle.Interval := 1000;
  fTmrIdle.OnTimer := OnIdleTimeOut;
  fTmrIdle.Enabled := True;

  fSrv.OnClientConnected := OnSrvSockConnect;

  fSrv.StartServer(fPort);
End;

destructor TicqDCM.Destroy;
Begin
  fTmrIdle.Enabled := False;
  fTmrIdle.OnTimer := nil;
  fTmrIdle.Free;

  If fDestroying then Exit;
  fDestroying := True;
  fSrv.OnClientConnected := nil;
  fSrv.StopServer;
  fSrv.Free;
  While fUL.Count > 0 do
    DeleteUser(PicqDirectUser(fUL.items[0])^.UIN);
  fUL.Free;
  fDCL.Free;
  FreeMemory(fpUser);
End;

Procedure TicqDCM.OnIdleTimeOut(Sender: TObject);
Var
  i:integer;
  aTC:LongWord;
Begin

  If fUL.Count = 0 then Exit;
  aTC := GetTickCount - MAXTICKS_TIMEOUT;

  For i := 0 to fUL.Count -1 Do
    With PicqDirectUser(fUL[i])^ Do
      If LastActivity < aTC then Begin
        if DCMain <> -1 then
          DeleteDC(DCMain);
    End;
End;

Function TicqDCM.ExtIP:LongWord;
Begin
  Result := fpUser^.ExtIP;
End;

Function TicqDCM.IntIP:LongWord;
Begin
  Result := fpUser^.IntIP;
End;

procedure TicqDCM.OnSrvSockConnect(Sender: TObject; Socket: TMySocket);
Begin
  // Using Temp DC until recv PEER_INIT with user info.
  fTmpDC := TicqDCNormal.Create(0,Socket, True);
  GetMem(fTmpDC.fpUser, SizeOf(TicqDirectUser));
  fTmpDC.MyUIN := MyUin;
  fTmpDC.fManager := Self;
  fTmpDC.fRemUIN := 0;
  With fTmpDC.fpUser^ Do Begin
    UIN        := 0;
    DCMain     := -1;
    DCRecvFile := -1;
    DCSendFile := -1;
    DCChat     := -1;
  End;

  // Proxy Settings
  fTmpDC.FProxyType := ProxyType;
  fTmpDC.FProxyHost := ProxyHost;
  fTmpDC.FProxyPort := ProxyPort;
  fTmpDC.FProxyAuth := ProxyAuth;
  fTmpDC.FProxyPass := ProxyPass;
  fTmpDC.FUserID    := FUserID;
  fTmpDC.FResolve   := FResolve;
  fTmpDC.UseProxyResolve := UseProxyResolve;
  // Events
  fTmpDC.FOnError   := InternalOnErrorProc;
  fTmpDC.FOnPktDump := InternalOnPktDump;
  fTmpDC.fOnHandle  := InternalOnHandle;
  fTmpDC.fOnDCEvent := HandleDCEvent;
  fpUser^.DCMain := fDCL.Add(fTmpDC);  // Add Connection to List
End;

procedure TicqDCM.InternalOnErrorProc(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String);
Begin
  If Assigned(fOnError) then
    fOnError(Sender, ErrorType, ErrorMsg);
End;

procedure TicqDCM.InternalOnPktDump(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean; UIN: Cardinal);
Begin
  If assigned(fOnPktDump) then
    fOnPktDump(Sender, Buffer, BufLen, Incoming, UIN);
End;

procedure TicqDCM.InternalOnHandle(Sender: TObject; UIN: LongWord; Pak: PRawPkt; Len: LongWord);
Begin
  If Assigned(fOnHandle) then
    fOnHandle(Sender, UIN, Pak, Len);
End;

Procedure TicqDCM.HandleDCEvent(Sender: TicqBaseDC);
Var
  dcRF:TicqDCRecvFile;
  dcSF:TicqDCSendFile;
Begin

  // Handle Event From one of the DC's
  Case Sender.EventType Of

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -