Main.pas
Falk0ner, вс, 06/07/2008 - 15:34.
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Author: Alexander Vaga
EMail: alexander_vaga@hotmail.com
Creation: May, 2002
Legal issues: Copyright (C) 2002 by Alexander Vaga
Kyiv, Ukraine
This software is provided 'as-is', without any express or
implied warranty. In no event will the author be held liable
for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it
and redistribute it freely.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{$A-,B+,C+,D+,E-,F-,G+,H+,I+,J+,K-,L+,M+,N+,O-,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1}
unit Main;
interface
uses
Windows, Messages, SysUtils, Graphics,
Forms, Dialogs, ComCtrls, Buttons, ToolWin,
ExtCtrls, Menus, ImgList, ScktComp, Controls,
StdCtrls, Classes, inifiles,
Types, Packet;
type
TForm1 = class(TForm)
MainT: TTimer;
StatusMenu: TPopupMenu;
OnlineConnected1: TMenuItem;
FreeForChat1: TMenuItem;
sep1: TMenuItem;
Away1: TMenuItem;
NAExtendedAway1: TMenuItem;
sep2: TMenuItem;
OccupiedUrgentMsgs1: TMenuItem;
DNDDoNotDisturb1: TMenuItem;
sep3: TMenuItem;
PrivacyInvisible1: TMenuItem;
OfflineDiscconnect1: TMenuItem;
Panel1: TPanel;
Panel3: TPanel;
Splitter1: TSplitter;
CLI: TClientSocket;
BG: TPanel;
Memo: TMemo;
StatusBtn: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure InitUser;
procedure InitLogs;
procedure CloseLogs;
procedure ConnectMode(Mode : boolean);
procedure MainTTimer(Sender: TObject);
procedure OnlineConnected1Click(Sender: TObject);
procedure Away1Click(Sender: TObject);
procedure DNDDoNotDisturb1Click(Sender: TObject);
procedure PrivacyInvisible1Click(Sender: TObject);
procedure OfflineDiscconnect1Click(Sender: TObject);
procedure OccupiedUrgentMsgs1Click(Sender: TObject);
procedure FreeForChat1Click(Sender: TObject);
procedure NAExtendedAway1Click(Sender: TObject);
procedure CLIConnect(Sender: TObject; Socket: TCustomWinSocket);
procedure CLI_ReadData(Sender: TObject; Socket: TCustomWinSocket);
procedure CLIDisconnect(Sender: TObject; Socket: TCustomWinSocket);
procedure PacketSend(p:PPack);
procedure ShowUserONStatus(p:PPack);
procedure SNAC_15_3(p:PPack);
procedure SNAC_4_7(p:PPack);
procedure icq_Login(Status : longint);
procedure SetStatus(Status:longint);
procedure StatusChange(Status:longint);
procedure AuthorizePart(p:PPack);
procedure WorkPart(p:PPack);
procedure DoMsg(on_off:boolean;typemes,lenmes:integer; data:PCharArray; r_uin:longint; DateTime:TDateTime);
procedure DoSimpleMsg(r_uin:longint; Text:string);
procedure ClearFIFO;
procedure debugFILE(tmp:PPack; Direction:char);
procedure LogMessage(s:string);
procedure StatusBtnClick(Sender: TObject);
private{ Private declarations }
public { Public declarations }
protected { Protected declarations }
published { Published declarations }
end;
var Form1 : TForm1;
UIN : longint;
NICK : string;
PASSWORD : string;
ICQStatus : longint;
DIM_IP : IPArray;
Local_IP : string;
Local_Name : string;
SEQ : word;
FLAP : FLAP_HDR;
FLAP_DATA : TByteArray;
Index : integer;
NeedBytes : integer;
sCOOKIE : string;
Cookie : word;
WorkAddress : string;
WorkPort : integer;
log,mess : text;
const
isLogged : boolean = false;
isAuth : boolean = true;
isHDR : boolean = true;
HeadFIFO : PFLAP_Item = nil;
implementation
{$R *.DFM}
(****************************************************************)
procedure TForm1.PacketSend(p:PPack);
begin
SetLengthPacket(p);
CLI.socket.sendbuf(p^.data,p^.length);
debugFILE(p,'>');
PacketDelete(p);
end;
(****************************************************************)
procedure TForm1.ConnectMode(Mode : boolean);
begin
case Mode of
true: begin
isLogged := true;
case ICQStatus of
STATE_ONLINE: StatusBtn.Caption := 'online';
STATE_AWAY: StatusBtn.Caption := 'away';
STATE_DND: StatusBtn.Caption := 'dnd';
STATE_OCCUPIED: StatusBtn.Caption := 'occupied';
STATE_FREEFORCHAT: StatusBtn.Caption := 'freeforchat';
STATE_N_A: StatusBtn.Caption := 'na';
STATE_INVISIBLE: StatusBtn.Caption := 'invisible';
else StatusBtn.Caption := 'offline';
end;
end;
false: begin
If CLI.Active then CLI.Close;
ClearFIFO;
isLogged := false;
StatusBtn.Caption := 'offline';
end;
end;
end;
(****************************************************************)
procedure TForm1.FormCreate(Sender: TObject);
begin
InitUser;
InitLogs;
end;
(****************************************************************)
procedure TForm1.debugFILE(tmp:PPack; Direction:char);
begin
writeln(log,DateTimeToStr(Now)+' =================================');
writeln(log,Direction+'FLAP: '+inttohex(tmp^.Sign,2)+' '+
inttohex(tmp^.ChID,2)+' '+inttohex(swap(tmp^.SEQ),4)+' '+
inttohex(swap(tmp^.Len),4)+' '+'['+inttostr(swap(tmp^.Len))+']');
writeln(log,Direction+'SNACK: $'+inttohex(swap(tmp^.SNAC.FamilyID),4)+
':'+inttohex(swap(tmp^.SNAC.SubTypeID),4)+
' flags:$'+inttohex(swap(word(tmp^.SNAC.Flags)),4)+
' ref:$'+inttohex(DSwap(tmp^.SNAC.RequestID),8));
writeln(log,Dim2Str(@(tmp^.FLAP_BODY),swap(tmp^.FLAP.Len)));
writeln(log,Dim2Hex(@(tmp^.FLAP_BODY),swap(tmp^.FLAP.Len)));
writeln(log,'');
end;
(****************************************************************)
procedure TForm1.CLIDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
M(Memo,'Disconnected: '+Socket.RemoteAddress);
end;
(****************************************************************)
procedure TForm1.CLIConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
M(Memo,'Connected: '+Socket.RemoteAddress);
end;
(****************************************************************)
procedure TForm1.CLI_ReadData(Sender: TObject; Socket: TCustomWinSocket);
var num,Bytes,fact : integer;
pFIFO,CurrFIFO : PFLAP_Item;
buf : array[0..100] of byte;
begin
num := Socket.ReceiveLength;
if isHDR then begin
if num>=6 then begin
Socket.ReceiveBuf(FLAP,6);
NeedBytes := swap(FLAP.Len);
Index := 0;
isHDR := not isHDR;
end else begin
M(memo,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
Socket.ReceiveBuf(buf,num);
M(Memo,Dim2Hex(@(buf),num));
M(memo,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
end;
end else begin
Bytes := NeedBytes;
fact := Socket.ReceiveBuf(FLAP_DATA[Index],Bytes);
inc(Index,fact);
dec(NeedBytes,fact);
if NeedBytes = 0 then begin
New(pFIFO);
pFIFO^.FLAP := FLAP;
pFIFO^. := nil;
GetMem(pFIFO^.DATA,Index);
move(FLAP_DATA,PFIFO^.Data^,swap(FLAP.Len));
// AddToLast
CurrFIFO:=HeadFIFO;
if HeadFIFO<>nil then begin
while CurrFIFO<>nil do
if CurrFIFO^.=nil then begin
CurrFIFO^.:=pFIFO;
break;
end else CurrFIFO:=CurrFIFO^.;
end else HeadFIFO:=pFIFO; // list is empty
isHDR := not isHDR;
end;
end;
end;
(****************************************************************)
procedure TForm1.MainTTimer(Sender: TObject);
var FindFIFO : PFLAP_Item;
tmp : PPack;
begin
MainT.Enabled := false;
while HeadFIFO<>nil do begin
// Get HeadFIFO
FindFIFO := HeadFIFO;
if HeadFIFO^.=nil then HeadFIFO := nil
else HeadFIFO := HeadFIFO^.;
// creating new packet
tmp := PacketNew;
// Fill the packet
PacketAppend(tmp,@FindFIFO^.FLAP,sizeof(FLAP_HDR));
PacketAppend(tmp,FindFIFO^.DATA,swap(FindFIFO^.FLAP.Len));
// Release packet`s memory
FreeMem(FindFIFO^.DATA,swap(FindFIFO^.FLAP.Len));
Dispose(FindFIFO);
//
debugFILE(tmp,'<');
if isAuth then AuthorizePart(tmp)
else WorkPart(tmp);
// Deleting packet
PacketDelete(tmp);
end;
MainT.Enabled := true;
end;
(****************************************************************)
procedure TForm1.AuthorizePart(p:PPack);
var ss : string;
T : integer;
tmp : PPack;
begin
PacketGoto(p,sizeof(FLAP_HDR)); // goto FLAP_DATA
// Authorize Server ACK
if (swap(p^.Len)=4)and
(swap(p^.SNAC.FamilyID)=0)and
(swap(p^.SNAC.SubTypeID)=1) then begin
M(Memo,'<Authorize Server CONNECT');
// Auth Request (Login)
SEQ := random($7FFF);
tmp := CreatePacket(1,SEQ);
PacketAppend32(tmp,DSwap(1));
TLVAppendStr(tmp,$1,s(UIN));
TLVAppendStr(tmp,$2,Calc_Pass(PASSWORD));
TLVAppendStr(tmp,$3,'ICQ Inc. - Product of ICQ (TM).2000a.4.31.1.3143.85');
TLVAppendWord(tmp,$16,$010A);
TLVAppendWord(tmp,$17,$0004); // for 2000a
TLVAppendWord(tmp,$18,$001F);
TLVAppendWord(tmp,$19,$0001);
TLVAppendWord(tmp,$1A,$0C47);
TLVAppendDWord(tmp,$14,$00000055);
TLVAppendStr(tmp,$0F,'en');
TLVAppendStr(tmp,$0E,'us');
PacketSend(tmp);
M(Memo,'>Auth Request (Login)');
end else // Auth Response (COOKIE or ERROR)
if (TLVReadStr(p,ss)=1){and(ss=s(UIN))}then begin
T := TLVReadStr(p,ss);
case T of
5: begin // BOS-IP:PORT
M(Memo,'<Auth Responce (COOKIE)');
WorkAddress := copy(ss,1,pos(':',ss)-1);
WorkPort := strtoint(copy(ss,pos(':',ss)+1,length(ss)-pos(':',ss)));
if (TLVReadStr(p,sCOOKIE)=6)then begin;;;;
// Empty packet for disconnect
tmp:=CreatePacket(4,SEQ); // ChID=4
PacketSend(tmp);
// Disconnect from Autorize Server
OfflineDiscconnect1Click(self);
isAuth := false;
// Connecting to BOS
CLI.Address := WorkAddress;
CLI.Host := '';
CLI.Port := WorkPort;
M(Memo,'');
M(Memo,'>>> Connecting to BOS: '+ss);
CLI.Open;
end;
end;
4,8: begin
M(Memo,'<Auth ERROR');
M(Memo,'TLV($'+inttohex(T,2)+') ERROR');
M(Memo,'STRING: '+ss);
if pos('http://',ss)>0 then begin
end;
TLVReadStr(p,ss); M(Memo,ss);
OfflineDiscconnect1Click(self);
M(Memo,'');
end;
end;
end;
end;
(****************************************************************)
procedure TForm1.WorkPart(p:PPack);
var ss,ss2,sErr : string;
// T : integer;
tmp : PPack;
i : integer;
begin
if p^.FLAP.ChID = 4 then begin // SERVER GONNA DISCONNECT
PacketGoto(p,sizeof(FLAP_HDR));
TLVReadStr(p,ss); M(Memo,ss);
TLVReadStr(p,ss2); M(Memo,ss2);
OfflineDiscconnect1Click(self);
sErr:='Str1: ';
for i:=1 to length(ss) do sErr:=sErr+inttohex(byte(ss[i]),2)+' ';
sErr:=sErr+#13#10+'Str2: '+ss2+#13#10+#13#10;
ShowMessage('Another Computer Use YOUR UIN!'#13#10+#13#10+
sErr+'...i gonna to disconnect');
exit;
end;
PacketGoto(p,sizeof(FLAP_HDR)+sizeof(SNAC_HDR));
// BOS Connection ACK
if (swap(p^.Len)=4)and
(swap(p^.SNAC.FamilyID)=0)and
(swap(p^.SNAC.SubTypeID)=1) then begin
M(Memo,'<BOS connection ACK');
// BOS Sign-ON (COOKIE)
SEQ := random($7FFF);
tmp := CreatePacket(1,SEQ);
PacketAppend32(tmp,DSwap(1));
TLVAppendStr(tmp,$6,sCOOKIE);
PacketSend(tmp);
M(Memo,'>BOS Sign-ON (COOKIE)');
end else // BOS-Host ready
if (swap(p^.SNAC.FamilyID)=1)and
(swap(p^.SNAC.SubTypeID)=3) then begin
M(Memo,'<BOS-Host ready');
// I`m ICQ client, not AIM
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$17);
PacketAppend32(tmp,dswap($00010003));
PacketAppend32(tmp,dswap($00020001));
PacketAppend32(tmp,dswap($00030001));
PacketAppend32(tmp,dswap($00150001));
PacketAppend32(tmp,dswap($00040001));
PacketAppend32(tmp,dswap($00060001));
PacketAppend32(tmp,dswap($00090001));
PacketAppend32(tmp,dswap($000A0001));
PacketSend(tmp);
M(Memo,'>"I`m ICQ client, not AIM"');
end else // ACK to "I`m ICQ Client"
if (swap(p^.SNAC.FamilyID)=$1)and // ACK
(swap(p^.SNAC.SubTypeID)=$18) then begin
M(Memo,'<ACK to "I`m ICQ client"');
// Rate Information Request
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$6);
PacketSend(tmp);
M(Memo,'>Rate Information Request');
end else // Rate Information Response
if (swap(p^.SNAC.FamilyID)=$1)and
(swap(p^.SNAC.SubTypeID)=$7) then begin
M(Memo,'<Rate Information Response');
// ACK to Rate Information Response
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$8);
PacketAppend32(tmp,DSwap($00010002));
PacketAppend32(tmp,DSwap($00030004));
PacketAppend16(tmp,Swap($0005));
PacketSend(tmp);
M(Memo,'>ACK to Rate Response');
// Request Personal Info
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$0E);
PacketSend(tmp);
M(Memo,'>Request Personal Info');
// Request Rights for Location service
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$2,$02);
PacketSend(tmp);
M(Memo,'>Request Rights for Location service');
// Request Rights for Buddy List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$3,$02);
PacketSend(tmp);
M(Memo,'>Request Rights for Buddy List');
// Request Rights for ICMB
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$4,$04);
PacketSend(tmp);
M(Memo,'>Request Rights for ICMB');
// Request BOS Rights
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$02);
PacketSend(tmp);
M(Memo,'>Request BOS Rights');
end else // Personal Information
if (swap(p^.SNAC.FamilyID)=$1)and
(swap(p^.SNAC.SubTypeID)=$F) then begin
M(Memo,'<Personal Information');
end else // Rights for location service
if (swap(p^.SNAC.FamilyID)=$2)and
(swap(p^.SNAC.SubTypeID)=$3) then begin
M(Memo,'<Rights for location service');
end else // Rights for byddy list
if (swap(p^.SNAC.FamilyID)=$3)and
(swap(p^.SNAC.SubTypeID)=$3) then begin
M(Memo,'<Rights for byddy list');
end else // Rights for ICMB
if (swap(p^.SNAC.FamilyID)=$4)and
(swap(p^.SNAC.SubTypeID)=$5) then begin
M(Memo,'<Rights for ICMB');
end else // BOS Rights
if (swap(p^.SNAC.FamilyID)=$9)and
(swap(p^.SNAC.SubTypeID)=$3) then begin
M(Memo,'<BOS Rights');
// Set ICMB parameters
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$4,$2);
PacketAppend16(tmp,swap($0));
PacketAppend32(tmp,dswap($3));
PacketAppend16(tmp,swap($1F40));
PacketAppend16(tmp,swap($03E7));
PacketAppend16(tmp,swap($03E7));
PacketAppend16(tmp,swap($0));
PacketAppend16(tmp,swap($0));
PacketSend(tmp);
M(Memo,'>Set ICMB parameters');
// Set User Info (capability)
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$2,$4); // tlv(5)=capability
TLVAppendStr(tmp,5,#$09#$46#$13#$49#$4C#$7F#$11#$D1+
#$82#$22#$44#$45#$53#$54#$00#$00+
#$09#$46#$13#$44#$4C#$7F#$11#$D1+
#$82#$22#$44#$45#$53#$54#$00#$00);
PacketSend(tmp);
M(Memo,'>Set User Info (capability)');
// Send Contact List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$3,$4);
PacketAppendB_String(tmp,s(UIN));
// PacketAppendB_String(tmp,s(someUIN));
PacketSend(tmp);
M(Memo,'>Send Contact List (1)');
case ICQStatus of
STATE_INVISIBLE: begin
// Send Visible List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$5);
PacketSend(tmp);
M(Memo,'>Send Visible List (0)');
end;
else begin
// Send Invisible List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$7);
PacketSend(tmp);
M(Memo,'>Send Invisible List (0)');
end;
end;//case
ConnectMode(true);
SetStatus(ICQStatus);
M(Memo,'>Set Status Code');
// Client Ready
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$2);
PacketAppend32(tmp,dswap($00010003));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00020001));
PacketAppend32(tmp,dswap($0101028A));
PacketAppend32(tmp,dswap($00030001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00150001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00040001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00060001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00090001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($000A0003));
PacketAppend32(tmp,dswap($0110028A));
PacketSend(tmp);
M(Memo,'>Client Ready');
// Get offline messages
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$15,$2);
PacketAppend32(tmp,dswap($0001000A));
PacketAppend16(tmp,swap($0800));
PacketAppend32(tmp,UIN);
PacketAppend16(tmp,swap($3C00));
PacketAppend16(tmp,swap($0200));
PacketSend(tmp);
M(Memo,'>Get offline messages');
// Get Banner Address
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$15,$2);
PacketAppend16(tmp,swap($0001));
ss:='<key>BannersIP</key>';
PacketAppend16(tmp,swap(14+length(ss)+1));
PacketAppend16(tmp,swap($2100));
PacketAppend32(tmp,UIN);
PacketAppend16(tmp,swap($D007)); // Type
PacketAppend16(tmp,swap($0300)); // Cookie
PacketAppend16(tmp,swap($9808)); // SubType = xml-style (LNTS)
PacketAppendString(tmp,ss); // '<key>BannersIP</key>'
PacketSend(tmp);
M(Memo,'>Get Banner Address');
end else // Reject notification
if (swap(p^.SNAC.FamilyID)=$3)and
(swap(p^.SNAC.SubTypeID)=$0A) then begin
M(Memo,'');
M(Memo,'<Reject from UIN: '+PacketReadB_String(p));
M(Memo,'');
end else // UIN ON-line
if (swap(p^.SNAC.FamilyID)=$3)and
(swap(p^.SNAC.SubTypeID)=$0B) then begin
M(Memo,'');
ShowUserONStatus(p);
M(Memo,'');
end else // UIN OFF-line ???
if (swap(p^.SNAC.FamilyID)=$3)and
(swap(p^.SNAC.SubTypeID)=$0C) then begin
M(Memo,'');
M(Memo,'<UIN OFF-line: '+PacketReadB_String(p));
M(Memo,'');
end else // SNAC 15,3 Meny purposes (offlines messages)
if (swap(p^.SNAC.FamilyID)=$15)and
(swap(p^.SNAC.SubTypeID)=$3) then begin
M(Memo,'');
SNAC_15_3(p);
M(Memo,'');
end else // SNAC 4,7 Incoming message
if (swap(p^.SNAC.FamilyID)=$4)and
(swap(p^.SNAC.SubTypeID)=$7) then begin
M(Memo,'');
SNAC_4_7(p);
M(Memo,'');
end else begin
M(Memo,'');
M(Memo,'???? Unrecognized SNAC: ????????');
M(Memo,'???? SNAC [$'+inttohex(swap(p^.SNAC.FamilyID),2)+':$'+
inttohex(swap(p^.SNAC.SubTypeID),2)+']');
M(Memo,'');
end;
end;
(****************************************************************)
procedure TForm1.ShowUserONStatus(p:PPack);
var T : word;
k,cnt : integer;
UINonline,TLV : string;
r_ip,r_r_ip,r_status : longint;
begin
UINonline := PacketReadB_String(p);
M(Memo,'<UIN ON-line: '+UINonline);
PacketRead16(p);
cnt := swap(PacketRead16(p));
for k:=1 to cnt do begin
T := TLVReadStr(p,TLV);
case T of
6: begin // STATUS
move(TLV[1],IPArray(r_status),4);
r_status := DSwap(r_status);
M(Memo,'#'+s(k)+' TLV($'+inttohex(T,2)+')'+
' STATUS: $'+inttohex(r_status,8));
end;
$A: begin // IP
move(TLV[1],IPArray(r_ip),4);
M(Memo,'#'+s(k)+' TLV($'+inttohex(T,2)+')'+
' IP: '+IPToStr(IPArray(r_ip)));
end;
$C: begin // REAL_IP
move(TLV[1],IPArray(r_r_ip),4);
M(Memo,'#'+s(k)+' TLV($'+inttohex(T,2)+')'+
' Real IP: '+IPToStr(IPArray(r_r_ip)));
end;
//else M(Memo,'??? #'+s(k)+' TLV($'+inttohex(T,2)+')');
end;
end;
end;
(****************************************************************)
procedure TForm1.SNAC_15_3(p:PPack);
var MessageType : word;
{myUIN,}hisUIN : longint;
SubType : array[0..3] of byte;
MessageSubType : longint absolute SubType;
year,month,day,hour,minute,typemes,{subtypemes,}lenmes : word;
tmp : PPack;
sTemp,URL : string;
begin
PacketRead32(p);
PacketRead16(p);
{myUIN := }PacketRead32(p);
MessageType := swap(PacketRead16(p));
{Cookie := }swap(PacketRead16(p));
//M(Memo,'<Cookie: $'+inttohex(Cookie,4));
case MessageType of
$DA07: begin
SubType[3] := 0;
SubType[2] := PacketRead8(p);
SubType[1] := PacketRead8(p);
SubType[0] := PacketRead8(p);
if(MessageSubType and $FF)<>$0A then begin
M(Memo,'<FAIL: SubType:$'+inttohex(MessageSubType,4));
end;
case MessageSubType of
$A2080A: begin // Banner URL
sTemp := PacketReadString(p);
sTemp[pos('<',sTemp)] :='_';
URL := 'http://'+copy(sTemp,pos('>',sTemp)+1,pos('<',sTemp)-pos('>',sTemp)-1);
M(Memo,'<Banner HTML-Server: '+URL);
end;
else M(Memo,'<??? SNAC 15,3; Type:$DA07; SubType: $'+inttohex(MessageSubType,6));
end;//
end;
$4200: begin // END of offline messages
//M(Memo,'<Message-Type: $'+inttohex(MessageType,4));
M(Memo,'<End of OFFline messages');
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$15,$2);
PacketAppend16(tmp,swap($0001)); // TLV(1)
PacketAppend32(tmp,dswap($000A0800));
PacketAppend32(tmp,UIN);
PacketAppend16(tmp,swap($3E00)); // ACK
PacketAppend16(tmp,swap($0200));
PacketSend(tmp);
//M(Memo,'>ACK it');
end;
$4100: begin // OFFLINE MESSAGE
hisUIN := PacketRead32(p); // LE
//M(Memo,'<Message-Type: $'+inttohex(MessageType,4));
M(Memo,'<OFFLINE MESSAGE from UIN: '+s(hisUIN));
year := PacketRead16(p);
month := PacketRead8(p);
day := PacketRead8(p);
hour := PacketRead8(p);
minute := PacketRead8(p);
typemes := PacketRead8(p);
{subtypemes := }PacketRead8(p);
lenmes := PacketRead16(p);
DoMsg(false,typemes,lenmes,PCharArray(@(p^.data[p^.cursor])),
hisUIN,UTC2LT(year,month,day,hour,minute));
end;
else M(Memo,'<??? SNAC 15,3; Type: $'+inttohex(MessageType,4));
end;//case
end;
(****************************************************************)
procedure TForm1.SNAC_4_7(p:PPack); // INCOMING MESSAGES
var i,cnt,T,MessageFormat,SubMode,SubMode2,Empty : word;
{myUIN,}hisUIN : longint;
SubType : array[0..3] of byte;
MessageSubType : longint absolute SubType;
tmp,tmp2,tmp3 : PPack;
sTemp : string;
dTemp : TByteArray;
typemes,{subtypemes,}unk,modifier,lenmes : word;
//for snac 4,0B (ack for msg-2 type)
d1,d2 : longint;
ACK : TByteArray;
ind : word;
begin
d1:=PacketRead32(p);
d2:=PacketRead32(p);
MessageFormat := swap(PacketRead16(p));
sTemp := PacketReadB_String(p);
ind:=0;
PLONG(@(ACK[ind]))^:=d1; inc(ind,4);
PLONG(@(ACK[ind]))^:=d2; inc(ind,4);
PWORD(@(ACK[ind]))^:=swap(MessageFormat);inc(ind,2);
PBYTE(@(ACK[ind]))^:=length(sTemp);inc(ind,1);
MOVE(sTemp[1],ACK[ind],length(sTemp));inc(ind,length(sTemp));
PWORD(@(ACK[ind]))^:=swap($0003);inc(ind,2);
try hisUIN := strtoint(sTemp); except hisUIN:=0; end;
M(Memo,'<From: '+sTemp);
PacketRead16(p); //warning level? garbage of OSCAR protocol
cnt := swap(PacketRead16(p)); // num of TLVs
for i:=1 to cnt do
if TLVReadStr(p,sTemp)=6 then begin { this is a HIS STATUS } end;
case MessageFormat of
$0001: begin
//M(Memo,'<Message-format: 1 (SIMPLY message)');
TLVReadStr(p,sTemp);
// copy TLV(2) to TMP
tmp := PacketNew;
PacketAppend(tmp,@(sTemp[1]),length(sTemp));
PacketGoto(tmp,0); // goto !!!!!
// work it
PacketRead16(tmp);
PacketRead16(tmp);
PacketRead8(tmp);
PacketRead16(tmp);
lenmes := swap(PacketRead16(tmp))-4;
PacketRead32(tmp);
PacketRead(tmp,@sTemp[1],lenmes);
SetLength(sTemp,lenmes);
DoSimpleMsg(hisUIN,sTemp);
// delete TMP
PacketDelete(tmp);
end;
$0002: begin
//M(Memo,'<Message-format: 2 (ADVANCED message)');
TLVReadStr(p,sTemp);
// copy TLV(5) to TMP
tmp := PacketNew;
PacketAppend(tmp,@(sTemp[1]),length(sTemp));
PacketGoto(tmp,0); // goto !!!!!
// work it
SubMode := swap(PacketRead16(tmp));
PacketRead32(tmp);
PacketRead32(tmp);
PacketRead(tmp,@dTemp,16); //capability 16 bytes
case SubMode of
$0000: begin
//M(Memo,'SubMode: $0000 NORMAL');
{T := }TLVReadWord(tmp,SubMode2);// 0001-normal 0002-file reply
TLVReadWord(tmp,Empty);// TLV(F) empty
T := TLVReadStr(tmp,sTemp);
if T=$2711 then begin
MOVE(sTemp[1],ACK[ind],47);inc(ind,47);
PLONG(@(ACK[ind]))^:=0; inc(ind,4);
//******************************************
tmp2 := PacketNew;
PacketAppend(tmp2,@(sTemp[1]),length(sTemp));
PacketGoto(tmp2,0); // goto !!!!!
PacketRead(tmp2,@dTemp,26);
PacketRead8(tmp2);
PacketRead16(tmp2);
PacketRead16(tmp2);
PacketRead16(tmp2);
PacketRead(tmp2,@dTemp,12);
typemes := PacketRead8(tmp2);
{subtypemes := }PacketRead8(tmp2);
unk:=swap(PacketRead16(tmp2));//0200
modifier:=swap(PacketRead16(tmp2));//0100
M(Memo,'Unk: $'+inttohex(unk,4));
M(Memo,'Modifier: $'+inttohex(modifier,4));
lenmes := PacketRead16(tmp2);
DoMsg(true,typemes,lenmes,PCharArray(@(tmp2^.data[tmp2^.cursor])),
hisUIN,Now2DateTime);
// delete TMP2
PacketDelete(tmp2);
PWORD(@(ACK[ind]))^:=1; inc(ind,2);
PBYTE(@(ACK[ind]))^:=0; inc(ind,1);
PLONG(@(ACK[ind]))^:=0; inc(ind,4);
PLONG(@(ACK[ind]))^:=-1; inc(ind,4);
// Sending Ack
tmp3 := CreatePacket($2,SEQ);
SNACAppend(tmp3,$4,$0B);
PacketAppend(tmp3,@ACK[0],ind);
PacketSend(tmp3);
//******************************************
end;// IF
end; //Submode:$0000
$0001: M(Memo,'SubMode:$0001 ??? message canceled ???');
$0002: M(Memo,'SubMode:$0002 FILE-ACK (not yet)');
end;//case SubMode
// delete TMP
PacketDelete(tmp);
end;
$0004: begin
//M(Memo,'<Message-format: 4 (url or contacts or auth-req or userAddedYou)');
TLVReadStr(p,sTemp);
// copy TLV(5) to TMP
tmp := PacketNew;
PacketAppend(tmp,@(sTemp[1]),length(sTemp));
PacketGoto(tmp,0); // goto !!!!!
// work it
hisUIN := PacketRead32(tmp);
typemes := PacketRead8(tmp);
{subtypemes := }PacketRead8(tmp);
lenmes := PacketRead16(tmp);
DoMsg(true,typemes,lenmes,PCharArray(@(tmp^.data[tmp^.cursor])),
hisUIN,Now2DateTime);
// delete TMP
PacketDelete(tmp);
end;
else M(Memo,'<??? SNAC 4,7; Message-format: '+s(MessageFormat));
end;//case MessageFormat
end;
(****************************************************************)
procedure TForm1.DoMsg(on_off:boolean;typemes,lenmes:integer; data:PCharArray; r_uin:longint; DateTime:TDateTime);
var i,pos1,pos2 : integer;
sTemp,sLog,sNN,sDT : string;
LTemp : array[1..6] of string;
begin
if (lenmes-1)=0 then exit;
setlength(sTemp,lenmes-1); // -1 for final string char #0
move(data^,sTemp[1],lenmes-1);
for i:=1 to 6 do LTemp[i]:='';
if (typemes <> TYPE_MSG)and(typemes<>0) then begin
if sTemp[length(sTemp)]<>#$FE then sTemp:=sTemp+#$FE;
pos2:=0;
for i:=1 to 6 do begin
pos1 := pos2+1;
pos2 := pos(#$FE,sTemp);
if pos2 = 0 then break;
LTemp[i] := copy(sTemp,pos1,pos2-pos1);
sTemp[pos2] := #$FF;
end;
end;
sNN := '';
case on_off of
true: sDT := '<-[A] ';
false: sDT := '<-[O] ';
end;
sDT := sDT+DateTimeToStr(DateTime)+' ';
case typemes of
0,TYPE_MSG:
FmtStr(sLog,sNN+' ['+s(r_uin)+'] "%s"',[sTemp]);
TYPE_ADDED:
FmtStr(sLog,'UIN:%d has added you to their contact list.'+
'Nick:%s FName:%s LName:%s E-mail:%s',
[r_uin,LTemp[1],LTemp[2],LTemp[3],LTemp[4]]);
TYPE_AUTH_REQ:
FmtStr(sLog,'UIN:%d has requested your authorization.'+
'Nick:%s FName:%s LName:%s E-mail:%s '#13#10'Reason:"%s"',
[r_uin,LTemp[1],LTemp[2],LTemp[3],LTemp[4],LTemp[6]]);
TYPE_URL:
FmtStr(sLog,'URL: UIN:%d, '#13#10'URL:%s, '#13#10'Description:"%s"',
[r_uin,LTemp[2],LTemp[1]]);
TYPE_WEBPAGER:
FmtStr(sLog,'WebPager: UIN:%d, Nick:%s, EMail:%s, '#13#10'"%s"',
[r_uin,LTemp[1],LTemp[4],LTemp[6]]);
TYPE_EXPRESS:
FmtStr(sLog,'MailExpress: UIN:%d, Nick:%s, EMail:%s, '#13#10'"%s"',
[r_uin,LTemp[1],LTemp[4],LTemp[6]]);
else FmtStr(sLog,'Instant message type %d from UIN:%d, '#13#10'Message:"%s"',
[typemes,r_uin,sTemp]);
end;//case
sLog := sDT+sLog;
M(Memo,sLog); LogMessage(sLog);
end;
(****************************************************************)
procedure TForm1.DoSimpleMsg(r_uin:longint; Text:string);
var sLog : string;
begin
sLog:= '<-[S] '+DateTimeToStr(Now)+' '+'['+s(r_uin)+'] "'+Text+'"';
M(Memo,sLog); LogMessage(sLog);
end;
(****************************************************************)
procedure TForm1.SetStatus(Status:longint);
var tmp : PPack;
begin
ICQStatus := Status;
// Set Status Code
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$1E);
TLVAppendDWord(tmp,6,ICQStatus);
TLVAppendWord(tmp,8,$0000);
// imitation TLV(C)
PacketAppend32(tmp,dswap($000C0025)); // TLV(C)
StrToIP(Get_my_IP,DIM_IP);
PacketAppend(tmp,@DIM_IP,4); // IP address
PacketAppend32(tmp,dswap(28000+random(1000)));// Port
PacketAppend8(tmp,$04);
PacketAppend16(tmp,swap($0007));
PacketAppend16(tmp,swap($466B));
PacketAppend16(tmp,swap($AE68));
PacketAppend32(tmp,dswap($00000050));
PacketAppend32(tmp,dswap($00000003));
PacketAppend32(tmp,dswap(SecsSince1970));
PacketAppend32(tmp,dswap(SecsSince1970));
PacketAppend32(tmp,dswap(SecsSince1970));
PacketAppend16(tmp,swap($0000));
PacketSend(tmp);
case ICQStatus of
STATE_ONLINE: StatusBtn.Caption := 'online';
STATE_AWAY: StatusBtn.Caption := 'away';
STATE_DND: StatusBtn.Caption := 'dnd';
STATE_OCCUPIED: StatusBtn.Caption := 'occupied';
STATE_FREEFORCHAT: StatusBtn.Caption := 'freeforchat';
STATE_N_A: StatusBtn.Caption := 'na';
STATE_INVISIBLE: StatusBtn.Caption := 'invisible';
else StatusBtn.Caption := 'offline';
end;
end;
(****************************************************************)
procedure TForm1.StatusChange(Status:longint);
var tmp : PPack;
begin
if(not OL)then begin
Get_My_IP;
if not OL then begin
M(Memo,'OFF-line');
exit;
end;
end;
if (not CLI.Active) then icq_Login(Status)
else if (not isLogged) then exit // logging now ...
else begin
ICQStatus := Status;
case ICQStatus of
STATE_INVISIBLE: begin
// Send Visible List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$5);
PacketSend(tmp);
M(Memo,'>Send Visible List (0)');
end;
else begin
// Send Invisible List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$7);
PacketSend(tmp);
M(Memo,'>Send Invisible List (0)');
end;
end;//case
// Set Status Code
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$1E);
TLVAppendDWord(tmp,6,ICQStatus);
PacketSend(tmp);
case ICQStatus of
STATE_ONLINE: StatusBtn.Caption := 'online';
STATE_AWAY: StatusBtn.Caption := 'away';
STATE_DND: StatusBtn.Caption := 'dnd';
STATE_OCCUPIED: StatusBtn.Caption := 'occupied';
STATE_FREEFORCHAT: StatusBtn.Caption := 'freeforchat';
STATE_N_A: StatusBtn.Caption := 'na';
STATE_INVISIBLE: StatusBtn.Caption := 'invisible';
else StatusBtn.Caption := 'offline';
end;
end;
end;
(****************************************************************)
procedure TForm1.OnlineConnected1Click(Sender: TObject);
begin
StatusChange(STATE_ONLINE);
end;
(****************************************************************)
procedure TForm1.Away1Click(Sender: TObject);
begin
StatusChange(STATE_AWAY);
end;
(****************************************************************)
procedure TForm1.DNDDoNotDisturb1Click(Sender: TObject);
begin
StatusChange(STATE_DND);
end;
(****************************************************************)
procedure TForm1.PrivacyInvisible1Click(Sender: TObject);
begin
StatusChange(STATE_INVISIBLE);
end;
(****************************************************************)
procedure TForm1.OfflineDiscconnect1Click(Sender: TObject);
begin
ConnectMode(false);
end;
(****************************************************************)
procedure TForm1.OccupiedUrgentMsgs1Click(Sender: TObject);
begin
StatusChange(STATE_OCCUPIED);
end;
(****************************************************************)
procedure TForm1.FreeForChat1Click(Sender: TObject);
begin
StatusChange(STATE_FREEFORCHAT);
end;
(****************************************************************)
procedure TForm1.NAExtendedAway1Click(Sender: TObject);
begin
StatusChange(STATE_N_A);
end;
(****************************************************************)
procedure TForm1.icq_Login(Status : longint);
begin
randomize;
SEQ := random($7FFF);
Local_IP := Get_my_IP;
StrToIP(Local_IP,DIM_IP);
ICQStatus := status;
if CLI.Active then CLI.Close;
isAuth := true;
isHDR := true;
CLI.Address :='';
CLI.Host := 'login.icq.com';
CLI.Port := 5190;
M(Memo,'>>>>>>>>>> login.icq.com:5190 <<<<<<<<<<<');
CLI.Open;
end;
(****************************************************************)
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
OfflineDiscconnect1Click(self);
CloseLogs;
end;
(****************************************************************)
procedure TForm1.InitLogs;
begin
assignfile(mess,s(UIN)+'.mes');
try if FileExists(s(UIN)+'.mes') then append(mess)
else rewrite(mess);
M(Memo,DateTimeToStr(Now));
except end;
assignfile(log,s(UIN)+'.log');
try if FileExists(s(UIN)+'.log') then append(log)
else rewrite(log);
except end;
end;
(****************************************************************)
procedure TForm1.CloseLogs;
begin
try closefile(mess); except end;
try closefile(log); except end;
end;
(****************************************************************)
procedure TForm1.LogMessage(s:string);
begin
try writeln(mess,s); except end;
end;
(****************************************************************)
procedure TForm1.InitUser;
var cfg : TIniFile;
begin
cfg := TIniFile.Create(ExtractFilePath(ParamStr(0))+'nICQ.ini');
try
UIN := cfg.ReadInteger('User','Uin',0);
NICK := cfg.ReadString('User','Nick','');
PASSWORD := cfg.ReadString('User','Password','');
finally cfg.Free; end;
Caption := NICK+' : '+s(UIN);
end;
(****************************************************************)
procedure TForm1.ClearFIFO;
var Find : PFLAP_Item;
begin
repeat
Find := HeadFIFO;
if HeadFIFO<>nil then begin
if HeadFIFO^.<>nil then
HeadFIFO := HeadFIFO^.
else HeadFIFO := nil;
end;
if Find<>nil then begin
FreeMem(Find^.DATA,swap(Find^.FLAP.Len));
Dispose(Find);
end;
until Find=nil;
end;
(****************************************************************)
procedure TForm1.StatusBtnClick(Sender: TObject);
begin
StatusMenu.Popup(Left+Width-20,+Height-50);
end;
end.
Author: Alexander Vaga
EMail: alexander_vaga@hotmail.com
Creation: May, 2002
Legal issues: Copyright (C) 2002 by Alexander Vaga
Kyiv, Ukraine
This software is provided 'as-is', without any express or
implied warranty. In no event will the author be held liable
for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it
and redistribute it freely.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{$A-,B+,C+,D+,E-,F-,G+,H+,I+,J+,K-,L+,M+,N+,O-,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1}
unit Main;
interface
uses
Windows, Messages, SysUtils, Graphics,
Forms, Dialogs, ComCtrls, Buttons, ToolWin,
ExtCtrls, Menus, ImgList, ScktComp, Controls,
StdCtrls, Classes, inifiles,
Types, Packet;
type
TForm1 = class(TForm)
MainT: TTimer;
StatusMenu: TPopupMenu;
OnlineConnected1: TMenuItem;
FreeForChat1: TMenuItem;
sep1: TMenuItem;
Away1: TMenuItem;
NAExtendedAway1: TMenuItem;
sep2: TMenuItem;
OccupiedUrgentMsgs1: TMenuItem;
DNDDoNotDisturb1: TMenuItem;
sep3: TMenuItem;
PrivacyInvisible1: TMenuItem;
OfflineDiscconnect1: TMenuItem;
Panel1: TPanel;
Panel3: TPanel;
Splitter1: TSplitter;
CLI: TClientSocket;
BG: TPanel;
Memo: TMemo;
StatusBtn: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure InitUser;
procedure InitLogs;
procedure CloseLogs;
procedure ConnectMode(Mode : boolean);
procedure MainTTimer(Sender: TObject);
procedure OnlineConnected1Click(Sender: TObject);
procedure Away1Click(Sender: TObject);
procedure DNDDoNotDisturb1Click(Sender: TObject);
procedure PrivacyInvisible1Click(Sender: TObject);
procedure OfflineDiscconnect1Click(Sender: TObject);
procedure OccupiedUrgentMsgs1Click(Sender: TObject);
procedure FreeForChat1Click(Sender: TObject);
procedure NAExtendedAway1Click(Sender: TObject);
procedure CLIConnect(Sender: TObject; Socket: TCustomWinSocket);
procedure CLI_ReadData(Sender: TObject; Socket: TCustomWinSocket);
procedure CLIDisconnect(Sender: TObject; Socket: TCustomWinSocket);
procedure PacketSend(p:PPack);
procedure ShowUserONStatus(p:PPack);
procedure SNAC_15_3(p:PPack);
procedure SNAC_4_7(p:PPack);
procedure icq_Login(Status : longint);
procedure SetStatus(Status:longint);
procedure StatusChange(Status:longint);
procedure AuthorizePart(p:PPack);
procedure WorkPart(p:PPack);
procedure DoMsg(on_off:boolean;typemes,lenmes:integer; data:PCharArray; r_uin:longint; DateTime:TDateTime);
procedure DoSimpleMsg(r_uin:longint; Text:string);
procedure ClearFIFO;
procedure debugFILE(tmp:PPack; Direction:char);
procedure LogMessage(s:string);
procedure StatusBtnClick(Sender: TObject);
private{ Private declarations }
public { Public declarations }
protected { Protected declarations }
published { Published declarations }
end;
var Form1 : TForm1;
UIN : longint;
NICK : string;
PASSWORD : string;
ICQStatus : longint;
DIM_IP : IPArray;
Local_IP : string;
Local_Name : string;
SEQ : word;
FLAP : FLAP_HDR;
FLAP_DATA : TByteArray;
Index : integer;
NeedBytes : integer;
sCOOKIE : string;
Cookie : word;
WorkAddress : string;
WorkPort : integer;
log,mess : text;
const
isLogged : boolean = false;
isAuth : boolean = true;
isHDR : boolean = true;
HeadFIFO : PFLAP_Item = nil;
implementation
{$R *.DFM}
(****************************************************************)
procedure TForm1.PacketSend(p:PPack);
begin
SetLengthPacket(p);
CLI.socket.sendbuf(p^.data,p^.length);
debugFILE(p,'>');
PacketDelete(p);
end;
(****************************************************************)
procedure TForm1.ConnectMode(Mode : boolean);
begin
case Mode of
true: begin
isLogged := true;
case ICQStatus of
STATE_ONLINE: StatusBtn.Caption := 'online';
STATE_AWAY: StatusBtn.Caption := 'away';
STATE_DND: StatusBtn.Caption := 'dnd';
STATE_OCCUPIED: StatusBtn.Caption := 'occupied';
STATE_FREEFORCHAT: StatusBtn.Caption := 'freeforchat';
STATE_N_A: StatusBtn.Caption := 'na';
STATE_INVISIBLE: StatusBtn.Caption := 'invisible';
else StatusBtn.Caption := 'offline';
end;
end;
false: begin
If CLI.Active then CLI.Close;
ClearFIFO;
isLogged := false;
StatusBtn.Caption := 'offline';
end;
end;
end;
(****************************************************************)
procedure TForm1.FormCreate(Sender: TObject);
begin
InitUser;
InitLogs;
end;
(****************************************************************)
procedure TForm1.debugFILE(tmp:PPack; Direction:char);
begin
writeln(log,DateTimeToStr(Now)+' =================================');
writeln(log,Direction+'FLAP: '+inttohex(tmp^.Sign,2)+' '+
inttohex(tmp^.ChID,2)+' '+inttohex(swap(tmp^.SEQ),4)+' '+
inttohex(swap(tmp^.Len),4)+' '+'['+inttostr(swap(tmp^.Len))+']');
writeln(log,Direction+'SNACK: $'+inttohex(swap(tmp^.SNAC.FamilyID),4)+
':'+inttohex(swap(tmp^.SNAC.SubTypeID),4)+
' flags:$'+inttohex(swap(word(tmp^.SNAC.Flags)),4)+
' ref:$'+inttohex(DSwap(tmp^.SNAC.RequestID),8));
writeln(log,Dim2Str(@(tmp^.FLAP_BODY),swap(tmp^.FLAP.Len)));
writeln(log,Dim2Hex(@(tmp^.FLAP_BODY),swap(tmp^.FLAP.Len)));
writeln(log,'');
end;
(****************************************************************)
procedure TForm1.CLIDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
M(Memo,'Disconnected: '+Socket.RemoteAddress);
end;
(****************************************************************)
procedure TForm1.CLIConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
M(Memo,'Connected: '+Socket.RemoteAddress);
end;
(****************************************************************)
procedure TForm1.CLI_ReadData(Sender: TObject; Socket: TCustomWinSocket);
var num,Bytes,fact : integer;
pFIFO,CurrFIFO : PFLAP_Item;
buf : array[0..100] of byte;
begin
num := Socket.ReceiveLength;
if isHDR then begin
if num>=6 then begin
Socket.ReceiveBuf(FLAP,6);
NeedBytes := swap(FLAP.Len);
Index := 0;
isHDR := not isHDR;
end else begin
M(memo,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
Socket.ReceiveBuf(buf,num);
M(Memo,Dim2Hex(@(buf),num));
M(memo,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
end;
end else begin
Bytes := NeedBytes;
fact := Socket.ReceiveBuf(FLAP_DATA[Index],Bytes);
inc(Index,fact);
dec(NeedBytes,fact);
if NeedBytes = 0 then begin
New(pFIFO);
pFIFO^.FLAP := FLAP;
pFIFO^. := nil;
GetMem(pFIFO^.DATA,Index);
move(FLAP_DATA,PFIFO^.Data^,swap(FLAP.Len));
// AddToLast
CurrFIFO:=HeadFIFO;
if HeadFIFO<>nil then begin
while CurrFIFO<>nil do
if CurrFIFO^.=nil then begin
CurrFIFO^.:=pFIFO;
break;
end else CurrFIFO:=CurrFIFO^.;
end else HeadFIFO:=pFIFO; // list is empty
isHDR := not isHDR;
end;
end;
end;
(****************************************************************)
procedure TForm1.MainTTimer(Sender: TObject);
var FindFIFO : PFLAP_Item;
tmp : PPack;
begin
MainT.Enabled := false;
while HeadFIFO<>nil do begin
// Get HeadFIFO
FindFIFO := HeadFIFO;
if HeadFIFO^.=nil then HeadFIFO := nil
else HeadFIFO := HeadFIFO^.;
// creating new packet
tmp := PacketNew;
// Fill the packet
PacketAppend(tmp,@FindFIFO^.FLAP,sizeof(FLAP_HDR));
PacketAppend(tmp,FindFIFO^.DATA,swap(FindFIFO^.FLAP.Len));
// Release packet`s memory
FreeMem(FindFIFO^.DATA,swap(FindFIFO^.FLAP.Len));
Dispose(FindFIFO);
//
debugFILE(tmp,'<');
if isAuth then AuthorizePart(tmp)
else WorkPart(tmp);
// Deleting packet
PacketDelete(tmp);
end;
MainT.Enabled := true;
end;
(****************************************************************)
procedure TForm1.AuthorizePart(p:PPack);
var ss : string;
T : integer;
tmp : PPack;
begin
PacketGoto(p,sizeof(FLAP_HDR)); // goto FLAP_DATA
// Authorize Server ACK
if (swap(p^.Len)=4)and
(swap(p^.SNAC.FamilyID)=0)and
(swap(p^.SNAC.SubTypeID)=1) then begin
M(Memo,'<Authorize Server CONNECT');
// Auth Request (Login)
SEQ := random($7FFF);
tmp := CreatePacket(1,SEQ);
PacketAppend32(tmp,DSwap(1));
TLVAppendStr(tmp,$1,s(UIN));
TLVAppendStr(tmp,$2,Calc_Pass(PASSWORD));
TLVAppendStr(tmp,$3,'ICQ Inc. - Product of ICQ (TM).2000a.4.31.1.3143.85');
TLVAppendWord(tmp,$16,$010A);
TLVAppendWord(tmp,$17,$0004); // for 2000a
TLVAppendWord(tmp,$18,$001F);
TLVAppendWord(tmp,$19,$0001);
TLVAppendWord(tmp,$1A,$0C47);
TLVAppendDWord(tmp,$14,$00000055);
TLVAppendStr(tmp,$0F,'en');
TLVAppendStr(tmp,$0E,'us');
PacketSend(tmp);
M(Memo,'>Auth Request (Login)');
end else // Auth Response (COOKIE or ERROR)
if (TLVReadStr(p,ss)=1){and(ss=s(UIN))}then begin
T := TLVReadStr(p,ss);
case T of
5: begin // BOS-IP:PORT
M(Memo,'<Auth Responce (COOKIE)');
WorkAddress := copy(ss,1,pos(':',ss)-1);
WorkPort := strtoint(copy(ss,pos(':',ss)+1,length(ss)-pos(':',ss)));
if (TLVReadStr(p,sCOOKIE)=6)then begin;;;;
// Empty packet for disconnect
tmp:=CreatePacket(4,SEQ); // ChID=4
PacketSend(tmp);
// Disconnect from Autorize Server
OfflineDiscconnect1Click(self);
isAuth := false;
// Connecting to BOS
CLI.Address := WorkAddress;
CLI.Host := '';
CLI.Port := WorkPort;
M(Memo,'');
M(Memo,'>>> Connecting to BOS: '+ss);
CLI.Open;
end;
end;
4,8: begin
M(Memo,'<Auth ERROR');
M(Memo,'TLV($'+inttohex(T,2)+') ERROR');
M(Memo,'STRING: '+ss);
if pos('http://',ss)>0 then begin
end;
TLVReadStr(p,ss); M(Memo,ss);
OfflineDiscconnect1Click(self);
M(Memo,'');
end;
end;
end;
end;
(****************************************************************)
procedure TForm1.WorkPart(p:PPack);
var ss,ss2,sErr : string;
// T : integer;
tmp : PPack;
i : integer;
begin
if p^.FLAP.ChID = 4 then begin // SERVER GONNA DISCONNECT
PacketGoto(p,sizeof(FLAP_HDR));
TLVReadStr(p,ss); M(Memo,ss);
TLVReadStr(p,ss2); M(Memo,ss2);
OfflineDiscconnect1Click(self);
sErr:='Str1: ';
for i:=1 to length(ss) do sErr:=sErr+inttohex(byte(ss[i]),2)+' ';
sErr:=sErr+#13#10+'Str2: '+ss2+#13#10+#13#10;
ShowMessage('Another Computer Use YOUR UIN!'#13#10+#13#10+
sErr+'...i gonna to disconnect');
exit;
end;
PacketGoto(p,sizeof(FLAP_HDR)+sizeof(SNAC_HDR));
// BOS Connection ACK
if (swap(p^.Len)=4)and
(swap(p^.SNAC.FamilyID)=0)and
(swap(p^.SNAC.SubTypeID)=1) then begin
M(Memo,'<BOS connection ACK');
// BOS Sign-ON (COOKIE)
SEQ := random($7FFF);
tmp := CreatePacket(1,SEQ);
PacketAppend32(tmp,DSwap(1));
TLVAppendStr(tmp,$6,sCOOKIE);
PacketSend(tmp);
M(Memo,'>BOS Sign-ON (COOKIE)');
end else // BOS-Host ready
if (swap(p^.SNAC.FamilyID)=1)and
(swap(p^.SNAC.SubTypeID)=3) then begin
M(Memo,'<BOS-Host ready');
// I`m ICQ client, not AIM
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$17);
PacketAppend32(tmp,dswap($00010003));
PacketAppend32(tmp,dswap($00020001));
PacketAppend32(tmp,dswap($00030001));
PacketAppend32(tmp,dswap($00150001));
PacketAppend32(tmp,dswap($00040001));
PacketAppend32(tmp,dswap($00060001));
PacketAppend32(tmp,dswap($00090001));
PacketAppend32(tmp,dswap($000A0001));
PacketSend(tmp);
M(Memo,'>"I`m ICQ client, not AIM"');
end else // ACK to "I`m ICQ Client"
if (swap(p^.SNAC.FamilyID)=$1)and // ACK
(swap(p^.SNAC.SubTypeID)=$18) then begin
M(Memo,'<ACK to "I`m ICQ client"');
// Rate Information Request
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$6);
PacketSend(tmp);
M(Memo,'>Rate Information Request');
end else // Rate Information Response
if (swap(p^.SNAC.FamilyID)=$1)and
(swap(p^.SNAC.SubTypeID)=$7) then begin
M(Memo,'<Rate Information Response');
// ACK to Rate Information Response
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$8);
PacketAppend32(tmp,DSwap($00010002));
PacketAppend32(tmp,DSwap($00030004));
PacketAppend16(tmp,Swap($0005));
PacketSend(tmp);
M(Memo,'>ACK to Rate Response');
// Request Personal Info
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$0E);
PacketSend(tmp);
M(Memo,'>Request Personal Info');
// Request Rights for Location service
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$2,$02);
PacketSend(tmp);
M(Memo,'>Request Rights for Location service');
// Request Rights for Buddy List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$3,$02);
PacketSend(tmp);
M(Memo,'>Request Rights for Buddy List');
// Request Rights for ICMB
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$4,$04);
PacketSend(tmp);
M(Memo,'>Request Rights for ICMB');
// Request BOS Rights
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$02);
PacketSend(tmp);
M(Memo,'>Request BOS Rights');
end else // Personal Information
if (swap(p^.SNAC.FamilyID)=$1)and
(swap(p^.SNAC.SubTypeID)=$F) then begin
M(Memo,'<Personal Information');
end else // Rights for location service
if (swap(p^.SNAC.FamilyID)=$2)and
(swap(p^.SNAC.SubTypeID)=$3) then begin
M(Memo,'<Rights for location service');
end else // Rights for byddy list
if (swap(p^.SNAC.FamilyID)=$3)and
(swap(p^.SNAC.SubTypeID)=$3) then begin
M(Memo,'<Rights for byddy list');
end else // Rights for ICMB
if (swap(p^.SNAC.FamilyID)=$4)and
(swap(p^.SNAC.SubTypeID)=$5) then begin
M(Memo,'<Rights for ICMB');
end else // BOS Rights
if (swap(p^.SNAC.FamilyID)=$9)and
(swap(p^.SNAC.SubTypeID)=$3) then begin
M(Memo,'<BOS Rights');
// Set ICMB parameters
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$4,$2);
PacketAppend16(tmp,swap($0));
PacketAppend32(tmp,dswap($3));
PacketAppend16(tmp,swap($1F40));
PacketAppend16(tmp,swap($03E7));
PacketAppend16(tmp,swap($03E7));
PacketAppend16(tmp,swap($0));
PacketAppend16(tmp,swap($0));
PacketSend(tmp);
M(Memo,'>Set ICMB parameters');
// Set User Info (capability)
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$2,$4); // tlv(5)=capability
TLVAppendStr(tmp,5,#$09#$46#$13#$49#$4C#$7F#$11#$D1+
#$82#$22#$44#$45#$53#$54#$00#$00+
#$09#$46#$13#$44#$4C#$7F#$11#$D1+
#$82#$22#$44#$45#$53#$54#$00#$00);
PacketSend(tmp);
M(Memo,'>Set User Info (capability)');
// Send Contact List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$3,$4);
PacketAppendB_String(tmp,s(UIN));
// PacketAppendB_String(tmp,s(someUIN));
PacketSend(tmp);
M(Memo,'>Send Contact List (1)');
case ICQStatus of
STATE_INVISIBLE: begin
// Send Visible List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$5);
PacketSend(tmp);
M(Memo,'>Send Visible List (0)');
end;
else begin
// Send Invisible List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$7);
PacketSend(tmp);
M(Memo,'>Send Invisible List (0)');
end;
end;//case
ConnectMode(true);
SetStatus(ICQStatus);
M(Memo,'>Set Status Code');
// Client Ready
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$2);
PacketAppend32(tmp,dswap($00010003));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00020001));
PacketAppend32(tmp,dswap($0101028A));
PacketAppend32(tmp,dswap($00030001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00150001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00040001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00060001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($00090001));
PacketAppend32(tmp,dswap($0110028A));
PacketAppend32(tmp,dswap($000A0003));
PacketAppend32(tmp,dswap($0110028A));
PacketSend(tmp);
M(Memo,'>Client Ready');
// Get offline messages
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$15,$2);
PacketAppend32(tmp,dswap($0001000A));
PacketAppend16(tmp,swap($0800));
PacketAppend32(tmp,UIN);
PacketAppend16(tmp,swap($3C00));
PacketAppend16(tmp,swap($0200));
PacketSend(tmp);
M(Memo,'>Get offline messages');
// Get Banner Address
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$15,$2);
PacketAppend16(tmp,swap($0001));
ss:='<key>BannersIP</key>';
PacketAppend16(tmp,swap(14+length(ss)+1));
PacketAppend16(tmp,swap($2100));
PacketAppend32(tmp,UIN);
PacketAppend16(tmp,swap($D007)); // Type
PacketAppend16(tmp,swap($0300)); // Cookie
PacketAppend16(tmp,swap($9808)); // SubType = xml-style (LNTS)
PacketAppendString(tmp,ss); // '<key>BannersIP</key>'
PacketSend(tmp);
M(Memo,'>Get Banner Address');
end else // Reject notification
if (swap(p^.SNAC.FamilyID)=$3)and
(swap(p^.SNAC.SubTypeID)=$0A) then begin
M(Memo,'');
M(Memo,'<Reject from UIN: '+PacketReadB_String(p));
M(Memo,'');
end else // UIN ON-line
if (swap(p^.SNAC.FamilyID)=$3)and
(swap(p^.SNAC.SubTypeID)=$0B) then begin
M(Memo,'');
ShowUserONStatus(p);
M(Memo,'');
end else // UIN OFF-line ???
if (swap(p^.SNAC.FamilyID)=$3)and
(swap(p^.SNAC.SubTypeID)=$0C) then begin
M(Memo,'');
M(Memo,'<UIN OFF-line: '+PacketReadB_String(p));
M(Memo,'');
end else // SNAC 15,3 Meny purposes (offlines messages)
if (swap(p^.SNAC.FamilyID)=$15)and
(swap(p^.SNAC.SubTypeID)=$3) then begin
M(Memo,'');
SNAC_15_3(p);
M(Memo,'');
end else // SNAC 4,7 Incoming message
if (swap(p^.SNAC.FamilyID)=$4)and
(swap(p^.SNAC.SubTypeID)=$7) then begin
M(Memo,'');
SNAC_4_7(p);
M(Memo,'');
end else begin
M(Memo,'');
M(Memo,'???? Unrecognized SNAC: ????????');
M(Memo,'???? SNAC [$'+inttohex(swap(p^.SNAC.FamilyID),2)+':$'+
inttohex(swap(p^.SNAC.SubTypeID),2)+']');
M(Memo,'');
end;
end;
(****************************************************************)
procedure TForm1.ShowUserONStatus(p:PPack);
var T : word;
k,cnt : integer;
UINonline,TLV : string;
r_ip,r_r_ip,r_status : longint;
begin
UINonline := PacketReadB_String(p);
M(Memo,'<UIN ON-line: '+UINonline);
PacketRead16(p);
cnt := swap(PacketRead16(p));
for k:=1 to cnt do begin
T := TLVReadStr(p,TLV);
case T of
6: begin // STATUS
move(TLV[1],IPArray(r_status),4);
r_status := DSwap(r_status);
M(Memo,'#'+s(k)+' TLV($'+inttohex(T,2)+')'+
' STATUS: $'+inttohex(r_status,8));
end;
$A: begin // IP
move(TLV[1],IPArray(r_ip),4);
M(Memo,'#'+s(k)+' TLV($'+inttohex(T,2)+')'+
' IP: '+IPToStr(IPArray(r_ip)));
end;
$C: begin // REAL_IP
move(TLV[1],IPArray(r_r_ip),4);
M(Memo,'#'+s(k)+' TLV($'+inttohex(T,2)+')'+
' Real IP: '+IPToStr(IPArray(r_r_ip)));
end;
//else M(Memo,'??? #'+s(k)+' TLV($'+inttohex(T,2)+')');
end;
end;
end;
(****************************************************************)
procedure TForm1.SNAC_15_3(p:PPack);
var MessageType : word;
{myUIN,}hisUIN : longint;
SubType : array[0..3] of byte;
MessageSubType : longint absolute SubType;
year,month,day,hour,minute,typemes,{subtypemes,}lenmes : word;
tmp : PPack;
sTemp,URL : string;
begin
PacketRead32(p);
PacketRead16(p);
{myUIN := }PacketRead32(p);
MessageType := swap(PacketRead16(p));
{Cookie := }swap(PacketRead16(p));
//M(Memo,'<Cookie: $'+inttohex(Cookie,4));
case MessageType of
$DA07: begin
SubType[3] := 0;
SubType[2] := PacketRead8(p);
SubType[1] := PacketRead8(p);
SubType[0] := PacketRead8(p);
if(MessageSubType and $FF)<>$0A then begin
M(Memo,'<FAIL: SubType:$'+inttohex(MessageSubType,4));
end;
case MessageSubType of
$A2080A: begin // Banner URL
sTemp := PacketReadString(p);
sTemp[pos('<',sTemp)] :='_';
URL := 'http://'+copy(sTemp,pos('>',sTemp)+1,pos('<',sTemp)-pos('>',sTemp)-1);
M(Memo,'<Banner HTML-Server: '+URL);
end;
else M(Memo,'<??? SNAC 15,3; Type:$DA07; SubType: $'+inttohex(MessageSubType,6));
end;//
end;
$4200: begin // END of offline messages
//M(Memo,'<Message-Type: $'+inttohex(MessageType,4));
M(Memo,'<End of OFFline messages');
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$15,$2);
PacketAppend16(tmp,swap($0001)); // TLV(1)
PacketAppend32(tmp,dswap($000A0800));
PacketAppend32(tmp,UIN);
PacketAppend16(tmp,swap($3E00)); // ACK
PacketAppend16(tmp,swap($0200));
PacketSend(tmp);
//M(Memo,'>ACK it');
end;
$4100: begin // OFFLINE MESSAGE
hisUIN := PacketRead32(p); // LE
//M(Memo,'<Message-Type: $'+inttohex(MessageType,4));
M(Memo,'<OFFLINE MESSAGE from UIN: '+s(hisUIN));
year := PacketRead16(p);
month := PacketRead8(p);
day := PacketRead8(p);
hour := PacketRead8(p);
minute := PacketRead8(p);
typemes := PacketRead8(p);
{subtypemes := }PacketRead8(p);
lenmes := PacketRead16(p);
DoMsg(false,typemes,lenmes,PCharArray(@(p^.data[p^.cursor])),
hisUIN,UTC2LT(year,month,day,hour,minute));
end;
else M(Memo,'<??? SNAC 15,3; Type: $'+inttohex(MessageType,4));
end;//case
end;
(****************************************************************)
procedure TForm1.SNAC_4_7(p:PPack); // INCOMING MESSAGES
var i,cnt,T,MessageFormat,SubMode,SubMode2,Empty : word;
{myUIN,}hisUIN : longint;
SubType : array[0..3] of byte;
MessageSubType : longint absolute SubType;
tmp,tmp2,tmp3 : PPack;
sTemp : string;
dTemp : TByteArray;
typemes,{subtypemes,}unk,modifier,lenmes : word;
//for snac 4,0B (ack for msg-2 type)
d1,d2 : longint;
ACK : TByteArray;
ind : word;
begin
d1:=PacketRead32(p);
d2:=PacketRead32(p);
MessageFormat := swap(PacketRead16(p));
sTemp := PacketReadB_String(p);
ind:=0;
PLONG(@(ACK[ind]))^:=d1; inc(ind,4);
PLONG(@(ACK[ind]))^:=d2; inc(ind,4);
PWORD(@(ACK[ind]))^:=swap(MessageFormat);inc(ind,2);
PBYTE(@(ACK[ind]))^:=length(sTemp);inc(ind,1);
MOVE(sTemp[1],ACK[ind],length(sTemp));inc(ind,length(sTemp));
PWORD(@(ACK[ind]))^:=swap($0003);inc(ind,2);
try hisUIN := strtoint(sTemp); except hisUIN:=0; end;
M(Memo,'<From: '+sTemp);
PacketRead16(p); //warning level? garbage of OSCAR protocol
cnt := swap(PacketRead16(p)); // num of TLVs
for i:=1 to cnt do
if TLVReadStr(p,sTemp)=6 then begin { this is a HIS STATUS } end;
case MessageFormat of
$0001: begin
//M(Memo,'<Message-format: 1 (SIMPLY message)');
TLVReadStr(p,sTemp);
// copy TLV(2) to TMP
tmp := PacketNew;
PacketAppend(tmp,@(sTemp[1]),length(sTemp));
PacketGoto(tmp,0); // goto !!!!!
// work it
PacketRead16(tmp);
PacketRead16(tmp);
PacketRead8(tmp);
PacketRead16(tmp);
lenmes := swap(PacketRead16(tmp))-4;
PacketRead32(tmp);
PacketRead(tmp,@sTemp[1],lenmes);
SetLength(sTemp,lenmes);
DoSimpleMsg(hisUIN,sTemp);
// delete TMP
PacketDelete(tmp);
end;
$0002: begin
//M(Memo,'<Message-format: 2 (ADVANCED message)');
TLVReadStr(p,sTemp);
// copy TLV(5) to TMP
tmp := PacketNew;
PacketAppend(tmp,@(sTemp[1]),length(sTemp));
PacketGoto(tmp,0); // goto !!!!!
// work it
SubMode := swap(PacketRead16(tmp));
PacketRead32(tmp);
PacketRead32(tmp);
PacketRead(tmp,@dTemp,16); //capability 16 bytes
case SubMode of
$0000: begin
//M(Memo,'SubMode: $0000 NORMAL');
{T := }TLVReadWord(tmp,SubMode2);// 0001-normal 0002-file reply
TLVReadWord(tmp,Empty);// TLV(F) empty
T := TLVReadStr(tmp,sTemp);
if T=$2711 then begin
MOVE(sTemp[1],ACK[ind],47);inc(ind,47);
PLONG(@(ACK[ind]))^:=0; inc(ind,4);
//******************************************
tmp2 := PacketNew;
PacketAppend(tmp2,@(sTemp[1]),length(sTemp));
PacketGoto(tmp2,0); // goto !!!!!
PacketRead(tmp2,@dTemp,26);
PacketRead8(tmp2);
PacketRead16(tmp2);
PacketRead16(tmp2);
PacketRead16(tmp2);
PacketRead(tmp2,@dTemp,12);
typemes := PacketRead8(tmp2);
{subtypemes := }PacketRead8(tmp2);
unk:=swap(PacketRead16(tmp2));//0200
modifier:=swap(PacketRead16(tmp2));//0100
M(Memo,'Unk: $'+inttohex(unk,4));
M(Memo,'Modifier: $'+inttohex(modifier,4));
lenmes := PacketRead16(tmp2);
DoMsg(true,typemes,lenmes,PCharArray(@(tmp2^.data[tmp2^.cursor])),
hisUIN,Now2DateTime);
// delete TMP2
PacketDelete(tmp2);
PWORD(@(ACK[ind]))^:=1; inc(ind,2);
PBYTE(@(ACK[ind]))^:=0; inc(ind,1);
PLONG(@(ACK[ind]))^:=0; inc(ind,4);
PLONG(@(ACK[ind]))^:=-1; inc(ind,4);
// Sending Ack
tmp3 := CreatePacket($2,SEQ);
SNACAppend(tmp3,$4,$0B);
PacketAppend(tmp3,@ACK[0],ind);
PacketSend(tmp3);
//******************************************
end;// IF
end; //Submode:$0000
$0001: M(Memo,'SubMode:$0001 ??? message canceled ???');
$0002: M(Memo,'SubMode:$0002 FILE-ACK (not yet)');
end;//case SubMode
// delete TMP
PacketDelete(tmp);
end;
$0004: begin
//M(Memo,'<Message-format: 4 (url or contacts or auth-req or userAddedYou)');
TLVReadStr(p,sTemp);
// copy TLV(5) to TMP
tmp := PacketNew;
PacketAppend(tmp,@(sTemp[1]),length(sTemp));
PacketGoto(tmp,0); // goto !!!!!
// work it
hisUIN := PacketRead32(tmp);
typemes := PacketRead8(tmp);
{subtypemes := }PacketRead8(tmp);
lenmes := PacketRead16(tmp);
DoMsg(true,typemes,lenmes,PCharArray(@(tmp^.data[tmp^.cursor])),
hisUIN,Now2DateTime);
// delete TMP
PacketDelete(tmp);
end;
else M(Memo,'<??? SNAC 4,7; Message-format: '+s(MessageFormat));
end;//case MessageFormat
end;
(****************************************************************)
procedure TForm1.DoMsg(on_off:boolean;typemes,lenmes:integer; data:PCharArray; r_uin:longint; DateTime:TDateTime);
var i,pos1,pos2 : integer;
sTemp,sLog,sNN,sDT : string;
LTemp : array[1..6] of string;
begin
if (lenmes-1)=0 then exit;
setlength(sTemp,lenmes-1); // -1 for final string char #0
move(data^,sTemp[1],lenmes-1);
for i:=1 to 6 do LTemp[i]:='';
if (typemes <> TYPE_MSG)and(typemes<>0) then begin
if sTemp[length(sTemp)]<>#$FE then sTemp:=sTemp+#$FE;
pos2:=0;
for i:=1 to 6 do begin
pos1 := pos2+1;
pos2 := pos(#$FE,sTemp);
if pos2 = 0 then break;
LTemp[i] := copy(sTemp,pos1,pos2-pos1);
sTemp[pos2] := #$FF;
end;
end;
sNN := '';
case on_off of
true: sDT := '<-[A] ';
false: sDT := '<-[O] ';
end;
sDT := sDT+DateTimeToStr(DateTime)+' ';
case typemes of
0,TYPE_MSG:
FmtStr(sLog,sNN+' ['+s(r_uin)+'] "%s"',[sTemp]);
TYPE_ADDED:
FmtStr(sLog,'UIN:%d has added you to their contact list.'+
'Nick:%s FName:%s LName:%s E-mail:%s',
[r_uin,LTemp[1],LTemp[2],LTemp[3],LTemp[4]]);
TYPE_AUTH_REQ:
FmtStr(sLog,'UIN:%d has requested your authorization.'+
'Nick:%s FName:%s LName:%s E-mail:%s '#13#10'Reason:"%s"',
[r_uin,LTemp[1],LTemp[2],LTemp[3],LTemp[4],LTemp[6]]);
TYPE_URL:
FmtStr(sLog,'URL: UIN:%d, '#13#10'URL:%s, '#13#10'Description:"%s"',
[r_uin,LTemp[2],LTemp[1]]);
TYPE_WEBPAGER:
FmtStr(sLog,'WebPager: UIN:%d, Nick:%s, EMail:%s, '#13#10'"%s"',
[r_uin,LTemp[1],LTemp[4],LTemp[6]]);
TYPE_EXPRESS:
FmtStr(sLog,'MailExpress: UIN:%d, Nick:%s, EMail:%s, '#13#10'"%s"',
[r_uin,LTemp[1],LTemp[4],LTemp[6]]);
else FmtStr(sLog,'Instant message type %d from UIN:%d, '#13#10'Message:"%s"',
[typemes,r_uin,sTemp]);
end;//case
sLog := sDT+sLog;
M(Memo,sLog); LogMessage(sLog);
end;
(****************************************************************)
procedure TForm1.DoSimpleMsg(r_uin:longint; Text:string);
var sLog : string;
begin
sLog:= '<-[S] '+DateTimeToStr(Now)+' '+'['+s(r_uin)+'] "'+Text+'"';
M(Memo,sLog); LogMessage(sLog);
end;
(****************************************************************)
procedure TForm1.SetStatus(Status:longint);
var tmp : PPack;
begin
ICQStatus := Status;
// Set Status Code
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$1E);
TLVAppendDWord(tmp,6,ICQStatus);
TLVAppendWord(tmp,8,$0000);
// imitation TLV(C)
PacketAppend32(tmp,dswap($000C0025)); // TLV(C)
StrToIP(Get_my_IP,DIM_IP);
PacketAppend(tmp,@DIM_IP,4); // IP address
PacketAppend32(tmp,dswap(28000+random(1000)));// Port
PacketAppend8(tmp,$04);
PacketAppend16(tmp,swap($0007));
PacketAppend16(tmp,swap($466B));
PacketAppend16(tmp,swap($AE68));
PacketAppend32(tmp,dswap($00000050));
PacketAppend32(tmp,dswap($00000003));
PacketAppend32(tmp,dswap(SecsSince1970));
PacketAppend32(tmp,dswap(SecsSince1970));
PacketAppend32(tmp,dswap(SecsSince1970));
PacketAppend16(tmp,swap($0000));
PacketSend(tmp);
case ICQStatus of
STATE_ONLINE: StatusBtn.Caption := 'online';
STATE_AWAY: StatusBtn.Caption := 'away';
STATE_DND: StatusBtn.Caption := 'dnd';
STATE_OCCUPIED: StatusBtn.Caption := 'occupied';
STATE_FREEFORCHAT: StatusBtn.Caption := 'freeforchat';
STATE_N_A: StatusBtn.Caption := 'na';
STATE_INVISIBLE: StatusBtn.Caption := 'invisible';
else StatusBtn.Caption := 'offline';
end;
end;
(****************************************************************)
procedure TForm1.StatusChange(Status:longint);
var tmp : PPack;
begin
if(not OL)then begin
Get_My_IP;
if not OL then begin
M(Memo,'OFF-line');
exit;
end;
end;
if (not CLI.Active) then icq_Login(Status)
else if (not isLogged) then exit // logging now ...
else begin
ICQStatus := Status;
case ICQStatus of
STATE_INVISIBLE: begin
// Send Visible List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$5);
PacketSend(tmp);
M(Memo,'>Send Visible List (0)');
end;
else begin
// Send Invisible List
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$9,$7);
PacketSend(tmp);
M(Memo,'>Send Invisible List (0)');
end;
end;//case
// Set Status Code
tmp := CreatePacket(2,SEQ);
SNACAppend(tmp,$1,$1E);
TLVAppendDWord(tmp,6,ICQStatus);
PacketSend(tmp);
case ICQStatus of
STATE_ONLINE: StatusBtn.Caption := 'online';
STATE_AWAY: StatusBtn.Caption := 'away';
STATE_DND: StatusBtn.Caption := 'dnd';
STATE_OCCUPIED: StatusBtn.Caption := 'occupied';
STATE_FREEFORCHAT: StatusBtn.Caption := 'freeforchat';
STATE_N_A: StatusBtn.Caption := 'na';
STATE_INVISIBLE: StatusBtn.Caption := 'invisible';
else StatusBtn.Caption := 'offline';
end;
end;
end;
(****************************************************************)
procedure TForm1.OnlineConnected1Click(Sender: TObject);
begin
StatusChange(STATE_ONLINE);
end;
(****************************************************************)
procedure TForm1.Away1Click(Sender: TObject);
begin
StatusChange(STATE_AWAY);
end;
(****************************************************************)
procedure TForm1.DNDDoNotDisturb1Click(Sender: TObject);
begin
StatusChange(STATE_DND);
end;
(****************************************************************)
procedure TForm1.PrivacyInvisible1Click(Sender: TObject);
begin
StatusChange(STATE_INVISIBLE);
end;
(****************************************************************)
procedure TForm1.OfflineDiscconnect1Click(Sender: TObject);
begin
ConnectMode(false);
end;
(****************************************************************)
procedure TForm1.OccupiedUrgentMsgs1Click(Sender: TObject);
begin
StatusChange(STATE_OCCUPIED);
end;
(****************************************************************)
procedure TForm1.FreeForChat1Click(Sender: TObject);
begin
StatusChange(STATE_FREEFORCHAT);
end;
(****************************************************************)
procedure TForm1.NAExtendedAway1Click(Sender: TObject);
begin
StatusChange(STATE_N_A);
end;
(****************************************************************)
procedure TForm1.icq_Login(Status : longint);
begin
randomize;
SEQ := random($7FFF);
Local_IP := Get_my_IP;
StrToIP(Local_IP,DIM_IP);
ICQStatus := status;
if CLI.Active then CLI.Close;
isAuth := true;
isHDR := true;
CLI.Address :='';
CLI.Host := 'login.icq.com';
CLI.Port := 5190;
M(Memo,'>>>>>>>>>> login.icq.com:5190 <<<<<<<<<<<');
CLI.Open;
end;
(****************************************************************)
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
OfflineDiscconnect1Click(self);
CloseLogs;
end;
(****************************************************************)
procedure TForm1.InitLogs;
begin
assignfile(mess,s(UIN)+'.mes');
try if FileExists(s(UIN)+'.mes') then append(mess)
else rewrite(mess);
M(Memo,DateTimeToStr(Now));
except end;
assignfile(log,s(UIN)+'.log');
try if FileExists(s(UIN)+'.log') then append(log)
else rewrite(log);
except end;
end;
(****************************************************************)
procedure TForm1.CloseLogs;
begin
try closefile(mess); except end;
try closefile(log); except end;
end;
(****************************************************************)
procedure TForm1.LogMessage(s:string);
begin
try writeln(mess,s); except end;
end;
(****************************************************************)
procedure TForm1.InitUser;
var cfg : TIniFile;
begin
cfg := TIniFile.Create(ExtractFilePath(ParamStr(0))+'nICQ.ini');
try
UIN := cfg.ReadInteger('User','Uin',0);
NICK := cfg.ReadString('User','Nick','');
PASSWORD := cfg.ReadString('User','Password','');
finally cfg.Free; end;
Caption := NICK+' : '+s(UIN);
end;
(****************************************************************)
procedure TForm1.ClearFIFO;
var Find : PFLAP_Item;
begin
repeat
Find := HeadFIFO;
if HeadFIFO<>nil then begin
if HeadFIFO^.<>nil then
HeadFIFO := HeadFIFO^.
else HeadFIFO := nil;
end;
if Find<>nil then begin
FreeMem(Find^.DATA,swap(Find^.FLAP.Len));
Dispose(Find);
end;
until Find=nil;
end;
(****************************************************************)
procedure TForm1.StatusBtnClick(Sender: TObject);
begin
StatusMenu.Popup(Left+Width-20,+Height-50);
end;
end.
Отправить комментарий