ICQClient.pas
资源名称:DarkMoon.rar [点击查看]
上传用户:hndmjx
上传日期:2014-09-16
资源大小:3369k
文件大小:92k
源码类别:
Delphi控件源码
开发平台:
Delphi
- unit ICQClient {v. 1.18f};
- {************************************************
- For updates checkout: http://www.cobans.net
- (C) Alex Demchenko(alex@ritlabs.com)
- *************************************************}
- {$R-} //Remove range checking
- {$DEFINE USE_FORMS} //If you don't use forms unit remove this line
- //Some needed defines, do not remove them!
- {$IFDEF VER90}
- {$DEFINE OLD_DELPHI}
- {$ENDIF}
- {$IFDEF VER100}
- {$DEFINE OLD_DELPHI}
- {$ENDIF}
- {$IFDEF VER120}
- {$DEFINE OLD_DELPHI}
- {$ENDIF}
- {$IFDEF VER130}
- {$DEFINE OLD_DELPHI}
- {$ENDIF}
- interface
- uses
- Windows, Messages, Classes {StringLists}, {$IFDEF USE_FORMS}Forms {AllocateHwnd/DeallocateHwnd}, {$ENDIF}
- WinSock, ICQWorks, MySocket, ICQDirect;
- {$IFNDEF USE_FORMS}
- {$DEFINE OLD_DELPHI}
- {$ENDIF}
- type
- //UIN Entry used in direct connections
- PUINEntry = ^TUINEntry;
- TUINEntry = record
- UIN: LongWord;
- Nick: ShortString;
- CType: Word;
- CTag: Word;
- CGroupID: Word;
- CGroup: ShortString;
- end;
- TMyTimer = class;
- //Callback function types
- THandlePkt = procedure(Flap: TFlapHdr; Buffer: Pointer) of object;
- TOnMsgProc = procedure(Sender: TObject; Msg, UIN: String) of object;
- TOnURLProc = procedure(Sender: TObject; Description, URL, UIN: String) of object;
- TOnStatusChange = procedure(Sender: TObject; UIN: String; Status: LongWord) of object;
- TOnOnlineInfo = procedure(Sender: TObject; UIN: String; Port: Word; InternalIP, ExternalIP: String; ProtoVer: Byte) of object;
- TOnUserEvent = procedure(Sender: TObject; UIN: String) of object;
- TOnUserGeneralInfo = procedure(Sender: TObject; UIN, NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip, Country: String; TimeZone: Byte; PublishEmail: Boolean) of object;
- TOnUserWorkInfo = procedure (Sender: TObject; UIN, WCity, WState, WPhone, WFax, FAddress, WZip, WCountry, WCompany, WDepartment, WPosition, WOccupation, WHomePage: String) of object;
- TOnUserInfoMore = procedure (Sender: TObject; UIN: String; Age: Word; Gender: Byte; HomePage: String; BirthYear: Word; BirthMonth: Word; BirthDay: Word; Lang1, Lang2, Lang3: String) of object;
- TOnUserInfoAbout = procedure(Sender: TObject; UIN, About: String) of object;
- TOnUserInfoInterests = procedure(Sender: TObject; UIN: String; Interests: TStringList) of object;
- TOnUserInfoMoreEmails = procedure(Sender: TObject; UIN: String; Emails: TStringList) of object;
- TOnUserInfoBackground = procedure(Sender: TObject; UIN: String; Pasts, Affiliations: TStringList) of object;
- TOnUserFound = procedure(Sender: TObject; UIN, Nick, FirstName, LastName, Email: String; Status: Word; Gender, Age: Byte; SearchComplete: Boolean; Authorize: Boolean) of object;
- TOnServerListRecv = procedure(Sender: TObject; SrvContactList: TList) of object;
- TOnAdvMsgAck = procedure(Sender: TObject; UIN: String; ID: Word; AcceptType: Byte; AcceptMsg: String) of object;
- TOnAutoMsgResponse = procedure(Sender: TObject; UIN: String; ID: Word; RespStatus: Byte; Msg: String) of object;
- TOnContactListRecv = procedure(Sender: TObject; UIN: String; ContactList: TStringList) of object;
- TOnContactListReq = procedure(Sender: TObject; UIN, Reason: String) of object;
- TOnDirectPktAck = procedure(Sender: TObject; ID: Word) of object;
- TOnSMSAck = procedure(Sender: TObject; Source, Network, MsgId: String; Deliverable: Boolean) of object;
- TOnSMSReply = procedure(Sender: TObject; Source, SmsSender, Time, Text: String) of object;
- TOnInfoChanged = procedure(Sender: TObject; InfoType: TInfoType; ChangedOk: Boolean) of object;
- TOnAuthResponse = procedure(Sender: TObject; UIN: String; Granted: Boolean; Reason: String) of object;
- TOnChangeResponse = procedure(Sender: TObject; ErrorCode: Word) of object;
- TOnFTRequest = procedure(Sender: TObject; RequestRec: TFTRequestRec) of object;
- TOnUserInfoShort = procedure(Sender: TObject; UIN, NickName, FirstName, LastName, Email: String; UserFound, AuthRequired: Boolean) of object;
- {TICQNet -- Object implementing sending/receiving packets between Client and ICQ Server.}
- TICQNet = class(TMySock)
- private
- FSrcBuf: array[0..MAX_DATA_LEN - 1] of Byte; //. .
- FSrcLen: Word; //.PACKET READING.
- FNewFlap: TFlapHdr; //. DATA .
- FFlapSet: Boolean; //. .
- FHandlePkt: THandlePkt;
- protected
- procedure OnReceive(Buffer: Pointer; BufLen: LongWord); override;
- public
- constructor Create;
- destructor Destroy; override;
- procedure Connect; override;
- published
- property OnConnectError;
- property OnDisconnect;
- property OnPktParseA;
- property OnError;
- property OnHandlePkt: THandlePkt read FHandlePkt write FHandlePkt;
- end;
- {TICQClient -- ICQ Component}
- TICQClient = class(TComponent)
- private
- FSock: TICQNet; //Client's socket
- FLUIN: LongWord; //Client's UIN
- FLPass: String; //Client's password
- FFirstConnect: Boolean; //Flag, used in login sequence
- FSeq: Word; //Main Flap Seq
- FSeq2: Word; //TO_ICQSRV Seq
- FDSeq: Word; //Direct connection Seq
- 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
- FIp: String; //Ip to connect to
- FPort: Word; //Port to connect to
- FDConnCookie: LongWord; //Direct connection cookie
- FDirect: TDirectControl; //Direct control
- //-- Proxy settings
- FProxyType: TProxyType; //.
- FProxyHost: String; //.
- FProxyPort: Word; //. Proxy Configaration
- FProxyAuth: Boolean; //. Data
- FProxyPass: String; //.
- FUserID: String; //.
- FResolve: Boolean;
- //-- Events & other stuff --
- FContactLst: TStrings;
- FVisibleLst: TStrings;
- FInvisibleLst: TStrings;
- FOnMsg: TOnMsgProc;
- FOnURL: TOnURLProc;
- FOnOffMsg: TOnMsgProc;
- FOnOffURL: TOnURLProc;
- FOnLogin: TNotifyEvent;
- FOnPktParse: TOnAdvPktParse;
- FOnDPktParse: TOnAdvPktParse;
- FOnConnectionFailed: TNotifyEvent;
- FOnStatusChange: TOnStatusChange;
- FOnUserOffline: TOnUserEvent;
- FOnAddedYou: TOnUserEvent;
- FOnUserGeneralInfo: TOnUserGeneralInfo;
- FOnUserWorkInfo: TOnUserWorkInfo;
- FOnUserInfoMore: TOnUserInfoMore;
- FOnUserInfoAbout: TOnUserInfoAbout;
- FOnUserInfoInterests: TOnUserInfoInterests;
- FOnUserInfoMoreEmails: TOnUserInfoMoreEmails;
- FOnUserInfoBackground: TOnUserInfoBackground;
- FStatus: LongWord;
- FDoPlain: Boolean;
- FInfoChain: TStringList;
- FSInfoChain: TStringList;
- FLastInfoUin: String;
- FLastSInfoUin: String;
- FLoggedIn: Boolean;
- FRegisteringUIN: Boolean;
- FRegPassword: String;
- FOnUserFound: TOnUserFound;
- FOnUserNotFound: TNotifyEvent;
- FOnServerListRecv: TOnServerListRecv;
- FOnAdvMsgAck: TOnAdvMsgAck;
- FOnNewUINRegistered: TOnUserEvent;
- FOnNewUINRefused: TNotifyEvent;
- FOnAutoMsgResponse: TOnAutoMsgResponse;
- FAutoAwayMsg: String;
- FOnUnregisterOk: TNotifyEvent;
- FOnUnregBadPass: TNotifyEvent;
- FOnContactListRecv: TOnContactListRecv;
- FOnContactListReq: TOnContactListReq;
- FOnDirectPktAck: TOnDirectPktAck;
- FOnSmsRefused: TNotifyEvent;
- FOnSMSAck: TOnSMSAck;
- FOnOnlineInfo: TOnOnlineInfo;
- FUseDirect: Boolean;
- FOnError: TOnError;
- FTimer: TMyTimer;
- FTimeout: Byte;
- FOnSMSReply: TOnSMSReply;
- FOnInfoChanged: TOnInfoChanged;
- FOnAuthSet: TNotifyEvent;
- FOnAuthResponse: TOnAuthResponse;
- FOnChangeResponse: TOnChangeResponse;
- FOnFTRequest: TOnFTRequest;
- FOnFTInit: TOnFTInit;
- FOnFTStart: TOnFTStart;
- FOnFTFileData: TOnFTFileData;
- FLastError: String;
- FOnUserInfoShort: TOnUserInfoShort;
- procedure InitNetICQ;
- procedure OnIntError(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String);
- procedure HandlePacket(Flap: TFlapHdr; Data: Pointer);
- procedure SetStatus(NewStatus: LongWord);
- //-- Handling Snac packet procedures
- procedure HSnac0407(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- //procedure HSnac1503(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HSnac030B(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HSnac131C(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HSnac1319(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HSnac1306(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HSnac040b(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HSnac1705(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HSnac131b(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HSnac130e(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- procedure HDirectMsg(Sender: TObject; UIN: LongWord; Pak: PRawPkt; Len: LongWord);
- procedure FTOnConnectError(Sender: TObject);
- procedure FTOnDisconnect(Sender: TObject);
- procedure FTOnDirectParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean);
- procedure FTOnPktParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean);
- procedure OnFTInitProc(Sender: TObject; UIN: LongWord; FileCount, TotalBytes, Speed: LongWord; NickName: String);
- procedure OnFTStartProc(Sender: TObject; StartRec: TFTStartRec; FileName: String; FileSize, Speed: LongWord);
- procedure OnFTFileDataProc(Sender: TObject; UIN: LongWord; Data: Pointer; DataLen: LongWord; LastPacket: Boolean);
- procedure SetContactList(Value: TStrings);
- procedure SetVisibleList(Value: TStrings);
- procedure SetInvisibleList(Value: TStrings);
- procedure OnTimeout(Sender: TObject);
- public
- procedure HSnac1503(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Login(Status: LongWord = S_ONLINE);
- procedure RegisterNewUIN(const Password: String);
- procedure Disconnect;
- procedure SendMessage(UIN: LongWord; const Msg: String);
- procedure SendURL(UIN: LongWord; const URL, Description: String);
- function AddContact(UIN: LongWord): Boolean;
- procedure RemoveContact(UIN: LongWord);
- procedure RemoveContactVisible(UIN: LongWord);
- procedure RemoveContactInvisible(UIN: LongWord);
- procedure RequestInfo(UIN: LongWord);
- procedure RequestInfoShort(UIN: LongWord);
- procedure SearchByMail(const Email: String);
- procedure SearchByUIN(UIN: LongWord);
- procedure SearchByName(const FirstName, LastName, NickName, Email: String);
- procedure SearchRandom(Group: Word);
- 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);
- procedure SetSelfInfoGeneral(NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip, Country: String; TimeZone: Byte; PublishEmail: Boolean);
- procedure SetSelfInfoMore(Age: Word; Gender: Byte; const HomePage: String; BirthYear: Word; BirthMonth, BirthDay: Byte; Language1, Language2, Language3: String);
- procedure SetSelfInfoAbout(const About: String);
- procedure RequestContactList;
- procedure DestroyUINList(var List: TList);
- procedure SendSMS(const Destination, Text: String);
- procedure SendMessageAdvanced(UIN: LongWord; const Msg: String; ID: Word; RTFFormat: Boolean);
- function SendMessageDirect(UIN: LongWord; const Msg: String; RTFFormat: Boolean): Word;
- procedure RequestAwayMsg(UIN: LongWord; ID: Word; ReqStatus: Byte);
- procedure UnregisterUIN(const Password: String);
- procedure ChangePassword(const NewPassword: String);
- procedure ChangePasswordPtr(Buffer: Pointer; BufLen: Word);
- function DirectConnectionEstabilished(UIN: LongWord): Boolean;
- function SendContacts(UIN: LongWord; Contacts: TStringList; ID: Word): Boolean;
- function RequestContacts(UIN: LongWord; const Reason: String; ID: Word): Boolean;
- function SendContactsDC(UIN: LongWord; Contacts: TStringList): Word;
- function RequestContactsDC(UIN: LongWord; const Reason: String): Word;
- procedure SendKeepAlive;
- procedure SetAuthorization(AuthorizationRequired, WebAware: Boolean);
- procedure SendAuthRequest(UIN: LongWord; Msg: String);
- procedure SSLChangeStart(FirstUpload: Boolean);
- procedure SSLChangeEnd;
- procedure SSLAddGroup(GroupName: String; GroupID: Word);
- procedure SSLAddUser(GroupID, UserID: Word; UIN, Name, SMSNumber: String; Authorize, UpdateUser: Boolean);
- procedure SSLDelUser(GroupID, UserID: Word; UIN, Name, SMSNumber: String; Authorize: Boolean);
- procedure SSLDelGroup(GroupName: String; GroupID: Word);
- procedure SSLUpdateGroup(GroupName: String; GroupID: Word; UserIDs: TStringList);
- procedure SSLAddUserIntoList(UserID: Word; UIN: String; BuddyType: Word);
- procedure SSLDelUserFromList(UserID: Word; UIN: String; BuddyType: Word);
- function FTResponse(ResponseRec: TFTRequestRec; Accept: Boolean; Reason: String): Boolean;
- procedure FTCancel(UIN: LongWord);
- function FTStartResponse(StartRec: TFTStartRec): Boolean;
- property LastError: String read FLastError;
- property Status: LongWord read FStatus write SetStatus;
- property LoggedIn: Boolean read FLoggedIn;
- published
- property DisableDirectConnections: Boolean read FUseDirect write FUseDirect default False;
- property ProxyType: TProxyType read FProxyType write FProxyType default P_NONE;
- property ProxyHost: String read FProxyHost write FProxyHost;
- property ProxyPort: Word read FProxyPort write FProxyPort;
- property ProxyUserID: String read FUserID write FUserID;
- property ProxyResolve: Boolean read FResolve write FResolve default False;
- property ProxyAuth: Boolean read FProxyAuth write FProxyAuth default False;
- property ProxyPass: String read FProxyPass write FProxyPass;
- property UIN: LongWord read FLUIN write FLUIN;
- property Password: String read FLPass write FLPass;
- property ICQServer: String read FIp write FIp;
- property ICQPort: Word read FPort write FPort;
- property ConvertToPlaintext: Boolean read FDoPlain write FDoPlain;
- property ContactList: TStrings read FContactLst write SetContactList;
- property VisibleList: TStrings read FVisibleLst write SetVisibleList;
- property InvisibleList: TStrings read FInvisibleLst write SetInvisibleList;
- property AutoAwayMessage: String read FAutoAwayMsg write FAutoAwayMsg;
- property OnLogin: TNotifyEvent read FOnLogin write FOnLogin;
- property OnMessageRecv: TOnMsgProc read FOnMsg write FOnMsg;
- property OnURLRecv: TOnURLProc read FOnURL write FOnURL;
- property OnOfflineMsgRecv: TOnMsgProc read FOnOffMsg write FOnOffMsg;
- property OnOfflineURLRecv: TOnURLProc read FOnOffURL write FOnOffURL;
- property OnPktParse: TOnAdvPktParse read FOnPktParse write FOnPktParse;
- property OnPktDirectParse: TOnAdvPktParse read FOnDPktParse write FOnDPktParse;
- property OnConnectionFailed: TNotifyEvent read FOnConnectionFailed write FOnConnectionFailed;
- property OnStatusChange: TOnStatusChange read FOnStatusChange write FOnStatusChange;
- property OnUserOffline: TOnUserEvent read FOnUserOffline write FOnUserOffline;
- property OnAddedYou: TOnUserEvent read FOnAddedYou write FOnAddedYou;
- property OnUserGeneralInfo: TOnUserGeneralInfo read FOnUserGeneralInfo write FOnUserGeneralInfo;
- property OnUserWorkInfo: TOnUserWorkInfo read FOnUserWorkInfo write FOnUserWorkInfo;
- property OnUserInfoMore: TOnUserInfoMore read FOnUserInfoMore write FOnUserInfoMore;
- property OnUserInfoAbout: TOnUserInfoAbout read FOnUserInfoAbout write FOnUserInfoAbout;
- property OnUserInfoInterests: TOnUserInfoInterests read FOnUserInfoInterests write FOnUserInfoInterests;
- property OnUserInfoMoreEmails: TOnUserInfoMoreEmails read FOnUserInfoMoreEmails write FOnUserInfoMoreEmails;
- property OnUserInfoBackground: TOnUserInfoBackground read FOnUserInfoBackground write FOnUserInfoBackground;
- property OnUserFound: TOnUserFound read FOnUserFound write FOnUserFound;
- property OnUserNotFound: TNotifyEvent read FOnUserNotFound write FOnUserNotFound;
- property OnServerListRecv: TOnServerListRecv read FOnServerListRecv write FOnServerListRecv;
- property OnAdvancedMsgAck: TOnAdvMsgAck read FOnAdvMsgAck write FOnAdvMsgAck;
- property OnNewUINRegistered: TOnUserEvent read FOnNewUINRegistered write FOnNewUINRegistered;
- property OnNewUINRefused: TNotifyEvent read FOnNewUINRefused write FOnNewUINRefused;
- property OnAutoMsgResponse: TOnAutoMsgResponse read FOnAutoMsgResponse write FOnAutoMsgResponse;
- property OnUnregisterOk: TNotifyEvent read FOnUnregisterOk write FOnUnregisterOk;
- property OnUnregisterBadPassword: TNotifyEvent read FOnUnregBadPass write FOnUnregBadPass;
- property OnContactListRecv: TOnContactListRecv read FOnContactListRecv write FOnContactListRecv;
- property OnContactListRequest: TOnContactListReq read FOnContactListReq write FOnContactListReq;
- property OnDirectPacketAck: TOnDirectPktAck read FOnDirectPktAck write FOnDirectPktAck;
- property OnSMSRefused: TNotifyEvent read FOnSmsRefused write FOnSmsRefused;
- property OnSMSAck: TOnSMSAck read FOnSMSAck write FOnSMSAck;
- property OnOnlineInfo: TOnOnlineInfo read FOnOnlineInfo write FOnOnlineInfo;
- property OnError: TOnError read FOnError write FOnError;
- property ConnectionTimeout: Byte read FTimeout write FTimeout;
- property OnSMSReply: TOnSMSReply read FOnSMSReply write FOnSMSReply;
- property OnInfoChanged: TOnInfoChanged read FOnInfoChanged write FOnInfoChanged;
- property OnAuthorizationChangedOk: TNotifyEvent read FOnAuthSet write FOnAuthSet;
- property OnAuthResponse: TOnAuthResponse read FOnAuthResponse write FOnAuthResponse;
- property OnSSLChangeResponse: TOnChangeResponse read FOnChangeResponse write FOnChangeResponse;
- property OnFTRequest: TOnFTRequest read FOnFTRequest write FOnFTRequest;
- property OnFTInit: TOnFTInit read FOnFTInit write FOnFTInit;
- property OnFTStart: TOnFTStart read FOnFTStart write FOnFTStart;
- property OnFTFileData: TOnFTFileData read FOnFTFileData write FOnFTFileData;
- property OnUserInfoShort: TOnUserInfoShort read FOnUserInfoShort write FOnUserInfoShort;
- end;
- TMyTimer = class(TObject)
- private
- FInterval: LongWord;
- FWindowHandle: THandle;
- FOnTimer: TNotifyEvent;
- FEnabled: Boolean;
- FTag: Integer;
- procedure UpdateTimer;
- procedure SetEnabled(Value: Boolean);
- procedure SetInterval(Value: LongWord);
- procedure SetOnTimer(Value: TNotifyEvent);
- procedure WndProc(var Msg: TMessage);
- protected
- procedure Timer; dynamic;
- public
- constructor Create;
- destructor Destroy; override;
- property Tag: Integer read FTag write FTag;
- published
- property Enabled: Boolean read FEnabled write SetEnabled default True;
- property Interval: LongWord read FInterval write SetInterval default 1000;
- property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer;
- end;
- procedure Register;
- implementation
- {-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-}
- {*** CONSTRUCTOR ***}
- constructor TICQNet.Create;
- begin
- inherited Create;
- end;
- {*** DESTRUCTOR ***}
- destructor TICQNet.Destroy;
- begin
- inherited;
- end;
- procedure TICQNet.Connect;
- begin
- FSrcLen := 0;
- FFlapSet := False;
- inherited;
- end;
- {No proxy data is received here.}
- procedure TICQNet.OnReceive(Buffer: Pointer; BufLen: LongWord);
- var
- i, len: LongWord;
- flap: TFlapHdr;
- begin
- inherited;
- for i := 0 to BufLen - 1 do
- begin
- FSrcBuf[FSrcLen] := PByte(LongWord(Buffer) + i)^;
- Inc(FSrcLen);
- //Searching for the Flap header
- if (FSrcLen >= TFLAPSZ) and (not FFlapSet) then
- begin
- FFlapSet := True;
- FNewFlap := PFlapHdr(@FSrcBuf)^;
- FNewFlap.DataLen := Swap16(FNewFlap.DataLen);
- FNewFlap.Seq := Swap16(FNewFlap.Seq);
- if FNewFlap.DataLen > 8192 then
- begin
- if Assigned(OnError) then
- OnError(Self, ERR_PROTOCOL, 'Length of received packet exceeds maximum supported by protocol. Len = ' + IntToStr(FNewFlap.DataLen));
- Disconnect;
- Exit;
- end;
- end;
- //Whole packet was received
- if FSrcLen = FNewFlap.DataLen + TFLAPSZ then
- begin
- if FNewFlap.Ident <> $2a then
- begin
- if Assigned(OnError) then
- OnError(Self, ERR_PROTOCOL, 'Received malformed packet');
- Disconnect;
- Exit;
- end;
- Move(FNewFlap, flap, SizeOf(FNewFlap));
- //Preparing structures for receiving the next packet
- FNewFlap.DataLen := 0;
- len := FSrcLen; FSrcLen := 0;
- FFlapSet := False;
- //Dump packet (if needed)
- if Assigned(OnPktParseA) then
- OnPktParseA(Self, @FSrcBuf, len, True);
- //Handling packet
- if Assigned(OnHandlePkt) then
- FHandlePkt(flap, Ptr(LongWord(@FSrcBuf) + TFLAPSZ));
- end;
- end;
- end;
- {-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-}
- {*** CONSTRUCTOR ***}
- constructor TICQClient.Create(AOwner: TComponent);
- begin
- inherited;
- FLastError := ''; //Last error
- FContactLst := TStringList.Create; //Contact list
- FVisibleLst := TStringList.Create; //Visible list
- FInvisibleLst := TStringList.Create; //Invisible list
- FInfoChain := TStringList.Create; //Info request chain
- FSInfoChain := TStringList.Create; //Short info request chain
- //Socket for working with TCP
- FSock := TICQNet.Create;
- FSock.OnError := OnIntError;
- FTimer := TMyTimer.Create; //Timeout timer
- FTimer.OnTimer := OnTimeout; //Set timeout event
- FTimer.Enabled := False; //Disable timer by default
- Randomize; //Initialize random generator
- FSeq := Random($AAAA); //Choose random seq, which is used in Flap header
- FDirect := nil; //Do not initialize direct control until we connect
- end;
- {*** DESTRUCTOR ***}
- destructor TICQClient.Destroy;
- begin
- if FDirect <> nil then
- FDirect.Free;
- FSock.OnConnectError := nil;
- FSock.OnConnectProc := nil;
- FSock.OnDisconnect := nil;
- FSock.OnError := nil;
- FSock.OnReceiveProc := nil;
- FSock.Free;
- FTimer.OnTimer := nil;
- FTimer.Free;
- //Free TStringList objects
- FContactLst.Free;
- FVisibleLst.Free;
- FInvisibleLst.Free;
- FInfoChain.Free;
- FSInfoChain.Free;
- inherited;
- end;
- {Set NetICQ's properties}
- procedure TICQClient.InitNetICQ;
- begin
- //Assign properties
- FSock.Host := FIp;
- FSock.Port := FPort;
- FSock.ProxyType := FProxyType;
- FSock.ProxyHost := FProxyHost;
- FSock.ProxyPort := FProxyPort;
- FSock.ProxyUserID := FUserID;
- FSock.ProxyAuth := FProxyAuth;
- FSock.ProxyPass := FProxyPass;
- FSock.UseProxyResolve := ProxyResolve;
- //Assign events
- FSock.OnHandlePkt := HandlePacket;
- FSock.OnDisconnect := FTOnDisconnect;
- FSock.OnConnectError := FTOnConnectError;
- FSock.OnPktParseA := FTOnPktParse;
- end;
- {Called when error happened.}
- procedure TICQClient.OnIntError(Sender: TObject; ErrorType: TErrorType; ErrorMsg: String);
- begin
- FLastError := ErrorMsg;
- if Assigned(OnError) then
- FOnError(Self, ErrorType, ErrorMsg);
- end;
- {Logins to server.}
- procedure TICQClient.Login(Status: LongWord = S_ONLINE);
- begin
- if FDirect <> nil then
- begin
- FDirect.OnError := nil;
- FDirect.OnHandle := nil;
- FDirect.OnPktDump := nil;
- FDirect.Free;
- end;
- if not DisableDirectConnections then
- begin
- FDirect := TDirectControl.Create(FLUIN);
- FDirect.OnPktDump := FTOnDirectParse;
- FDirect.OnHandle := HDirectMsg;
- FDirect.OnError := OnIntError;
- FDirect.OnFTInit := OnFTInitProc;
- FDirect.OnFTStart := OnFTStartProc;
- FDirect.OnFTFileData := OnFTFileDataProc;
- //Assign proxy settings
- FDirect.ProxyType := ProxyType;
- FDirect.ProxyHost := ProxyHost;
- FDirect.ProxyPort := ProxyPort;
- FDirect.ProxyUserID := ProxyUserID;
- FDirect.ProxyAuth := ProxyAuth;
- FDirect.ProxyPass := ProxyPass;
- FDirect.UseProxyResolve := ProxyResolve;
- end;
- FDSeq := Random(High(Word));
- FSeq2 := 2;
- FCookie := '';
- FFirstConnect := True;
- FStatus := Status;
- FLoggedIn := False;
- FRegisteringUIN := False;
- InitNetICQ;
- FTimer.Interval := FTimeout * 1000;
- FTimer.Enabled := False;
- if FTimeout <> 0 then
- FTimer.Enabled := True;
- FSock.Connect;
- end;
- {Registers a new UIN.}
- procedure TICQClient.RegisterNewUIN(const Password: String);
- begin
- FRegisteringUIN := True;
- FRegPassword := Password;
- FLoggedIn := False;
- InitNetICQ;
- FTimer.Interval := FTimeout * 1000;
- FTimer.Enabled := True;
- FSock.Connect;
- end;
- {Disconnect user from server.}
- procedure TICQClient.Disconnect;
- begin
- FTimer.Enabled := False;
- FSock.Disconnect;
- if Assigned(OnConnectionFailed) then
- FOnConnectionFailed(Self);
- end;
- {Send a message to UIN.}
- procedure TICQClient.SendMessage(UIN: LongWord; const Msg: String);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_SENDMSG(@pkt, 0, Random($FFFFAA), UIN, Msg, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Send an URL message to UIN.}
- procedure TICQClient.SendURL(UIN: LongWord; const URL, Description: String);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_SENDURL(@pkt, 0, Random($FFFFAA), FLUIN, UIN, URL, Description, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Adds UIN to contact list after logon(when you are online), UIN automaticly
- added to ContactList TStrings. After adding the UIN you will receive status
- notifications. Returns True when UIN is added to the list(it wasn't there before).}
- function TICQClient.AddContact(UIN: LongWord): Boolean;
- var
- pkt: TRawPkt;
- begin
- Result := False;
- if FContactLst.IndexOf(IntToStr(UIN)) < 0 then
- begin
- FContactLst.Add(IntToStr(UIN));
- Result := True;
- end else
- Exit;
- if not LoggedIn then Exit;
- CreateCLI_ADDCONTACT(@pkt, IntToStr(UIN), FSeq); {SNAC(x03/x04)}
- FSock.SendData(pkt, pkt.Len);
- end;
- {Removes UIN from contact list. Use while you are online.}
- procedure TICQClient.RemoveContact(UIN: LongWord);
- var
- idx: Integer;
- pkt: TRawPkt;
- begin
- idx := FContactLst.IndexOf(IntToStr(UIN));
- if idx > -1 then
- FContactLst.Delete(idx);
- if not LoggedIn then Exit;
- CreateCLI_REMOVECONTACT(@pkt, UIN, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Removes UIN from the visible list. Use while you are online.}
- procedure TICQClient.RemoveContactVisible(UIN: LongWord);
- var
- idx: Integer;
- pkt: TRawPkt;
- begin
- idx := FVisibleLst.IndexOf(IntToStr(UIN));
- if idx > -1 then
- FVisibleLst.Delete(idx);
- if not LoggedIn then Exit;
- CreateCLI_REMVISIBLE(@pkt, UIN, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Removes UIN from the invisible list. Use while you are online.}
- procedure TICQClient.RemoveContactInvisible(UIN: LongWord);
- var
- idx: Integer;
- pkt: TRawPkt;
- begin
- idx := FInvisibleLst.IndexOf(IntToStr(UIN));
- if idx > -1 then
- FInvisibleLst.Delete(idx);
- if not LoggedIn then Exit;
- CreateCLI_REMINVISIBLE(@pkt, UIN, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Query info about UIN. As answer you will recieve theese events: OnUserWorkInfo,
- OnUserInfoMore, OnUserInfoAbout, OnUserInfoInterests, OnUserInfoMoreEmails,
- OnUserFound.}
- procedure TICQClient.RequestInfo(UIN: LongWord);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- FInfoChain.Values[IntToStr(FSeq2)] := IntToStr(UIN);
- CreateCLI_METAREQINFO(@pkt, FLUIN, UIN, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Request short info(nick, first, last, email) of UIN.}
- procedure TICQClient.RequestInfoShort(UIN: LongWord);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- FSInfoChain.Values[IntToStr(FSeq2)] := IntToStr(UIN);
- CreateCLI_METAREQINFO_SHORT(@pkt, FLUIN, UIN, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Searches user by Mail}
- procedure TICQClient.SearchByMail(const Email: String);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_SEARCHBYMAIL(@pkt, FLUIN, Email, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Searches user by UIN}
- procedure TICQClient.SearchByUIN(UIN: LongWord);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_SEARCHBYUIN(@pkt, FLUIN, UIN, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Searches user by Name and other data}
- procedure TICQClient.SearchByName(const FirstName, LastName, NickName, Email: String);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_SEARCHBYNAME(@pkt, FLUIN, FirstName, LastName, NickName, Email, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Searches random user from Group, where Group id could be found in RandGroups:
- array[1..11]...(ICQWorks.pas) constant. As answer you will receive OnUserFound
- notification, only one user will be found.}
- procedure TICQClient.SearchRandom(Group: Word);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_SEARCHRANDOM(@pkt, FLUIN, Group, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Searches user in 'White Pages'. As answer you will receive OnUserFound notification
- when at least one user found or OnUserNotFound if such user does not exist.}
- procedure TICQClient.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);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_SEARCHWP(@pkt, FLUIN, FirstName, LastName, NickName, Email,
- MinAge, MaxAge,
- Gender,
- StrToLanguageI(Language),
- City, StrToCountryI(Country),
- Company,
- Department,
- Position,
- StrToOccupationI(Occupation),
- StrToOrganizationI(Organization),
- OrganKeyWords,
- StrToPastI(PastAffiliation),
- AffiKeyWords,
- KeyWord,
- Ord(Online),
- FSeq,
- FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Set general info about yourself. You can skip some parameters (eg. use '' -
- empty strings) to unspecify some info. }
- procedure TICQClient.SetSelfInfoGeneral(NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip, Country: String; TimeZone: Byte; PublishEmail: Boolean);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- //Truncate state if more then 3 chars
- if Length(State) > 3 then
- State := Copy(State, 0, 3);
- CreateCLI_METASETGENERAL(@pkt, FLUIN, NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip, StrToCountryI(Country), TimeZone, PublishEmail, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Set more info about yourself.}
- procedure TICQClient.SetSelfInfoMore(Age: Word; Gender: Byte; const HomePage: String; BirthYear: Word; BirthMonth, BirthDay: Byte; Language1, Language2, Language3: String);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_METASETMORE(@pkt, FLUIN, Age, Gender, HomePage, BirthYear, BirthMonth, BirthDay, StrToLanguageI(Language1), StrToLanguageI(Language2), StrToLanguageI(Language3), FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Set info about yourself.}
- procedure TICQClient.SetSelfInfoAbout(const About: String);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_METASETABOUT(@pkt, FLUIN, About, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Requests server side contact list. For more info look at OnServerListRecv event.}
- procedure TICQClient.RequestContactList;
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- CreateCLI_REQROSTER(@pkt, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Releases memory used while parsing the server side contact list.}
- procedure TICQClient.DestroyUINList(var List: TList);
- var
- i: Word;
- begin
- if List = nil then Exit;
- if List.Count > 0 then
- for i := 0 to List.Count - 1 do
- FreeMem(List.Items[i], SizeOf(TUINEntry)); //Free allocated memory for TUINEntry
- List.Free;
- List := nil;
- end;
- {Sends sms message to Destination with Text.}
- procedure TICQClient.SendSMS(const Destination, Text: String);
- var
- pkt: TRawPkt;
- begin
- if (Length(Text) = 0) or (not LoggedIn) then Exit;
- CreateCLI_SENDSMS(@pkt, FLUIN, Destination, Text, GetACP, GetSMSTime, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Sends Msg to UIN with advanced options, after UIN has got your message you will
- receive confirmation. ID - randomly generated value, may be used for packet acknowledgements
- (see OnAdvancedMsgAck event). If your Msg is in the RTF(RichText Format), then RTFFormat
- parameter should be True, otherwise - False. Beware of using the RTF Format, some clients
- (old versions of ICQ, linux & windows clones) don't support it.}
- procedure TICQClient.SendMessageAdvanced(UIN: LongWord; const Msg: String; ID: Word; RTFFormat: Boolean);
- var
- pkt: TRawPkt;
- begin
- if (Length(Msg) = 0) or (not LoggedIn) then Exit;
- CreateCLI_SENDMSG_ADVANCED(@pkt, 0, ID, UIN, Msg, RTFFormat, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Send message to client dirrectly when it's possible}
- function TICQClient.SendMessageDirect(UIN: LongWord; const Msg: String; RTFFormat: Boolean): Word;
- var
- lpkt: TRawPkt;
- begin
- Result := 0;
- if FDirect = nil then Exit;
- if (FDSeq = 0) then Inc(FSeq);
- Result := CreatePEER_MSG(@lpkt, Msg, RTFFormat, FDSeq);
- if not FDirect.SendData(UIN, @lpkt) then
- Result := 0;
- end;
- {Request an away messages, set when user changes status.}
- procedure TICQClient.RequestAwayMsg(UIN: LongWord; ID: Word; ReqStatus: Byte);
- var
- pkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_REQAWAYMSG(@pkt, 0, ID, UIN, ReqStatus, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Unregister an UIN number.}
- procedure TICQClient.UnregisterUIN(const Password: String);
- var
- pkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_UNREGUIN(@pkt, FLUIN, Password, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Change current password to NewPassword.}
- procedure TICQClient.ChangePassword(const NewPassword: String);
- var
- pkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_METASETPASS(@pkt, FLUIN, NewPassword, nil, 0, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Change current password to Buffer's value.}
- procedure TICQClient.ChangePasswordPtr(Buffer: Pointer; BufLen: Word);
- var
- pkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_METASETPASS(@pkt, FLUIN, '', Buffer, BufLen, FSeq, FSeq2);
- FSock.SendData(pkt, pkt.Len);
- end;
- {Returns True if direct connection with UIN has been estabilished.}
- function TICQClient.DirectConnectionEstabilished(UIN: LongWord): Boolean;
- begin
- Result := False;
- if FDirect = nil then Exit;
- Result := FDirect.ConnectionEstabilished(UIN);
- end;
- {Send contacts to UIN through server.}
- function TICQClient.SendContacts(UIN: LongWord; Contacts: TStringList; ID: Word): Boolean;
- var
- pkt: TRawPkt;
- begin
- Result := False;
- if not LoggedIn then Exit;
- CreateCLI_SENDCONTACTS(@pkt, 0, ID, UIN, Contacts, FSeq);
- FSock.SendData(pkt, pkt.Len);
- Result := True;
- end;
- {Request contacts from UIN through server.}
- function TICQClient.RequestContacts(UIN: LongWord; const Reason: String; ID: Word): Boolean;
- var
- pkt: TRawPkt;
- begin
- Result := False;
- if not LoggedIn then Exit;
- CreateCLI_SENDCONTACTS_REQ(@pkt, 0, ID, UIN, Reason, FSeq);
- FSock.SendData(pkt, pkt.Len);
- Result := True;
- end;
- {Sends contacts to UIN directly. Returns ID of the packet or 0 if failed.}
- function TICQClient.SendContactsDC(UIN: LongWord; Contacts: TStringList): Word;
- var
- pkt: TRawPkt;
- begin
- Result := 0;
- if FDirect = nil then Exit;
- if (FDSeq = 0) then Inc(FSeq);
- Result := CreatePEER_CONTACTS(@pkt, Contacts, FDSeq);
- if not FDirect.SendData(UIN, @pkt) then
- Result := 0;
- end;
- {Request contacts from UIN directly. Returns ID of the packet or 0 if failed.}
- function TICQClient.RequestContactsDC(UIN: LongWord; const Reason: String): Word;
- var
- lpkt: TRawPkt;
- begin
- Result := 0;
- if FDirect = nil then Exit;
- if (FDSeq = 0) then Inc(FSeq);
- Result := CreatePEER_CONTACTREQ(@lpkt, Reason, FDSeq);
- if not FDirect.SendData(UIN, @lpkt) then
- Result := 0;
- end;
- {Send keep alive packet.}
- procedure TICQClient.SendKeepAlive;
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_KEEPALIVE(@lpkt, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Set AuthorizationRequired and WebAware options.}
- procedure TICQClient.SetAuthorization(AuthorizationRequired, WebAware: Boolean);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_METASETPERMISSIONS(@lpkt, FLUIN, AuthorizationRequired, WebAware, FSeq, FSeq2);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Request authorization.}
- procedure TICQClient.SendAuthRequest(UIN: LongWord; Msg: String);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_REQAUTH(@lpkt, UIN, Msg, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Start changes of SSL.}
- procedure TICQClient.SSLChangeStart(FirstUpload: Boolean);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_ADDSTART(@lpkt, FirstUpload, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {End changes of SSL.}
- procedure TICQClient.SSLChangeEnd;
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_ADDEND(@lpkt, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Add group to SSL.}
- procedure TICQClient.SSLAddGroup(GroupName: String; GroupID: Word);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_ADDBUDDY(@lpkt, GroupName, '', '', GroupID, 0, BUDDY_GROUP, False, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Add user to SSL.}
- procedure TICQClient.SSLAddUser(GroupID, UserID: Word; UIN, Name, SMSNumber: String; Authorize, UpdateUser: Boolean);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- if not UpdateUser then
- CreateCLI_ADDBUDDY(@lpkt, UIN, Name, SMSNumber, GroupID, UserID, BUDDY_NORMAL, Authorize, FSeq)
- else
- CreateCLI_UPDATEBUDDY(@lpkt, UIN, Name, SMSNumber, GroupID, UserID, BUDDY_NORMAL, Authorize, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Remove user from SSL.}
- procedure TICQClient.SSLDelUser(GroupID, UserID: Word; UIN, Name, SMSNumber: String; Authorize: Boolean);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_DELETEBUDDY(@lpkt, UIN, Name, SMSNumber, GroupID, UserID, BUDDY_NORMAL, Authorize, True, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Remove group from SSL.}
- procedure TICQClient.SSLDelGroup(GroupName: String; GroupID: Word);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_DELETEBUDDY(@lpkt, GroupName, '', '', GroupID, 0, BUDDY_GROUP, False, True, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Update group's ids.}
- procedure TICQClient.SSLUpdateGroup(GroupName: String; GroupID: Word; UserIDs: TStringList);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_UPDATEGROUP(@lpkt, GroupName, GroupID, UserIDs, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Add user to the specified SSL's list.}
- procedure TICQClient.SSLAddUserIntoList(UserID: Word; UIN: String; BuddyType: Word);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_ADDBUDDY(@lpkt, UIN, '', '', $0000, UserID, BuddyType, False, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Remove user from the specified SSL's list.}
- procedure TICQClient.SSLDelUserFromList(UserID: Word; UIN: String; BuddyType: Word);
- var
- lpkt: TRawPkt;
- begin
- if (not LoggedIn) then Exit;
- CreateCLI_DELETEBUDDY(@lpkt, UIN, '', '', $0000, UserID, BuddyType, False, True, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- {Send response on a file request.}
- function TICQClient.FTResponse(ResponseRec: TFTRequestRec; Accept: Boolean; Reason: String): Boolean;
- var
- lpkt: TRawPkt;
- begin
- if DisableDirectConnections then
- begin
- Result := False;
- Exit;
- end;
- if not Accept then
- begin
- if ResponseRec.ReqType <> 0 then
- begin
- {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}
- CreateCLI_SENDMSG_FILEDECLINE(@lpkt, ResponseRec.Seq, ResponseRec.ITime, ResponseRec.IRandomID,
- ResponseRec.UIN, ResponseRec.FileSize,
- ResponseRec.Description, ResponseRec.FileName, Reason, 0, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- Result := True;
- Exit;
- end;
- end;
- if FDirect <> nil then
- if FDirect.AddFileUser(ResponseRec.UIN, ResponseRec.Port) then
- begin
- {Send response through estabilished direct connection}
- if ResponseRec.ReqType = 0 then
- begin
- CreatePEER_FILEINIT(@lpkt, True, ResponseRec.Description, ResponseRec.FileName, ResponseRec.Port,
- ResponseRec.FileSize, ResponseRec.Seq, Reason, Accept);
- Result := FDirect.SendData(ResponseRec.UIN, @lpkt);
- end else
- {Send response through server}
- begin
- CreateCLI_SENDMSG_FILEACK(@lpkt, ResponseRec.Seq, ResponseRec.ITime, ResponseRec.IRandomID,
- ResponseRec.UIN, ResponseRec.FileSize, ResponseRec.Description, ResponseRec.FileName,
- ResponseRec.Port, FSeq);
- FSock.SendData(lpkt, lpkt.Len);
- Result := True;
- end;
- Exit;
- end else
- OnIntError(Self, ERR_WARNING, 'Could not add user for sending/receiving files');
- Result := False;
- end;
- procedure TICQClient.FTCancel(UIN: LongWord);
- begin
- if FDirect <> nil then
- FDirect.StopFileReceiving(UIN);
- end;
- function TICQClient.FTStartResponse(StartRec: TFTStartRec): Boolean;
- var
- lpkt: TRawPkt;
- begin
- Result := False;
- if FDirect = nil then Exit;
- CreatePEER_FILE_INIT2(@lpkt, StartRec.FilesCount, $00000000, StartRec.Speed);
- Result := FDirect.SendDataFile(StartRec.UIN, @lpkt);
- end;
- {@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}
- {Handling of all incoming packets}
- procedure TICQClient.HandlePacket(Flap: TFlapHdr; Data: Pointer);
- var
- FUIN: String;
- FData: String;
- pkt: TRawPkt;
- T: Word;
- Snac: TSnacHdr;
- i: Word;
- begin
- case Flap.ChID of
- 1: //Channel 1
- begin
- {SRV_HELLO}
- if Flap.DataLen = 4 then
- begin
- if FRegisteringUIN then
- begin
- //Send CLI_HELLO
- CreateCLI_HELLO(@pkt, FSeq);
- FSock.SendData(pkt, pkt.Len);
- //Register a new UIN.
- CreateCLI_REGISTERUSER(@pkt, FRegPassword, FSeq);
- FSock.SendData(pkt, pkt.Len);
- Exit;
- end;
- if FFirstConnect then
- begin
- //Send login packet
- CreateCLI_IDENT(@pkt, FLUIN, FLPass, FSeq);
- FSock.SendData(pkt, pkt.len);
- end
- else
- begin
- //Sending the cookie(second stage of login sequence)
- CreateCLI_COOKIE(@pkt, FCookie, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- end;
- FFirstConnect := False;
- end;
- 2: //Channel 2
- begin
- Move(Data^, pkt.Data, Flap.DataLen); pkt.Len := 0;
- GetSnac(@pkt, Snac);
- case Snac.Family of
- $01: //Family x01
- case Snac.SubType of
- $03: {SRV_FAMILIES}
- begin
- CreateCLI_FAMILIES(@pkt, FSeq); {SNAC(x01/x17)}
- FSock.SendData(pkt, pkt.Len);
- end;
- $07: {SRV_RATES}
- begin
- CreateCLI_ACKRATES(@pkt, FSeq); {SNAC(x01/x08)}
- FSock.SendData(pkt, pkt.Len);
- CreateCLI_SETICBM(@pkt, FSeq); {SNAC(x04/x02)}
- FSock.SendData(pkt, pkt.Len);
- CreateCLI_REQINFO(@pkt, FSeq); {SNAC(x01/x0E)}
- FSock.SendData(pkt, pkt.Len);
- CreateCLI_REQLOCATION(@pkt, FSeq); {SNAC(x02/x02)}
- FSock.SendData(pkt, pkt.Len);
- CreateCLI_REQBUDDY(@pkt, FSeq); {SNAC(x03/x02)}
- FSock.SendData(pkt, pkt.Len);
- CreateCLI_REQICBM(@pkt, FSeq); {SNAC(x04/x04)}
- FSock.SendData(pkt, pkt.Len);
- CreateCLI_REQBOS(@pkt, FSeq); {SNAC(x09/x02)}
- FSock.SendData(pkt, pkt.Len);
- //FConnecting := False;
- end;
- $13: {SRV_MOTD}
- begin
- CreateCLI_RATESREQUEST(@pkt, FSeq); {SNAC(x01/x06)}
- FSock.SendData(pkt, pkt.Len);
- end;
- end;
- $03: //Family x03
- begin
- case Snac.SubType of
- $0B: {SRV_USERONLINE}
- HSnac030B(Flap, Snac, @pkt);
- $0C: {SRV_USEROFFLINE}
- begin
- FData := GetStr(@pkt, GetInt(@pkt, 1));
- if Assigned(OnUserOffline) then
- FOnUserOffline(Self, FData);
- end;
- end;
- end;
- $04: //Family x04
- if Snac.SubType = $07 then {SRV_MSG}
- HSnac0407(Flap, Snac, @pkt)
- else if Snac.SubType = $0b then {SRV_MSGACK}
- HSnac040b(Flap, Snac, @pkt);
- $09: //Family x09
- begin
- if Snac.SubType = $03 then
- begin
- CreateCLI_SETUSERINFO(@pkt, FSeq); {SNAC(x02/x04)}
- FSock.SendData(pkt, pkt.Len);
- if FContactLst.Count > 0 then
- for i := 0 to FContactLst.Count - 1 do
- begin
- CreateCLI_ADDCONTACT(@pkt, FContactLst.Strings[i], FSeq); {SNAC(x03/x04)}
- FSock.SendData(pkt, pkt.Len);
- end;
- if StatusToStr(FStatus) <> 'Invisible' then
- begin
- CreateCLI_ADDINVISIBLE(@pkt, FInvisibleLst, FSeq); {SNAC(x09/x07)}
- FSock.SendData(pkt, pkt.Len);
- end else
- begin
- CreateCLI_ADDVISIBLE(@pkt, FVisibleLst, FSeq); {SNAC(x09/x05)}
- FSock.SendData(pkt, pkt.Len);
- end;
- FDConnCookie := Random(High(Integer));
- if FDirect <> nil then
- begin
- if ProxyType = P_NONE then
- i := FDirect.BindPort
- else
- i := 0;
- CreateCLI_SETSTATUS(@pkt, FStatus, GetLocalIP, i, FDConnCookie, FProxyType, FSeq) {SNAC(x01/x1E)}
- end else
- CreateCLI_SETSTATUS(@pkt, FStatus, 0, 0, 0, FProxyType, FSeq); {SNAC(x01/x1E)}
- FSock.SendData(pkt, pkt.Len);
- CreateCLI_READY(@pkt, FSeq); {SNAC(x01/x02)}
- FSock.SendData(pkt, pkt.Len);
- CreateCLI_TOICQSRV(@pkt, FLUIN, CMD_REQOFFMSG, nil, 0, FSeq, FSeq2);{SNAC(x15/x02)}
- FSock.SendData(pkt, pkt.Len);
- {OnLogin Event}
- FLoggedIn := True;
- FTimer.Enabled := False;
- FInfoChain.Clear;
- FSInfoChain.Clear;
- if Assigned(OnLogin) then
- FOnLogin(Self);
- end;
- end;
- $13: //Family x13
- begin
- if Snac.SubType = $0e then
- HSnac130e(Flap, Snac, @pkt) {SRV_UPDATE_ACK}
- else if Snac.SubType = $1B then
- HSnac131b(Flap, Snac, @pkt) {SRV_AUTH}
- else if Snac.SubType = $1C then {SRV_ADDEDYOU}
- HSnac131C(Flap, Snac, @pkt)
- else if Snac.SubType = $19 then {SRV_AUTH_REQ}
- HSnac1319(Flap, Snac, @pkt)
- else if Snac.SubType = $06 then {SRV_REPLYROSTER}
- HSnac1306(Flap, Snac, @pkt);
- end;
- $15: //Family x15
- begin
- if Snac.SubType = $03 then {SRV_FROMICQSRV}
- HSnac1503(Flap, Snac, @pkt);
- end;
- $17:
- begin
- if Snac.SubType = $01 then {SRV_REGREFUSED}
- begin
- if Assigned(OnNewUINRefused) then
- FOnNewUINRefused(Self);
- end else
- if Snac.SubType = $05 then
- HSnac1705(Flap, Snac, @pkt);
- end;
- end;
- end;
- 4: //Channel 4
- begin
- if FLoggedIn or FRegisteringUIN then
- begin
- FTOnConnectError(Self);
- FSock.Disconnect;
- Exit;
- end;
- Move(Data^, pkt.Data, Flap.DataLen); pkt.Len := 0;
- //SRV_COOKIE
- FUIN := GetTLVStr(@pkt, T); //Client's UIN in ASCII format
- if T <> 1 then
- begin
- OnIntError(nil, ERR_PROTOCOL, 'Received malformed login packet');
- FTOnConnectError(Self);
- FSock.Disconnect;
- Exit;
- end;
- FData := GetTLVStr(@pkt, T); //IP, Port to connect to
- if T = 4 then
- begin
- OnIntError(nil, ERR_LOGIN, 'Bad password');
- FTOnConnectError(Self);
- Exit;
- end else
- if T = 8 then
- begin
- OnIntError(nil, ERR_LOGIN, 'Too often logins');
- FTOnConnectError(Self);
- Exit;
- end else
- if T <> 5 then
- begin
- OnIntError(nil, ERR_PROTOCOL, 'Received malformed login packet');
- FTOnConnectError(Self);
- FSock.Disconnect;
- Exit;
- end;
- FCookie := GetTLVStr(@pkt, T); //Cookie used in second stage of login
- if T <> 6 then
- begin
- OnIntError(nil, ERR_PROTOCOL, 'Received malformed login packet');
- FTOnConnectError(Self);
- FSock.Disconnect;
- Exit;
- end;
- //Sending CLI_GOODBYE
- PktInit(@pkt, 4, FSeq);
- PktFinal(@pkt);
- FSock.SendData(pkt, pkt.Len);
- FSock.Disconnect;
- //Assigning new IP and Port to connect to in second attemp
- InitNetICQ;
- FSock.Host := Copy(FData, 0, Pos(':', FData) - 1);
- FSock.Port := StrToInt(Copy(FData, Pos(':', FData) + 1, Length(FData) - Pos(':', FData)));
- if (FSock.Port = 0) then
- begin
- OnIntError(nil, ERR_PROTOCOL, 'Received malformed login packet');
- FTOnConnectError(Self);
- Exit;
- end;
- FSock.Connect;
- end;
- end;
- end;
- {////////////////////////////////////////////////////////////////////////////////////////////////////}
- procedure TICQClient.SetStatus(NewStatus: LongWord);
- var
- pkt: TRawPkt;
- begin
- if not LoggedIn then Exit;
- if (StatusToStr(FStatus) = 'Invisible') and (StatusToStr(NewStatus) <> 'Invisible') then
- begin
- CreateCLI_ADDINVISIBLE(@pkt, FInvisibleLst, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end else
- if (StatusToStr(NewStatus) = 'Invisible') and (StatusToStr(FStatus) <> 'Invisible') then
- begin
- CreateCLI_ADDVISIBLE(@pkt, FVisibleLst, FSeq);
- FSock.SendData(pkt, pkt.Len);
- end;
- CreateCLI_SETSTATUS_SHORT(@pkt, NewStatus, FSeq);
- FSock.SendData(pkt, pkt.Len);
- FStatus := NewStatus;
- end;
- {Handling packet with messages}
- procedure TICQClient.HSnac0407(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- ITime, IRandomID: LongWord;
- ULen: Word;
- c, i: Word;
- ack_pkt: TRawPkt;
- chunks: array[0..49] of Byte;
- Msg, UIN: String;
- MsgType: Word;
- Desc, URL: String;
- v: Byte;
- atype: String;
- XML: String;
- XMLTime, XMLSource, XMLSender, XMLText: String;
- FName, FDesc: String;
- FSize: LongWord;
- FFSeq: Word;
- Rec: TFTRequestRec;
- TCMD: String;
- List: TStringList;
- begin
- ITime := GetInt(Pkt, 4); //Time
- IRandomID := GetInt(Pkt, 2); //RandomID
- Inc(Pkt^.Len, 2); //Unknown: empty
- Msg := '';
- {Subtypes}
- case GetInt(Pkt, 2) of
- 1: //Simply(old-type) message
- begin
- UIN := GetStr(Pkt, GetInt(Pkt, 1));
- Inc(Pkt^.Len, 2);
- c := GetInt(Pkt, 2); //A count of the number of following TLVs.
- for i := 0 to c - 1 do //Skip all TLVs
- begin
- Inc(Pkt^.Len, 2);
- Inc(Pkt^.Len, GetInt(Pkt, 2));
- end;
- if GetInt(Pkt, 2) = 2 then //TLV with message remain
- begin
- Inc(Pkt^.Len, 4); //TLV length + Unknown const
- Inc(Pkt^.Len, GetInt(Pkt, 2)); //Counts of following bytes + following bytes
- Inc(Pkt^.Len, 2); //x0101, Unknown, constant
- ULen := GetInt(Pkt, 2) - 4; //Length of the message + 4
- Inc(Pkt^.Len, 4); //Unknown seems to be constant
- Msg := GetStr(Pkt, ULen); //The actual message text. There will be no ending NULL.
- if (Length(Msg) > 0) and Assigned(OnMessageRecv) then
- FOnMsg(Self, Msg, UIN);
- end;
- end;
- 2: //Adnavced(new-type)
- begin
- UIN := GetStr(Pkt, GetInt(Pkt, 1));
- for c := 0 to 5 do
- begin
- if GetInt(Pkt, 2) = 5 then
- begin
- Inc(Pkt^.Len, 2);
- if GetInt(Pkt, 2) <> 0 then //ACKTYPE: 0x0000 - This is a normal message
- Exit;
- Inc(Pkt^.Len, 16); //File signature
- Inc(Pkt^.Len, 8); //TIME + RANDOM
- for i := 0 to 5 do
- begin
- if GetInt(Pkt, 2) = $2711 then //Searching for TLV(2711) (with sources)
- begin
- Inc(Pkt^.Len, 2); //TLV Length
- Move(Ptr(LongWord(Pkt) + Pkt^.Len)^, chunks, 47);
- 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.
- Exit;
- Inc(Pkt^.Len, 26);
- FFSeq := GetInt(Pkt, 2);
- Inc(Pkt^.Len, 16);
- MsgType := GetInt(Pkt, 1);
- Inc(Pkt^.Len, 5);
- if MsgType = M_FILE then //File request
- begin
- FDesc := GetLNTS(Pkt); //File description
- Inc(Pkt^.Len, 4); //Unknown: 00 00 00 00
- FName := GetLNTS(Pkt); //File name
- FSize := GetLInt(Pkt, 4); //File size
- {Set the records' items}
- Rec.ITime := ITime;
- Rec.IRandomID := IRandomID;
- Rec.UIN := StrToInt(UIN);
- Rec.FileSize := FSize;
- Rec.Description := FDesc;
- Rec.FileName := FName;
- Rec.Seq := FFSeq;
- Rec.ReqType := $01;
- if Assigned(OnFTRequest) then
- FOnFTRequest(Self, Rec);
- Exit;
- end else
- if MsgType = M_ADVANCED then //Advanced message container
- begin
- GetLNTS(Pkt); //Empty message (contains only a null terminator)
- Inc(Pkt^.Len, 2); //Following length
- Inc(Pkt^.Len, 16); //Signature
- Inc(Pkt^.Len, 2); //Unknown: empty
- TCMD := GetDWStr(Pkt); //Text command
- if TCMD = 'Contacts' then
- begin
- Inc(Pkt^.Len, 4); //Following length
- Msg := GetDWStr(Pkt); //Message containing a list with contacts
- List := TStringList.Create; //Create temporary list
- ParseContacts(Msg, List); //Parse message with contacts
- if Assigned(OnContactListRecv) then
- FOnContactListRecv(Self, UIN, List);
- end else
- if TCMD = 'Request For Contacts' then
- begin
- Inc(Pkt^.Len, 15); //15 unknown bytes
- Inc(Pkt^.Len, 4); //Following length
- Msg := GetDWStr(Pkt); //Message containing a reason
- if Assigned(OnContactListRequest) then
- FOnContactListReq(Self, UIN, Msg);
- end;
- end
- else
- Msg := GetLNTS(Pkt); //The actual message text. There will be ending NULL.
- {Sending ACK of the message}
- PktInit(@ack_pkt, 2, FSeq); //Channel 2
- PktSnac(@ack_pkt, $04, $0B, 0, 0); //SNAC(x04/x0B)
- Move(Ptr(LongWord(Pkt) + TSNACSZ)^, Ptr(LongWord(@ack_pkt) + ack_pkt.Len)^, 10); //First 10 bytes of TLV(2711)
- Inc(ack_pkt.Len, 10); //Skip first 10 bytes copied from TLV(2711) which were added before
- PktLStr(@ack_pkt, UIN); //User's UIN
- PktInt(@ack_pkt, $0003, 2); //00 03
- PktAddArrBuf(@ack_pkt, @chunks, 47); //First 47 bytes of source packet (with message)
- PktInt(@ack_pkt, $00000000, 4); //00 00 00 00
- //If it's an auto-away message request
- if MsgType and $E0 = $E0 then
- PktLNTS(@ack_pkt, FAutoAwayMsg) //Auto-away message
- else begin
- PktInt(@ack_pkt, 1, 1); //01
- PktInt(@ack_pkt, 0, 4); //00 00 00 00
- PktInt(@ack_pkt, 0, 2); //00 00
- PktInt(@ack_pkt, $FFFFFF00, 4); //FF FF FF 00
- end;
- PktFinal(@ack_pkt);
- FSock.SendData(ack_pkt, ack_pkt.Len);
- if (Length(Msg) > 0) then
- begin
- if MsgType = M_PLAIN then
- begin
- if FDoPlain then Msg := Rtf2Txt(Msg); //Convert message from RTF to plaintext when needed
- if Assigned(OnMessageRecv) then
- FOnMsg(Self, Msg, UIN)
- end else
- if MsgType = M_URL then
- begin
- Desc := Copy(Msg, 0, Pos(#$fe, Msg) - 1);
- URL := Copy(Msg, Pos(#$fe, Msg) + 1, Length(Msg) - Pos(#$fe, Msg));
- if Assigned(OnURLRecv) then
- FOnURL(Self, Desc, URL, UIN);
- end;
- end;
- Exit;
- end else
- Inc(Pkt^.Len, GetInt(Pkt, 2));
- end;
- end else
- Inc(Pkt^.Len, GetInt(Pkt, 2));
- end;
- end;
- 4: //Another message type
- begin
- UIN := GetLStr(Pkt);
- for i := 0 to 4 do
- begin
- v := GetInt(Pkt, 1);
- if (v = 5) or ((GetInt(Pkt, 1) = 5) and (v = 0)) then //TLV(5) was found
- begin
- if v = 5 then //Some modifications for MAC clients
- Inc(Pkt^.Len, 40)
- else
- Inc(Pkt^.Len, 2);
- GetLInt(Pkt, 4); //UIN
- MsgType := GetLInt(Pkt, 2); //Message-type
- Msg := GetLNTS(Pkt); //Message
- if MsgType = $1a then //Probably advanced msg format
- begin
- Inc(Pkt^.Len, 20); //20 unknown bytes
- atype := GetDWStr(Pkt); //Advanced msg sub-type
- if atype = 'ICQSMS' then //Corresponds to received SMS message in XML formatted message
- begin
- Inc(Pkt^.Len, 3); //00 00 00
- Inc(Pkt^.Len, 4); //4-byte little endian length of the following data
- XML := GetStr(Pkt, GetLInt(Pkt, 4)); //XML entry of SMS response
- XMLSource := GetXMLEntry('source', XML); //Source, usually: 'ICQ'
- XMLSender := GetXMLEntry('sender', XML); //Source cellular number
- XMLText := GetXMLEntry('text', XML); //Text of reply
- XMLTime := GetXMLEntry('time', XML); //Time of sending reply
- if Assigned(OnSMSReply) then
- FOnSMSReply(Self, XMLSource, XMLSender, XMLTime, UTF8ToStrSmart(XMLText));
- end;
- Exit;
- end;
- if (Length(Msg) > 0) then
- begin
- if MsgType = M_PLAIN then
- begin
- if FDoPlain then Msg := Rtf2Txt(Msg); //Convert message from RTF to plaintext when needed
- if Assigned(OnMessageRecv) then
- FOnMsg(Self, Msg, UIN)
- end
- else if MsgType = M_URL then
- begin
- Desc := Copy(Msg, 0, Pos(#$fe, Msg) - 1);
- URL := Copy(Msg, Pos(#$fe, Msg) + 1, Length(Msg) - Pos(#$fe, Msg));
- if Assigned(OnURLRecv) then
- FOnURL(Self, Desc, URL, UIN);
- end;
- end;
- Exit;
- end else
- Inc(Pkt^.Len, GetInt(Pkt, 2));
- end;
- end;
- end;
- end;
- {Handling old type packets ICQ_FROMSRV}
- procedure TICQClient.HSnac1503(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- FMsgType: Word;
- lpkt: TRawPkt;
- FNick, FFirst, FLast, FEmail, FCity,
- FState, FPhone, FFax, FStreet, FCellular,
- FZip, FCountry, FCompany, FDepartment,
- FPosition, FOccupation, FHomePage,
- FLang1, FLang2, FLang3, FAbout: String;
- FTimeZone: Byte;
- FPublishEmail: Boolean;
- FAge, FYear: Word;
- FGender, FMonth, FDay: Byte;
- Msg, UIN, URL, Desc: String;
- List, List2: TStringList;
- C, i: Byte;
- WW: Word;
- FStatus: Word;
- cmd: Word;
- seq: Word;
- FSmsSource, FSmsDeliverable, FSmsNetwork, FMsgId: String;
- FAuthorize: Byte;
- begin
- if GetInt(Pkt, 2) = 1 then //TLV(1)
- begin
- Inc(Pkt^.Len, 8);
- case GetInt(Pkt, 2) of
- $4100: //SRV_OFFLINEMSG
- begin
- Inc(Pkt^.Len, 2); //The sequence number this packet is a response to.
- UIN := IntToStr(GetLInt(Pkt, 4)); //Source UIN
- Inc(Pkt^.Len, 6); //Date/time etc...
- FMsgType := GetLInt(Pkt, 2); //The type of message sent, like URL message or the like.
- Msg := GetLNTS(Pkt);
- if FDoPlain then Msg := Rtf2Txt(Msg); //Convert message from RTF to plaintext when needed
- if FMsgType = M_PLAIN then
- begin
- if Assigned(OnOfflineMsgRecv) then
- FOnOffMsg(Self, Msg, UIN);
- end else
- if FMsgType = M_URL then
- begin
- Desc := Copy(Msg, 0, Pos(#$fe, Msg) - 1);
- URL := Copy(Msg, Pos(#$fe, Msg) + 1, Length(Msg) - Pos(#$fe, Msg));
- if Assigned(OnOfflineURLRecv) then
- FOnOffURL(Self, Desc, URL, UIN);
- end;
- end;
- $4200: //All offline messages were sent, so we ACKING them
- begin
- FSeq2 := 2;
- CreateCLI_ACKOFFLINEMSGS(@lpkt, FLUIN, FSeq, FSeq2);
- FSock.SendData(lpkt, lpkt.Len);
- end;
- $da07: //SRV_META
- begin
- seq := GetLInt(Pkt, 2);
- cmd := GetInt(Pkt, 2);
- case cmd of
- $0100: //SRV_SMSREFUSED
- begin
- if Assigned(OnSMSRefused) then
- FOnSMSRefused(Self);
- end;
- $9600: //SRV_SMSACK
- begin
- if GetInt(Pkt, 1) <> $0a then Exit;
- Inc(Pkt^.Len, 12);
- Msg := GetStr(Pkt, GetLInt(Pkt, 2));
- FSmsSource := GetXMLEntry('source', Msg);
- FSmsDeliverable := GetXMLEntry('deliverable', Msg);
- FSmsNetwork := GetXMLEntry('network', Msg);
- FMsgId := GetXMLEntry('message_id', Msg);
- if Assigned(OnSMSAck) then
- FOnSMSAck(Self, FSmsSource, FSmsNetwork, FMsgId, FSmsDeliverable = 'Yes');
- end;
- $b400: //SRV_METAUNREG_BADPASS Channel: 2, Snac(0x15, 0x03) 2010/180
- begin
- case GetInt(Pkt, 1) of
- $0a:
- begin
- if Assigned(OnUnregisterOk) then
- FOnUnregisterOk(Self);
- CreateCLI_GOODBYE(@lpkt, FSeq); //Send CLI_GOODBYE, it forces server to disconnect us
- FSock.SendData(lpkt, lpkt.Len);
- end;
- $14: if Assigned(OnUnregisterBadPassword) then
- FOnUnregBadPass(Self);
- end;
- end;
- $c800: //SRV_METAGENERAL Channel: 2, SNAC(0x15,0x03) 2010/200
- begin
- FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
- if GetInt(Pkt, 1) <> $0a then Exit;
- FNick := GetLNTS(Pkt);
- FFirst := GetLNTS(Pkt);
- FLast := GetLNTS(Pkt);
- FEmail := GetLNTS(Pkt);
- FCity := GetLNTS(Pkt);
- FState := GetLNTS(Pkt);
- FPhone := GetLNTS(Pkt);
- FFax := GetLNTS(Pkt);
- FStreet := GetLNTS(Pkt);
- FCellular := GetLNTS(Pkt);
- FZip := GetLNTS(Pkt);
- FCountry := CountryToStr(GetLInt(Pkt, 2));
- FTimeZone := GetInt(Pkt, 1);
- if GetInt(Pkt, 1) = 1 then
- FPublishEmail := True
- else
- FPublishEmail := False;
- if Assigned(OnUserGeneralInfo) then
- FOnUserGeneralInfo(Self, FLastInfoUin, FNick, FFirst,
- FLast, FEmail, FCity, FState, FPhone,
- FFax, FStreet, FCellular, FZip, FCountry,
- FTimeZone, FPublishEmail
- );
- end;
- $d200: //SRV_METAWORK Channel: 2, SNAC(0x15,0x3) 2010/210
- begin
- FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
- if GetInt(Pkt, 1) <> $0a then Exit;
- FCity := GetLNTS(Pkt);
- FState := GetLNTS(Pkt);
- FPhone := GetLNTS(Pkt);
- FFax := GetLNTS(Pkt);
- FStreet := GetLNTS(Pkt);
- FZip := GetLNTS(Pkt);
- FCountry := CountryToStr(GetLInt(Pkt, 2));
- FCompany := GetLNTS(Pkt);
- FDepartment := GetLNTS(Pkt);
- FPosition := GetLNTS(Pkt);
- FOccupation := OccupationToStr(GetLInt(Pkt, 2));
- FHomePage := GetLNTS(Pkt);
- if Assigned(OnUserWorkInfo) then
- FOnUserWorkInfo(Self, FLastInfoUin, FCity, FState, FPhone,
- FFax, FStreet, FZip, FCountry, FCompany, FDepartment, FPosition,
- FOccupation, FHomePage
- );
- end;
- $dc00: //SRV_METAMORE Channel: 2, SNAC(0x15,0x3) 2010/220
- begin
- FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
- if GetInt(Pkt, 1) <> $0a then Exit;
- FAge := GetLInt(Pkt, 2);
- if Integer(FAge) < 0 then
- FAge := 0;
- FGender := GetInt(Pkt, 1);
- FHomePage := GetLNTS(Pkt);
- FYear := GetLInt(Pkt, 2);
- FMonth := GetInt(Pkt, 1);
- FDay := GetInt(Pkt, 1);
- FLang1 := LanguageToStr(GetInt(Pkt, 1));
- FLang2 := LanguageToStr(GetInt(Pkt, 1));
- FLang3 := LanguageToStr(GetInt(Pkt, 1));
- if Assigned(OnUserInfoMore) then
- FOnUserInfoMore(Self, FLastInfoUin, FAge, FGender, FHomePage,
- FYear, FMonth, FDay, FLang1, FLang2, FLang3
- );
- end;
- $e600: //Channel: 2, SNAC(0x15,0x3) 2010/230
- begin
- FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
- if GetInt(Pkt, 1) <> $0a then Exit;
- FAbout := GetLNTS(Pkt);
- if Assigned(OnUserInfoAbout) then
- FOnUserInfoAbout(Self, FLastInfoUin, FAbout);
- end;
- $eb00: //Channel: 2, SNAC(21,3) 2010/235
- begin
- FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
- if GetInt(Pkt, 1) <> $0a then Exit;
- c := GetInt(Pkt, 1); //The number of email addresses to follow. May be zero. Each consist of the following parameters:
- List := TStringList.Create;
- if c > 0 then
- for i := 0 to c - 1 do
- begin
- GetInt(Pkt, 1); //Publish email address? 1 = yes, 0 = no.
- List.Add(GetLNTS(Pkt)); //The email address.
- end;
- if Assigned(OnUserInfoMoreEmails) then
- FOnUserInfoMoreEmails(Self, FLastInfoUin, List)
- else
- List.Free;
- end;
- $f000: //Channel: 2, SNAC(21,3) 2010/240
- begin
- FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
- if GetInt(Pkt, 1) <> $0a then Exit;
- c := GetInt(Pkt, 1);
- List := TStringList.Create;
- if c > 0 then
- for i := 0 to c - 1 do
- begin
- WW := GetLInt(Pkt, 2);
- List.Add(InterestToStr(WW) + '=' + GetLNTS(Pkt))
- end;
- if Assigned(OnUserInfoInterests) then
- FOnUserInfoInterests(Self, FLastInfoUin, List)
- else
- List.Free;
- end;
- $a401, $ae01: //SRV_METAFOUND Channel: 2, SNAC(21,3) 2010/420 or Channel: 2, SNAC(21,3) 2010/430
- begin
- if GetInt(Pkt, 1) <> $0a then
- begin
- if Assigned(OnUserNotFound) then
- FOnUserNotFound(Self);
- Exit;
- end;
- Inc(Pkt^.Len, 2); //Length of the following data.
- UIN := IntToStr(GetLInt(Pkt, 4)); //The user's UIN.
- FNick := GetLNTS(Pkt); //The user's nick name.
- FFirst := GetLNTS(Pkt); //The user's first name.
- FLast := GetLNTS(Pkt); //The user's last name.
- FEmail := GetLNTS(Pkt); //The user's email address.
- FAuthorize := GetInt(Pkt, 1); //Authorize: 1 = no, 0 = yes.
- FStatus := GetLInt(Pkt, 2); //0 = Offline, 1 = Online, 2 = not Webaware.
- FGender := GetInt(Pkt, 1); //The user's gender. 1 = female, 2 = male, 0 = not specified.
- FAge := GetInt(Pkt, 1); //The user's age.
- if Assigned(OnUserFound) then
- FOnUserFound(Self, UIN, FNick, FFirst, FLast, FEmail, FStatus, FGender, FAge, cmd = $ae01, FAuthorize = $00);
- end;
- $6603:
- begin
- if GetInt(Pkt, 1) <> $0a then
- begin
- if Assigned(OnUserNotFound) then
- FOnUserNotFound(Self);
- Exit;
- end;
- UIN := IntToStr(GetLInt(Pkt, 4)); //The user's UIN.
- if Assigned(OnUserFound) then
- FOnUserFound(Self, UIN, '', '', '', '', 0, 0, 0, True, False);
- end;
- $fa00:
- begin
- FLastInfoUin := FInfoChain.Values[IntToStr(seq)];
- if GetInt(Pkt, 1) <> $0a then Exit;
- List := TStringList.Create;
- List2 := TStringList.Create;
- c := GetInt(Pkt, 1); //The number of background items to follow. May be zero. Each background item consists of the following two parameters
- if c > 0 then
- for i := 0 to c - 1 do
- begin
- WW := GetLInt(Pkt, 2); //The group this background is in, according to a table.
- if WW >= 8191 then Exit;
- List.Add(PastToStr(WW) + '=' + GetLNTS(Pkt)) //A longer description of this background item.
- end;
- c := GetInt(Pkt, 1); //The number of affiliations to follow. May be zero. Each affiliation consists of the following parameters:
- if c > 0 then
- for i := 0 to c - 1 do
- begin
- WW := GetLInt(Pkt, 2); //The group this affiliation is in, according to a table.
- if WW >= 8191 then Exit;
- List2.Add(AffiliationToStr(WW) + '=' + GetLNTS(Pkt)) //A longer description of the affiliation.
- end;
- if Assigned(OnUserInfoBackground) then
- FOnUserInfoBackground(Self, FLastInfoUin, List, List2)
- else begin
- List.Free;
- List2.Free;
- end;
- end;
- $0401: //SRV_METAINFO Channel: 2, SNAC(21,3) 2010/260
- begin
- FLastSInfoUin := FSInfoChain.Values[IntToStr(seq)];
- if FSInfoChain.IndexOfName(IntToStr(seq)) >= 0 then
- FSInfoChain.Delete(FSInfoChain.IndexOfName(IntToStr(seq)));
- if GetInt(Pkt, 1) <> $0a then
- begin
- if Assigned(OnUserInfoShort) then
- FOnUserInfoShort(Self, FLastSInfoUIN, '', '', '', '', False, False);
- Exit;
- end else
- begin
- FNick := GetLNTS(Pkt); //Nickname
- FFirst := GetLNTS(Pkt); //Firstname
- FLast := GetLNTS(Pkt); //Lastname
- FEmail := GetLNTS(Pkt); //Email
- if Assigned(OnUserInfoShort) then
- FOnUserInfoShort(Self, FLastSInfoUIN, FNick, FFirst, FLast, FEmail, True, GetInt(Pkt, 1) <> $01);
- end;
- end;
- $aa00:
- if Assigned(OnInfoChanged) then
- FOnInfoChanged(Self, INFO_PASSWORD, GetInt(Pkt, 1) = $0a);
- $6400: //SRV_METAGENERALDONE Channel: 2, SNAC(21,3) 2010/100
- if Assigned(OnInfoChanged) then
- FOnInfoChanged(Self, INFO_GENERAL, GetInt(Pkt, 1) = $0a);
- $7800: //SRV_METAMOREDONE Channel: 2, SNAC(21,3) 2010/120
- if Assigned(OnInfoChanged) then
- FOnInfoChanged(Self, INFO_MORE, GetInt(Pkt, 1) = $0a);
- $8200: //SRV_METAABOUTDONE Channel: 2, SNAC(21,3) 2010/130
- if Assigned(OnInfoChanged) then
- FOnInfoChanged(Self, INFO_ABOUT, GetInt(Pkt, 1) = $0a);
- $a000: //SRV_AUTHSET Channel: 2, SNAC(21, 3) 2010/160
- if Assigned(OnAuthorizationChangedOk) then
- FOnAuthSet(Self);
- end;
- end;
- end;
- end;
- end;
- {Handling packet with status changes}
- {$WARNINGS OFF}
- procedure TICQClient.HSnac030B(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- function NumToIp(Addr: LongWord): String;
- var
- inaddr: in_addr;
- begin
- inaddr.S_addr := Addr;
- Result := inet_ntoa(inaddr);
- end;
- var
- c, i: Word;
- UIN: String;
- Status: LongWord;
- FIntIP, FExtIP: LongWord;
- FIntPort: Word;
- FConnFlag: Byte;
- FDconCookie: LongWord;
- FProtoVer: Word;
- begin
- UIN := GetStr(Pkt, GetInt(Pkt, 1));
- Inc(Pkt^.Len, 2);
- c := GetInt(Pkt, 2);
- if c < 1 then Exit;
- for i := 0 to c - 1 do
- begin
- case GetInt(Pkt, 2) of
- $0c:
- begin
- Inc(Pkt^.Len, 2); //TLV's Length
- FIntIP := GetLInt(Pkt, 4); //Internal IP
- FIntPort := GetInt(Pkt, 4); //Internal port
- FConnFlag := GetInt(Pkt, 1); //Connection flag
- FProtoVer := GetInt(Pkt, 2); //Protocol version
- FDconCookie := GetLInt(Pkt, 4); //Direct connection cookie
- Inc(Pkt^.Len, 22); //Skip remaining data
- end;
- $0a:
- begin
- Inc(Pkt^.Len, 2); //TLV's Length
- FExtIP := GetLInt(Pkt, 4); //External IP
- if (FConnFlag = $04) or (FConnFlag = $02) then
- begin
- if FDirect <> nil then
- FDirect.AddUser(StrToInt(UIN), FDConCookie, FExtIP, FIntIP, FIntPort);
- end else
- OnIntError(nil, ERR_WARNING, 'Cannot estabilish direct connection because remote client uses unknown proxy type');
- end;
- $06:
- begin
- Inc(Pkt^.Len, 2); //TLV's Length
- Status := GetInt(Pkt, 4); //Online status
- if (not DisableDirectConnections) and (FDirect <> nil) then
- FDirect.EstabilishConnection(StrToInt(UIN));
- if Assigned(OnStatusChange) then
- FOnStatusChange(Self, UIN, Status);
- if Assigned(OnOnlineInfo) then
- FOnOnlineInfo(Self, UIN, FIntPort, NumToIp(FIntIP), NumToIp(FExtIP), FProtoVer);
- Exit;
- end else
- Inc(Pkt^.Len, GetInt(Pkt, 2));
- end;
- end;
- end;
- {$WARNINGS ON}
- {Handling AddedYou packet}
- procedure TICQClient.HSnac131C(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- T: Word;
- UIN: String;
- begin
- Inc(Pkt^.Len, 2);
- GetTLVInt(Pkt, T);
- if T <> 1 then Exit;
- UIN := GetLStr(Pkt);
- if Assigned(OnAddedYou) then
- FOnAddedYou(Self, UIN);
- end;
- {Authorization request, we are automaticly authorizing the user}
- procedure TICQClient.HSnac1319(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- FUin: String;
- FReason: String;
- opkt: TRawPkt;
- begin
- Inc(Pkt^.Len, 8);
- FUin := GetLStr(Pkt);
- FReason := GetStr(Pkt, Swap16(GetInt(Pkt, 2)));
- CreateCLI_AUTHORIZE(@opkt, StrToInt(FUin), 1, '', FSeq);
- FSock.SendData(opkt, opkt.Len);
- end;
- {This packet contains your complete server side contact list.}
- procedure TICQClient.HSnac1306(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- GroupIdents: TStringList;
- UINList: TList;
- procedure ReadChunk;
- var
- Len: Word;
- FGroup: ShortString;
- CTag, CId, CType: Word;
- TLen: Word;
- TType: Word;
- FNick: ShortString;
- lpEntry: PUINEntry;
- begin
- FGroup := GetWStr(Pkt); //The name of the group.
- 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.
- 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.
- CType := GetInt(Pkt, 2); //This field seems to indicate what type of group this is.
- Len := GetInt(Pkt, 2); //The length in bytes of the following TLVs.
- FNick := '';
- while Integer(Len) > 0 do
- begin
- TType := GetInt(Pkt, 2); //TLV Type
- TLen := GetInt(Pkt, 2); //TLV Len
- if TType = $0131 then
- FNick := UTF8ToStrSmart(GetStr(Pkt, TLen))
- else
- Inc(Pkt^.Len, TLen); //Skip this TLV
- Dec(len, TLen + 4); //TLV length + 2 bytes type + 2 bytes length
- end;
- //Group header
- if (FGroup <> '') and (CType = 1) and (CTag <> 0) and (CId = 0) then
- GroupIdents.Values[IntToStr(CTag)] := UTF8ToStrSmart(FGroup);
- //UIN entry
- if (CType = 0) or (CType = 2) or (CType = 3) or (CType = $e) then
- begin
- GetMem(lpEntry, SizeOf(lpEntry^));
- lpEntry^.UIN := StrToInt(FGroup);
- lpEntry^.Nick := FNick;
- lpEntry^.CType := CType;
- lpEntry^.CTag := CId;
- lpEntry^.CGroupID := CTag;
- UINList.Add(lpEntry);
- end;
- end;
- var
- count, T: Word;
- i: Word;
- begin
- GetTLVInt(Pkt, T); if T <> 6 then Exit;
- Inc(Pkt^.Len, 4); //02 00 02 00 - UNKNOWNs
- 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.
- if count < 1 then Exit;
- GroupIdents := TStringList.Create;
- UINList := TList.Create;
- for i := 0 to count - 1 do
- ReadChunk;
- if UINList.Count > 0 then
- for i := 0 to UINList.Count - 1 do
- PUINEntry(UINList.Items[i])^.CGroup := GroupIdents.Values[IntToStr(PUINEntry(UINList.Items[i])^.CGroupID)];
- GroupIdents.Free;
- if Assigned(OnServerListRecv) then
- FOnServerListRecv(Self, UINList)
- else
- DestroyUINList(UINList);
- end;
- {This packet contains ack to message you've sent.}
- procedure TICQClient.HSnac040b(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- RetCode: Word;
- RetAcc: Byte;
- RetMsg: String;
- MsgType: Byte;
- FUIN: String;
- begin
- Inc(Pkt^.Len, 4); //Time
- RetCode := GetInt(Pkt, 2); //Random ID
- Inc(Pkt^.Len, 4); //Other data :)
- FUIN := GetLStr(Pkt); //User's UIN
- Inc(Pkt^.Len, 2); //00 03
- Inc(Pkt^.Len, 45); //Skip 50 bytes of packet
- MsgType := GetInt(Pkt, 1); //Msg-type
- Inc(Pkt^.Len, 1); //Msg-flags
- RetAcc := GetInt(Pkt, 1); //Accept type
- Inc(Pkt^.Len, 3); //Unknown
- if (RetAcc <> ACC_NORMAL) and (RetAcc <> ACC_NO_OCCUPIED) and
- (RetAcc <> ACC_NO_DND) and (RetAcc <> ACC_AWAY) and
- (RetAcc <> ACC_NA) and (RetAcc <> ACC_CONTACTLST) then Exit;
- if MsgType and $E0 = $E0 then
- begin
- RetMsg := GetLNTS(Pkt);
- if Assigned(OnAutoMsgResponse) then
- FOnAutoMsgResponse(Self, FUIN, RetCode, MsgType, RetMsg);
- Exit;
- end;
- if RetAcc <> ACC_NORMAL then
- begin
- RetMsg := GetLNTS(Pkt);
- end else
- RetMsg := '';
- if Assigned(OnAdvancedMsgAck) then
- FOnAdvMsgAck(Self, FUIN, RetCode, RetAcc, RetMsg);
- end;
- {This packet contains response with new UIN created.}
- procedure TICQClient.HSnac1705(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- UIN: String;
- begin
- if GetInt(Pkt, 2) <> $01 then Exit; //TLV(01)
- Inc(Pkt^.Len, 2); //TLV's length
- Inc(Pkt^.Len, 2); //The length of the following data in bytes.
- Inc(Pkt^.Len, 4); //Unknown: empty.
- Inc(Pkt^.Len, 4); //Unknown: 0x2d000300 = 754975488.
- Inc(Pkt^.Len, 4); //Your port number as the server sees it.
- Inc(Pkt^.Len, 4); //Your IP address as the server sees it.
- Inc(Pkt^.Len, 4); //Unknown: 0x4 = 4.
- Inc(Pkt^.Len, 4); //The same UNKNOWN2 as sent in CLI_REGISTERUSER.
- Inc(Pkt^.Len, 16); //16 empty bytes
- UIN := IntToStr(GetLInt(Pkt, 4)); //New UIN
- if Assigned(OnNewUINRegistered) then //Call associated event
- FOnNewUINRegistered(Self, UIN);
- end;
- {This packet contains reponse to CLI_REQAUTH.}
- procedure TICQClient.HSnac131b(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- T: Word;
- UIN, Reason: String;
- Granted: Boolean;
- begin
- Inc(Pkt^.Len, 2); //Unknown: 6.
- GetTLVInt(Pkt, T); //Unknown.
- UIN := GetLStr(Pkt); //The UIN that granted authorization.
- Granted := GetInt(Pkt, 1) = $01; //00 - Rejected, 01 - Granted.
- Reason := GetWStr(Pkt); //Reason, can be null.
- if Assigned(OnAuthResponse) then
- FOnAuthResponse(Self, UIN, Granted, Reason);
- end;
- {This command is sent as what is perhaps an acknowledgement reply to at least CLI_ADDBUDDY and CLI_UPDATEGROUP.}
- procedure TICQClient.HSnac130e(Flap: TFlapHdr; Snac: TSnacHdr; Pkt: PRawPkt);
- var
- T: Word;
- ErrCode: Word;
- begin
- Inc(Pkt^.Len, 2); //Unknown: 6. Guess: The length in bytes of the following data.
- GetTLVInt(Pkt, T); //Unknown.
- ErrCode := GetInt(Pkt, 2); //ErrorCode
- if (ErrCode <> ERRSSL_AUTH) and (ErrCode <> ERRSSL_NOERROR) and (ErrCode <> ERRSSL_NOTFOUND) and
- (ErrCode <> ERRSSL_EXISTS) then
- ErrCode := ERRSSL_OTHER;
- if Assigned(OnSSLChangeResponse) then
- FOnChangeResponse(Self, ErrCode);
- end;
- {Handle packet with message sent directly}
- procedure TICQClient.HDirectMsg(Sender: TObject; UIN: LongWord; Pak: PRawPkt; Len: LongWord);
- var
- Msg: String;
- lpkt: TRawPkt;
- LSeq: Word;
- cmd, scmd: Word;
- S, Desc, URL: String;
- List: TStringList;
- FText: String;
- FileLen: LongWord;
- Port: Word;
- rec: TFTRequestRec;
- begin
- if not DecryptPak(Ptr(LongWord(Pak) + 2), Pak^.Len - 2, 8) then Exit;
- Pak.Len := 2;
- if GetInt(Pak, 1) <> $02 then Exit; //02 - PEER_MSG
- Inc(Pak^.Len, 4); //Packet checksum
- cmd := GetLInt(Pak, 2); //Command
- Inc(Pak^.Len, 2); //Unknown: 0xe = 14.
- LSeq := GetLInt(Pak, 2); //Sequence number.
- Inc(Pak^.Len, 12); //Unknown: 12 empty bytes
- scmd := GetLInt(Pak, 2); //Sub command
- case cmd of
- $07ee: //2030 - normal message.
- begin
- if scmd = $0001 then //Simple message
- begin
- Inc(Pak^.Len, 2); //Unknown: empty.
- Inc(Pak^.Len, 2); //Our status.
- Msg := GetLNTS(Pak); //Finally the message.
- if Assigned(OnMessageRecv) then
- FOnMsg(Self, Msg, IntToStr(UIN));
- end else
- if scmd and $03e0 = $03e0 then //Read auto-away message
- begin
- CreatePEER_AUTOMSG_ACK(@lpkt, FAutoAwayMsg, scmd, LSeq); //Send ACK with auto msg reponse
- FDirect.SendData(UIN, @lpkt);
- Exit; //Do not send another ACK
- end else
- if scmd = $001a then //Advanced message format
- begin
- Inc(Pak^.Len, 27); //Skip 27 bytes of mostly unknown data
- S := GetStr(Pak, GetLInt(Pak, 4));
- if S = 'Contacts' then //Receive contacts
- begin
- Inc(Pak^.Len, 19); //Skip another 19 bytes of empty data + some lengths
- S := GetStr(Pak, GetLInt(Pak, 4));
- List := TStringList.Create;
- ParseContacts(S, List);
- if Assigned(OnContactListRecv) then
- FOnContactListRecv(Self, IntToStr(UIN), List)
- else
- List.Free;
- end else
- if S = 'Send Web Page Address (URL)' then
- begin
- Inc(Pak^.Len, 19); //Skip another 19 bytes of empty data + some lengths
- S := GetStr(Pak, GetLInt(Pak, 4));
- if Assigned(OnURLRecv) then
- begin
- Desc := Copy(S, 0, Pos(#$fe, S) - 1);
- URL := Copy(S, Pos(#$fe, S) + 1, Length(S) - Pos(#$fe, S));
- if Assigned(OnURLRecv) then
- FOnURL(Self, Desc, URL, IntToStr(Uin));
- end;
- end else
- if S = 'Request For Contacts' then
- begin
- Inc(Pak^.Len, 19); //Skip another 19 bytes of empty data + some lengths
- S := GetStr(Pak, GetLInt(Pak, 4));
- if Assigned(OnContactListRequest) then
- FOnContactListReq(Self, IntToStr(UIN), S)
- end else
- if S = 'File' then
- begin
- Inc(Pak^.Len, 19); //Skip another 19 bytes of empty data + some lengths
- Desc := GetStr(Pak, GetLInt(Pak, 4)); //Description
- Port := GetInt(Pak, 2); //Port
- Inc(Pak^.Len, 2); //Seq
- FileLen := GetLInt(Pak, 2);
- if FileLen > 0 then
- begin
- FText := GetStr(Pak, FileLen - 1); //Filename
- Inc(Pak^.Len, 1); //Null terminator
- end else FText := '';
- FileLen := GetLInt(Pak, 4); //Filelength
- rec.ReqType := 0;
- rec.UIN := UIN;
- rec.Description := Desc;
- rec.FileName := FText;
- rec.FileSize := FileLen;
- rec.Seq := LSeq;
- rec.Port := Port;
- if Assigned(OnFTRequest) then
- FOnFTRequest(Self, rec);
- Exit;
- end;
- end;
- end;
- $07da: //Packet acks
- begin
- if Assigned(OnDirectPacketAck) then
- FOnDirectPktAck(Self, LSeq);
- end;
- end;
- //ACK received packet, if this packet isn't a "cancel given message" or "acknowledge message"
- if (cmd <> $07da) and (cmd <> $07d0) then
- begin
- if FDirect <> nil then
- begin
- CreatePEER_MSGACK(@lpkt, LSeq);
- FDirect.SendData(UIN, @lpkt);
- end;
- end;
- end;
- procedure TICQClient.FTOnConnectError(Sender: TObject);
- begin
- FLoggedIn := False;
- FTimer.Enabled := False;
- if Assigned(OnConnectionFailed) then
- FOnConnectionFailed(Self);
- end;
- procedure TICQClient.FTOnDisconnect(Sender: TObject);
- begin
- FTimer.Enabled := False;
- if FLoggedIn then
- begin
- FLoggedIn := False;
- if Assigned(OnConnectionFailed) then
- FOnConnectionFailed(Self);
- end;
- end;
- procedure TICQClient.FTOnDirectParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean);
- begin
- if Assigned(OnPktDirectParse) then
- FOnDPktParse(Self, Buffer, BufLen, Incoming);
- end;
- procedure TICQClient.FTOnPktParse(Sender: TObject; Buffer: Pointer; BufLen: LongWord; Incoming: Boolean);
- begin
- if Assigned(OnPktParse) then
- FOnPktParse(Self, Buffer, BufLen, Incoming);
- end;
- procedure TICQClient.OnFTInitProc(Sender: TObject; UIN: LongWord; FileCount, TotalBytes, Speed: LongWord; NickName: String);
- begin
- if Assigned(OnFTInit) then
- FOnFTInit(Self, UIN, FileCount, TotalBytes, Speed, NickName);
- end;
- procedure TICQClient.OnFTStartProc(Sender: TObject; StartRec: TFTStartRec; FileName: String; FileSize, Speed: LongWord);
- begin
- if Assigned(OnFTStart) then
- FOnFTStart(Self, StartRec, FileName, FileSize, Speed);
- end;
- procedure TICQClient.OnFTFileDataProc(Sender: TObject; UIN: LongWord; Data: Pointer; DataLen: LongWord; LastPacket: Boolean);
- begin
- if Assigned(OnFTFileData) then
- FOnFTFileData(Self, UIN, Data, DataLen, LastPacket);
- end;
- procedure TICQClient.SetContactList(Value: TStrings);
- begin
- FContactLst.Assign(Value);
- end;
- procedure TICQClient.SetVisibleList(Value: TStrings);
- begin
- FVisibleLst.Assign(Value);
- end;
- procedure TICQClient.SetInvisibleList(Value: TStrings);
- begin
- FInvisibleLst.Assign(Value);
- end;
- procedure TICQClient.OnTimeout;
- begin
- FTimer.Enabled := False;
- FSock.Disconnect;
- OnIntError(Self, ERR_CONNTIMEOUT, 'Connection timed out');
- if Assigned(OnConnectionFailed) then
- FOnConnectionFailed(Self);
- end;
- {**************************************************************************}
- constructor TMyTimer.Create;
- begin
- inherited Create;
- FEnabled := True;
- FInterval := 1000;
- {$IFDEF OLD_DELPHI}
- FWindowHandle := AllocateHWnd(WndProc);
- {$ELSE}
- FWindowHandle := Classes.AllocateHWnd(WndProc); {Remove 'depricated' warning}
- {$ENDIF}
- end;
- destructor TMyTimer.Destroy;
- begin
- SetEnabled(False);
- {$IFDEF OLD_DELPHI}
- DeallocateHWnd(FWindowHandle);
- {$ELSE}
- Classes.DeallocateHWnd(FWindowHandle); {Remove 'depricated' warning}
- {$ENDIF}
- inherited;
- end;
- procedure TMyTimer.WndProc(var Msg: TMessage);
- begin
- with Msg do
- if Msg = WM_TIMER then
- try
- Timer;
- except
- end
- else
- Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
- end;
- procedure TMyTimer.UpdateTimer;
- begin
- KillTimer(FWindowHandle, 1);
- if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then
- SetTimer(FWindowHandle, 1, FInterval, nil);
- end;
- procedure TMyTimer.SetEnabled(Value: Boolean);
- begin
- if Value <> FEnabled then
- begin
- FEnabled := Value;
- UpdateTimer;
- end;
- end;
- procedure TMyTimer.SetInterval(Value: Cardinal);
- begin
- if Value <> FInterval then
- begin
- FInterval := Value;
- UpdateTimer;
- end;
- end;
- procedure TMyTimer.SetOnTimer(Value: TNotifyEvent);
- begin
- FOnTimer := Value;
- UpdateTimer;
- end;
- procedure TMyTimer.Timer;
- begin
- if Assigned(FOnTimer) then FOnTimer(Self);
- end;
- {*********************************************************************}
- procedure Register;
- begin
- RegisterComponents('Standard', [TICQClient]);
- end;
- end.