Main.pas
01.01.2007
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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^.Next := 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^.Next=nil then begin CurrFIFO^.Next:=pFIFO; break; end else CurrFIFO:=CurrFIFO^.Next; 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^.Next=nil then HeadFIFO := nil else HeadFIFO := HeadFIFO^.Next; // 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^.Next<>nil then HeadFIFO := HeadFIFO^.Next 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,Top+Height-50); end; end.