ICQClient.pas
上传用户:hndmjx
上传日期:2014-09-16
资源大小:3369k
文件大小:92k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit ICQClient {v. 1.18f};
  2. {************************************************
  3.     For updates checkout: http://www.cobans.net
  4.       (C) Alex Demchenko(alex@ritlabs.com)
  5. *************************************************}
  6. {$R-}                   //Remove range checking
  7. {$DEFINE USE_FORMS}     //If you don't use forms unit remove this line
  8. //Some needed defines, do not remove them!
  9. {$IFDEF VER90}
  10.   {$DEFINE OLD_DELPHI}
  11. {$ENDIF}
  12. {$IFDEF VER100}
  13.   {$DEFINE OLD_DELPHI}
  14. {$ENDIF}
  15. {$IFDEF VER120}
  16.   {$DEFINE OLD_DELPHI}
  17. {$ENDIF}
  18. {$IFDEF VER130}
  19.   {$DEFINE OLD_DELPHI}
  20. {$ENDIF}
  21. interface
  22. uses
  23.   Windows, Messages, Classes {StringLists}, {$IFDEF USE_FORMS}Forms {AllocateHwnd/DeallocateHwnd}, {$ENDIF}
  24.   WinSock, ICQWorks, MySocket, ICQDirect;
  25. {$IFNDEF USE_FORMS}
  26.   {$DEFINE OLD_DELPHI}
  27. {$ENDIF}
  28. type
  29.   //UIN Entry used in direct connections
  30.   PUINEntry = ^TUINEntry;
  31.   TUINEntry = record
  32.     UIN: LongWord;
  33.     Nick: ShortString;
  34.     CType: Word;
  35.     CTag: Word;
  36.     CGroupID: Word;
  37.     CGroup: ShortString;
  38.   end;
  39.   TMyTimer = class;
  40.   //Callback function types
  41.   THandlePkt = procedure(Flap: TFlapHdr; Buffer: Pointer) of object;
  42.   TOnMsgProc = procedure(Sender: TObject; Msg, UIN: String) of object;
  43.   TOnURLProc = procedure(Sender: TObject; Description, URL, UIN: String) of object;
  44.   TOnStatusChange = procedure(Sender: TObject; UIN: String; Status: LongWord) of object;
  45.   TOnOnlineInfo = procedure(Sender: TObject; UIN: String; Port: Word; InternalIP, ExternalIP: String; ProtoVer: Byte) of object;
  46.   TOnUserEvent = procedure(Sender: TObject; UIN: String) of object;
  47.   TOnUserGeneralInfo = procedure(Sender: TObject; UIN, NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip, Country: String; TimeZone: Byte; PublishEmail: Boolean) of object;
  48.   TOnUserWorkInfo = procedure (Sender: TObject; UIN, WCity, WState, WPhone, WFax, FAddress, WZip, WCountry, WCompany, WDepartment, WPosition, WOccupation, WHomePage: String) of object;
  49.   TOnUserInfoMore = procedure (Sender: TObject; UIN: String; Age: Word; Gender: Byte; HomePage: String; BirthYear: Word; BirthMonth: Word; BirthDay: Word; Lang1, Lang2, Lang3: String) of object;
  50.   TOnUserInfoAbout = procedure(Sender: TObject; UIN, About: String) of object;
  51.   TOnUserInfoInterests = procedure(Sender: TObject; UIN: String; Interests: TStringList) of object;
  52.   TOnUserInfoMoreEmails = procedure(Sender: TObject; UIN: String; Emails: TStringList) of object;
  53.   TOnUserInfoBackground = procedure(Sender: TObject; UIN: String; Pasts, Affiliations: TStringList) of object;
  54.   TOnUserFound = procedure(Sender: TObject; UIN, Nick, FirstName, LastName, Email: String; Status: Word; Gender, Age: Byte; SearchComplete: Boolean; Authorize: Boolean) of object;
  55.   TOnServerListRecv = procedure(Sender: TObject; SrvContactList: TList) of object;
  56.   TOnAdvMsgAck = procedure(Sender: TObject; UIN: String; ID: Word; AcceptType: Byte; AcceptMsg: String) of object;
  57.   TOnAutoMsgResponse = procedure(Sender: TObject; UIN: String; ID: Word; RespStatus: Byte; Msg: String) of object;
  58.   TOnContactListRecv = procedure(Sender: TObject; UIN: String; ContactList: TStringList) of object;
  59.   TOnContactListReq = procedure(Sender: TObject; UIN, Reason: String) of object;
  60.   TOnDirectPktAck = procedure(Sender: TObject; ID: Word) of object;
  61.   TOnSMSAck = procedure(Sender: TObject; Source, Network, MsgId: String; Deliverable: Boolean) of object;
  62.   TOnSMSReply = procedure(Sender: TObject; Source, SmsSender, Time, Text: String) of object;
  63.   TOnInfoChanged = procedure(Sender: TObject; InfoType: TInfoType; ChangedOk: Boolean) of object;
  64.   TOnAuthResponse = procedure(Sender: TObject; UIN: String; Granted: Boolean; Reason: String) of object;
  65.   TOnChangeResponse = procedure(Sender: TObject; ErrorCode: Word) of object;
  66.   TOnFTRequest = procedure(Sender: TObject; RequestRec: TFTRequestRec) of object;
  67.   TOnUserInfoShort = procedure(Sender: TObject; UIN, NickName, FirstName, LastName, Email: String; UserFound, AuthRequired: Boolean) of object;
  68.   {TICQNet -- Object implementing sending/receiving packets between Client and ICQ Server.}
  69.   TICQNet = class(TMySock)
  70.   private
  71.     FSrcBuf: array[0..MAX_DATA_LEN - 1] of Byte;        //.              .
  72.     FSrcLen: Word;                                      //.PACKET READING.
  73.     FNewFlap: TFlapHdr;                                 //.     DATA     .
  74.     FFlapSet: Boolean;                                  //.              .
  75.     FHandlePkt: THandlePkt;
  76.   protected
  77.     procedure OnReceive(Buffer: Pointer; BufLen: LongWord); override;
  78.   public
  79.     constructor Create;
  80.     destructor Destroy; override;
  81.     procedure Connect; override;
  82.   published
  83.     property OnConnectError;
  84.     property OnDisconnect;
  85.     property OnPktParseA;
  86.     property OnError;
  87.     property OnHandlePkt: THandlePkt read FHandlePkt write FHandlePkt;
  88.   end;
  89.   {TICQClient -- ICQ Component}
  90.   TICQClient = class(TComponent)
  91.   private
  92.     FSock: TICQNet;                                     //Client's socket
  93.     FLUIN: LongWord;                                    //Client's UIN
  94.     FLPass: String;                                     //Client's password
  95.     FFirstConnect: Boolean;                             //Flag, used in login sequence
  96.     FSeq: Word;                                         //Main Flap Seq
  97.     FSeq2: Word;                                        //TO_ICQSRV Seq
  98.     FDSeq: Word;                                        //Direct connection Seq
  99.     FCookie: String;                                    //Temporary cookie, used in login sequence, we can use String type, becouse ICQ server doesn't send 0x00 chars in it's Cookie part
  100.     FIp: String;                                        //Ip to connect to
  101.     FPort: Word;                                        //Port to connect to
  102.     FDConnCookie: LongWord;                             //Direct connection cookie
  103.     FDirect: TDirectControl;                            //Direct control
  104.     //-- Proxy settings
  105.     FProxyType: TProxyType;                             //.
  106.     FProxyHost: String;                                 //.
  107.     FProxyPort: Word;                                   //. Proxy Configaration
  108.     FProxyAuth: Boolean;                                //.        Data
  109.     FProxyPass: String;                                 //.
  110.     FUserID: String;                                    //.
  111.     FResolve: Boolean;
  112.     //-- Events & other stuff --
  113.     FContactLst: TStrings;
  114.     FVisibleLst: TStrings;
  115.     FInvisibleLst: TStrings;
  116.     FOnMsg: TOnMsgProc;
  117.     FOnURL: TOnURLProc;
  118.     FOnOffMsg: TOnMsgProc;
  119.     FOnOffURL: TOnURLProc;
  120.     FOnLogin: TNotifyEvent;
  121.     FOnPktParse: TOnAdvPktParse;
  122.     FOnDPktParse: TOnAdvPktParse;
  123.     FOnConnectionFailed: TNotifyEvent;
  124.     FOnStatusChange: TOnStatusChange;
  125.     FOnUserOffline: TOnUserEvent;
  126.     FOnAddedYou: TOnUserEvent;
  127.     FOnUserGeneralInfo: TOnUserGeneralInfo;
  128.     FOnUserWorkInfo: TOnUserWorkInfo;
  129.     FOnUserInfoMore: TOnUserInfoMore;
  130.     FOnUserInfoAbout: TOnUserInfoAbout;
  131.     FOnUserInfoInterests: TOnUserInfoInterests;
  132.     FOnUserInfoMoreEmails: TOnUserInfoMoreEmails;
  133.     FOnUserInfoBackground: TOnUserInfoBackground;
  134.     FStatus: LongWord;
  135.     FDoPlain: Boolean;
  136.     FInfoChain: TStringList;
  137.     FSInfoChain: TStringList;
  138.     FLastInfoUin: String;
  139.     FLastSInfoUin: String;
  140.     FLoggedIn: Boolean;
  141.     FRegisteringUIN: Boolean;
  142.     FRegPassword: String;
  143.     FOnUserFound: TOnUserFound;
  144.     FOnUserNotFound: TNotifyEvent;
  145.     FOnServerListRecv: TOnServerListRecv;
  146.     FOnAdvMsgAck: TOnAdvMsgAck;
  147.     FOnNewUINRegistered: TOnUserEvent;
  148.     FOnNewUINRefused: TNotifyEvent;
  149.     FOnAutoMsgResponse: TOnAutoMsgResponse;
  150.     FAutoAwayMsg: String;
  151.     FOnUnregisterOk: TNotifyEvent;
  152.     FOnUnregBadPass: TNotifyEvent;
  153.     FOnContactListRecv: TOnContactListRecv;
  154.     FOnContactListReq: TOnContactListReq;
  155.     FOnDirectPktAck: TOnDirectPktAck;
  156.     FOnSmsRefused: TNotifyEvent;
  157.     FOnSMSAck: TOnSMSAck;
  158.     FOnOnlineInfo: TOnOnlineInfo;
  159.     FUseDirect: Boolean;
  160.     FOnError: TOnError;
  161.     FTimer: TMyTimer;
  162.     FTimeout: Byte;
  163.     FOnSMSReply: TOnSMSReply;
  164.     FOnInfoChanged: TOnInfoChanged;
  165.     FOnAuthSet: TNotifyEvent;
  166.     FOnAuthResponse: TOnAuthResponse;
  167.     FOnChangeResponse: TOnChangeResponse;
  168.     FOnFTRequest: TOnFTRequest;
  169.     FOnFTInit: TOnFTInit;
  170.     FOnFTStart: TOnFTStart;
  171.     FOnFTFileData: TOnFTFileData;
  172.     FLastError: String;
  173.     FOnUserInfoShort: TOnUserInfoShort;
  174.     procedure InitNetICQ;
  175.     procedure OnIntError(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String);
  176.     procedure HandlePacket(Flap: TFlapHdr; Data: Pointer);
  177.     procedure SetStatus(NewStatus: LongWord);
  178.     //-- Handling Snac packet procedures
  179.     procedure HSnac0407(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  180.     //procedure HSnac1503(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  181.     procedure HSnac030B(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  182.     procedure HSnac131C(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  183.     procedure HSnac1319(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  184.     procedure HSnac1306(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  185.     procedure HSnac040b(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  186.     procedure HSnac1705(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  187.     procedure HSnac131b(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  188.     procedure HSnac130e(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  189.     procedure HDirectMsg(Sender: TObject; UIN: LongWord; Pak: PRawPkt; Len: LongWord);
  190.     procedure FTOnConnectError(Sender: TObject);
  191.     procedure FTOnDisconnect(Sender: TObject);
  192.     procedure FTOnDirectParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean);
  193.     procedure FTOnPktParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean);
  194.     procedure OnFTInitProc(Sender: TObject; UIN: LongWord; FileCount, TotalBytes, Speed: LongWord; NickName: String);
  195.     procedure OnFTStartProc(Sender: TObject; StartRec: TFTStartRec; FileName: String; FileSize, Speed: LongWord);
  196.     procedure OnFTFileDataProc(Sender: TObject; UIN: LongWord; Data: Pointer; DataLen: LongWord; LastPacket: Boolean);
  197.     procedure SetContactList(Value: TStrings);
  198.     procedure SetVisibleList(Value: TStrings);
  199.     procedure SetInvisibleList(Value: TStrings);
  200.     procedure OnTimeout(Sender: TObject);
  201.   public
  202.     procedure HSnac1503(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  203.     constructor Create(AOwner: TComponent); override;
  204.     destructor Destroy; override;
  205.     procedure Login(Status: LongWord = S_ONLINE);
  206.     procedure RegisterNewUIN(const Password: String);
  207.     procedure Disconnect;
  208.     procedure SendMessage(UIN: LongWord; const Msg: String);
  209.     procedure SendURL(UIN: LongWord; const URL, Description: String);
  210.     function AddContact(UIN: LongWord): Boolean;
  211.     procedure RemoveContact(UIN: LongWord);
  212.     procedure RemoveContactVisible(UIN: LongWord);
  213.     procedure RemoveContactInvisible(UIN: LongWord);
  214.     procedure RequestInfo(UIN: LongWord);
  215.     procedure RequestInfoShort(UIN: LongWord);    
  216.     procedure SearchByMail(const Email: String);
  217.     procedure SearchByUIN(UIN: LongWord);
  218.     procedure SearchByName(const FirstName, LastName, NickName, Email: String);
  219.     procedure SearchRandom(Group: Word);
  220.     procedure SearchWhitePages(const FirstName, LastName, NickName, Email: String; MinAge, MaxAge: Word; Gender: Byte; const Language, City, Country, Company, Department, Position, Occupation, Organization, OrganKeyWords, PastAffiliation, AffiKeyWords, KeyWord: String; Online: Boolean);
  221.     procedure SetSelfInfoGeneral(NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip, Country: String; TimeZone: Byte; PublishEmail: Boolean);
  222.     procedure SetSelfInfoMore(Age: Word; Gender: Byte; const HomePage: String; BirthYear: Word; BirthMonth, BirthDay: Byte; Language1, Language2, Language3: String);
  223.     procedure SetSelfInfoAbout(const About: String);
  224.     procedure RequestContactList;
  225.     procedure DestroyUINList(var List: TList);
  226.     procedure SendSMS(const Destination, Text: String);
  227.     procedure SendMessageAdvanced(UIN: LongWord; const Msg: String; ID: Word; RTFFormat: Boolean);
  228.     function SendMessageDirect(UIN: LongWord; const Msg: String; RTFFormat: Boolean): Word;
  229.     procedure RequestAwayMsg(UIN: LongWord; ID: Word; ReqStatus: Byte);
  230.     procedure UnregisterUIN(const Password: String);
  231.     procedure ChangePassword(const NewPassword: String);
  232.     procedure ChangePasswordPtr(Buffer: Pointer; BufLen: Word);
  233.     function DirectConnectionEstabilished(UIN: LongWord): Boolean;
  234.     function SendContacts(UIN: LongWord; Contacts: TStringList; ID: Word): Boolean;
  235.     function RequestContacts(UIN: LongWord; const Reason: String; ID: Word): Boolean;
  236.     function SendContactsDC(UIN: LongWord; Contacts: TStringList): Word;
  237.     function RequestContactsDC(UIN: LongWord; const Reason: String): Word;
  238.     procedure SendKeepAlive;
  239.     procedure SetAuthorization(AuthorizationRequired, WebAware: Boolean);
  240.     procedure SendAuthRequest(UIN: LongWord; Msg: String);
  241.     procedure SSLChangeStart(FirstUpload: Boolean);
  242.     procedure SSLChangeEnd;
  243.     procedure SSLAddGroup(GroupName: String; GroupID: Word);
  244.     procedure SSLAddUser(GroupID, UserID: Word; UIN, Name, SMSNumber: String; Authorize, UpdateUser: Boolean);
  245.     procedure SSLDelUser(GroupID, UserID: Word; UIN, Name, SMSNumber: String; Authorize: Boolean);
  246.     procedure SSLDelGroup(GroupName: String; GroupID: Word);
  247.     procedure SSLUpdateGroup(GroupName: String; GroupID: Word; UserIDs: TStringList);
  248.     procedure SSLAddUserIntoList(UserID: Word; UIN: String; BuddyType: Word);
  249.     procedure SSLDelUserFromList(UserID: Word; UIN: String; BuddyType: Word);
  250.     function FTResponse(ResponseRec: TFTRequestRec; Accept: Boolean; Reason: String): Boolean;
  251.     procedure FTCancel(UIN: LongWord);
  252.     function FTStartResponse(StartRec: TFTStartRec): Boolean;
  253.     property LastError: String read FLastError;
  254.     property Status: LongWord read FStatus write SetStatus;
  255.     property LoggedIn: Boolean read FLoggedIn;
  256.   published
  257.     property DisableDirectConnections: Boolean read FUseDirect write FUseDirect default False;
  258.     property ProxyType: TProxyType read FProxyType write FProxyType default P_NONE;
  259.     property ProxyHost: String read FProxyHost write FProxyHost;
  260.     property ProxyPort: Word read FProxyPort write FProxyPort;
  261.     property ProxyUserID: String read FUserID write FUserID;
  262.     property ProxyResolve: Boolean read FResolve write FResolve default False;
  263.     property ProxyAuth: Boolean read FProxyAuth write FProxyAuth default False;
  264.     property ProxyPass: String read FProxyPass write FProxyPass;
  265.     property UIN: LongWord read FLUIN write FLUIN;
  266.     property Password: String read FLPass write FLPass;
  267.     property ICQServer: String read FIp write FIp;
  268.     property ICQPort: Word read FPort write FPort;
  269.     property ConvertToPlaintext: Boolean read FDoPlain write FDoPlain;
  270.     property ContactList: TStrings read FContactLst write SetContactList;
  271.     property VisibleList: TStrings read FVisibleLst write SetVisibleList;
  272.     property InvisibleList: TStrings read FInvisibleLst write SetInvisibleList;
  273.     property AutoAwayMessage: String read FAutoAwayMsg write FAutoAwayMsg;
  274.     property OnLogin: TNotifyEvent read FOnLogin write FOnLogin;
  275.     property OnMessageRecv: TOnMsgProc read FOnMsg write FOnMsg;
  276.     property OnURLRecv: TOnURLProc read FOnURL write FOnURL;
  277.     property OnOfflineMsgRecv: TOnMsgProc read FOnOffMsg write FOnOffMsg;
  278.     property OnOfflineURLRecv: TOnURLProc read FOnOffURL write FOnOffURL;
  279.     property OnPktParse: TOnAdvPktParse read FOnPktParse write FOnPktParse;
  280.     property OnPktDirectParse: TOnAdvPktParse read FOnDPktParse write FOnDPktParse;
  281.     property OnConnectionFailed: TNotifyEvent read FOnConnectionFailed write FOnConnectionFailed;
  282.     property OnStatusChange: TOnStatusChange read FOnStatusChange write FOnStatusChange;
  283.     property OnUserOffline: TOnUserEvent read FOnUserOffline write FOnUserOffline;
  284.     property OnAddedYou: TOnUserEvent read FOnAddedYou write FOnAddedYou;
  285.     property OnUserGeneralInfo: TOnUserGeneralInfo read FOnUserGeneralInfo write FOnUserGeneralInfo;
  286.     property OnUserWorkInfo: TOnUserWorkInfo read FOnUserWorkInfo write FOnUserWorkInfo;
  287.     property OnUserInfoMore: TOnUserInfoMore read FOnUserInfoMore write FOnUserInfoMore;
  288.     property OnUserInfoAbout: TOnUserInfoAbout read FOnUserInfoAbout write FOnUserInfoAbout;
  289.     property OnUserInfoInterests: TOnUserInfoInterests read FOnUserInfoInterests write FOnUserInfoInterests;
  290.     property OnUserInfoMoreEmails: TOnUserInfoMoreEmails read FOnUserInfoMoreEmails write FOnUserInfoMoreEmails;
  291.     property OnUserInfoBackground: TOnUserInfoBackground read FOnUserInfoBackground write FOnUserInfoBackground;
  292.     property OnUserFound: TOnUserFound read FOnUserFound write FOnUserFound;
  293.     property OnUserNotFound: TNotifyEvent read FOnUserNotFound write FOnUserNotFound;
  294.     property OnServerListRecv: TOnServerListRecv read FOnServerListRecv write FOnServerListRecv;
  295.     property OnAdvancedMsgAck: TOnAdvMsgAck read FOnAdvMsgAck write FOnAdvMsgAck;
  296.     property OnNewUINRegistered: TOnUserEvent read FOnNewUINRegistered write FOnNewUINRegistered;
  297.     property OnNewUINRefused: TNotifyEvent read FOnNewUINRefused write FOnNewUINRefused;
  298.     property OnAutoMsgResponse: TOnAutoMsgResponse read FOnAutoMsgResponse write FOnAutoMsgResponse;
  299.     property OnUnregisterOk: TNotifyEvent read FOnUnregisterOk write FOnUnregisterOk;
  300.     property OnUnregisterBadPassword: TNotifyEvent read FOnUnregBadPass write FOnUnregBadPass;
  301.     property OnContactListRecv: TOnContactListRecv read FOnContactListRecv write FOnContactListRecv;
  302.     property OnContactListRequest: TOnContactListReq read FOnContactListReq write FOnContactListReq;
  303.     property OnDirectPacketAck: TOnDirectPktAck read FOnDirectPktAck write FOnDirectPktAck;
  304.     property OnSMSRefused: TNotifyEvent read FOnSmsRefused write FOnSmsRefused;
  305.     property OnSMSAck: TOnSMSAck read FOnSMSAck write FOnSMSAck;
  306.     property OnOnlineInfo: TOnOnlineInfo read FOnOnlineInfo write FOnOnlineInfo;
  307.     property OnError: TOnError read FOnError write FOnError;
  308.     property ConnectionTimeout: Byte read FTimeout write FTimeout;
  309.     property OnSMSReply: TOnSMSReply read FOnSMSReply write FOnSMSReply;
  310.     property OnInfoChanged: TOnInfoChanged read FOnInfoChanged write FOnInfoChanged;
  311.     property OnAuthorizationChangedOk: TNotifyEvent read FOnAuthSet write FOnAuthSet;
  312.     property OnAuthResponse: TOnAuthResponse read FOnAuthResponse write FOnAuthResponse;
  313.     property OnSSLChangeResponse: TOnChangeResponse read FOnChangeResponse write FOnChangeResponse;
  314.     property OnFTRequest: TOnFTRequest read FOnFTRequest write FOnFTRequest;
  315.     property OnFTInit: TOnFTInit read FOnFTInit write FOnFTInit;
  316.     property OnFTStart: TOnFTStart read FOnFTStart write FOnFTStart;
  317.     property OnFTFileData: TOnFTFileData read FOnFTFileData write FOnFTFileData;
  318.     property OnUserInfoShort: TOnUserInfoShort read FOnUserInfoShort write FOnUserInfoShort;
  319.   end;
  320.   TMyTimer = class(TObject)
  321.   private
  322.     FInterval: LongWord;
  323.     FWindowHandle: THandle;
  324.     FOnTimer: TNotifyEvent;
  325.     FEnabled: Boolean;
  326.     FTag: Integer;
  327.     procedure UpdateTimer;
  328.     procedure SetEnabled(Value: Boolean);
  329.     procedure SetInterval(Value: LongWord);
  330.     procedure SetOnTimer(Value: TNotifyEvent);
  331.     procedure WndProc(var Msg: TMessage);
  332.   protected
  333.     procedure Timer; dynamic;
  334.   public
  335.     constructor Create;
  336.     destructor Destroy; override;
  337.     property Tag: Integer read FTag write FTag;
  338.   published
  339.     property Enabled: Boolean read FEnabled write SetEnabled default True;
  340.     property Interval: LongWord read FInterval write SetInterval default 1000;
  341.     property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer;
  342.   end;
  343. procedure Register;
  344. implementation
  345. {-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-}
  346. {*** CONSTRUCTOR ***}
  347. constructor TICQNet.Create;
  348. begin
  349.   inherited Create;
  350. end;
  351. {*** DESTRUCTOR ***}
  352. destructor TICQNet.Destroy;
  353. begin
  354.   inherited;
  355. end;
  356. procedure TICQNet.Connect;
  357. begin
  358.   FSrcLen := 0;
  359.   FFlapSet := False;
  360.   inherited;
  361. end;
  362. {No proxy data is received here.}
  363. procedure TICQNet.OnReceive(Buffer: Pointer; BufLen: LongWord);
  364. var
  365.   i, len: LongWord;
  366.   flap: TFlapHdr;
  367. begin
  368.   inherited;
  369.   for i := 0 to BufLen - 1 do
  370.   begin
  371.     FSrcBuf[FSrcLen] := PByte(LongWord(Buffer) + i)^;
  372.     Inc(FSrcLen);
  373.     //Searching for the Flap header
  374.     if (FSrcLen >= TFLAPSZ) and (not FFlapSet) then
  375.     begin
  376.       FFlapSet := True;
  377.       FNewFlap := PFlapHdr(@FSrcBuf)^;
  378.       FNewFlap.DataLen := Swap16(FNewFlap.DataLen);
  379.       FNewFlap.Seq := Swap16(FNewFlap.Seq);
  380.       if FNewFlap.DataLen > 8192 then
  381.       begin
  382.         if Assigned(OnError) then
  383.           OnError(Self, ERR_PROTOCOL, 'Length of received packet exceeds maximum supported by protocol. Len = ' + IntToStr(FNewFlap.DataLen));
  384.         Disconnect;
  385.         Exit;
  386.       end;
  387.     end;
  388.     //Whole packet was received
  389.     if FSrcLen = FNewFlap.DataLen + TFLAPSZ then
  390.     begin
  391.       if FNewFlap.Ident <> $2a then
  392.       begin
  393.         if Assigned(OnError) then
  394.           OnError(Self, ERR_PROTOCOL, 'Received malformed packet');
  395.         Disconnect;
  396.         Exit;
  397.       end;
  398.       Move(FNewFlap, flap, SizeOf(FNewFlap));      
  399.       //Preparing structures for receiving the next packet
  400.       FNewFlap.DataLen := 0;
  401.       len := FSrcLen; FSrcLen := 0;
  402.       FFlapSet := False;
  403.       //Dump packet (if needed)
  404.       if Assigned(OnPktParseA) then
  405.         OnPktParseA(Self, @FSrcBuf, len, True);
  406.       //Handling packet
  407.       if Assigned(OnHandlePkt) then
  408.         FHandlePkt(flap, Ptr(LongWord(@FSrcBuf) + TFLAPSZ));
  409.     end;
  410.   end;
  411. end;
  412. {-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-}
  413. {*** CONSTRUCTOR ***}
  414. constructor TICQClient.Create(AOwner: TComponent);
  415. begin
  416.   inherited;
  417.   FLastError := '';                     //Last error
  418.   FContactLst := TStringList.Create;    //Contact list
  419.   FVisibleLst := TStringList.Create;    //Visible list
  420.   FInvisibleLst := TStringList.Create;  //Invisible list
  421.   FInfoChain := TStringList.Create;     //Info request chain
  422.   FSInfoChain := TStringList.Create;    //Short info request chain
  423.   //Socket for working with TCP
  424.   FSock := TICQNet.Create;
  425.   FSock.OnError := OnIntError;
  426.   FTimer := TMyTimer.Create;              //Timeout timer
  427.   FTimer.OnTimer := OnTimeout;          //Set timeout event
  428.   FTimer.Enabled := False;              //Disable timer by default
  429.   Randomize;                            //Initialize random generator
  430.   FSeq := Random($AAAA);                //Choose random seq, which is used in Flap header
  431.   FDirect := nil;                       //Do not initialize direct control until we connect
  432. end;
  433. {*** DESTRUCTOR ***}
  434. destructor TICQClient.Destroy;
  435. begin
  436.   if FDirect <> nil then
  437.     FDirect.Free;
  438.   FSock.OnConnectError := nil;
  439.   FSock.OnConnectProc := nil;
  440.   FSock.OnDisconnect := nil;
  441.   FSock.OnError := nil;
  442.   FSock.OnReceiveProc := nil;
  443.   FSock.Free;
  444.   FTimer.OnTimer := nil;
  445.   FTimer.Free;
  446.   //Free TStringList objects
  447.   FContactLst.Free;
  448.   FVisibleLst.Free;
  449.   FInvisibleLst.Free;
  450.   FInfoChain.Free;
  451.   FSInfoChain.Free;
  452.   inherited;
  453. end;
  454. {Set NetICQ's properties}
  455. procedure TICQClient.InitNetICQ;
  456. begin
  457.   //Assign properties
  458.   FSock.Host := FIp;
  459.   FSock.Port := FPort;
  460.   FSock.ProxyType := FProxyType;
  461.   FSock.ProxyHost := FProxyHost;
  462.   FSock.ProxyPort := FProxyPort;
  463.   FSock.ProxyUserID := FUserID;
  464.   FSock.ProxyAuth := FProxyAuth;
  465.   FSock.ProxyPass := FProxyPass;
  466.   FSock.UseProxyResolve := ProxyResolve;
  467.   //Assign events
  468.   FSock.OnHandlePkt := HandlePacket;
  469.   FSock.OnDisconnect := FTOnDisconnect;
  470.   FSock.OnConnectError := FTOnConnectError;
  471.   FSock.OnPktParseA := FTOnPktParse;
  472. end;
  473. {Called when error happened.}
  474. procedure TICQClient.OnIntError(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String);
  475. begin
  476.   FLastError := ErrorMsg;
  477.   if Assigned(OnError) then
  478.     FOnError(Self, ErrorType, ErrorMsg);
  479. end;
  480. {Logins to server.}
  481. procedure TICQClient.Login(Status: LongWord = S_ONLINE);
  482. begin
  483.   if FDirect <> nil then
  484.   begin
  485.     FDirect.OnError := nil;
  486.     FDirect.OnHandle := nil;
  487.     FDirect.OnPktDump := nil;
  488.     FDirect.Free;
  489.   end;
  490.   if not DisableDirectConnections then
  491.   begin
  492.     FDirect := TDirectControl.Create(FLUIN);
  493.     FDirect.OnPktDump := FTOnDirectParse;
  494.     FDirect.OnHandle := HDirectMsg;
  495.     FDirect.OnError := OnIntError;
  496.     FDirect.OnFTInit := OnFTInitProc;
  497.     FDirect.OnFTStart := OnFTStartProc;
  498.     FDirect.OnFTFileData := OnFTFileDataProc;
  499.     //Assign proxy settings
  500.     FDirect.ProxyType := ProxyType;
  501.     FDirect.ProxyHost := ProxyHost;
  502.     FDirect.ProxyPort := ProxyPort;
  503.     FDirect.ProxyUserID := ProxyUserID;
  504.     FDirect.ProxyAuth := ProxyAuth;
  505.     FDirect.ProxyPass := ProxyPass;
  506.     FDirect.UseProxyResolve := ProxyResolve;
  507.   end;
  508.   FDSeq := Random(High(Word));
  509.   FSeq2 := 2;
  510.   FCookie := '';
  511.   FFirstConnect := True;
  512.   FStatus := Status;
  513.   FLoggedIn := False;
  514.   FRegisteringUIN := False;
  515.   InitNetICQ;
  516.   FTimer.Interval := FTimeout * 1000;
  517.   FTimer.Enabled := False;
  518.   if FTimeout <> 0 then
  519.     FTimer.Enabled := True;
  520.     
  521.   FSock.Connect;
  522. end;
  523. {Registers a new UIN.}
  524. procedure TICQClient.RegisterNewUIN(const Password: String);
  525. begin
  526.   FRegisteringUIN := True;
  527.   FRegPassword := Password;
  528.   FLoggedIn := False;
  529.   InitNetICQ;
  530.   FTimer.Interval := FTimeout * 1000;
  531.   FTimer.Enabled := True;
  532.   FSock.Connect;
  533. end;
  534. {Disconnect user from server.}
  535. procedure TICQClient.Disconnect;
  536. begin
  537.   FTimer.Enabled := False;
  538.   FSock.Disconnect;
  539.   if Assigned(OnConnectionFailed) then
  540.     FOnConnectionFailed(Self);
  541. end;
  542. {Send a message to UIN.}
  543. procedure TICQClient.SendMessage(UIN: LongWord; const Msg: String);
  544. var
  545.   pkt: TRawPkt;
  546. begin
  547.   if not LoggedIn then Exit;
  548.   CreateCLI_SENDMSG(@pkt, 0, Random($FFFFAA), UIN, Msg, FSeq);
  549.   FSock.SendData(pkt, pkt.Len);
  550. end;
  551. {Send an URL message to UIN.}
  552. procedure TICQClient.SendURL(UIN: LongWord; const URL, Description: String);
  553. var
  554.   pkt: TRawPkt;
  555. begin
  556.   if not LoggedIn then Exit;
  557.   CreateCLI_SENDURL(@pkt, 0, Random($FFFFAA), FLUIN, UIN, URL, Description, FSeq);
  558.   FSock.SendData(pkt, pkt.Len);
  559. end;
  560. {Adds UIN to contact list after logon(when you are online), UIN automaticly
  561. added to ContactList TStrings. After adding the UIN you will receive status
  562. notifications. Returns True when UIN is added to the list(it wasn't there before).}
  563. function TICQClient.AddContact(UIN: LongWord): Boolean;
  564. var
  565.   pkt: TRawPkt;
  566. begin
  567.   Result := False;
  568.   if FContactLst.IndexOf(IntToStr(UIN)) < 0 then
  569.   begin
  570.     FContactLst.Add(IntToStr(UIN));
  571.     Result := True;
  572.   end else
  573.     Exit;
  574.   if not LoggedIn then Exit;
  575.   CreateCLI_ADDCONTACT(@pkt, IntToStr(UIN), FSeq);           {SNAC(x03/x04)}
  576.   FSock.SendData(pkt, pkt.Len);
  577. end;
  578. {Removes UIN from contact list. Use while you are online.}
  579. procedure TICQClient.RemoveContact(UIN: LongWord);
  580. var
  581.   idx: Integer;
  582.   pkt: TRawPkt;
  583. begin
  584.   idx := FContactLst.IndexOf(IntToStr(UIN));
  585.   if idx > -1 then
  586.     FContactLst.Delete(idx);
  587.   if not LoggedIn then Exit;
  588.   CreateCLI_REMOVECONTACT(@pkt, UIN, FSeq);
  589.   FSock.SendData(pkt, pkt.Len);
  590. end;
  591. {Removes UIN from the visible list. Use while you are online.}
  592. procedure TICQClient.RemoveContactVisible(UIN: LongWord);
  593. var
  594.   idx: Integer;
  595.   pkt: TRawPkt;
  596. begin
  597.   idx := FVisibleLst.IndexOf(IntToStr(UIN));
  598.   if idx > -1 then
  599.     FVisibleLst.Delete(idx);
  600.   if not LoggedIn then Exit;
  601.   CreateCLI_REMVISIBLE(@pkt, UIN, FSeq);
  602.   FSock.SendData(pkt, pkt.Len);
  603. end;
  604. {Removes UIN from the invisible list. Use while you are online.}
  605. procedure TICQClient.RemoveContactInvisible(UIN: LongWord);
  606. var
  607.   idx: Integer;
  608.   pkt: TRawPkt;
  609. begin
  610.   idx := FInvisibleLst.IndexOf(IntToStr(UIN));
  611.   if idx > -1 then
  612.     FInvisibleLst.Delete(idx);
  613.   if not LoggedIn then Exit;
  614.   CreateCLI_REMINVISIBLE(@pkt, UIN, FSeq);
  615.   FSock.SendData(pkt, pkt.Len);
  616. end;
  617. {Query info about UIN. As answer you will recieve theese events: OnUserWorkInfo,
  618. OnUserInfoMore, OnUserInfoAbout, OnUserInfoInterests, OnUserInfoMoreEmails,
  619. OnUserFound.}
  620. procedure TICQClient.RequestInfo(UIN: LongWord);
  621. var
  622.   pkt: TRawPkt;
  623. begin
  624.   if not LoggedIn then Exit;
  625.   FInfoChain.Values[IntToStr(FSeq2)] := IntToStr(UIN);  
  626.   CreateCLI_METAREQINFO(@pkt, FLUIN, UIN, FSeq, FSeq2);
  627.   FSock.SendData(pkt, pkt.Len);
  628. end;
  629. {Request short info(nick, first, last, email) of UIN.}
  630. procedure TICQClient.RequestInfoShort(UIN: LongWord);
  631. var
  632.   pkt: TRawPkt;
  633. begin
  634.   if not LoggedIn then Exit;
  635.   FSInfoChain.Values[IntToStr(FSeq2)] := IntToStr(UIN);
  636.   CreateCLI_METAREQINFO_SHORT(@pkt, FLUIN, UIN, FSeq, FSeq2);
  637.   FSock.SendData(pkt, pkt.Len);
  638. end;
  639. {Searches user by Mail}
  640. procedure TICQClient.SearchByMail(const Email: String);
  641. var
  642.   pkt: TRawPkt;
  643. begin
  644.   if not LoggedIn then Exit;
  645.   CreateCLI_SEARCHBYMAIL(@pkt, FLUIN, Email, FSeq, FSeq2);
  646.   FSock.SendData(pkt, pkt.Len);
  647. end;
  648. {Searches user by UIN}
  649. procedure TICQClient.SearchByUIN(UIN: LongWord);
  650. var
  651.   pkt: TRawPkt;
  652. begin
  653.   if not LoggedIn then Exit;
  654.   CreateCLI_SEARCHBYUIN(@pkt, FLUIN, UIN, FSeq, FSeq2);
  655.   FSock.SendData(pkt, pkt.Len);
  656. end;
  657. {Searches user by Name and other data}
  658. procedure TICQClient.SearchByName(const FirstName, LastName, NickName, Email: String);
  659. var
  660.   pkt: TRawPkt;
  661. begin
  662.   if not LoggedIn then Exit;
  663.   CreateCLI_SEARCHBYNAME(@pkt, FLUIN, FirstName, LastName, NickName, Email, FSeq, FSeq2);
  664.   FSock.SendData(pkt, pkt.Len);
  665. end;
  666. {Searches random user from Group, where Group id could be found in RandGroups:
  667. array[1..11]...(ICQWorks.pas) constant. As answer you will receive OnUserFound
  668. notification, only one user will be found.}
  669. procedure TICQClient.SearchRandom(Group: Word);
  670. var
  671.   pkt: TRawPkt;
  672. begin
  673.   if not LoggedIn then Exit;
  674.   CreateCLI_SEARCHRANDOM(@pkt, FLUIN, Group, FSeq, FSeq2);
  675.   FSock.SendData(pkt, pkt.Len);
  676. end;
  677. {Searches user in 'White Pages'. As answer you will receive OnUserFound notification
  678. when at least one user found or OnUserNotFound if such user does not exist.}
  679. procedure TICQClient.SearchWhitePages(const FirstName, LastName, NickName, Email: String; MinAge, MaxAge: Word;
  680.   Gender: Byte; const Language, City, Country, Company, Department, Position, Occupation,
  681.   Organization, OrganKeyWords, PastAffiliation, AffiKeyWords, KeyWord: String; Online: Boolean);
  682. var
  683.   pkt: TRawPkt;
  684. begin
  685.   if not LoggedIn then Exit;
  686.   CreateCLI_SEARCHWP(@pkt, FLUIN, FirstName, LastName, NickName, Email,
  687.     MinAge, MaxAge,
  688.     Gender,
  689.     StrToLanguageI(Language),
  690.     City, StrToCountryI(Country),
  691.     Company,
  692.     Department,
  693.     Position,
  694.     StrToOccupationI(Occupation),
  695.     StrToOrganizationI(Organization),
  696.     OrganKeyWords,
  697.     StrToPastI(PastAffiliation),
  698.     AffiKeyWords,
  699.     KeyWord,
  700.     Ord(Online),
  701.     FSeq,
  702.     FSeq2);
  703.   FSock.SendData(pkt, pkt.Len);
  704. end;
  705. {Set general info about yourself. You can skip some parameters (eg. use '' -
  706. empty strings) to unspecify some info. }
  707. procedure TICQClient.SetSelfInfoGeneral(NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip, Country: String; TimeZone: Byte; PublishEmail: Boolean);
  708. var
  709.   pkt: TRawPkt;
  710. begin
  711.   if not LoggedIn then Exit;
  712.   //Truncate state if more then 3 chars
  713.   if Length(State) > 3 then
  714.     State := Copy(State, 0, 3);
  715.   CreateCLI_METASETGENERAL(@pkt, FLUIN, NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip, StrToCountryI(Country), TimeZone, PublishEmail, FSeq, FSeq2);
  716.   FSock.SendData(pkt, pkt.Len);
  717. end;
  718. {Set more info about yourself.}
  719. procedure TICQClient.SetSelfInfoMore(Age: Word; Gender: Byte; const HomePage: String; BirthYear: Word; BirthMonth, BirthDay: Byte; Language1, Language2, Language3: String);
  720. var
  721.   pkt: TRawPkt;
  722. begin
  723.   if not LoggedIn then Exit;
  724.   CreateCLI_METASETMORE(@pkt, FLUIN, Age, Gender, HomePage, BirthYear, BirthMonth, BirthDay, StrToLanguageI(Language1), StrToLanguageI(Language2), StrToLanguageI(Language3), FSeq, FSeq2);
  725.   FSock.SendData(pkt, pkt.Len);
  726. end;
  727. {Set info about yourself.}
  728. procedure TICQClient.SetSelfInfoAbout(const About: String);
  729. var
  730.   pkt: TRawPkt;
  731. begin
  732.   if not LoggedIn then Exit;
  733.   CreateCLI_METASETABOUT(@pkt, FLUIN, About, FSeq, FSeq2);
  734.   FSock.SendData(pkt, pkt.Len);
  735. end;
  736. {Requests server side contact list. For more info look at OnServerListRecv event.}
  737. procedure TICQClient.RequestContactList;
  738. var
  739.   pkt: TRawPkt;
  740. begin
  741.   if not LoggedIn then Exit;
  742.   CreateCLI_REQROSTER(@pkt, FSeq);
  743.   FSock.SendData(pkt, pkt.Len);
  744. end;
  745. {Releases memory used while parsing the server side contact list.}
  746. procedure TICQClient.DestroyUINList(var List: TList);
  747. var
  748.   i: Word;
  749. begin
  750.   if List = nil then Exit;
  751.   if List.Count > 0 then
  752.     for i := 0 to List.Count - 1 do
  753.       FreeMem(List.Items[i], SizeOf(TUINEntry)); //Free allocated memory for TUINEntry
  754.   List.Free;
  755.   List := nil;
  756. end;
  757. {Sends sms message to Destination with Text.}
  758. procedure TICQClient.SendSMS(const Destination, Text: String);
  759. var
  760.   pkt: TRawPkt;
  761. begin
  762.   if (Length(Text) = 0) or (not LoggedIn) then Exit;
  763.   CreateCLI_SENDSMS(@pkt, FLUIN, Destination, Text, GetACP, GetSMSTime, FSeq, FSeq2);
  764.   FSock.SendData(pkt, pkt.Len);
  765. end;
  766. {Sends Msg to UIN with advanced options, after UIN has got your message you will
  767. receive confirmation. ID - randomly generated value, may be used for packet acknowledgements
  768. (see OnAdvancedMsgAck event). If your Msg is in the RTF(RichText Format), then RTFFormat
  769. parameter should be True, otherwise - False. Beware of using the RTF Format, some clients
  770. (old versions of ICQ, linux & windows clones) don't support it.}
  771. procedure TICQClient.SendMessageAdvanced(UIN: LongWord; const Msg: String; ID: Word; RTFFormat: Boolean);
  772. var
  773.   pkt: TRawPkt;
  774. begin
  775.   if (Length(Msg) = 0) or (not LoggedIn) then Exit;
  776.   CreateCLI_SENDMSG_ADVANCED(@pkt, 0, ID, UIN, Msg, RTFFormat, FSeq);
  777.   FSock.SendData(pkt, pkt.Len);
  778. end;
  779. {Send message to client dirrectly when it's possible}
  780. function TICQClient.SendMessageDirect(UIN: LongWord; const Msg: String; RTFFormat: Boolean): Word;
  781. var
  782.   lpkt: TRawPkt;
  783. begin
  784.   Result := 0;
  785.   if FDirect = nil then Exit;
  786.   if (FDSeq = 0) then Inc(FSeq);
  787.   Result := CreatePEER_MSG(@lpkt, Msg, RTFFormat, FDSeq);
  788.   if not FDirect.SendData(UIN, @lpkt) then
  789.     Result := 0;
  790. end;
  791. {Request an away messages, set when user changes status.}
  792. procedure TICQClient.RequestAwayMsg(UIN: LongWord; ID: Word; ReqStatus: Byte);
  793. var
  794.   pkt: TRawPkt;
  795. begin
  796.   if (not LoggedIn) then Exit;
  797.   CreateCLI_REQAWAYMSG(@pkt, 0, ID, UIN, ReqStatus, FSeq);
  798.   FSock.SendData(pkt, pkt.Len);
  799. end;
  800. {Unregister an UIN number.}
  801. procedure TICQClient.UnregisterUIN(const Password: String);
  802. var
  803.   pkt: TRawPkt;
  804. begin
  805.   if (not LoggedIn) then Exit;
  806.   CreateCLI_UNREGUIN(@pkt, FLUIN, Password, FSeq, FSeq2);
  807.   FSock.SendData(pkt, pkt.Len);
  808. end;
  809. {Change current password to NewPassword.}
  810. procedure TICQClient.ChangePassword(const NewPassword: String);
  811. var
  812.   pkt: TRawPkt;
  813. begin
  814.   if (not LoggedIn) then Exit;
  815.   CreateCLI_METASETPASS(@pkt, FLUIN, NewPassword, nil, 0, FSeq, FSeq2);
  816.   FSock.SendData(pkt, pkt.Len);
  817. end;
  818. {Change current password to Buffer's value.}
  819. procedure TICQClient.ChangePasswordPtr(Buffer: Pointer; BufLen: Word);
  820. var
  821.   pkt: TRawPkt;
  822. begin
  823.   if (not LoggedIn) then Exit;
  824.   CreateCLI_METASETPASS(@pkt, FLUIN, '', Buffer, BufLen, FSeq, FSeq2);
  825.   FSock.SendData(pkt, pkt.Len);
  826. end;
  827. {Returns True if direct connection with UIN has been estabilished.}
  828. function TICQClient.DirectConnectionEstabilished(UIN: LongWord): Boolean;
  829. begin
  830.   Result := False;
  831.   if FDirect = nil then Exit;
  832.   Result := FDirect.ConnectionEstabilished(UIN);
  833. end;
  834. {Send contacts to UIN through server.}
  835. function TICQClient.SendContacts(UIN: LongWord; Contacts: TStringList; ID: Word): Boolean;
  836. var
  837.   pkt: TRawPkt;
  838. begin
  839.   Result := False;
  840.   if not LoggedIn then Exit;
  841.   CreateCLI_SENDCONTACTS(@pkt, 0, ID, UIN, Contacts, FSeq);
  842.   FSock.SendData(pkt, pkt.Len);
  843.   Result := True;
  844. end;
  845. {Request contacts from UIN through server.}
  846. function TICQClient.RequestContacts(UIN: LongWord; const Reason: String; ID: Word): Boolean;
  847. var
  848.   pkt: TRawPkt;
  849. begin
  850.   Result := False;
  851.   if not LoggedIn then Exit;
  852.   CreateCLI_SENDCONTACTS_REQ(@pkt, 0, ID, UIN, Reason, FSeq);
  853.   FSock.SendData(pkt, pkt.Len);
  854.   Result := True;  
  855. end;
  856. {Sends contacts to UIN directly. Returns ID of the packet or 0 if failed.}
  857. function TICQClient.SendContactsDC(UIN: LongWord; Contacts: TStringList): Word;
  858. var
  859.   pkt: TRawPkt;
  860. begin
  861.   Result := 0;
  862.   if FDirect = nil then Exit;
  863.   if (FDSeq = 0) then Inc(FSeq);
  864.   Result := CreatePEER_CONTACTS(@pkt, Contacts, FDSeq);
  865.   if not FDirect.SendData(UIN, @pkt) then
  866.     Result := 0;
  867. end;
  868. {Request contacts from UIN directly. Returns ID of the packet or 0 if failed.}
  869. function TICQClient.RequestContactsDC(UIN: LongWord; const Reason: String): Word;
  870. var
  871.   lpkt: TRawPkt;
  872. begin
  873.   Result := 0;
  874.   if FDirect = nil then Exit;
  875.   if (FDSeq = 0) then Inc(FSeq);
  876.   Result := CreatePEER_CONTACTREQ(@lpkt, Reason, FDSeq);
  877.   if not FDirect.SendData(UIN, @lpkt) then
  878.     Result := 0;
  879. end;
  880. {Send keep alive packet.}
  881. procedure TICQClient.SendKeepAlive;
  882. var
  883.   lpkt: TRawPkt;
  884. begin
  885.   if (not LoggedIn) then Exit;
  886.   CreateCLI_KEEPALIVE(@lpkt, FSeq);
  887.   FSock.SendData(lpkt, lpkt.Len);
  888. end;
  889. {Set AuthorizationRequired and WebAware options.}
  890. procedure TICQClient.SetAuthorization(AuthorizationRequired, WebAware: Boolean);
  891. var
  892.   lpkt: TRawPkt;
  893. begin
  894.   if (not LoggedIn) then Exit;
  895.   CreateCLI_METASETPERMISSIONS(@lpkt, FLUIN, AuthorizationRequired, WebAware, FSeq, FSeq2);
  896.   FSock.SendData(lpkt, lpkt.Len);
  897. end;
  898. {Request authorization.}
  899. procedure TICQClient.SendAuthRequest(UIN: LongWord; Msg: String);
  900. var
  901.   lpkt: TRawPkt;
  902. begin
  903.   if (not LoggedIn) then Exit;
  904.   CreateCLI_REQAUTH(@lpkt, UIN, Msg, FSeq);
  905.   FSock.SendData(lpkt, lpkt.Len);
  906. end;
  907. {Start changes of SSL.}
  908. procedure TICQClient.SSLChangeStart(FirstUpload: Boolean);
  909. var
  910.   lpkt: TRawPkt;
  911. begin
  912.   if (not LoggedIn) then Exit;
  913.   CreateCLI_ADDSTART(@lpkt, FirstUpload, FSeq);
  914.   FSock.SendData(lpkt, lpkt.Len);
  915. end;
  916. {End changes of SSL.}
  917. procedure TICQClient.SSLChangeEnd;
  918. var
  919.   lpkt: TRawPkt;
  920. begin
  921.   if (not LoggedIn) then Exit;
  922.   CreateCLI_ADDEND(@lpkt, FSeq);
  923.   FSock.SendData(lpkt, lpkt.Len);
  924. end;
  925. {Add group to SSL.}
  926. procedure TICQClient.SSLAddGroup(GroupName: String; GroupID: Word);
  927. var
  928.   lpkt: TRawPkt;
  929. begin
  930.   if (not LoggedIn) then Exit;
  931.   CreateCLI_ADDBUDDY(@lpkt, GroupName, '', '', GroupID, 0, BUDDY_GROUP, False, FSeq);
  932.   FSock.SendData(lpkt, lpkt.Len);
  933. end;
  934. {Add user to SSL.}
  935. procedure TICQClient.SSLAddUser(GroupID, UserID: Word; UIN, Name, SMSNumber: String; Authorize, UpdateUser: Boolean);
  936. var
  937.   lpkt: TRawPkt;
  938. begin
  939.   if (not LoggedIn) then Exit;
  940.   if not UpdateUser then
  941.     CreateCLI_ADDBUDDY(@lpkt, UIN, Name, SMSNumber, GroupID, UserID, BUDDY_NORMAL, Authorize, FSeq)
  942.   else
  943.     CreateCLI_UPDATEBUDDY(@lpkt, UIN, Name, SMSNumber, GroupID, UserID, BUDDY_NORMAL, Authorize, FSeq);
  944.   FSock.SendData(lpkt, lpkt.Len);
  945. end;
  946. {Remove user from SSL.}
  947. procedure TICQClient.SSLDelUser(GroupID, UserID: Word; UIN, Name, SMSNumber: String; Authorize: Boolean);
  948. var
  949.   lpkt: TRawPkt;
  950. begin
  951.   if (not LoggedIn) then Exit;
  952.   CreateCLI_DELETEBUDDY(@lpkt, UIN, Name, SMSNumber, GroupID, UserID, BUDDY_NORMAL, Authorize, True, FSeq);
  953.   FSock.SendData(lpkt, lpkt.Len);
  954. end;
  955. {Remove group from SSL.}
  956. procedure TICQClient.SSLDelGroup(GroupName: String; GroupID: Word);
  957. var
  958.   lpkt: TRawPkt;
  959. begin
  960.   if (not LoggedIn) then Exit;
  961.   CreateCLI_DELETEBUDDY(@lpkt, GroupName, '', '', GroupID, 0, BUDDY_GROUP, False, True, FSeq);
  962.   FSock.SendData(lpkt, lpkt.Len);
  963. end;
  964. {Update group's ids.}
  965. procedure TICQClient.SSLUpdateGroup(GroupName: String; GroupID: Word; UserIDs: TStringList);
  966. var
  967.   lpkt: TRawPkt;
  968. begin
  969.   if (not LoggedIn) then Exit;
  970.   CreateCLI_UPDATEGROUP(@lpkt, GroupName, GroupID, UserIDs, FSeq);
  971.   FSock.SendData(lpkt, lpkt.Len);
  972. end;
  973. {Add user to the specified SSL's list.}
  974. procedure TICQClient.SSLAddUserIntoList(UserID: Word; UIN: String; BuddyType: Word);
  975. var
  976.   lpkt: TRawPkt;
  977. begin
  978.   if (not LoggedIn) then Exit;
  979.   CreateCLI_ADDBUDDY(@lpkt, UIN, '', '', $0000, UserID, BuddyType, False, FSeq);
  980.   FSock.SendData(lpkt, lpkt.Len);
  981. end;
  982. {Remove user from the specified SSL's list.}
  983. procedure TICQClient.SSLDelUserFromList(UserID: Word; UIN: String; BuddyType: Word);
  984. var
  985.   lpkt: TRawPkt;
  986. begin
  987.   if (not LoggedIn) then Exit;
  988.   CreateCLI_DELETEBUDDY(@lpkt, UIN, '', '', $0000, UserID, BuddyType, False, True, FSeq);
  989.   FSock.SendData(lpkt, lpkt.Len);
  990. end;
  991. {Send response on a file request.}
  992. function TICQClient.FTResponse(ResponseRec: TFTRequestRec; Accept: Boolean; Reason: String): Boolean;
  993. var
  994.   lpkt: TRawPkt;
  995. begin
  996.   if DisableDirectConnections then
  997.   begin
  998.     Result := False;
  999.     Exit;
  1000.   end;
  1001.   if not Accept then
  1002.   begin
  1003.     if ResponseRec.ReqType <> 0 then
  1004.     begin
  1005.       {Never tested because didn't see when ICQ request ft through server, miranda-icq doest this but doesn't handle file declines even from real ICQ}
  1006.       CreateCLI_SENDMSG_FILEDECLINE(@lpkt, ResponseRec.Seq, ResponseRec.ITime, ResponseRec.IRandomID,
  1007.         ResponseRec.UIN, ResponseRec.FileSize,
  1008.         ResponseRec.Description, ResponseRec.FileName, Reason, 0, FSeq);
  1009.       FSock.SendData(lpkt, lpkt.Len);
  1010.       Result := True;
  1011.       Exit;
  1012.     end;
  1013.   end;
  1014.   if FDirect <> nil then
  1015.   if FDirect.AddFileUser(ResponseRec.UIN, ResponseRec.Port) then
  1016.     begin
  1017.       {Send response through estabilished direct connection}
  1018.       if ResponseRec.ReqType = 0 then
  1019.       begin
  1020.         CreatePEER_FILEINIT(@lpkt, True, ResponseRec.Description, ResponseRec.FileName, ResponseRec.Port,
  1021.           ResponseRec.FileSize, ResponseRec.Seq, Reason, Accept);
  1022.         Result := FDirect.SendData(ResponseRec.UIN, @lpkt);
  1023.       end else
  1024.       {Send response through server}
  1025.       begin
  1026.         CreateCLI_SENDMSG_FILEACK(@lpkt, ResponseRec.Seq, ResponseRec.ITime, ResponseRec.IRandomID,
  1027.           ResponseRec.UIN, ResponseRec.FileSize, ResponseRec.Description, ResponseRec.FileName,
  1028.           ResponseRec.Port, FSeq);
  1029.         FSock.SendData(lpkt, lpkt.Len);
  1030.         Result := True;
  1031.       end;
  1032.       Exit;
  1033.     end else
  1034.       OnIntError(Self, ERR_WARNING, 'Could not add user for sending/receiving files');
  1035.   Result := False;
  1036. end;
  1037. procedure TICQClient.FTCancel(UIN: LongWord);
  1038. begin
  1039.   if FDirect <> nil then
  1040.     FDirect.StopFileReceiving(UIN);
  1041. end;
  1042. function TICQClient.FTStartResponse(StartRec: TFTStartRec): Boolean;
  1043. var
  1044.   lpkt: TRawPkt;
  1045. begin
  1046.   Result := False;
  1047.   if FDirect = nil then Exit;
  1048.   CreatePEER_FILE_INIT2(@lpkt, StartRec.FilesCount, $00000000, StartRec.Speed);
  1049.   Result := FDirect.SendDataFile(StartRec.UIN, @lpkt);
  1050. end;
  1051. {@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}
  1052. {Handling of all incoming packets}
  1053. procedure TICQClient.HandlePacket(Flap: TFlapHdr; Data: Pointer);
  1054. var
  1055.   FUIN: String;
  1056.   FData: String;
  1057.   pkt: TRawPkt;
  1058.   T: Word;
  1059.   Snac: TSnacHdr;
  1060.   i: Word;
  1061. begin
  1062.   case Flap.ChID of
  1063.     1: //Channel 1
  1064.     begin
  1065.       {SRV_HELLO}
  1066.       if Flap.DataLen = 4 then
  1067.       begin
  1068.         if FRegisteringUIN then
  1069.         begin
  1070.           //Send CLI_HELLO
  1071.           CreateCLI_HELLO(@pkt, FSeq);
  1072.           FSock.SendData(pkt, pkt.Len);
  1073.           //Register a new UIN.
  1074.           CreateCLI_REGISTERUSER(@pkt, FRegPassword, FSeq);
  1075.           FSock.SendData(pkt, pkt.Len);
  1076.           Exit;
  1077.         end;
  1078.         if FFirstConnect then
  1079.         begin
  1080.           //Send login packet
  1081.           CreateCLI_IDENT(@pkt, FLUIN, FLPass, FSeq);
  1082.           FSock.SendData(pkt, pkt.len);
  1083.         end
  1084.         else
  1085.         begin
  1086.           //Sending the cookie(second stage of login sequence)
  1087.           CreateCLI_COOKIE(@pkt, FCookie, FSeq);
  1088.           FSock.SendData(pkt, pkt.Len);
  1089.         end;
  1090.       end;
  1091.       FFirstConnect := False;
  1092.     end;
  1093.     2: //Channel 2
  1094.     begin
  1095.       Move(Data^, pkt.Data, Flap.DataLen); pkt.Len := 0;
  1096.       GetSnac(@pkt, Snac);
  1097.       case Snac.Family of
  1098.         $01: //Family x01
  1099.           case Snac.SubType of
  1100.             $03: {SRV_FAMILIES}
  1101.             begin
  1102.               CreateCLI_FAMILIES(@pkt, FSeq);           {SNAC(x01/x17)}
  1103.               FSock.SendData(pkt, pkt.Len);
  1104.             end;
  1105.             $07: {SRV_RATES}
  1106.             begin
  1107.               CreateCLI_ACKRATES(@pkt, FSeq);           {SNAC(x01/x08)}
  1108.               FSock.SendData(pkt, pkt.Len);
  1109.               CreateCLI_SETICBM(@pkt, FSeq);            {SNAC(x04/x02)}
  1110.               FSock.SendData(pkt, pkt.Len);
  1111.               CreateCLI_REQINFO(@pkt, FSeq);            {SNAC(x01/x0E)}
  1112.               FSock.SendData(pkt, pkt.Len);
  1113.               CreateCLI_REQLOCATION(@pkt, FSeq);        {SNAC(x02/x02)}
  1114.               FSock.SendData(pkt, pkt.Len);
  1115.               CreateCLI_REQBUDDY(@pkt, FSeq);           {SNAC(x03/x02)}
  1116.               FSock.SendData(pkt, pkt.Len);
  1117.               CreateCLI_REQICBM(@pkt, FSeq);            {SNAC(x04/x04)}
  1118.               FSock.SendData(pkt, pkt.Len);
  1119.               CreateCLI_REQBOS(@pkt, FSeq);             {SNAC(x09/x02)}
  1120.               FSock.SendData(pkt, pkt.Len);
  1121.               //FConnecting := False;
  1122.             end;
  1123.             $13: {SRV_MOTD}
  1124.             begin
  1125.               CreateCLI_RATESREQUEST(@pkt, FSeq);       {SNAC(x01/x06)}
  1126.               FSock.SendData(pkt, pkt.Len);
  1127.             end;
  1128.           end;
  1129.         $03: //Family x03
  1130.         begin
  1131.           case Snac.SubType of
  1132.             $0B: {SRV_USERONLINE}
  1133.               HSnac030B(Flap, Snac, @pkt);
  1134.             $0C: {SRV_USEROFFLINE}
  1135.             begin
  1136.               FData := GetStr(@pkt, GetInt(@pkt, 1));
  1137.               if Assigned(OnUserOffline) then
  1138.                 FOnUserOffline(Self, FData);
  1139.             end;
  1140.           end;
  1141.         end;
  1142.         $04: //Family x04
  1143.           if Snac.SubType = $07 then {SRV_MSG}
  1144.             HSnac0407(Flap, Snac, @pkt)
  1145.           else if Snac.SubType = $0b then {SRV_MSGACK}
  1146.             HSnac040b(Flap, Snac, @pkt);
  1147.         $09: //Family x09
  1148.         begin
  1149.           if Snac.SubType = $03 then
  1150.           begin
  1151.             CreateCLI_SETUSERINFO(@pkt, FSeq);                                  {SNAC(x02/x04)}
  1152.             FSock.SendData(pkt, pkt.Len);
  1153.             if FContactLst.Count > 0 then
  1154.               for i := 0 to FContactLst.Count - 1 do
  1155.               begin
  1156.                 CreateCLI_ADDCONTACT(@pkt, FContactLst.Strings[i], FSeq);       {SNAC(x03/x04)}
  1157.                 FSock.SendData(pkt, pkt.Len);
  1158.               end;
  1159.             if StatusToStr(FStatus) <> 'Invisible' then
  1160.             begin
  1161.               CreateCLI_ADDINVISIBLE(@pkt, FInvisibleLst, FSeq);                {SNAC(x09/x07)}
  1162.               FSock.SendData(pkt, pkt.Len);
  1163.             end else
  1164.             begin
  1165.               CreateCLI_ADDVISIBLE(@pkt, FVisibleLst, FSeq);                    {SNAC(x09/x05)}
  1166.               FSock.SendData(pkt, pkt.Len);
  1167.             end;
  1168.             FDConnCookie := Random(High(Integer));
  1169.             if FDirect <> nil then
  1170.             begin
  1171.               if ProxyType = P_NONE then
  1172.                 i := FDirect.BindPort
  1173.               else
  1174.                 i := 0;
  1175.               CreateCLI_SETSTATUS(@pkt, FStatus, GetLocalIP, i, FDConnCookie, FProxyType, FSeq)  {SNAC(x01/x1E)}
  1176.             end else
  1177.               CreateCLI_SETSTATUS(@pkt, FStatus, 0, 0, 0, FProxyType, FSeq);    {SNAC(x01/x1E)}
  1178.             FSock.SendData(pkt, pkt.Len);
  1179.             CreateCLI_READY(@pkt, FSeq);                                        {SNAC(x01/x02)}
  1180.             FSock.SendData(pkt, pkt.Len);
  1181.             CreateCLI_TOICQSRV(@pkt, FLUIN, CMD_REQOFFMSG, nil, 0, FSeq, FSeq2);{SNAC(x15/x02)}
  1182.             FSock.SendData(pkt, pkt.Len);
  1183.             {OnLogin Event}
  1184.             FLoggedIn := True;
  1185.             FTimer.Enabled := False;
  1186.             FInfoChain.Clear;
  1187.             FSInfoChain.Clear;
  1188.             if Assigned(OnLogin) then
  1189.               FOnLogin(Self);
  1190.           end;
  1191.         end;
  1192.         $13: //Family x13
  1193.         begin
  1194.           if Snac.SubType = $0e then
  1195.             HSnac130e(Flap, Snac, @pkt) {SRV_UPDATE_ACK}
  1196.           else if Snac.SubType = $1B then
  1197.             HSnac131b(Flap, Snac, @pkt) {SRV_AUTH}
  1198.           else if Snac.SubType = $1C then {SRV_ADDEDYOU}
  1199.             HSnac131C(Flap, Snac, @pkt)
  1200.           else if Snac.SubType = $19 then {SRV_AUTH_REQ}
  1201.             HSnac1319(Flap, Snac, @pkt)
  1202.           else if Snac.SubType = $06 then {SRV_REPLYROSTER}
  1203.             HSnac1306(Flap, Snac, @pkt);
  1204.         end;
  1205.         $15: //Family x15
  1206.         begin
  1207.           if Snac.SubType = $03 then {SRV_FROMICQSRV}
  1208.             HSnac1503(Flap, Snac, @pkt);
  1209.         end;
  1210.         $17:
  1211.         begin
  1212.           if Snac.SubType = $01 then {SRV_REGREFUSED}
  1213.           begin
  1214.             if Assigned(OnNewUINRefused) then
  1215.               FOnNewUINRefused(Self);
  1216.           end else
  1217.           if Snac.SubType = $05 then
  1218.             HSnac1705(Flap, Snac, @pkt);
  1219.         end;
  1220.       end;
  1221.     end;
  1222.     4: //Channel 4
  1223.     begin
  1224.       if FLoggedIn or FRegisteringUIN then
  1225.       begin
  1226.         FTOnConnectError(Self);
  1227.         FSock.Disconnect;
  1228.         Exit;
  1229.       end;
  1230.       Move(Data^, pkt.Data, Flap.DataLen); pkt.Len := 0;
  1231.       //SRV_COOKIE
  1232.       FUIN  := GetTLVStr(@pkt, T);                //Client's UIN in ASCII format
  1233.       if T <> 1 then
  1234.       begin
  1235.         OnIntError(nil, ERR_PROTOCOL, 'Received malformed login packet');
  1236.         FTOnConnectError(Self);
  1237.         FSock.Disconnect;
  1238.         Exit;
  1239.       end;
  1240.       FData := GetTLVStr(@pkt, T);                //IP, Port to connect to
  1241.       if T = 4 then
  1242.       begin
  1243.         OnIntError(nil, ERR_LOGIN, 'Bad password');
  1244.         FTOnConnectError(Self);
  1245.         Exit;
  1246.       end else
  1247.       if T = 8 then
  1248.       begin
  1249.         OnIntError(nil, ERR_LOGIN, 'Too often logins');
  1250.         FTOnConnectError(Self);
  1251.         Exit;
  1252.       end else
  1253.       if T <> 5 then
  1254.       begin
  1255.         OnIntError(nil, ERR_PROTOCOL, 'Received malformed login packet');
  1256.         FTOnConnectError(Self);
  1257.         FSock.Disconnect;
  1258.         Exit;
  1259.       end;
  1260.       FCookie := GetTLVStr(@pkt, T);              //Cookie used in second stage of login
  1261.       if T <> 6 then
  1262.       begin
  1263.         OnIntError(nil, ERR_PROTOCOL, 'Received malformed login packet');
  1264.         FTOnConnectError(Self);
  1265.         FSock.Disconnect;
  1266.         Exit;
  1267.       end;
  1268.       //Sending CLI_GOODBYE
  1269.       PktInit(@pkt, 4, FSeq);
  1270.       PktFinal(@pkt);
  1271.       FSock.SendData(pkt, pkt.Len);
  1272.       FSock.Disconnect;
  1273.       //Assigning new IP and Port to connect to in second attemp
  1274.       InitNetICQ;
  1275.       FSock.Host := Copy(FData, 0, Pos(':', FData) - 1);
  1276.       FSock.Port := StrToInt(Copy(FData, Pos(':', FData) + 1, Length(FData) - Pos(':', FData)));
  1277.       if (FSock.Port = 0) then
  1278.       begin
  1279.         OnIntError(nil, ERR_PROTOCOL, 'Received malformed login packet');
  1280.         FTOnConnectError(Self);
  1281.         Exit;
  1282.       end;
  1283.       FSock.Connect;
  1284.     end;
  1285.   end;
  1286. end;
  1287. {////////////////////////////////////////////////////////////////////////////////////////////////////}
  1288. procedure TICQClient.SetStatus(NewStatus: LongWord);
  1289. var
  1290.   pkt: TRawPkt;
  1291. begin
  1292.   if not LoggedIn then Exit;
  1293.   if (StatusToStr(FStatus) = 'Invisible') and (StatusToStr(NewStatus) <> 'Invisible') then
  1294.   begin
  1295.     CreateCLI_ADDINVISIBLE(@pkt, FInvisibleLst, FSeq);
  1296.     FSock.SendData(pkt, pkt.Len);
  1297.   end else
  1298.   if (StatusToStr(NewStatus) = 'Invisible') and (StatusToStr(FStatus) <> 'Invisible') then
  1299.   begin
  1300.     CreateCLI_ADDVISIBLE(@pkt, FVisibleLst, FSeq);
  1301.     FSock.SendData(pkt, pkt.Len);
  1302.   end;
  1303.   CreateCLI_SETSTATUS_SHORT(@pkt, NewStatus, FSeq);
  1304.   FSock.SendData(pkt, pkt.Len);
  1305.   FStatus := NewStatus;
  1306. end;
  1307. {Handling packet with messages}
  1308. procedure TICQClient.HSnac0407(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  1309. var
  1310.   ITime, IRandomID: LongWord;
  1311.   ULen: Word;
  1312.   c, i: Word;
  1313.   ack_pkt: TRawPkt;
  1314.   chunks: array[0..49] of Byte;
  1315.   Msg, UIN: String;
  1316.   MsgType: Word;
  1317.   Desc, URL: String;
  1318.   v: Byte;
  1319.   atype: String;
  1320.   XML: String;
  1321.   XMLTime, XMLSource, XMLSender, XMLText: String;
  1322.   FName, FDesc: String;
  1323.   FSize: LongWord;
  1324.   FFSeq: Word;
  1325.   Rec: TFTRequestRec;
  1326.   TCMD: String;
  1327.   List: TStringList;
  1328. begin
  1329.   ITime := GetInt(Pkt, 4);                      //Time
  1330.   IRandomID := GetInt(Pkt, 2);                  //RandomID
  1331.   Inc(Pkt^.Len, 2);                             //Unknown: empty
  1332.   Msg := '';
  1333.   {Subtypes}
  1334.   case GetInt(Pkt, 2) of
  1335.     1:                                          //Simply(old-type) message
  1336.     begin
  1337.       UIN := GetStr(Pkt, GetInt(Pkt, 1));
  1338.       Inc(Pkt^.Len, 2);
  1339.       c := GetInt(Pkt, 2);                      //A count of the number of following TLVs.
  1340.       for i := 0 to c - 1 do                    //Skip all TLVs
  1341.       begin
  1342.         Inc(Pkt^.Len, 2);
  1343.         Inc(Pkt^.Len, GetInt(Pkt, 2));
  1344.       end;
  1345.       if GetInt(Pkt, 2) = 2 then                //TLV with message remain
  1346.       begin
  1347.         Inc(Pkt^.Len, 4);                       //TLV length + Unknown const
  1348.         Inc(Pkt^.Len, GetInt(Pkt, 2));          //Counts of following bytes + following bytes
  1349.         Inc(Pkt^.Len, 2);                       //x0101, Unknown, constant
  1350.         ULen := GetInt(Pkt, 2) - 4;             //Length of the message + 4
  1351.         Inc(Pkt^.Len, 4);                       //Unknown seems to be constant
  1352.         Msg := GetStr(Pkt, ULen);               //The actual message text. There will be no ending NULL.
  1353.         if (Length(Msg) > 0) and Assigned(OnMessageRecv) then
  1354.           FOnMsg(Self, Msg, UIN);
  1355.       end;
  1356.     end;
  1357.     2:                                          //Adnavced(new-type)
  1358.     begin
  1359.       UIN := GetStr(Pkt, GetInt(Pkt, 1));
  1360.       for c := 0 to 5 do
  1361.       begin
  1362.         if GetInt(Pkt, 2) = 5 then
  1363.         begin
  1364.           Inc(Pkt^.Len, 2);
  1365.           if GetInt(Pkt, 2) <> 0 then           //ACKTYPE: 0x0000 - This is a normal message
  1366.             Exit;
  1367.           Inc(Pkt^.Len, 16);                    //File signature
  1368.           Inc(Pkt^.Len, 8);                     //TIME + RANDOM
  1369.           for i := 0 to 5 do
  1370.           begin
  1371.             if GetInt(Pkt, 2) = $2711 then      //Searching for TLV(2711) (with sources)
  1372.             begin
  1373.               Inc(Pkt^.Len, 2);                 //TLV Length
  1374.               Move(Ptr(LongWord(Pkt) + Pkt^.Len)^, chunks, 47);
  1375.               if GetInt(Pkt, 1) <> $1B then     //If this value is not present, this is not a message packet. Also, ICQ2001b does not send an ACK, SNAC(4,B), if this is not 0x1B.
  1376.                 Exit;
  1377.               Inc(Pkt^.Len, 26);
  1378.               FFSeq := GetInt(Pkt, 2);
  1379.               Inc(Pkt^.Len, 16);
  1380.               MsgType := GetInt(Pkt, 1);
  1381.               Inc(Pkt^.Len, 5);
  1382.               if MsgType = M_FILE then          //File request
  1383.               begin
  1384.                 FDesc := GetLNTS(Pkt);          //File description
  1385.                 Inc(Pkt^.Len, 4);               //Unknown: 00 00 00 00
  1386.                 FName := GetLNTS(Pkt);          //File name
  1387.                 FSize := GetLInt(Pkt, 4);       //File size
  1388.                 {Set the records' items}
  1389.                 Rec.ITime := ITime;
  1390.                 Rec.IRandomID := IRandomID;
  1391.                 Rec.UIN := StrToInt(UIN);
  1392.                 Rec.FileSize := FSize;
  1393.                 Rec.Description := FDesc;
  1394.                 Rec.FileName := FName;
  1395.                 Rec.Seq := FFSeq;
  1396.                 Rec.ReqType := $01;
  1397.                 if Assigned(OnFTRequest) then
  1398.                   FOnFTRequest(Self, Rec);
  1399.                 Exit;
  1400.               end else
  1401.               if MsgType = M_ADVANCED then      //Advanced message container
  1402.               begin
  1403.                 GetLNTS(Pkt);                   //Empty message (contains only a null terminator)
  1404.                 Inc(Pkt^.Len, 2);               //Following length
  1405.                 Inc(Pkt^.Len, 16);              //Signature
  1406.                 Inc(Pkt^.Len, 2);               //Unknown: empty
  1407.                 TCMD := GetDWStr(Pkt);          //Text command
  1408.                 if TCMD = 'Contacts' then
  1409.                 begin
  1410.                   Inc(Pkt^.Len, 4);             //Following length
  1411.                   Msg := GetDWStr(Pkt);         //Message containing a list with contacts
  1412.                   List := TStringList.Create;   //Create temporary list
  1413.                   ParseContacts(Msg, List);     //Parse message with contacts
  1414.                   if Assigned(OnContactListRecv) then
  1415.                     FOnContactListRecv(Self, UIN, List);
  1416.                 end else
  1417.                 if TCMD = 'Request For Contacts' then
  1418.                 begin
  1419.                   Inc(Pkt^.Len, 15);            //15 unknown bytes
  1420.                   Inc(Pkt^.Len, 4);             //Following length
  1421.                   Msg := GetDWStr(Pkt);         //Message containing a reason
  1422.                   if Assigned(OnContactListRequest) then
  1423.                     FOnContactListReq(Self, UIN, Msg);
  1424.                 end;
  1425.               end
  1426.               else
  1427.                 Msg := GetLNTS(Pkt);            //The actual message text. There will be ending NULL.
  1428.               {Sending ACK of the message}
  1429.               PktInit(@ack_pkt, 2, FSeq);               //Channel 2
  1430.               PktSnac(@ack_pkt, $04, $0B, 0, 0);        //SNAC(x04/x0B)
  1431.               Move(Ptr(LongWord(Pkt) + TSNACSZ)^, Ptr(LongWord(@ack_pkt) + ack_pkt.Len)^, 10); //First 10 bytes of TLV(2711)
  1432.               Inc(ack_pkt.Len, 10);                     //Skip first 10 bytes copied from TLV(2711) which were added before
  1433.               PktLStr(@ack_pkt, UIN);                   //User's UIN
  1434.               PktInt(@ack_pkt, $0003, 2);               //00 03
  1435.               PktAddArrBuf(@ack_pkt, @chunks, 47);      //First 47 bytes of source packet (with message)
  1436.               PktInt(@ack_pkt, $00000000, 4);           //00 00 00 00
  1437.               //If it's an auto-away message request
  1438.               if MsgType and $E0 = $E0 then
  1439.                 PktLNTS(@ack_pkt, FAutoAwayMsg)         //Auto-away message
  1440.               else begin
  1441.                 PktInt(@ack_pkt, 1, 1);                 //01
  1442.                 PktInt(@ack_pkt, 0, 4);                 //00 00 00 00
  1443.                 PktInt(@ack_pkt, 0, 2);                 //00 00
  1444.                 PktInt(@ack_pkt, $FFFFFF00, 4);         //FF FF FF 00
  1445.               end;
  1446.               PktFinal(@ack_pkt);
  1447.               FSock.SendData(ack_pkt, ack_pkt.Len);
  1448.               if (Length(Msg) > 0) then
  1449.               begin
  1450.                 if MsgType = M_PLAIN then
  1451.                 begin
  1452.                   if FDoPlain then Msg := Rtf2Txt(Msg);   //Convert message from RTF to plaintext when needed
  1453.                   if Assigned(OnMessageRecv) then
  1454.                     FOnMsg(Self, Msg, UIN)
  1455.                 end else
  1456.                 if MsgType = M_URL then
  1457.                 begin
  1458.                   Desc := Copy(Msg, 0, Pos(#$fe, Msg) - 1);
  1459.                   URL := Copy(Msg, Pos(#$fe, Msg) + 1, Length(Msg) - Pos(#$fe, Msg));
  1460.                   if Assigned(OnURLRecv) then
  1461.                     FOnURL(Self, Desc, URL, UIN);
  1462.                 end;
  1463.               end;
  1464.               Exit;
  1465.             end else
  1466.               Inc(Pkt^.Len, GetInt(Pkt, 2));
  1467.           end;
  1468.         end else
  1469.           Inc(Pkt^.Len, GetInt(Pkt, 2));
  1470.       end;
  1471.     end;
  1472.     4:                                                  //Another message type
  1473.     begin
  1474.       UIN := GetLStr(Pkt);
  1475.       for i := 0 to 4 do
  1476.       begin
  1477.         v := GetInt(Pkt, 1);
  1478.         if (v = 5) or ((GetInt(Pkt, 1) = 5) and (v = 0)) then    //TLV(5) was found
  1479.         begin
  1480.           if v = 5 then                                 //Some modifications for MAC clients
  1481.             Inc(Pkt^.Len, 40)
  1482.           else
  1483.             Inc(Pkt^.Len, 2);
  1484.           GetLInt(Pkt, 4);                              //UIN
  1485.           MsgType := GetLInt(Pkt, 2);                   //Message-type
  1486.           Msg := GetLNTS(Pkt);                          //Message
  1487.           if MsgType = $1a then                         //Probably advanced msg format
  1488.           begin
  1489.             Inc(Pkt^.Len, 20);                          //20 unknown bytes
  1490.             atype := GetDWStr(Pkt);                     //Advanced msg sub-type
  1491.             if atype = 'ICQSMS' then                    //Corresponds to received SMS message in XML formatted message
  1492.             begin
  1493.               Inc(Pkt^.Len, 3);                         //00 00 00
  1494.               Inc(Pkt^.Len, 4);                         //4-byte little endian length of the following data
  1495.               XML := GetStr(Pkt, GetLInt(Pkt, 4));      //XML entry of SMS response
  1496.               XMLSource := GetXMLEntry('source', XML);  //Source, usually: 'ICQ'
  1497.               XMLSender := GetXMLEntry('sender', XML);  //Source cellular number
  1498.               XMLText := GetXMLEntry('text', XML);      //Text of reply
  1499.               XMLTime := GetXMLEntry('time', XML);      //Time of sending reply
  1500.               if Assigned(OnSMSReply) then
  1501.                 FOnSMSReply(Self, XMLSource, XMLSender, XMLTime, UTF8ToStrSmart(XMLText));
  1502.             end;
  1503.             Exit;
  1504.           end;
  1505.           if (Length(Msg) > 0) then
  1506.           begin
  1507.             if MsgType = M_PLAIN then
  1508.             begin
  1509.               if FDoPlain then Msg := Rtf2Txt(Msg);     //Convert message from RTF to plaintext when needed
  1510.               if Assigned(OnMessageRecv) then
  1511.                 FOnMsg(Self, Msg, UIN)
  1512.             end
  1513.             else if MsgType = M_URL then
  1514.             begin
  1515.               Desc := Copy(Msg, 0, Pos(#$fe, Msg) - 1);
  1516.               URL := Copy(Msg, Pos(#$fe, Msg) + 1, Length(Msg) - Pos(#$fe, Msg));
  1517.               if Assigned(OnURLRecv) then
  1518.                 FOnURL(Self, Desc, URL, UIN);
  1519.             end;
  1520.           end;
  1521.           Exit;
  1522.         end else
  1523.           Inc(Pkt^.Len, GetInt(Pkt, 2));
  1524.       end;
  1525.     end;
  1526.   end;
  1527. end;
  1528. {Handling old type packets ICQ_FROMSRV}
  1529. procedure TICQClient.HSnac1503(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  1530. var
  1531.   FMsgType: Word;
  1532.   lpkt: TRawPkt;
  1533.   FNick, FFirst, FLast, FEmail, FCity,
  1534.   FState, FPhone, FFax, FStreet, FCellular,
  1535.   FZip, FCountry, FCompany, FDepartment,
  1536.   FPosition, FOccupation, FHomePage,
  1537.   FLang1, FLang2, FLang3, FAbout: String;
  1538.   FTimeZone: Byte;
  1539.   FPublishEmail: Boolean;
  1540.   FAge, FYear: Word;
  1541.   FGender, FMonth, FDay: Byte;
  1542.   Msg, UIN, URL, Desc: String;
  1543.   List, List2: TStringList;
  1544.   C, i: Byte;
  1545.   WW: Word;
  1546.   FStatus: Word;
  1547.   cmd: Word;
  1548.   seq: Word;
  1549.   FSmsSource, FSmsDeliverable, FSmsNetwork, FMsgId: String;
  1550.   FAuthorize: Byte;
  1551. begin
  1552.   if GetInt(Pkt, 2) = 1 then                      //TLV(1)
  1553.   begin
  1554.     Inc(Pkt^.Len, 8);
  1555.     case GetInt(Pkt, 2) of
  1556.       $4100:                                      //SRV_OFFLINEMSG
  1557.       begin
  1558.         Inc(Pkt^.Len, 2);                         //The sequence number this packet is a response to.
  1559.         UIN := IntToStr(GetLInt(Pkt, 4));         //Source UIN
  1560.         Inc(Pkt^.Len, 6);                         //Date/time etc...
  1561.         FMsgType := GetLInt(Pkt, 2);              //The type of message sent, like URL message or the like.
  1562.         Msg := GetLNTS(Pkt);
  1563.         if FDoPlain then Msg := Rtf2Txt(Msg);     //Convert message from RTF to plaintext when needed
  1564.         if FMsgType = M_PLAIN then
  1565.         begin
  1566.           if Assigned(OnOfflineMsgRecv) then
  1567.             FOnOffMsg(Self, Msg, UIN);
  1568.         end else
  1569.         if FMsgType = M_URL then
  1570.         begin
  1571.           Desc := Copy(Msg, 0, Pos(#$fe, Msg) - 1);
  1572.           URL := Copy(Msg, Pos(#$fe, Msg) + 1, Length(Msg) - Pos(#$fe, Msg));
  1573.           if Assigned(OnOfflineURLRecv) then
  1574.             FOnOffURL(Self, Desc, URL, UIN);
  1575.         end;
  1576.       end;
  1577.       $4200: //All offline messages were sent, so we ACKING them
  1578.       begin
  1579.         FSeq2 := 2;
  1580.         CreateCLI_ACKOFFLINEMSGS(@lpkt, FLUIN, FSeq, FSeq2);
  1581.         FSock.SendData(lpkt, lpkt.Len);
  1582.       end;
  1583.       $da07: //SRV_META
  1584.       begin
  1585.         seq := GetLInt(Pkt, 2);
  1586.         cmd := GetInt(Pkt, 2);
  1587.         case cmd of
  1588.           $0100: //SRV_SMSREFUSED
  1589.           begin
  1590.             if Assigned(OnSMSRefused) then
  1591.               FOnSMSRefused(Self);
  1592.           end;
  1593.           $9600: //SRV_SMSACK
  1594.           begin
  1595.             if GetInt(Pkt, 1) <> $0a then Exit;
  1596.             Inc(Pkt^.Len, 12);
  1597.             Msg := GetStr(Pkt, GetLInt(Pkt, 2));
  1598.             FSmsSource := GetXMLEntry('source', Msg);
  1599.             FSmsDeliverable := GetXMLEntry('deliverable', Msg);
  1600.             FSmsNetwork := GetXMLEntry('network', Msg);
  1601.             FMsgId := GetXMLEntry('message_id', Msg);
  1602.             if Assigned(OnSMSAck) then
  1603.               FOnSMSAck(Self, FSmsSource, FSmsNetwork, FMsgId, FSmsDeliverable = 'Yes');
  1604.           end;
  1605.           $b400: //SRV_METAUNREG_BADPASS Channel: 2, Snac(0x15, 0x03) 2010/180
  1606.           begin
  1607.             case GetInt(Pkt, 1) of
  1608.               $0a:
  1609.               begin
  1610.                 if Assigned(OnUnregisterOk) then
  1611.                   FOnUnregisterOk(Self);
  1612.                 CreateCLI_GOODBYE(@lpkt, FSeq);     //Send CLI_GOODBYE, it forces server to disconnect us
  1613.                 FSock.SendData(lpkt, lpkt.Len);
  1614.               end;
  1615.               $14: if Assigned(OnUnregisterBadPassword) then
  1616.                 FOnUnregBadPass(Self);
  1617.             end;
  1618.           end;
  1619.           $c800: //SRV_METAGENERAL Channel: 2, SNAC(0x15,0x03) 2010/200
  1620.           begin
  1621.             FLastInfoUin := FInfoChain.Values[IntToStr(seq)];          
  1622.             if GetInt(Pkt, 1) <> $0a then Exit;
  1623.             FNick := GetLNTS(Pkt);
  1624.             FFirst := GetLNTS(Pkt);
  1625.             FLast := GetLNTS(Pkt);
  1626.             FEmail := GetLNTS(Pkt);
  1627.             FCity := GetLNTS(Pkt);
  1628.             FState := GetLNTS(Pkt);
  1629.             FPhone := GetLNTS(Pkt);
  1630.             FFax := GetLNTS(Pkt);
  1631.             FStreet := GetLNTS(Pkt);
  1632.             FCellular := GetLNTS(Pkt);
  1633.             FZip := GetLNTS(Pkt);
  1634.             FCountry := CountryToStr(GetLInt(Pkt, 2));
  1635.             FTimeZone := GetInt(Pkt, 1);
  1636.             if GetInt(Pkt, 1) = 1 then
  1637.               FPublishEmail := True
  1638.             else
  1639.               FPublishEmail := False;
  1640.             if Assigned(OnUserGeneralInfo) then
  1641.               FOnUserGeneralInfo(Self, FLastInfoUin, FNick, FFirst,
  1642.                 FLast, FEmail, FCity, FState, FPhone,
  1643.                 FFax, FStreet, FCellular, FZip, FCountry,
  1644.                 FTimeZone, FPublishEmail
  1645.               );
  1646.           end;
  1647.           $d200: //SRV_METAWORK Channel: 2, SNAC(0x15,0x3) 2010/210
  1648.           begin
  1649.             FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
  1650.             if GetInt(Pkt, 1) <> $0a then Exit;
  1651.             FCity := GetLNTS(Pkt);
  1652.             FState := GetLNTS(Pkt);
  1653.             FPhone := GetLNTS(Pkt);
  1654.             FFax := GetLNTS(Pkt);
  1655.             FStreet := GetLNTS(Pkt);
  1656.             FZip := GetLNTS(Pkt);
  1657.             FCountry := CountryToStr(GetLInt(Pkt, 2));
  1658.             FCompany := GetLNTS(Pkt);
  1659.             FDepartment := GetLNTS(Pkt);
  1660.             FPosition := GetLNTS(Pkt);
  1661.             FOccupation := OccupationToStr(GetLInt(Pkt, 2));
  1662.             FHomePage := GetLNTS(Pkt);
  1663.             if Assigned(OnUserWorkInfo) then
  1664.               FOnUserWorkInfo(Self, FLastInfoUin, FCity, FState, FPhone,
  1665.                 FFax, FStreet, FZip, FCountry, FCompany, FDepartment, FPosition,
  1666.                 FOccupation, FHomePage
  1667.               );
  1668.           end;
  1669.           $dc00: //SRV_METAMORE Channel: 2, SNAC(0x15,0x3) 2010/220
  1670.           begin
  1671.             FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
  1672.             if GetInt(Pkt, 1) <> $0a then Exit;
  1673.             FAge := GetLInt(Pkt, 2);
  1674.             if Integer(FAge) < 0 then
  1675.               FAge := 0;
  1676.             FGender := GetInt(Pkt, 1);
  1677.             FHomePage := GetLNTS(Pkt);
  1678.             FYear := GetLInt(Pkt, 2);
  1679.             FMonth := GetInt(Pkt, 1);
  1680.             FDay := GetInt(Pkt, 1);
  1681.             FLang1 := LanguageToStr(GetInt(Pkt, 1));
  1682.             FLang2 := LanguageToStr(GetInt(Pkt, 1));
  1683.             FLang3 := LanguageToStr(GetInt(Pkt, 1));
  1684.             if Assigned(OnUserInfoMore) then
  1685.               FOnUserInfoMore(Self, FLastInfoUin, FAge, FGender, FHomePage,
  1686.                 FYear, FMonth, FDay, FLang1, FLang2, FLang3
  1687.               );
  1688.           end;
  1689.           $e600: //Channel: 2, SNAC(0x15,0x3) 2010/230
  1690.           begin
  1691.             FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
  1692.             if GetInt(Pkt, 1) <> $0a then Exit;
  1693.             FAbout := GetLNTS(Pkt);
  1694.             if Assigned(OnUserInfoAbout) then
  1695.               FOnUserInfoAbout(Self, FLastInfoUin, FAbout);
  1696.           end;
  1697.           $eb00: //Channel: 2, SNAC(21,3) 2010/235
  1698.           begin
  1699.             FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
  1700.             if GetInt(Pkt, 1) <> $0a then Exit;
  1701.             c := GetInt(Pkt, 1);        //The number of email addresses to follow. May be zero. Each consist of the following parameters:
  1702.             List := TStringList.Create;
  1703.             if c > 0 then
  1704.               for i := 0 to c - 1 do
  1705.               begin
  1706.                 GetInt(Pkt, 1); //Publish email address? 1 = yes, 0 = no.
  1707.                 List.Add(GetLNTS(Pkt)); //The email address.
  1708.               end;
  1709.             if Assigned(OnUserInfoMoreEmails) then
  1710.               FOnUserInfoMoreEmails(Self, FLastInfoUin, List)
  1711.             else
  1712.               List.Free;
  1713.           end;
  1714.           $f000: //Channel: 2, SNAC(21,3) 2010/240
  1715.           begin
  1716.             FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
  1717.             if GetInt(Pkt, 1) <> $0a then Exit;
  1718.             c := GetInt(Pkt, 1);
  1719.             List := TStringList.Create;
  1720.             if c > 0 then
  1721.               for i := 0 to c - 1 do
  1722.               begin
  1723.                 WW := GetLInt(Pkt, 2);
  1724.                 List.Add(InterestToStr(WW) + '=' + GetLNTS(Pkt))
  1725.               end;
  1726.             if Assigned(OnUserInfoInterests) then
  1727.               FOnUserInfoInterests(Self, FLastInfoUin, List)
  1728.             else
  1729.               List.Free;
  1730.           end;
  1731.           $a401, $ae01: //SRV_METAFOUND Channel: 2, SNAC(21,3) 2010/420 or Channel: 2, SNAC(21,3) 2010/430
  1732.           begin
  1733.             if GetInt(Pkt, 1) <> $0a then
  1734.             begin
  1735.               if Assigned(OnUserNotFound) then
  1736.                 FOnUserNotFound(Self);
  1737.               Exit;
  1738.             end;
  1739.             Inc(Pkt^.Len, 2);                   //Length of the following data.
  1740.             UIN := IntToStr(GetLInt(Pkt, 4));   //The user's UIN.
  1741.             FNick := GetLNTS(Pkt);              //The user's nick name.
  1742.             FFirst := GetLNTS(Pkt);             //The user's first name.
  1743.             FLast := GetLNTS(Pkt);              //The user's last name.
  1744.             FEmail := GetLNTS(Pkt);             //The user's email address.
  1745.             FAuthorize := GetInt(Pkt, 1);       //Authorize: 1 = no, 0 = yes.
  1746.             FStatus := GetLInt(Pkt, 2);         //0 = Offline, 1 = Online, 2 = not Webaware.
  1747.             FGender := GetInt(Pkt, 1);          //The user's gender. 1 = female, 2 = male, 0 = not specified.
  1748.             FAge := GetInt(Pkt, 1);             //The user's age.
  1749.             if Assigned(OnUserFound) then
  1750.               FOnUserFound(Self, UIN, FNick, FFirst, FLast, FEmail, FStatus, FGender, FAge, cmd = $ae01, FAuthorize = $00);
  1751.           end;
  1752.           $6603:
  1753.           begin
  1754.             if GetInt(Pkt, 1) <> $0a then
  1755.             begin
  1756.               if Assigned(OnUserNotFound) then
  1757.                 FOnUserNotFound(Self);
  1758.               Exit;
  1759.             end;
  1760.             UIN := IntToStr(GetLInt(Pkt, 4));   //The user's UIN.
  1761.             if Assigned(OnUserFound) then
  1762.               FOnUserFound(Self, UIN, '', '', '', '', 0, 0, 0, True, False);
  1763.           end;
  1764.           $fa00:
  1765.           begin
  1766.             FLastInfoUin := FInfoChain.Values[IntToStr(seq)];          
  1767.             if GetInt(Pkt, 1) <> $0a then Exit;
  1768.             List := TStringList.Create;
  1769.             List2 := TStringList.Create;
  1770.             c := GetInt(Pkt, 1);                             //The number of background items to follow. May be zero. Each background item consists of the following two parameters
  1771.             if c > 0 then
  1772.               for i := 0 to c - 1 do
  1773.               begin
  1774.                 WW := GetLInt(Pkt, 2);                       //The group this background is in, according to a table.
  1775.                 if WW >= 8191 then Exit;
  1776.                 List.Add(PastToStr(WW) + '=' + GetLNTS(Pkt)) //A longer description of this background item.
  1777.               end;
  1778.             c := GetInt(Pkt, 1);                             //The number of affiliations to follow. May be zero. Each affiliation consists of the following parameters:
  1779.             if c > 0 then
  1780.               for i := 0 to c - 1 do
  1781.               begin
  1782.                 WW := GetLInt(Pkt, 2);                       //The group this affiliation is in, according to a table.
  1783.                 if WW >= 8191 then Exit;
  1784.                 List2.Add(AffiliationToStr(WW) + '=' + GetLNTS(Pkt)) //A longer description of the affiliation.
  1785.               end;
  1786.             if Assigned(OnUserInfoBackground) then
  1787.               FOnUserInfoBackground(Self, FLastInfoUin, List, List2)
  1788.             else begin
  1789.               List.Free;
  1790.               List2.Free;
  1791.             end;
  1792.           end;
  1793.           $0401: //SRV_METAINFO Channel: 2, SNAC(21,3) 2010/260
  1794.           begin
  1795.             FLastSInfoUin := FSInfoChain.Values[IntToStr(seq)];
  1796.             if FSInfoChain.IndexOfName(IntToStr(seq)) >= 0 then
  1797.               FSInfoChain.Delete(FSInfoChain.IndexOfName(IntToStr(seq)));
  1798.             if GetInt(Pkt, 1) <> $0a then
  1799.             begin
  1800.               if Assigned(OnUserInfoShort) then
  1801.                 FOnUserInfoShort(Self, FLastSInfoUIN, '', '', '', '', False, False);
  1802.               Exit;
  1803.             end else
  1804.             begin
  1805.               FNick := GetLNTS(Pkt);            //Nickname
  1806.               FFirst := GetLNTS(Pkt);           //Firstname
  1807.               FLast := GetLNTS(Pkt);            //Lastname
  1808.               FEmail := GetLNTS(Pkt);           //Email
  1809.               if Assigned(OnUserInfoShort) then
  1810.                 FOnUserInfoShort(Self, FLastSInfoUIN, FNick, FFirst, FLast, FEmail, True, GetInt(Pkt, 1) <> $01);
  1811.             end;
  1812.           end;
  1813.           $aa00:
  1814.             if Assigned(OnInfoChanged) then
  1815.               FOnInfoChanged(Self, INFO_PASSWORD, GetInt(Pkt, 1) = $0a);
  1816.           $6400: //SRV_METAGENERALDONE Channel: 2, SNAC(21,3) 2010/100
  1817.             if Assigned(OnInfoChanged) then
  1818.               FOnInfoChanged(Self, INFO_GENERAL, GetInt(Pkt, 1) = $0a);
  1819.           $7800: //SRV_METAMOREDONE Channel: 2, SNAC(21,3) 2010/120
  1820.             if Assigned(OnInfoChanged) then
  1821.               FOnInfoChanged(Self, INFO_MORE, GetInt(Pkt, 1) = $0a);
  1822.           $8200: //SRV_METAABOUTDONE Channel: 2, SNAC(21,3) 2010/130
  1823.             if Assigned(OnInfoChanged) then
  1824.               FOnInfoChanged(Self, INFO_ABOUT, GetInt(Pkt, 1) = $0a);
  1825.           $a000: //SRV_AUTHSET Channel: 2, SNAC(21, 3) 2010/160
  1826.             if Assigned(OnAuthorizationChangedOk) then
  1827.               FOnAuthSet(Self);
  1828.         end;
  1829.       end;
  1830.     end;
  1831.   end;
  1832. end;
  1833. {Handling packet with status changes}
  1834. {$WARNINGS OFF}
  1835. procedure TICQClient.HSnac030B(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  1836.   function NumToIp(Addr: LongWord): String;
  1837.   var
  1838.     inaddr: in_addr;
  1839.   begin
  1840.     inaddr.S_addr := Addr;
  1841.     Result := inet_ntoa(inaddr);
  1842.   end;
  1843. var
  1844.   c, i: Word;
  1845.   UIN: String;
  1846.   Status: LongWord;
  1847.   FIntIP, FExtIP: LongWord;
  1848.   FIntPort: Word;
  1849.   FConnFlag: Byte;
  1850.   FDconCookie: LongWord;
  1851.   FProtoVer: Word;
  1852. begin
  1853.   UIN := GetStr(Pkt, GetInt(Pkt, 1));
  1854.   Inc(Pkt^.Len, 2);
  1855.   c := GetInt(Pkt, 2);
  1856.   if c < 1 then Exit;
  1857.   for i := 0 to c - 1 do
  1858.   begin
  1859.     case GetInt(Pkt, 2) of
  1860.     $0c:
  1861.     begin
  1862.       Inc(Pkt^.Len, 2);                 //TLV's Length
  1863.       FIntIP := GetLInt(Pkt, 4);        //Internal IP
  1864.       FIntPort := GetInt(Pkt, 4);       //Internal port
  1865.       FConnFlag := GetInt(Pkt, 1);      //Connection flag
  1866.       FProtoVer := GetInt(Pkt, 2);      //Protocol version
  1867.       FDconCookie := GetLInt(Pkt, 4);   //Direct connection cookie
  1868.       Inc(Pkt^.Len, 22);                //Skip remaining data
  1869.     end;
  1870.     $0a:
  1871.     begin
  1872.       Inc(Pkt^.Len, 2);                 //TLV's Length
  1873.       FExtIP := GetLInt(Pkt, 4);        //External IP
  1874.       if (FConnFlag = $04) or (FConnFlag = $02) then
  1875.       begin
  1876.         if FDirect <> nil then
  1877.           FDirect.AddUser(StrToInt(UIN), FDConCookie, FExtIP, FIntIP, FIntPort);
  1878.       end else
  1879.         OnIntError(nil, ERR_WARNING, 'Cannot estabilish direct connection because remote client uses unknown proxy type');
  1880.     end;
  1881.     $06:
  1882.     begin
  1883.       Inc(Pkt^.Len, 2);                 //TLV's Length
  1884.       Status := GetInt(Pkt, 4);         //Online status
  1885.       if (not DisableDirectConnections) and (FDirect <> nil) then
  1886.         FDirect.EstabilishConnection(StrToInt(UIN));
  1887.       if Assigned(OnStatusChange) then
  1888.         FOnStatusChange(Self, UIN, Status);
  1889.       if Assigned(OnOnlineInfo) then
  1890.         FOnOnlineInfo(Self, UIN, FIntPort, NumToIp(FIntIP), NumToIp(FExtIP), FProtoVer);
  1891.       Exit;
  1892.     end else
  1893.       Inc(Pkt^.Len, GetInt(Pkt, 2));
  1894.     end;
  1895.   end;
  1896. end;
  1897. {$WARNINGS ON}
  1898. {Handling AddedYou packet}
  1899. procedure TICQClient.HSnac131C(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  1900. var
  1901.   T: Word;
  1902.   UIN: String;
  1903. begin
  1904.   Inc(Pkt^.Len, 2);
  1905.   GetTLVInt(Pkt, T);
  1906.   if T <> 1 then Exit;
  1907.   UIN := GetLStr(Pkt);
  1908.   if Assigned(OnAddedYou) then
  1909.     FOnAddedYou(Self, UIN);
  1910. end;
  1911. {Authorization request, we are automaticly authorizing the user}
  1912. procedure TICQClient.HSnac1319(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  1913. var
  1914.   FUin: String;
  1915.   FReason: String;
  1916.   opkt: TRawPkt;
  1917. begin
  1918.   Inc(Pkt^.Len, 8);
  1919.   FUin := GetLStr(Pkt);
  1920.   FReason := GetStr(Pkt, Swap16(GetInt(Pkt, 2)));
  1921.   CreateCLI_AUTHORIZE(@opkt, StrToInt(FUin), 1, '', FSeq);
  1922.   FSock.SendData(opkt, opkt.Len);
  1923. end;
  1924. {This packet contains your complete server side contact list.}
  1925. procedure TICQClient.HSnac1306(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  1926. var
  1927.   GroupIdents: TStringList;
  1928.   UINList: TList;
  1929.   procedure ReadChunk;
  1930.   var
  1931.     Len: Word;
  1932.     FGroup: ShortString;
  1933.     CTag, CId, CType: Word;
  1934.     TLen: Word;
  1935.     TType: Word;
  1936.     FNick: ShortString;
  1937.     lpEntry: PUINEntry;
  1938.   begin
  1939.     FGroup := GetWStr(Pkt);             //The name of the group.
  1940.     CTag := GetInt(Pkt, 2);             //This field seems to be a tag or marker associating different groups together into a larger group such as the Ignore List or 'General' contact list group, etc.
  1941.     CId := GetInt(Pkt, 2);              //This is a random number generated when the user is added to the contact list, or when the user is ignored.
  1942.     CType := GetInt(Pkt, 2);            //This field seems to indicate what type of group this is.
  1943.     Len := GetInt(Pkt, 2);              //The length in bytes of the following TLVs.
  1944.     FNick := '';
  1945.     while Integer(Len) > 0 do
  1946.     begin
  1947.       TType := GetInt(Pkt, 2);          //TLV Type
  1948.       TLen := GetInt(Pkt, 2);           //TLV Len
  1949.       if TType = $0131 then
  1950.         FNick := UTF8ToStrSmart(GetStr(Pkt, TLen))
  1951.       else
  1952.         Inc(Pkt^.Len, TLen);            //Skip this TLV
  1953.       Dec(len, TLen + 4);               //TLV length + 2 bytes type + 2 bytes length
  1954.     end;
  1955.     //Group header
  1956.     if (FGroup <> '') and (CType = 1) and (CTag <> 0) and (CId = 0) then
  1957.       GroupIdents.Values[IntToStr(CTag)] := UTF8ToStrSmart(FGroup);
  1958.     //UIN entry
  1959.     if (CType = 0) or (CType = 2) or (CType = 3) or (CType = $e) then
  1960.     begin
  1961.       GetMem(lpEntry, SizeOf(lpEntry^));
  1962.       lpEntry^.UIN := StrToInt(FGroup);
  1963.       lpEntry^.Nick := FNick;
  1964.       lpEntry^.CType := CType;
  1965.       lpEntry^.CTag := CId;
  1966.       lpEntry^.CGroupID := CTag;
  1967.       UINList.Add(lpEntry);
  1968.     end;
  1969.   end;
  1970. var
  1971.   count, T: Word;
  1972.   i: Word;
  1973. begin
  1974.   GetTLVInt(Pkt, T); if T <> 6 then Exit;
  1975.   Inc(Pkt^.Len, 4);                     //02 00 02 00 - UNKNOWNs
  1976.   count := GetInt(Pkt, 2);              //Total count of following groups. This is the size of the server side contact list and should be saved and sent with CLI_CHECKROSTER.
  1977.   if count < 1 then Exit;
  1978.   GroupIdents := TStringList.Create;
  1979.   UINList := TList.Create;
  1980.   for i := 0 to count - 1 do
  1981.     ReadChunk;
  1982.   if UINList.Count > 0 then
  1983.     for i := 0 to UINList.Count - 1 do
  1984.       PUINEntry(UINList.Items[i])^.CGroup := GroupIdents.Values[IntToStr(PUINEntry(UINList.Items[i])^.CGroupID)];
  1985.   GroupIdents.Free;
  1986.   if Assigned(OnServerListRecv) then
  1987.     FOnServerListRecv(Self, UINList)
  1988.   else
  1989.     DestroyUINList(UINList);
  1990. end;
  1991. {This packet contains ack to message you've sent.}
  1992. procedure TICQClient.HSnac040b(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  1993. var
  1994.   RetCode: Word;
  1995.   RetAcc: Byte;
  1996.   RetMsg: String;
  1997.   MsgType: Byte;
  1998.   FUIN: String;
  1999. begin
  2000.   Inc(Pkt^.Len, 4);                     //Time
  2001.   RetCode := GetInt(Pkt, 2);            //Random ID
  2002.   Inc(Pkt^.Len, 4);                     //Other data :)
  2003.   FUIN := GetLStr(Pkt);                 //User's UIN
  2004.   Inc(Pkt^.Len, 2);                     //00 03
  2005.   Inc(Pkt^.Len, 45);                    //Skip 50 bytes of packet
  2006.   MsgType := GetInt(Pkt, 1);            //Msg-type
  2007.   Inc(Pkt^.Len, 1);                     //Msg-flags
  2008.   RetAcc := GetInt(Pkt, 1);             //Accept type
  2009.   Inc(Pkt^.Len, 3);                     //Unknown
  2010.   if (RetAcc <> ACC_NORMAL) and (RetAcc <> ACC_NO_OCCUPIED) and
  2011.      (RetAcc <> ACC_NO_DND) and (RetAcc <> ACC_AWAY) and
  2012.      (RetAcc <> ACC_NA) and (RetAcc <> ACC_CONTACTLST) then Exit;
  2013.   if MsgType and $E0 = $E0 then
  2014.   begin
  2015.     RetMsg := GetLNTS(Pkt);
  2016.     if Assigned(OnAutoMsgResponse) then
  2017.       FOnAutoMsgResponse(Self, FUIN, RetCode, MsgType, RetMsg);
  2018.     Exit;
  2019.   end;
  2020.   if RetAcc <> ACC_NORMAL then
  2021.   begin
  2022.     RetMsg := GetLNTS(Pkt);
  2023.   end else
  2024.     RetMsg := '';
  2025.   if Assigned(OnAdvancedMsgAck) then
  2026.     FOnAdvMsgAck(Self, FUIN, RetCode, RetAcc, RetMsg);
  2027. end;
  2028. {This packet contains response with new UIN created.}
  2029. procedure TICQClient.HSnac1705(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  2030. var
  2031.   UIN: String;
  2032. begin
  2033.   if GetInt(Pkt, 2) <> $01 then Exit;   //TLV(01)
  2034.   Inc(Pkt^.Len, 2);                     //TLV's length
  2035.   Inc(Pkt^.Len, 2);                     //The length of the following data in bytes.
  2036.   Inc(Pkt^.Len, 4);                     //Unknown: empty.
  2037.   Inc(Pkt^.Len, 4);                     //Unknown: 0x2d000300 = 754975488.
  2038.   Inc(Pkt^.Len, 4);                     //Your port number as the server sees it.
  2039.   Inc(Pkt^.Len, 4);                     //Your IP address as the server sees it.
  2040.   Inc(Pkt^.Len, 4);                     //Unknown: 0x4 = 4.
  2041.   Inc(Pkt^.Len, 4);                     //The same UNKNOWN2 as sent in CLI_REGISTERUSER.
  2042.   Inc(Pkt^.Len, 16);                    //16 empty bytes
  2043.   UIN := IntToStr(GetLInt(Pkt, 4));     //New UIN
  2044.   if Assigned(OnNewUINRegistered) then  //Call associated event
  2045.     FOnNewUINRegistered(Self, UIN);
  2046. end;
  2047. {This packet contains reponse to CLI_REQAUTH.}
  2048. procedure TICQClient.HSnac131b(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  2049. var
  2050.   T: Word;
  2051.   UIN, Reason: String;
  2052.   Granted: Boolean;
  2053. begin
  2054.   Inc(Pkt^.Len, 2);                     //Unknown: 6.
  2055.   GetTLVInt(Pkt, T);                    //Unknown.
  2056.   UIN := GetLStr(Pkt);                  //The UIN that granted authorization.
  2057.   Granted := GetInt(Pkt, 1) = $01;      //00 - Rejected, 01 - Granted.
  2058.   Reason := GetWStr(Pkt);               //Reason, can be null.
  2059.   if Assigned(OnAuthResponse) then
  2060.     FOnAuthResponse(Self, UIN, Granted, Reason);
  2061. end;
  2062. {This command is sent as what is perhaps an acknowledgement reply to at least CLI_ADDBUDDY and CLI_UPDATEGROUP.}
  2063. procedure TICQClient.HSnac130e(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
  2064. var
  2065.   T: Word;
  2066.   ErrCode: Word;
  2067. begin
  2068.   Inc(Pkt^.Len, 2);                     //Unknown: 6. Guess: The length in bytes of the following data.
  2069.   GetTLVInt(Pkt, T);                    //Unknown.
  2070.   ErrCode := GetInt(Pkt, 2);            //ErrorCode
  2071.   if (ErrCode <> ERRSSL_AUTH) and (ErrCode <> ERRSSL_NOERROR) and (ErrCode <> ERRSSL_NOTFOUND) and
  2072.      (ErrCode <> ERRSSL_EXISTS) then
  2073.     ErrCode := ERRSSL_OTHER;
  2074.   if Assigned(OnSSLChangeResponse) then
  2075.     FOnChangeResponse(Self, ErrCode);
  2076. end;
  2077. {Handle packet with message sent directly}
  2078. procedure TICQClient.HDirectMsg(Sender: TObject; UIN: LongWord; Pak: PRawPkt; Len: LongWord);
  2079. var
  2080.   Msg: String;
  2081.   lpkt: TRawPkt;
  2082.   LSeq: Word;
  2083.   cmd, scmd: Word;
  2084.   S, Desc, URL: String;
  2085.   List: TStringList;
  2086.   FText: String;
  2087.   FileLen: LongWord;
  2088.   Port: Word;
  2089.   rec: TFTRequestRec;
  2090. begin
  2091.   if not DecryptPak(Ptr(LongWord(Pak) + 2), Pak^.Len - 2, 8) then Exit;
  2092.   Pak.Len := 2;
  2093.   if GetInt(Pak, 1) <> $02 then Exit;   //02 - PEER_MSG
  2094.   Inc(Pak^.Len, 4);                     //Packet checksum
  2095.   cmd := GetLInt(Pak, 2);               //Command
  2096.   Inc(Pak^.Len, 2);                     //Unknown: 0xe = 14.
  2097.   LSeq := GetLInt(Pak, 2);              //Sequence number.
  2098.   Inc(Pak^.Len, 12);                    //Unknown: 12 empty bytes
  2099.   scmd := GetLInt(Pak, 2);              //Sub command
  2100.   case cmd of
  2101.     $07ee:                              //2030 - normal message.
  2102.     begin
  2103.       if scmd = $0001 then              //Simple message
  2104.       begin
  2105.         Inc(Pak^.Len, 2);               //Unknown: empty.
  2106.         Inc(Pak^.Len, 2);               //Our status.
  2107.         Msg := GetLNTS(Pak);            //Finally the message.
  2108.         if Assigned(OnMessageRecv) then
  2109.           FOnMsg(Self, Msg, IntToStr(UIN));
  2110.       end else
  2111.       if scmd and $03e0 = $03e0 then    //Read auto-away message
  2112.       begin
  2113.         CreatePEER_AUTOMSG_ACK(@lpkt, FAutoAwayMsg, scmd, LSeq);        //Send ACK with auto msg reponse
  2114.         FDirect.SendData(UIN, @lpkt);
  2115.         Exit;                           //Do not send another ACK
  2116.       end else
  2117.       if scmd = $001a then              //Advanced message format
  2118.       begin
  2119.         Inc(Pak^.Len, 27);              //Skip 27 bytes of mostly unknown data
  2120.         S := GetStr(Pak, GetLInt(Pak, 4));
  2121.         if S = 'Contacts' then          //Receive contacts
  2122.         begin
  2123.           Inc(Pak^.Len, 19);            //Skip another 19 bytes of empty data + some lengths
  2124.           S := GetStr(Pak, GetLInt(Pak, 4));
  2125.           List := TStringList.Create;
  2126.           ParseContacts(S, List);
  2127.           if Assigned(OnContactListRecv) then
  2128.             FOnContactListRecv(Self, IntToStr(UIN), List)
  2129.           else
  2130.             List.Free;
  2131.         end else
  2132.         if S = 'Send Web Page Address (URL)' then
  2133.         begin
  2134.           Inc(Pak^.Len, 19);            //Skip another 19 bytes of empty data + some lengths
  2135.           S := GetStr(Pak, GetLInt(Pak, 4));
  2136.           if Assigned(OnURLRecv) then
  2137.           begin
  2138.             Desc := Copy(S, 0, Pos(#$fe, S) - 1);
  2139.             URL := Copy(S, Pos(#$fe, S) + 1, Length(S) - Pos(#$fe, S));
  2140.             if Assigned(OnURLRecv) then
  2141.               FOnURL(Self, Desc, URL, IntToStr(Uin));
  2142.           end;
  2143.         end else
  2144.         if S = 'Request For Contacts' then
  2145.         begin
  2146.           Inc(Pak^.Len, 19);            //Skip another 19 bytes of empty data + some lengths
  2147.           S := GetStr(Pak, GetLInt(Pak, 4));
  2148.           if Assigned(OnContactListRequest) then
  2149.             FOnContactListReq(Self, IntToStr(UIN), S)
  2150.         end else
  2151.         if S = 'File' then
  2152.         begin
  2153.           Inc(Pak^.Len, 19);                    //Skip another 19 bytes of empty data + some lengths
  2154.           Desc := GetStr(Pak, GetLInt(Pak, 4)); //Description
  2155.           Port := GetInt(Pak, 2);               //Port
  2156.           Inc(Pak^.Len, 2);                     //Seq
  2157.           FileLen := GetLInt(Pak, 2);
  2158.           if FileLen > 0 then
  2159.           begin
  2160.             FText := GetStr(Pak, FileLen - 1);  //Filename
  2161.             Inc(Pak^.Len, 1);                   //Null terminator
  2162.           end else FText := '';
  2163.           FileLen := GetLInt(Pak, 4);           //Filelength
  2164.           rec.ReqType := 0;
  2165.           rec.UIN := UIN;
  2166.           rec.Description := Desc;
  2167.           rec.FileName := FText;
  2168.           rec.FileSize := FileLen;
  2169.           rec.Seq := LSeq;
  2170.           rec.Port := Port;
  2171.           if Assigned(OnFTRequest) then
  2172.             FOnFTRequest(Self, rec);
  2173.           Exit;
  2174.         end;
  2175.       end;
  2176.     end;
  2177.     $07da:                              //Packet acks
  2178.     begin
  2179.       if Assigned(OnDirectPacketAck) then
  2180.         FOnDirectPktAck(Self, LSeq);
  2181.     end;
  2182.   end;
  2183.   //ACK received packet, if this packet isn't a "cancel given message" or "acknowledge message"
  2184.   if (cmd <> $07da) and (cmd <> $07d0) then
  2185.   begin
  2186.     if FDirect <> nil then
  2187.       begin
  2188.         CreatePEER_MSGACK(@lpkt, LSeq);
  2189.         FDirect.SendData(UIN, @lpkt);
  2190.       end;
  2191.   end;
  2192. end;
  2193. procedure TICQClient.FTOnConnectError(Sender: TObject);
  2194. begin
  2195.   FLoggedIn := False;
  2196.   FTimer.Enabled := False;
  2197.   if Assigned(OnConnectionFailed) then
  2198.     FOnConnectionFailed(Self);
  2199. end;
  2200. procedure TICQClient.FTOnDisconnect(Sender: TObject);
  2201. begin
  2202.   FTimer.Enabled := False;
  2203.   if FLoggedIn then
  2204.   begin
  2205.     FLoggedIn := False;
  2206.     if Assigned(OnConnectionFailed) then
  2207.       FOnConnectionFailed(Self);
  2208.   end;
  2209. end;
  2210. procedure TICQClient.FTOnDirectParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean);
  2211. begin
  2212.   if Assigned(OnPktDirectParse) then
  2213.     FOnDPktParse(Self, Buffer, BufLen, Incoming);
  2214. end;
  2215. procedure TICQClient.FTOnPktParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean);
  2216. begin
  2217.   if Assigned(OnPktParse) then
  2218.     FOnPktParse(Self, Buffer, BufLen, Incoming);
  2219. end;
  2220. procedure TICQClient.OnFTInitProc(Sender: TObject; UIN: LongWord; FileCount, TotalBytes, Speed: LongWord; NickName: String);
  2221. begin
  2222.   if Assigned(OnFTInit) then
  2223.     FOnFTInit(Self, UIN, FileCount, TotalBytes, Speed, NickName);
  2224. end;
  2225. procedure TICQClient.OnFTStartProc(Sender: TObject; StartRec: TFTStartRec; FileName: String; FileSize, Speed: LongWord);
  2226. begin
  2227.   if Assigned(OnFTStart) then
  2228.     FOnFTStart(Self, StartRec, FileName, FileSize, Speed);
  2229. end;
  2230. procedure TICQClient.OnFTFileDataProc(Sender: TObject; UIN: LongWord; Data: Pointer; DataLen: LongWord; LastPacket: Boolean);
  2231. begin
  2232.   if Assigned(OnFTFileData) then
  2233.     FOnFTFileData(Self, UIN, Data, DataLen, LastPacket);
  2234. end;
  2235. procedure TICQClient.SetContactList(Value: TStrings);
  2236. begin
  2237.   FContactLst.Assign(Value);
  2238. end;
  2239. procedure TICQClient.SetVisibleList(Value: TStrings);
  2240. begin
  2241.   FVisibleLst.Assign(Value);
  2242. end;
  2243. procedure TICQClient.SetInvisibleList(Value: TStrings);
  2244. begin
  2245.   FInvisibleLst.Assign(Value);
  2246. end;
  2247. procedure TICQClient.OnTimeout;
  2248. begin
  2249.   FTimer.Enabled := False;
  2250.   FSock.Disconnect;
  2251.   OnIntError(Self, ERR_CONNTIMEOUT, 'Connection timed out');
  2252.   if Assigned(OnConnectionFailed) then
  2253.     FOnConnectionFailed(Self);
  2254. end;
  2255. {**************************************************************************}
  2256. constructor TMyTimer.Create;
  2257. begin
  2258.   inherited Create;
  2259.   FEnabled := True;
  2260.   FInterval := 1000;
  2261.   {$IFDEF OLD_DELPHI}
  2262.   FWindowHandle := AllocateHWnd(WndProc);
  2263.   {$ELSE}
  2264.   FWindowHandle := Classes.AllocateHWnd(WndProc); {Remove 'depricated' warning}
  2265.   {$ENDIF}
  2266. end;
  2267. destructor TMyTimer.Destroy;
  2268. begin
  2269.   SetEnabled(False);
  2270.   {$IFDEF OLD_DELPHI}
  2271.   DeallocateHWnd(FWindowHandle);
  2272.   {$ELSE}
  2273.   Classes.DeallocateHWnd(FWindowHandle); {Remove 'depricated' warning}
  2274.   {$ENDIF}
  2275.   inherited;
  2276. end;
  2277. procedure TMyTimer.WndProc(var Msg: TMessage);
  2278. begin
  2279.   with Msg do
  2280.     if Msg = WM_TIMER then
  2281.       try
  2282.         Timer;
  2283.       except
  2284.       end
  2285.     else
  2286.       Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
  2287. end;
  2288. procedure TMyTimer.UpdateTimer;
  2289. begin
  2290.   KillTimer(FWindowHandle, 1);
  2291.   if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then
  2292.     SetTimer(FWindowHandle, 1, FInterval, nil);
  2293. end;
  2294. procedure TMyTimer.SetEnabled(Value: Boolean);
  2295. begin
  2296.   if Value <> FEnabled then
  2297.   begin
  2298.     FEnabled := Value;
  2299.     UpdateTimer;
  2300.   end;
  2301. end;
  2302. procedure TMyTimer.SetInterval(Value: Cardinal);
  2303. begin
  2304.   if Value <> FInterval then
  2305.   begin
  2306.     FInterval := Value;
  2307.     UpdateTimer;
  2308.   end;
  2309. end;
  2310. procedure TMyTimer.SetOnTimer(Value: TNotifyEvent);
  2311. begin
  2312.   FOnTimer := Value;
  2313.   UpdateTimer;
  2314. end;
  2315. procedure TMyTimer.Timer;
  2316. begin
  2317.   if Assigned(FOnTimer) then FOnTimer(Self);
  2318. end;
  2319. {*********************************************************************}
  2320. procedure Register;
  2321. begin
  2322.   RegisterComponents('Standard', [TICQClient]);
  2323. end;
  2324. end.