[AD]
[AD]

КомпьюТоп - каталог компьютерных сайтов





































































 
    вернуться назад Шутка...
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;
    ToolBar1: TToolBar;
    StatusBtn: TToolButton;
    Splitter1: TSplitter;
    CLI: TClientSocket;
    BG: TPanel;
    Memo: TMemo;
    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);
  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; // case
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  // is it a flap header ?
       if num>=6 then begin
         Socket.ReceiveBuf(FLAP,6);
         NeedBytes := swap(FLAP.Len);
         Index := 0;   // FLAP_DATA[0]
         isHDR := not isHDR; // goto FLAP_DATA
       end else begin
             M(memo,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
             Socket.ReceiveBuf(buf,num);
             M(Memo,Dim2Hex(@(buf),num));
             M(memo,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
           end;

     end else begin  // DATA-BLOCK
         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));
           // AddLast
           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; // goto FLAP_HDR
         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:='BannersIP';
       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); // 'BannersIP'
       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)');
            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
     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);
var  cfg : TIniFile;
begin
     randomize;  
     SEQ := random($7FFF);
     Local_IP := Get_my_IP; 
     StrToIP(Local_IP,DIM_IP);
     cfg := TIniFile.Create(ExtractFilePath(ParamStr(0))+'nICQ.ini');
     try initStatus := cfg.ReadInteger('User','Status',online);
     finally cfg.Free; end;
     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
   // Del ALL
   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;

(****************************************************************)

end.