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

Delphi控件源码

开发平台:

Delphi

  1.   Data: TRawPkt;
  2.   Pkt1: TRawPkt;
  3. const
  4.   TextCMD = 'File Transfer';
  5. begin
  6.   PktInitRaw(@Data);                            //Additional data packet
  7.   PktInitRaw(@Pkt1);                            //First temporary packet
  8.   PktAddArrBuf(@Pkt1, @FileSignature, 16);      //File signature
  9.   PktInt(@Pkt1, $0000, 2);                      //Unknown: empty
  10.   PktDWStr(@Pkt1, TextCMD);                     //Text command
  11.   PktInt(@Pkt1, $00000101, 4);                  //Unknown
  12.   PktInt(@Pkt1, $00000000, 4);                  //Unknown
  13.   PktInt(@Pkt1, $00000000, 4);                  //Unknown
  14.   PktInt(@Pkt1, $0000, 2);                      //Unknown
  15.   PktInt(@Pkt1, $00, 1);                        //Unknown
  16.   PktLInt(@Data, Pkt1.Len, 2);                  //Length of the first temp packet
  17.   PktAddArrBuf(@Data, @Pkt1, Pkt1.Len);         //Implode packets
  18.   PktInitRaw(@Pkt1);                            //Second additional packet
  19.   PktDWStr(@Pkt1, FileDesc);                    //File description
  20.   PktInt(@Pkt1, Port, 2);                       //Listeners port
  21.   PktInt(@Pkt1, $0000, 2);                      //Unknown
  22.   PktLNTS(@Pkt1, FileName);                     //Filename
  23.   PktLInt(@Pkt1, FileSize, 4);                  //Filesize
  24.   PktLInt(@Pkt1, Port, 4);                      //Listeners port again
  25.   PktLInt(@Data, Pkt1.Len, 4);                  //Length of the second temp packet
  26.   PktAddArrBuf(@Data, @Pkt1, Pkt1.Len);         //Implode packets
  27.   CreateCLI_SENDADVMSG_CUSTOM(Pkt, FFSeq, ITime, IRandom, UIN, $1a, $00, $0002, '', @Data, Data.Len, False, Seq);
  28. end;
  29. {Request an auto-away message.}
  30. procedure CreateCLI_REQAWAYMSG(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; Status: Byte; var Seq: Word);
  31. begin
  32.   CreateCLI_SENDADVMSG_CUSTOM(Pkt, $FFFF, ITime, IRandom, UIN, Status, $03, $0001, '', nil, 0, False, Seq);
  33. end;
  34. {Send contacts through server.}
  35. procedure CreateCLI_SENDCONTACTS(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; Contacts: TStringList; var Seq: Word);
  36. var
  37.   lpData: TRawPkt;
  38.   Pkt1: TRawPkt;
  39.   S: String;
  40. const
  41.   TextCMD = 'Contacts';
  42. begin
  43.   PktInitRaw(@lpData);                          //Init data packet
  44.   PktInitRaw(@Pkt1);                            //Init first temporary packet
  45.   PktAddArrBuf(@Pkt1, @ContactsSignature, 16);  //Contacs signature
  46.   PktInt(@Pkt1, $0000, 2);                      //0x0000 - Send contacts
  47.   PktDWStr(@Pkt1, TextCMD);                     //Text command
  48.   PktInt(@Pkt1, $00000000, 4);                  //Unknown
  49.   PktInt(@Pkt1, $00010000, 4);                  //Unknown
  50.   PktInt(@Pkt1, $00000000, 4);                  //Unknown
  51.   PktInt(@Pkt1, $0000, 2);                      //Unknown
  52.   PktInt(@Pkt1, $00, 1);                        //Unknown
  53.   PktLInt(@lpData, Pkt1.Len, 2);                //Length of the following packet (Pkt1)
  54.   PktAddArrBuf(@lpData, @Pkt1, Pkt1.Len);       //Implode packets
  55.   S := MakeContactsStr(Contacts);               //Create text list from string list
  56.   PktLInt(@lpData, Length(S) + 4, 4);           //Length of the following data
  57.   PktDWStr(@lpData, S);                         //Length of the following string
  58.   CreateCLI_SENDADVMSG_CUSTOM(Pkt, $FFFF, ITime, IRandom, UIN, $1a, $00, $0001, '', @lpData, lpData.Len, False, Seq);
  59. end;
  60. {Send contacts request through server.}
  61. procedure CreateCLI_SENDCONTACTS_REQ(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; Reason: String; var Seq: Word);
  62. var
  63.   lpData: TRawPkt;
  64.   Pkt1: TRawPkt;
  65. const
  66.   TextCMD = 'Request For Contacts';
  67. begin
  68.   PktInitRaw(@lpData);                          //Init data packet
  69.   PktInitRaw(@Pkt1);                            //Init first temporary packet
  70.   PktAddArrBuf(@Pkt1, @ContactsSignature, 16);  //Contacs signature
  71.   PktInt(@Pkt1, $0200, 2);                      //0x0200 - Request for contacts
  72.   PktDWStr(@Pkt1, TextCMD);                     //Text command
  73.   PktInt(@Pkt1, $00000000, 4);                  //Unknown
  74.   PktInt(@Pkt1, $00010000, 4);                  //Unknown
  75.   PktInt(@Pkt1, $00000000, 4);                  //Unknown
  76.   PktInt(@Pkt1, $0000, 2);                      //Unknown
  77.   PktInt(@Pkt1, $00, 1);                        //Unknown
  78.   PktLInt(@lpData, Pkt1.Len, 2);                //Length of the following packet (Pkt1)
  79.   PktAddArrBuf(@lpData, @Pkt1, Pkt1.Len);       //Implode packets
  80.   PktLInt(@lpData, Length(Reason) + 4, 4);      //Length of the following data
  81.   PktDWStr(@lpData, Reason);                    //Length of the following string
  82.   CreateCLI_SENDADVMSG_CUSTOM(Pkt, $FFFF, ITime, IRandom, UIN, $1a, $00, $0001, '', @lpData, lpData.Len, False, Seq);
  83. end;
  84. {Create a FILE_ACK showing that user declined file.}
  85. procedure CreateCLI_SENDMSG_FILEDECLINE(Pkt: PRawPkt; FFSeq: Word; ITime, IRandom, UIN, FileSize: LongWord; const FileDesc, FileName, Reason: String; Port: Word; var Seq: Word);
  86. var
  87.   Pkt1: TRawPkt;
  88. const
  89.   TextCMD = 'File Transfer';
  90. begin
  91.   PktInit(Pkt, 2, Seq);
  92.   PktSnac(Pkt, $04, $0b, $00000000, $0000);
  93.   PktInt(Pkt, ITime, 4);                        //Time
  94.   PktInt(Pkt, IRandom, 2);                      //RandomID
  95.   PktInt(Pkt, $0000, 2);                        //Unknown
  96.   PktInt(Pkt, $0002, 2);                        //Message type
  97.   PktLStr(Pkt, UIN);                            //Destination UIN
  98.   PktInt(Pkt, $0003, 2);                        //Unknown
  99.   PktInt(Pkt, $1b00, 2);                        //If this value is not present, this is not a message packet.
  100.   PktInt(Pkt, $0800, 2);                        //TCP version
  101.   PktInt(Pkt, $00000000, 4);                    //Unknown: empty
  102.   PktInt(Pkt, $00000000, 4);                    //Unknown: empty
  103.   PktInt(Pkt, $00000000, 4);                    //Unknown: empty
  104.   PktInt(Pkt, $00000000, 4);                    //Unknown: empty
  105.   PktInt(Pkt, $0000, 2);                        //Unknown: empty
  106.   PktInt(Pkt, $03, 1);                          //Unknown: 0x03
  107.   PktInt(Pkt, $00000000, 4);                    //Unknown: empty
  108.   PktInt(Pkt, FFSeq, 2);                        //SEQ1
  109.   PktInt(Pkt, $0e00, 2);                        //Unknown, seen: 0x1200 and 0x0e00.
  110.   PktInt(Pkt, FFSeq, 2);                        //SEQ1
  111.   PktInt(Pkt, $00000000, 4);                    //Capability: empty
  112.   PktInt(Pkt, $00000000, 4);                    //Capability: empty
  113.   PktInt(Pkt, $00000000, 4);                    //Capability: empty
  114.   PktInt(Pkt, $1a00, 2);                        //SUBCMD
  115.   PktInt(Pkt, $01000000, 4);                    //Unknown
  116.   if Length(Reason) = 0 then                    //Use null terminator as a message, even when reason is empty
  117.   begin
  118.     PktInt(Pkt, $0100, 2);
  119.     PktInt(Pkt, $00, 1);
  120.   end else
  121.     PktLNTS(Pkt, Reason);                       //Reason
  122.   PktInitRaw(@Pkt1);                            //Initialize raw packet
  123.   PktAddArrBuf(@Pkt1, @FileSignature, 16);      //File signature
  124.   PktInt(@Pkt1, $0000, 2);                      //Unknown: empty
  125.   PktDWStr(@Pkt1, TextCMD);                     //Text command
  126.   PktInt(@Pkt1, $00000101, 4);                  //Unknown
  127.   PktInt(@Pkt1, $00000000, 4);                  //Unknown
  128.   PktInt(@Pkt1, $00000000, 4);                  //Unknown
  129.   PktInt(@Pkt1, $0000, 2);                      //Unknown
  130.   PktInt(@Pkt1, $00, 1);                        //Unknown
  131.   PktLInt(Pkt, Pkt1.Len, 2);                    //Length of the first temp packet
  132.   PktAddArrBuf(Pkt, @Pkt1, Pkt1.Len);           //Implode packets
  133.   PktInitRaw(@Pkt1);                            //Second additional packet
  134.   PktDWStr(@Pkt1, FileDesc);                    //File description
  135.   PktInt(@Pkt1, Port, 2);                       //Listeners port
  136.   PktInt(@Pkt1, $0000, 2);                      //Unknown
  137.   PktLNTS(@Pkt1, FileName);                     //Filename
  138.   PktLInt(@Pkt1, FileSize, 4);                  //Filesize
  139.   PktLInt(@Pkt1, Port, 4);                      //Listeners port again
  140.   PktLInt(Pkt, Pkt1.Len, 4);                    //Length of the second temp packet
  141.   PktAddArrBuf(Pkt, @Pkt1, Pkt1.Len);           //Implode packets
  142.   PktFinal(Pkt);                                //Finalize packet
  143. end;
  144. {Sends CLI_HELLO, used in registering the new UIN}
  145. procedure CreateCLI_HELLO(Pkt: PRawPkt; var Seq: Word);
  146. begin
  147.   PktInit(Pkt, 1, Seq);                         //Channel 2
  148.   PktInt(Pkt, $00000001, 4);                    //Always sent as the first parameter of a Channel 1 packet.
  149.   PktFinal(Pkt);                                //Finalize packet
  150. end;
  151. {Sends CLI_HELLO, used in unregistering the existing UIN}
  152. procedure CreateCLI_GOODBYE(Pkt: PRawPkt; var Seq: Word);
  153. begin
  154.   PktInit(Pkt, 1, Seq);                         //Channel 2
  155.   PktFinal(Pkt);                                //Finalize packet
  156. end;
  157. {Register a new UIN.}
  158. procedure CreateCLI_REGISTERUSER(Pkt: PRawPkt; const Password: String; var Seq: Word);
  159. var
  160.   lpTLV01: TRawPkt;
  161. begin
  162.   PktInit(Pkt, 2, Seq);                         //Channel 2
  163.   PktSnac(Pkt, $17, $04, 0, 0);                 //Snac: Type x17/x04, ID x0000, Flags 0
  164.   PktInitRaw(@lpTLV01);                         //TLV(01), - this TLV contains all information needed to request a new UIN.
  165.   PktInt(@lpTLV01, $00000000, 4);               //Unknown: empty.
  166.   PktInt(@lpTLV01, $28000300, 4);               //Unknown.
  167.   PktInt(@lpTLV01, $00000000, 4);               //Unknown: empty.
  168.   PktInt(@lpTLV01, $00000000, 4);               //Unknown: empty.
  169.   PktInt(@lpTLV01, $9E270000, 4);               //Unknown. Seen: 03 46 00 00, B4 25 00 00, 9E 27 00 00.
  170.   PktInt(@lpTLV01, $9E270000, 4);               //Same UNKNOWN2 as above.
  171.   PktInt(@lpTLV01, $00000000, 4);               //Unknown: empty.
  172.   PktInt(@lpTLV01, $00000000, 4);               //Unknown: empty.
  173.   PktInt(@lpTLV01, $00000000, 4);               //Unknown: empty.
  174.   PktInt(@lpTLV01, $00000000, 4);               //Unknown: empty.
  175.   PktLNTS(@lpTLV01, Password);                  //The password to use with your new UIN.
  176.   PktInt(@lpTLV01, $9E270000, 4);               //The same UNKNOWN2 again.
  177.   PktInt(@lpTLV01, $0000, 2);                   //Unknown: empty.
  178.   PktInt(@lpTLV01, $0302, 2);                   //Unknown. Seen: CF 01, 03 02.
  179.   PktTLV(Pkt, $01, lpTLV01.Len, @lpTLV01);      //Incapsulate TLV01 into Pkt
  180.   PktFinal(Pkt);                                //Finalize packet
  181. end;
  182. {Unregister an UIN number.}
  183. procedure CreateCLI_UNREGUIN(Pkt: PRawPkt; UIN: LongWord; const Password: String; var Seq, Seq2: Word);
  184. var
  185.   lpkt: TRawPkt;
  186. begin
  187.   PktInitRaw(@lpkt);
  188.   PktInt(@lpkt, $c404, 2);                      //CLI_METAUNREG Channel: 2, SNAC(21,2) 2000/1220
  189.   PktLInt(@lpkt, UIN, 4);                       //User's UIN
  190.   PktLNTS(@lpkt, Password);                     //User's Password
  191.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  192. end;
  193. {Change user's password.}
  194. procedure CreateCLI_METASETPASS(Pkt: PRawPkt; UIN: LongWord; const Password: String; Buffer: Pointer; BufLen: Word; var Seq, Seq2: Word);
  195. var
  196.   lpkt: TRawPkt;
  197. begin
  198.   PktInitRaw(@lpkt);
  199.   PktInt(@lpkt, $2e04, 2);                      //CLI_METASETPASS Channel: 2, SNAC(21,2) 2000/1070
  200.   if Buffer <> nil then
  201.   begin
  202.     if BufLen > 0 then
  203.     begin
  204.       PktLInt(@lpkt, BufLen + 1, 2);
  205.       PktAddArrBuf(@lpkt, Buffer, BufLen);
  206.       PktInt(@lpkt, $00, 1);
  207.     end else
  208.       PktLInt(@lpkt, $0000, 2);
  209.   end else
  210.     PktLNTS(@lpkt, Password);                   //User's Password
  211.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  212. end;
  213. {Set permissions.}
  214. procedure CreateCLI_METASETPERMISSIONS(Pkt: PRawPkt; UIN: LongWord; AuthorizationRequired, WebAware: Boolean; var Seq, Seq2: Word);
  215. var
  216.   lpkt: TRawPkt;
  217. begin
  218.   PktInitRaw(@lpkt);
  219.   PktInt(@lpkt, $2404, 2);                      //CLI_METASETPERMISSION Channel: 2, SNAC(21,2) 2000/1060
  220.   PktInt(@lpkt, Ord(not AuthorizationRequired), 1); //Authorization required?
  221.   PktInt(@lpkt, Ord(WebAware), 1);              //Webaware?
  222.   PktInt(@lpkt, $0100, 2);                      //Unknown: 01 00
  223.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  224. end;
  225. procedure CreateCLI_METAREQINFO_SHORT(Pkt: PRawPkt; UIN, DestUIN: LongWord; var Seq, Seq2: Word);
  226. var
  227.   lpkt: TRawPkt;
  228. begin
  229.   PktInitRaw(@lpkt);
  230.   PktInt(@lpkt, $BA04, 2);                      //CLI_METAREQINFO_SHORT Channel: 2, SNAC(21,2) 2000/1210
  231.   PktLInt(@lpkt, DestUIN, 4);
  232.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  233. end;
  234. {Request authorization from another user so we can add them to our contact list.}
  235. procedure CreateCLI_REQAUTH(Pkt: PRawPkt; UIN: LongWord; Msg: String; var Seq: Word);
  236. begin
  237.   PktInit(Pkt, 2, Seq);                         //Channel 2
  238.   PktSnac(Pkt, $13, $18, $18, 0);               //SNAC: 0x13/0x18, Ref 0x00000018, Flags 0
  239.   PktLStr(Pkt, UIN);                            //The UIN of the user authorization is requested from.
  240.   PktWStr(Pkt, Msg);                            //Message sent to user in the authorization request.
  241.   PktInt(Pkt, $0000, 2);                        //Unknown: empty.
  242.   PktFinal(Pkt);                                //Finalize packet.
  243. end;
  244. {Keep alive packet.}
  245. procedure CreateCLI_KEEPALIVE(Pkt: PRawPkt; var Seq: Word);
  246. begin
  247.   PktInit(Pkt, 5, Seq);                         //Channel 5
  248.   PktFinal(Pkt);                                //Finalize packet
  249. end;
  250. {This SNAC is sent just before CLI_ADDBUDDY when adding a new contact to the
  251. contact list. This SNAC is NOT sent when adding a UIN to the Ignore list. A
  252. CLI_ADDEND when finished modifying the server side contact list.}
  253. procedure CreateCLI_ADDSTART(Pkt: PRawPkt; FirstUpload: Boolean; var Seq: Word);
  254. begin
  255.   PktInit(Pkt, 2, Seq);                         //Channel 2
  256.   PktSnac(Pkt, $13, $11, $00000011, 0);         //SNAC: 0x13/0x18, Ref 0x00000011, Flags 0
  257.   if FirstUpload then
  258.     PktInt(Pkt, $00010000, 4);                  //Add 0x00010000 value when uploading w/o authorization
  259.   PktFinal(Pkt);                                //Finalize packet
  260. end;
  261. {This SNAC is sent to tell the server that modifications to the server side contact
  262. list are finished.}
  263. procedure CreateCLI_ADDEND(Pkt: PRawPkt; var Seq: Word);
  264. begin
  265.   PktInit(Pkt, 2, Seq);                         //Channel 2
  266.   PktSnac(Pkt, $13, $12, $00000012, 0);         //SNAC: 0x13/0x18, Ref 0x00000012, Flags 0
  267.   PktFinal(Pkt);                                //Finalize packet
  268. end;
  269. {This SNAC contains a single header group as described in SRV_REPLYROSTER. Sent
  270. when a user is added to the contact list and updates the server side contact list.}
  271. procedure CreateCLI_UPDATEGROUP(Pkt: PRawPkt; Name: String; Tag: Word; IDs: TStringList; var Seq: Word);
  272. var
  273.   TLVC8: TRawPkt;
  274.   i: Word;
  275. begin
  276.   PktInit(Pkt, 2, Seq);                         //Channel 2
  277.   PktSnac(Pkt, $13, $09, 0, 0);                 //SNAC: 0x13/0x09, Ref 0x00000000, Flags 0
  278.   {Create temporary array with group values}
  279.   PktInitRaw(@TLVC8);
  280.   if IDs.Count > 0 then
  281.     for i := 0 to IDs.Count - 1 do
  282.       PktInt(@TLVC8, StrToInt(IDs.Strings[i]), 2);
  283.   PktWStr(Pkt, StrToUTF8(Name));                //The name of this group.
  284.   PktInt(Pkt, Tag, 2);                          //The tag ID of this group. All members of this group have the same ID.
  285.   PktInt(Pkt, $0000, 2);                        //The individual ID assigned to a contact. 0 for group headers.
  286.   PktInt(Pkt, $0001, 2);                        //The type of the group. 0x0001 - Larger grouping header.
  287.   PktInt(Pkt, TLVC8.Len + 4, 2);                //The number of bytes in the following TLVs. May be zero.
  288.   PktTLV(Pkt, $00c8, TLVC8.Len, @TLVC8);        //Sent only with group header, a list of all IDs in this group.
  289.   PktFinal(Pkt);                                //Finalize packet
  290. end;
  291. {Same as CreateCLI_UPDATEGROUP modified to use only with buddies. Prototype. Can be used for UPDATEBUDDY and ADDBUDDY}
  292. procedure __CreateCLI_UPDATEBUDDY(Pkt: PRawPkt; A: Byte; UIN, Name, SMSNumber: String; Tag, ID: Word; BuddyType: Word; NotAuthorized, IsGroup: Boolean; var Seq: Word);
  293. var
  294.   TLVs: TRawPkt;
  295. begin
  296.   PktInit(Pkt, 2, Seq);                         //Channel 2
  297.   PktSnac(Pkt, $13, A, 0, 0);                   //SNAC: 0x13/0x08|0x09, Ref 0x00000000, Flags 0
  298.   {Create temporary array with addition TLVs}
  299.   PktInitRaw(@TLVs);
  300.   if Name <> '' then
  301.     PktTLV(@TLVs, $0131, StrToUTF8(Name));
  302.   if NotAuthorized then
  303.     PktTLV(@TLVs, $0066, 0, 0);
  304.   if SMSNumber <> '' then
  305.     PktTLV(@TLVs, $013A, StrToUTF8(SMSNumber));
  306.   PktWStr(Pkt, UIN);                            //The name of this group/buddy's UIN
  307.   PktInt(Pkt, Tag, 2);                          //The tag ID of this group. All members of this group have the same ID.
  308.   PktInt(Pkt, ID, 2);                           //The individual ID assigned to a contact. 0 for group headers.
  309.   PktInt(Pkt, BuddyType, 2);                    //The type of the buddy.
  310.   if IsGroup or ((A = $0A) and (TLVs.Len <> 0)) or (A <> $0A) then
  311.     PktInt(Pkt, TLVs.Len, 2);                   //The number of bytes in the following TLVs. May be zero.
  312.   PktAddArrBuf(Pkt, @TLVs, TLVs.Len);           //Sent only with group header, a list of all IDs in this group.
  313.   PktFinal(Pkt);                                //Finalize packet
  314. end;
  315. {Update SSL buddy.}
  316. procedure CreateCLI_UPDATEBUDDY(Pkt: PRawPkt; UIN, Name, SMSNumber: String; Tag, ID: Word; BuddyType: Word; NotAuthorized: Boolean; var Seq: Word);
  317. begin
  318.   __CreateCLI_UPDATEBUDDY(Pkt, $09, UIN, Name, SMSNumber, Tag, ID, BuddyType, NotAuthorized, False, Seq);
  319. end;
  320. {Add SSL buddy.}
  321. procedure CreateCLI_ADDBUDDY(Pkt: PRawPkt; UIN, Name, SMSNumber: String; Tag, ID: Word; BuddyType: Word; NotAuthorized: Boolean; var Seq: Word);
  322. begin
  323.   __CreateCLI_UPDATEBUDDY(Pkt, $08, UIN, Name, SMSNumber, Tag, ID, BuddyType, NotAuthorized, False, Seq);
  324. end;
  325. {Delete buddy from SSL.}
  326. procedure CreateCLI_DELETEBUDDY(Pkt: PRawPkt; UIN, Name, SMSNumber: String; Tag, ID: Word; BuddyType: Word; NotAuthorized, IsGroup: Boolean; var Seq: Word);
  327. begin
  328.   __CreateCLI_UPDATEBUDDY(Pkt, $0A, UIN, Name, SMSNumber, Tag, ID, BuddyType, NotAuthorized, IsGroup, Seq);
  329. end;
  330. {Conver SNAC's numberic representation to string name}
  331. function SnacToStr(Family, SubType: Word): String;
  332. begin
  333.   Result := 'unknown';
  334.   {CLI}
  335.   if (Family = 1) and (SubType = 2) then
  336.     Result := 'CLI_READY'
  337.   else if (Family = 1) and (SubType = 6) then
  338.     Result := 'CLI_RATESREQUEST'
  339.   else if (Family = 1) and (SubType = 8) then
  340.     Result := 'CLI_ACKRATES'
  341.   else if (Family = 1) and (SubType = $E) then
  342.     Result := 'CLI_REQINFO'
  343.   else if (Family = 1) and (SubType = $17) then
  344.     Result := 'CLI_FAMILIES'
  345.   else if (Family = 1) and (SubType = $1E) then
  346.     Result := 'CLI_SETSTATUS'
  347.   else if (Family = 2) and (SubType = $2) then
  348.     Result := 'CLI_REQLOCATION'
  349.   else if (Family = 2) and (SubType = $4) then
  350.     Result := 'CLI_SETUSERINFO'
  351.   else if (Family = 3) and (SubType = $2) then
  352.     Result := 'CLI_REQBUDDY'
  353.   else if (Family = 3) and (SubType = $4) then
  354.     Result := 'CLI_ADDCONTACT'
  355.   else if (Family = 3) and (SubType = $5) then
  356.     Result := 'CLI_REMOVECONTACT'
  357.   else if (Family = 4) and (SubType = $2) then
  358.     Result := 'CLI_SETICBM'
  359.   else if (Family = 4) and (SubType = $4) then
  360.     Result := 'CLI_REQICBM'
  361.   else if (Family = 4) and (SubType = $6) then
  362.     Result := 'CLI_SENDMSG'
  363.   else if (Family = 4) and (SubType = $B) then
  364.     Result := 'CLI_ACKMSG'
  365.   else if (Family = 9) and (SubType = $2) then
  366.     Result := 'CLI_REQBOS'
  367.   else if (Family = 9) and (SubType = $5) then
  368.     Result := 'CLI_ADDVISIBLE'
  369.   else if (Family = 9) and (SubType = $6) then
  370.     Result := 'CLI_REMVISIBLE'
  371.   else if (Family = 9) and (SubType = $7) then
  372.     Result := 'CLI_ADDINVISIBLE'
  373.   else if (Family = 9) and (SubType = $8) then
  374.     Result := 'CLI_REMINVISIBLE'
  375.   else if (Family = $13) and (SubType = $2) then
  376.     Result := 'CLI_REQUNKNOWN'
  377.   else if (Family = $13) and (SubType = $4) then
  378.     Result := 'CLI_REQROSTER2'
  379.   else if (Family = $13) and (SubType = $5) then
  380.     Result := 'CLI_REQROSTER'
  381.   else if (Family = $13) and (SubType = $7) then
  382.     Result := 'CLI_UNKNOWN1'
  383.   else if (Family = $13) and (SubType = $8) then
  384.     Result := 'CLI_ADDBUDDY'
  385.   else if (Family = $13) and (SubType = $9) then
  386.     Result := 'CLI_UPDATEGROUP'
  387.   else if (Family = $13) and (SubType = $A) then
  388.     Result := 'CLI_DELETEBUDDY'
  389.   else if (Family = $13) and (SubType = $11) then
  390.     Result := 'CLI_ADDSTART'
  391.   else if (Family = $13) and (SubType = $12) then
  392.     Result := 'CLI_ADDEND'
  393.   else if (Family = $13) and (SubType = $18) then
  394.     Result := 'CLI_REQAUTH'
  395.   else if (Family = $13) and (SubType = $1A) then
  396.     Result := 'CLI_AUTHORIZE'
  397.   else if (Family = $15) and (SubType = $2) then
  398.     Result := 'CLI_TOICQSRV'
  399.   else if (Family = $17) and (SubType = $4) then
  400.     Result := 'CLI_REGISTERUSER'
  401.   {SRV}
  402.   else if (Family = $1) and (SubType = $3) then
  403.     Result := 'SRV_FAMILIES'
  404.   else if (Family = $1) and (SubType = $7) then
  405.     Result := 'SRV_RATES'
  406.   else if (Family = $1) and (SubType = $F) then
  407.     Result := 'SRV_REPLYINFO'
  408.   else if (Family = $1) and (SubType = $13) then
  409.     Result := 'SRV_MOTD'
  410.   else if (Family = $1) and (SubType = $18) then
  411.     Result := 'SRV_FAMILIES2'
  412.   else if (Family = $2) and (SubType = $3) then
  413.     Result := 'SRV_REPLYLOCATION'
  414.   else if (Family = $3) and (SubType = $3) then
  415.     Result := 'SRV_REPLYBUDDY'
  416.   else if (Family = $3) and (SubType = $B) then
  417.     Result := 'SRV_USERONLINE'
  418.   else if (Family = $3) and (SubType = $C) then
  419.     Result := 'SRV_USEROFFLINE'
  420.   else if (Family = $4) and (SubType = $5) then
  421.     Result := 'SRV_REPLYICBM'
  422.   else if (Family = $4) and (SubType = $7) then
  423.     Result := 'SRV_RECVMSG'
  424.   else if (Family = $4) and (SubType = $c) then
  425.     Result := 'SRV_MSGACK_ADVANCED'
  426.   else if (Family = $9) and (SubType = $3) then
  427.     Result := 'SRV_REPLYBOS'
  428.   else if (Family = $13) and (SubType = $3) then
  429.     Result := 'SRV_REPLYUNKNOWN'
  430.   else if (Family = $13) and (SubType = $6) then
  431.     Result := 'SRV_REPLYROSTER'
  432.   else if (Family = $13) and (SubType = $E) then
  433.     Result := 'SRV_UPDATEACK'
  434.   else if (Family = $13) and (SubType = $F) then
  435.     Result := 'SRV_REPLYROSTEROK'
  436.   else if (Family = $13) and (SubType = $19) then
  437.     Result := 'SRV_AUTHORIZATION_REQUEST'
  438.   else if (Family = $13) and (SubType = $1C) then
  439.     Result := 'SRV_ADDEDYOU'
  440.   else if (Family = $15) and (SubType = $3) then
  441.     Result := 'SRV_FROMICQSRV'
  442.   else if (Family = $17) and (SubType = $1) then
  443.     Result := 'SRV_REGREFUSED'
  444.   else if (Family = $17) and (SubType = $5) then
  445.     Result := 'SRV_NEWUIN';
  446. end;
  447. {Convert meta command to string representation.}
  448. function SrvMetaToStr(V1, V2: Word): String;
  449. begin
  450.   Result := '';
  451.   if V1 = 2000 then
  452.     case V2 of
  453.       1002: Result := 'CLI_METASETGENERAL';
  454.       1021: Result := 'CLI_METASETMORE';
  455.       1030: Result := 'CLI_METASETABOUT';
  456.       1060: Result := 'CLI_SETAUTH';
  457.       1070: Result := 'CLI_METASETPASS';
  458.       1210: Result := 'CLI_METAREQINFO_SHORT';
  459.       1220: Result := 'CLI_METAUNREG';      
  460.       1232: Result := 'CLI_METAREQINFO';
  461.       1331: Result := 'CLI_SEARCHWP';
  462.       1375: Result := 'CLI_SEARCHBYPERSINF';
  463.       1385: Result := 'CLI_SEARCHBYUIN';
  464.       1395: Result := 'CLI_SEARCHBYMAIL';
  465.       1870: Result := 'CLI_SEARCHRANDOM';
  466.       1880: Result := 'CLI_METASETRANDOM';
  467.       2200: Result := 'CLI_REQXML';
  468.       5250: Result := 'CLI_SENDSMS';
  469.     end
  470.   else if V1 = 2010 then
  471.     case V2 of
  472.       1:   Result := 'SRV_SMSREFUSED';
  473.       100: Result := 'SRV_METAGENERALDONE';
  474.       120: Result := 'SRV_METAMOREDONE';
  475.       130: Result := 'SRV_METAABOUTDONE';
  476.       150: Result := 'SRV_SMSACK';
  477.       160: Result := 'SRV_AUTHDONE';
  478.       170: Result := 'SRV_METAPASSDONE';
  479.       180: Result := 'SRV_METAUNREG';
  480.       200: Result := 'SRV_METAGENERAL';
  481.       210: Result := 'SRV_METAWORK';
  482.       220: Result := 'SRV_METAMORE';
  483.       230: Result := 'SRV_METAABOUT';
  484.       235: Result := 'SRV_METAMOREEMAIL';
  485.       240: Result := 'SRV_METAINTEREST';
  486.       250: Result := 'SRV_METABACKGROUND';
  487.       260: Result := 'SRV_METAINFO';
  488.       270: Result := 'SRV_META270';
  489.       420: Result := 'SRV_METAFOUND';
  490.       430: Result := 'SRV_METALAST';
  491.       870: Result := 'SRV_METARANDOM';
  492.       880: Result := 'SRV_METARANDOMDONE';
  493.     end
  494.   else if V1 = 60 then
  495.     Result := 'CLI_REQOFFLINEMSGS'
  496.   else if V1 = 62 then
  497.     Result := 'CLI_ACKOFFLINEMSGS'
  498.   else if V1 = 65 then
  499.     Result := 'SRV_OFFLINEMSG'
  500.   else if V1 = 66 then
  501.     Result := 'SRV_DONEOFFLINEMSGS';
  502.   if Result = '' then
  503.     Result := IntToStr(V1) + '/' + IntToStr(V2);
  504. end;
  505. {Convert peer command to string representation.}
  506. function PeerCmdToStr(Cmd: Byte): String;
  507. begin
  508.   case Cmd of
  509.     $00: Result := 'PEER_FILE_INIT';
  510.     $01: Result := 'PEER_INIT_ACK';
  511.     $02: Result := 'PEER_MSG';
  512.     $03: Result := 'PEER_INIT2';
  513.     $06: Result := 'PEER_FILEDATA';    
  514.     $ff: Result := 'PEER_INIT';
  515.   else
  516.     Result := '';
  517.   end;
  518. end;
  519. {Return Buffer in a string hex dump.}
  520. function DumpPacket(Buffer: Pointer; BufLen: Word): String;
  521. var
  522.   S: String;
  523.   i, n: Word;
  524. begin
  525.   for i := 1 to BufLen do
  526.   begin
  527.     S := S + IntToHex(PByte(LongWord(Buffer) + i - 1)^, 2) + ' ';
  528.     if i mod 16 = 0 then
  529.     begin
  530.       S := S + '  ';
  531.       for n := i - 15 to i do
  532.       begin
  533.         if (PByte(LongWord(Buffer) + n - 1)^ < $20) or (PByte(LongWord(Buffer) + n - 1)^ > $7F) then
  534.           S := S + '.'
  535.         else
  536.           S := S + PChar(Buffer)[n - 1];
  537.       end;
  538.       S := S + #13#10;
  539.     end;
  540.   end;
  541.   if BufLen mod 16 <> 0 then
  542.   begin
  543.     for i := 0 to 15 - (BufLen mod 16) do
  544.       S := S + '   ';
  545.     S := S + '  ';
  546.     for i := BufLen mod 16 downto 1 do
  547.     begin
  548.       if (PByte(LongWord(Buffer) + BufLen - i)^ < $20) or (PByte(LongWord(Buffer) + BufLen - i)^ > $7F) then
  549.         S := S + '.'
  550.       else
  551.         S := S + PChar(Buffer)[BufLen - i];
  552.     end;
  553.   end;
  554.   Result := S;
  555. end;
  556. {Convert RTF enabled text to plain.}
  557. function Rtf2Txt(const Value: String): String;
  558. var
  559.   i: Word;
  560.   tag: Boolean;
  561.   st: String;
  562. begin
  563.   Result := ''; tag := False; st := '';
  564.   if Value = '' then Exit;
  565.   if Copy(Value, 0, 6) <> '{rtf1' then
  566.   begin
  567.     Result := Value;
  568.     Exit;
  569.   end;
  570.   for i := 1 to Length(Value) do
  571.   begin
  572.     if Value[i] in ['', '}', '{'] then
  573.       tag := True;
  574.     if Value[i + 1] in ['', '}', '{'] then
  575.     begin
  576.       tag := False;
  577.       if st <> '' then
  578.       begin
  579.         if st = 'par' then Result := Result + #13#10
  580.         else if (st[1] = '''') and (Length(st) >= 3) then
  581.         begin
  582.           Delete(st, 1, 1);
  583.           Result := Result + Chr(HexToInt(Copy(st, 0, 2))) + Copy(st, 3, Length(st) - 2);
  584.         end
  585.         else if ((Pos(' ', st) > 0) or ((Copy(st, 0, 3) = 'par') and (st <> 'pard'))) and (st[Length(st)] <> ';') then
  586.         begin
  587.           while (Pos(#13, st) > 0) do Delete(st, Pos(#13, st), 1);
  588.           while (Pos(#10, st) > 0) do Delete(st, Pos(#10, st), 1);
  589.           if Copy(st, 0, 3) = 'par' then
  590.             Result := Result + #13#10 + Copy(st, 4, Length(st) - 3)
  591.           else
  592.             Result := Result + Copy(st, Pos(' ', st) + 1, Length(st) - Pos(' ', st));
  593.         end;
  594.       end;
  595.       st := '';
  596.     end;
  597.     if tag then
  598.       st := st + Value[i + 1];
  599.   end;
  600. end;
  601. function StatusToStr(Value: LongWord): String;
  602. begin
  603.   {Remove any used flags.}
  604.   Value := Value and not S_SHOWIP and not S_WEBAWARE and not S_ALLOWDCONN
  605.                  and not S_ALLOWDAUTH and not S_ALLOWDLIST;
  606.   if Value = S_INVISIBLE then
  607.     Result := 'Invisible'
  608.   else if Value = S_AWAY then
  609.     Result := 'Away'
  610.   else if Value = S_NA then
  611.     Result := 'N/A'
  612.   else if Value = S_OCCUPIED then
  613.     Result := 'Occupied'
  614.   else if Value = S_DND then
  615.     Result := 'DND'
  616.   else if Value = S_FFC then
  617.     Result := 'FFC'
  618.   else
  619.     Result := 'Online';
  620. end;
  621. function CountryToStr(Value: Word): String;
  622. var
  623.   i: Word;
  624. begin
  625.   Result := '';
  626.   for i := Low(Countries) to High(Countries) do
  627.     if Countries[i].Ident = Value then
  628.     begin
  629.       Result := Countries[i].Value;
  630.       Exit;
  631.     end;
  632. end;
  633. function LanguageToStr(Value: Byte): String;
  634. var
  635.   i: Byte;
  636. begin
  637.   for i := Low(Languages) to High(Languages) do
  638.     if Languages[i].Ident = Value then
  639.     begin
  640.       Result := Languages[i].Value;
  641.       Exit;
  642.     end;
  643.   Result := '';
  644. end;
  645. function OccupationToStr(Value: Word): String;
  646. begin
  647.   if (Value >= Low(Occupations)) and (Value <= High(Occupations)) then
  648.     Result := Occupations[Value].Value
  649.   else
  650.     Result := '';
  651. end;
  652. function InterestToStr(Value: Word): String;
  653. begin
  654.   if (Value >= Low(Interests)) and (Value <= High(Interests)) then
  655.     Result := Interests[Value].Value
  656.   else
  657.     Result := '';
  658. end;
  659. function PastToStr(Value: Word): String;
  660. var
  661.   i: Word;
  662. begin
  663.   for i := Low(Pasts) to High(Pasts) do
  664.     if Pasts[i].Ident = Value then
  665.     begin
  666.       Result := Pasts[i].Value;
  667.       Exit;
  668.     end;
  669.   Result := '';
  670. end;
  671. function AffiliationToStr(Value: Word): String;
  672. var
  673.   i: Word;
  674. begin
  675.   for i := Low(Organizations) to High(Organizations) do
  676.     if Organizations[i].Ident = Value then
  677.     begin
  678.       Result := Organizations[i].Value;
  679.       Exit;
  680.     end;
  681.   Result := '';
  682. end;
  683. {Local raw packet from file.}
  684. function LoadPacketRaw(Pkt: PRawPkt; const FName: String): Boolean;
  685. function TestDigit(Digit: Char): Boolean;
  686. begin
  687.   Result := False;
  688.   case Digit of
  689.     '0'..'9': Result := True;
  690.     'A', 'B', 'C', 'D', 'E', 'F',
  691.     'a', 'b', 'c', 'd', 'e', 'f': Result := True;
  692.   end;
  693. end;
  694. function Convert(Digit: Char): Byte;
  695. begin
  696.   Result := 0;
  697.   case Digit of
  698.     '0'..'9': Result := StrToInt(Digit);
  699.     'A', 'a': Result := $A;
  700.     'B', 'b': Result := $B;
  701.     'C', 'c': Result := $C;
  702.     'D', 'd': Result := $D;
  703.     'E', 'e': Result := $E;
  704.     'F', 'f': Result := $F;
  705.   end;
  706. end;
  707. var
  708.   F: TextFile;
  709.   c, c1: Char;
  710.   i: Integer;
  711. begin
  712.   PktInitRaw(Pkt);
  713.   System.Assign(F, FName); Reset(F);
  714.   while not Eof(F) do
  715.   begin
  716.     for i := 0 to 15 do
  717.     begin
  718.       Read(F, c);
  719.       Read(F, c1);
  720.       if TestDigit(c) and TestDigit(c1) then
  721.         PktInt(Pkt, Convert(c) shl 4 + Convert(c1), 1);
  722.       Read(F, c);
  723.       if c = '' then Break;
  724.     end;
  725.     Readln(F);
  726.   end;
  727.   System.Close(F);
  728.   Result := True;
  729. end;
  730. {Load low packet from file & extract snac header.}
  731. function LoadPacket(Pkt: PRawPkt; const FName: String; var Flap: TFlapHdr; var Snac: TSnacHdr): Boolean;
  732. begin
  733.   Result := LoadPacketRaw(Pkt, FName);
  734.   pkt^.Len := TFLAPSZ;
  735.   GetSnac(Pkt, Snac);
  736. end;
  737. {Checks if the FileName is exists.}
  738. function FileExists(const FileName: String): Boolean;
  739. var
  740.   Handle: THandle;
  741.   FindData: TWin32FindData;
  742. begin
  743.   Handle := FindFirstFile(PChar(FileName), FindData);
  744.   Result := (Handle <> INVALID_HANDLE_VALUE) and (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = 0);
  745.   Windows.FindClose(Handle);
  746. end;
  747. {Get size of a file.}
  748. function FileSize(const FName: String): LongWord;
  749. var
  750.   FileHandle: THandle;
  751. begin
  752.   Result := INVALID_FILE_SIZE;
  753.   FileHandle := CreateFile(PChar(FName), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_ALWAYS, 0, 0);
  754.   if FileHandle = INVALID_HANDLE_VALUE then Exit;
  755.   Result := GetFileSize(FileHandle, nil);
  756.   CloseHandle(FileHandle);
  757. end;
  758. {Add some Text to FName file.}
  759. procedure LogText(const FName, Text: String);
  760. var
  761.   F: TextFile;
  762. begin
  763.   if not FileExists(FName) then
  764.   begin
  765.     Assign(F, FName);
  766.     {$I-}
  767.     ReWrite(F);
  768.     if IOResult <> 0 then
  769.       Exit;
  770.     {$I+}
  771.     CloseFile(F);
  772.   end;
  773.   Assign(F, FName);
  774.   {$I-}
  775.   Append(F);
  776.   if IOResult <> 0 then
  777.     Exit;
  778.   Writeln(F, Text);
  779.   {$I+}
  780.   CloseFile(F);
  781. end;
  782. {Overloaded procedure equal to ShowMessage() from 'Dialogs' unit}
  783. procedure ShowMessage(const Value: String); overload;
  784. begin
  785.   MessageBox(0, PChar(Value), 'Message', 0);
  786. end;
  787. procedure ShowMessage(Value: LongWord); overload;
  788. begin
  789.   MessageBox(0, PChar(IntToStr(Value)), 'Message', 0);
  790. end;
  791. //Extract the name from the following string: 'AA=BB', where AA is name
  792. function ExtractName(const Value: String): String;
  793. var
  794.   i: Word;
  795. begin
  796.   Result := '';
  797.   i := Pos('=', Value);
  798.   if i = 0 then
  799.     Exit;
  800.   Result := Copy(Value, 0, i - 1);
  801. end;
  802. //Extract the value from the following string: 'AA=BB', where BB is value
  803. function ExtractValue(const Value: String): String;
  804. var
  805.   i: Word;
  806. begin
  807.   Result := '';
  808.   i := Pos('=', Value);
  809.   if i = 0 then
  810.     Exit;
  811.   Result := Copy(Value, i + 1, Length(Value) - i);
  812. end;
  813. {Convert string from UTF-8 format into ASCII}
  814. function UTF8ToStr(Value: String): String;
  815. var
  816.   buffer: Pointer;
  817.   BufLen: LongWord;
  818. begin
  819.   BufLen := Length(Value) + 4;
  820.   GetMem(buffer, BufLen);
  821.   FillChar(buffer^, BufLen, 0);
  822.   MultiByteToWideChar(CP_UTF8, 0, @Value[1], BufLen - 4, buffer, BufLen);
  823.   Result := WideCharToString(buffer);
  824.   FreeMem(buffer, BufLen);
  825. end;
  826. {Convert string from UTF-8 format mixed with standart ASCII symbols($00..$7f)}
  827. function UTF8ToStrSmart(Value: String): String;
  828. var
  829.   Digit: String;
  830.   i: Word;
  831.   HByte: Byte;
  832.   Len: Byte;
  833. begin
  834.   Result := '';
  835.   Len := 0;
  836.   if Value = '' then Exit;
  837.   for i := 1 to Length(Value) do
  838.   begin
  839.     if Len > 0 then
  840.     begin
  841.       Digit := Digit + Value[i];
  842.       Dec(Len);
  843.       if Len = 0 then
  844.         Result := Result + UTF8ToStr(Digit);
  845.     end else
  846.     begin
  847.       HByte := Ord(Value[i]);
  848.       if HByte in [$00..$7f] then       //Standart ASCII chars
  849.         Result := Result + Value[i]
  850.       else begin
  851.         //Get length of UTF-8 char
  852.         if HByte and $FC = $FC then
  853.           Len := 6
  854.         else if HByte and $F8 = $F8 then
  855.           Len := 5
  856.         else if HByte and $F0 = $F0 then
  857.           Len := 4
  858.         else if HByte and $E0 = $E0 then
  859.           Len := 3
  860.         else if HByte and $C0 = $C0 then
  861.           Len := 2
  862.         else begin
  863.           Result := Result + Value[i];
  864.           Continue;
  865.         end;
  866.         Dec(Len);
  867.         Digit := Value[i];
  868.       end;
  869.     end;
  870.   end;
  871. end;
  872. {Get an XML entry.}
  873. function GetXMLEntry(const Tag, Msg: String): String;
  874. var
  875.   p1, p2: Word;
  876. begin
  877.   p1 := Pos('<' + Tag + '>', Msg);
  878.   p2 := Pos('</' + Tag + '>', Msg);
  879.   Result := Copy(Msg, p1 + Length(Tag) + 2, p2 - p1 - Length(Tag) - 2);
  880. end;
  881. {SMS functions}
  882. {Convert string to UTF8 format}
  883. function StrToUTF8(Value: String): String;
  884. var
  885.   buffer: Pointer;
  886.   BufLen: LongWord;
  887.   lpBuf: Pointer;
  888. begin
  889.   BufLen := Length(Value) * 2 + 4;
  890.   GetMem(buffer, BufLen); FillChar(buffer^, BufLen, 0);
  891.   GetMem(lpBuf, BufLen); FillChar(lpBuf^, BufLen, 0);
  892.   StringToWideChar(Value, buffer, BufLen);
  893.   WideCharToMultiByte(CP_UTF8, 0, buffer, -1, lpBuf, BufLen, nil, nil);
  894.   FreeMem(buffer, BufLen);
  895.   Result := PChar(lpBuf);
  896.   FreeMem(lpBuf, BufLen);
  897. end;
  898. {Get current time in format like 'Mon, 19 Nov 2001 08:23:38 GMT'}
  899. function STime: String;
  900. var
  901.   buf: array[0..15] of Char;
  902.   recv_bytes: Integer;
  903.   SysTime: TSystemTime;
  904. begin
  905.   GetSystemTime(SysTime);
  906.   recv_bytes := GetTimeFormat(LANG_ENGLISH, TIME_FORCE24HOURFORMAT,
  907.     @SysTime, PChar('HH:mm:ss'), @buf, SizeOf(buf));
  908.   Result := Copy(buf, 0, recv_bytes);
  909. end;
  910. {Get current time in format like 'Mon, 19 Nov 2001 08:23:38 GMT'}
  911. function GetSMSTime: String;
  912.   function STime: String;
  913.   var
  914.     buf: array[0..15] of Char;
  915.     recv_bytes: Integer;
  916.     SysTime: TSystemTime;
  917.   begin
  918.     GetSystemTime(SysTime);
  919.     recv_bytes := GetTimeFormat(LANG_ENGLISH, TIME_FORCE24HOURFORMAT,
  920.       @SysTime, PChar('HH:mm:ss'), @buf, SizeOf(buf));
  921.     Result := Copy(buf, 0, recv_bytes);
  922.   end;
  923.   function SDate: String;
  924.   var
  925.     buf: array[0..15] of Char;
  926.     recv_bytes: Integer;
  927.     SysTime: TSystemTime;
  928.   begin
  929.     GetSystemTime(SysTime);
  930.     recv_bytes := GetDateFormat(LANG_ENGLISH, 0,
  931.       @SysTime, 'dd MMM yyyy', @buf, SizeOf(buf));
  932.     Result := Copy(buf, 0, recv_bytes);
  933.   end;
  934. begin
  935.   Result := SDate + ' ' + STime + ' GMT';
  936. end;
  937. const
  938.   client_check_data: PChar =
  939.     'As part of this software beta version Mirabilis is ' +
  940.     'granting a limited access to the ICQ network, ' +
  941.     'servers, directories, listings, information and databases ("' +
  942.     'ICQ Services and Information"). The ' +
  943.     'ICQ Service and Information may databases ("' +
  944.     'ICQ Services and Information"). The ' +
  945.     'ICQ Service and Information may'#0;
  946. {Decrypt peer packet.}
  947. function DecryptPak(Pak: Pointer; Size: LongWord; Ver: Byte): Boolean;
  948. var
  949.   hex, key, B1, M1, check: LongWord;
  950.   i: Word;
  951.   X1, X2, X3: Byte;
  952. begin
  953.   if Ver > 6 then
  954.   begin
  955.     Pak := Ptr(LongWord(Pak) + 1);
  956.     Dec(Size);
  957.   end;
  958.   { get checkcode }
  959.   check := PLongWord(pak)^;
  960.   { primary decryption }
  961.   key := $67657268 * size + check;
  962.   i := 4;
  963.   while i < Integer((size + 3) shr 2) do
  964.   begin
  965.     hex := key + Ord(client_check_data[i and $FF]);
  966.     PLongWord(LongWord(pak) + i)^ := PLongWord(LongWord(pak) + i)^ xor hex;
  967.     Inc(i, 4);
  968.   end;
  969.   B1 := (PByte(LongWord(pak) + 4)^ shl 24) or (PByte(LongWord(pak) + 6)^ shl 16) or (PByte(LongWord(pak) + 4)^ shl 8) or (PByte(LongWord(pak) + 6)^ shl 0);
  970.   { special decryption }
  971.   B1 := B1 xor check;
  972.   { validate packet }
  973.   M1 := (B1 shr 24) and $FF;
  974.   if (M1 < 10) or (M1 >= size) then
  975.   begin
  976.     Result := False;
  977.     Exit;
  978.   end;
  979.   X1 := PByte(LongWord(pak) + M1)^ xor $FF;
  980.   if (((B1 shr 16) and $FF) <> X1) then
  981.   begin
  982.     Result := False;
  983.     Exit;
  984.   end;
  985.   X2 := ((B1 shr 8) and $FF);
  986.   if (X2 < 220) then
  987.   begin
  988.     X3 := Ord(client_check_data[X2]) xor $FF;
  989.     if (B1 and $FF) <> X3 then
  990.     begin
  991.       Result := False;
  992.       Exit;
  993.     end;
  994.   end;
  995.   Result := True;
  996. end;
  997. {Encrypt peer packet.}
  998. procedure EncryptPak(Pak: Pointer; Size: LongWord; Ver: Byte);
  999. var
  1000.   B1, M1, check, hex, key: LongWord;
  1001.   i: Word;
  1002.   X1, X2, X3, at: Byte;
  1003.   p: PByte;
  1004. begin
  1005.   p := Pak;
  1006.   size := Size;
  1007.   if (Ver > 6) then
  1008.   begin
  1009.     Inc(p);
  1010.     Dec(Size);
  1011.   end;
  1012.   { calculate verification data }
  1013.   if size < 255 then
  1014.     M1 := (Random(High(Word)) mod (Integer(size - 10))) + 10
  1015.   else
  1016.     M1 := (Random(High(Word)) mod 245) + 10;
  1017.   X1 := PByte(LongWord(p) + M1)^ xor $FF;
  1018.   X2 := Random(High(Word)) mod 220;
  1019.   X3 := Ord(client_check_data[X2]) xor $FF;
  1020.   B1 := (PByte(LongWord(p) + 4)^ shl 24) or (PByte(LongWord(p) + 6)^ shl 16) or
  1021.         (PByte(LongWord(p) + 4)^ shl 8) or (PByte(LongWord(p) + 6)^);
  1022.   { calculate checkcode }
  1023.   check := (M1 shl 24) or (X1 shl 16) or (X2 shl 8) or X3;
  1024.   check := check xor B1;
  1025.   { main XOR key }
  1026.   key := $67657268 * size + check;
  1027.   { XORing the actual data }
  1028.   i := 0;
  1029.   while i < ((size + 3) div 4) do
  1030.   begin
  1031.     hex := key + Ord(client_check_data[i and $FF]);
  1032.     PLongWord(LongWord(p) + i)^ := PLongWord(LongWord(p) + i)^ xor hex;
  1033.     Inc(i, 4);
  1034.   end;
  1035.   { storing the checkcode }
  1036.   if Ver > 6 then at := 1 else at := 0;
  1037.   PLongWord(LongWord(pak) + at)^ := check;
  1038. end;
  1039. {This packet is sent during direct connection initialization between two ICQ clients.
  1040. It is sent by the originator of the connection to start the handshake and by the
  1041. receiver directly after it has sent the PEER_ACK packet as a reply to the originator's
  1042. PEER_INIT.}
  1043. procedure CreatePEER_INIT(Pkt: PRawPkt; Cookie, DestUIN, SrcUIN, SrcPort, SrcIPExt, SrcIPInt: LongWord; ProxyType: TProxyType);
  1044. begin
  1045.   PktInitRaw(Pkt);
  1046.   PktInt(Pkt, $ff, 1);          //The command: connect.
  1047.   PktInt(Pkt, $0800, 2);        //The peer-to-peer version this packet uses.
  1048.   PktInt(Pkt, $2b00, 2);        //The length of the following data in bytes.
  1049.   PktLInt(Pkt, DestUIN, 4);     //The UIN this packet is sent to.
  1050.   PktInt(Pkt, $0000, 2);        //Unknown: empty.
  1051.   PktLInt(Pkt, SrcPort, 4);     //The port the sender listens on.
  1052.   PktLInt(Pkt, SrcUIN, 4);      //The UIN of the sender.
  1053.   PktLInt(Pkt, SrcIPExt, 4);    //The IP of the sender as the server sees it.
  1054.   PktLInt(Pkt, SrcIPInt, 4);    //The local IP of the sender.
  1055.   if ProxyType = P_NONE then
  1056.     PktInt(Pkt, $04, 1)         //TCP connection flags: dirrect connection
  1057.   else
  1058.     PktInt(Pkt, $02, 1);        //TCP connection flags: 02 - SOCKS4/5 proxy
  1059.   PktLInt(Pkt, SrcPort, 4);     //The sender's "other" port.
  1060.   PktInt(Pkt, Cookie, 4);       //The connection cookie the server gave for this pair of UINs
  1061.   PktInt(Pkt, $50000000, 4);    //Unknown: 0x50 = 80.
  1062.   PktInt(Pkt, $03000000, 4);    //Unknown: 0x3 = 3.
  1063.   PktInt(Pkt, $00000000, 4);    //Unknown: empty.
  1064. end;
  1065. {This is an additional packet in the peer-to-peer handshake. The purpose is still
  1066. unknown. It is sent by the originator of the connection after he has acknowledged
  1067. the peer's PEER_INIT and by the peer as a reply to the originator's PEER_INIT2.}
  1068. procedure CreatePEER_INIT2(Pkt: PRawPkt; Ack: Boolean);
  1069. begin
  1070.   PktInitRaw(Pkt);
  1071.   PktInt(Pkt, $03, 1);          //The command: the last connect package
  1072.   PktInt(Pkt, $0a000000, 4);    //Unknown: 0xa = 10.
  1073.   PktInt(Pkt, $01000000, 4);    //Unknown: 0x1 = 1.
  1074.   if Ack then                   //
  1075.     PktInt(Pkt, $01000000, 4)   //Unknown. Use 01 00 00 00 = 0x1 = 1 for incoming,
  1076.   else                          //
  1077.     PktInt(Pkt, $00000000, 4);  //0 for outgoing connections.
  1078.   PktInt(Pkt, $00000000, 4);    //Unknown: empty.
  1079.   PktInt(Pkt, $00000000, 4);    //Unknown: empty.
  1080.   if Ack then                   //
  1081.     PktInt(Pkt, $01000400, 4)   //Unknown. Use 01 00 04 00 = 0x40001 for incoming
  1082.   else                          //
  1083.     PktInt(Pkt, $00000000, 4);  //and 0 for outgoing connections.
  1084.   PktInt(Pkt, $00000000, 4);    //Unknown: empty.
  1085.   if Ack then                   //
  1086.     PktInt(Pkt, $00000000, 4)   //Unknown. Use 0 on incoming,
  1087.   else                          //
  1088.     PktInt(Pkt, $01000400, 4);  //but 01 00 04 00 = 0x4001 for outgoing connections.
  1089. end;
  1090. {Acknowledges the receipt of a PEER_INIT packet.}
  1091. procedure CreatePEER_ACK(Pkt: PRawPkt);
  1092. begin
  1093.   PktInitRaw(Pkt);
  1094.   PktInt(Pkt, $01000000, 4);    //The command: acknowlegde the PEER_INIT
  1095. end;
  1096. {Basic header of outgoing PEER packet.}
  1097. procedure CreatePEER_HDR(Pkt: PRawPkt; Cmd, SubCmd, Seq: Word; Accept: Boolean);
  1098. begin
  1099.   PktInitRaw(Pkt);              //Init
  1100.   PktInt(Pkt, $02, 1);          //The command: send a message.
  1101.   PktInt(Pkt, $00000000, 4);    //The checksum of this packet.
  1102.   PktInt(Pkt, Cmd, 2);          //Message common type
  1103.   PktInt(Pkt, $0e00, 2);        //Unknown: 0xe = 14.
  1104.   PktLInt(Pkt, Seq, 2);         //Our sequence number.
  1105.   PktInt(Pkt, $00000000, 4);    //Unknown: empty.
  1106.   PktInt(Pkt, $00000000, 4);    //Unknown: empty.
  1107.   PktInt(Pkt, $00000000, 4);    //Unknown: empty.
  1108.   PktInt(Pkt, SubCmd, 2);       //The message type: message
  1109.   if Accept then
  1110.     PktInt(Pkt, $0000, 2)       //0x0000 - accept
  1111.   else
  1112.     PktInt(Pkt, $0100, 2);      //0x0100 - decline
  1113. end;
  1114. {Send a message to peer.}
  1115. function CreatePEER_MSG(Pkt: PRawPkt; const Msg: String; RTFFormat: Boolean; var Seq: Word): Word;
  1116. const
  1117.   StrGuid: String = '{97B12751-243C-4334-AD22-D6ABF73F1492}';
  1118. begin
  1119.   CreatePEER_HDR(Pkt, $ee07, $0100, Seq, True);
  1120.   PktInt(Pkt, $0000, 2);        //Our status.
  1121.   PktLNTS(Pkt, Msg);            //Finally the message.
  1122.   PktInt(Pkt, $00000000, 4);    //The foreground the client is expected to use.
  1123.   PktInt(Pkt, $ffffff00, 4);    //The background color the client is expected to show the message with.
  1124.   if RTFFormat then
  1125.   begin
  1126.     PktLInt(Pkt, Length(StrGuid), 4);    //This is a little-endian string length of the following GUID. This is only present in real messages sent by the latest 2001b client build 3659.
  1127.     PktStr(Pkt, StrGuid);                //This GUID seems to indicate that the client is capable of handling Multibyte Wide Character Strings as messages. Only present in real messages sent by build 3659 2001b clients.}
  1128.   end;
  1129.   EncryptPak(Pkt, Pkt^.Len, 8); //Encrypt packet
  1130.   Result := Seq; Inc(Seq);      //Inc Seq
  1131. end;
  1132. {Ack}
  1133. procedure CreatePEER_MSGACK(Pkt: PRawPkt; Seq: Word);
  1134. begin
  1135.   CreatePEER_HDR(Pkt, $da07, $0100, Seq, True);
  1136.   PktInt(Pkt, $0000, 2);        //Our status
  1137.   PktInt(Pkt, $0100, 2);        //Msg len = 1, Value = 0
  1138.   PktInt(Pkt, $00, 1);          //Msg null terminator
  1139.   PktInt(Pkt, $00000000, 4);    //The foreground the client is expected to use.
  1140.   PktInt(Pkt, $ffffff00, 4);    //The background color the client is expected to show the message with.
  1141.   EncryptPak(Pkt, Pkt^.Len, 8); //Encrypt packet
  1142. end;
  1143. {Response on auto-away msg request.}
  1144. procedure CreatePEER_AUTOMSG_ACK(Pkt: PRawPkt; Answer: String; Status, Seq: Word);
  1145. begin
  1146.   CreatePEER_HDR(Pkt, $da07, Swap16(Status), Seq, True);
  1147.   PktInt(Pkt, $0000, 2);        //Our status
  1148.   PktLNTS(Pkt, Answer);
  1149.   EncryptPak(Pkt, Pkt^.Len, 8); //Encrypt packet
  1150. end;
  1151. {Sends contacts to user.}
  1152. function CreatePEER_CONTACTS(Pkt: PRawPkt; Contacts: TStringList; var Seq: Word): Word;
  1153. const
  1154.   StrCmd: String = 'Contacts';
  1155. var
  1156.   S: String;
  1157. begin
  1158.   CreatePEER_HDR(Pkt, $ee07, $1a00, Seq, True);
  1159.   PktInt(Pkt, $0000, 2);        //Our status.
  1160.   PktInt(Pkt, $0100, 2);        //Message length: 2
  1161.   PktInt(Pkt, $00, 1);          //Null terminator
  1162.   PktInt(Pkt, $2d00, 2);        //Following length
  1163.   PktAddArrBuf(Pkt, @ContactsSignature, 16);     //14 unknown bytes
  1164.   PktInt(Pkt, $0000, 2);                //Possible command: send contacts
  1165.   PktLInt(Pkt, Length(StrCmd), 4);      //Length of the text command
  1166.   PktStr(Pkt, StrCmd);                  //Text command
  1167.   PktInt(Pkt, $00000000, 4);    //Unknown: empty
  1168.   PktInt(Pkt, $0001, 2);        //Unknown: 0x01
  1169.   PktInt(Pkt, $00000000, 4);    //Unknown: empty
  1170.   PktInt(Pkt, $00000000, 4);    //Unknown: empty
  1171.   PktInt(Pkt, $00, 1);          //Unknown: empty
  1172.   S := MakeContactsStr(Contacts);       //Create text list from string list
  1173.   PktLInt(Pkt, Length(S) + 4, 4);       //Length of the following data
  1174.   PktDWStr(Pkt, S);              //Length of the following string
  1175.   EncryptPak(Pkt, Pkt^.Len, 8); //Encrypt packet
  1176.   Result := Seq; Inc(Seq);      //Inc Seq
  1177. end;
  1178. function CreatePEER_CONTACTREQ(Pkt: PRawPkt; const Reason: String; var Seq: Word): Word;
  1179. const
  1180.   StrCmd: String = 'Request For Contacts';
  1181. begin
  1182.   CreatePEER_HDR(Pkt, $ee07, $1a00, Seq, True);
  1183.   PktInt(Pkt, $0000, 2);        //Our status.
  1184.   PktInt(Pkt, $0100, 2);        //Message length: 2
  1185.   PktInt(Pkt, $00, 1);          //Null terminator
  1186.   PktInt(Pkt, $3900, 2);        //Following length
  1187.   PktAddArrBuf(Pkt, @ContactsSignature, 16);   //16 unknown bytes
  1188.   PktInt(Pkt, $0200, 2);        //Possible command requesting contacts
  1189.   PktLInt(Pkt, Length(StrCmd), 4);    //Length of the text command
  1190.   PktStr(Pkt, StrCmd);          //Text command
  1191.   PktInt(Pkt, $00000000, 4);    //Unknown: empty
  1192.   PktInt(Pkt, $0001, 2);        //Unknown: 0x01
  1193.   PktInt(Pkt, $00000000, 4);    //Unknown: empty
  1194.   PktInt(Pkt, $00000000, 4);    //Unknown: empty
  1195.   PktInt(Pkt, $00, 1);          //Unknown: empty
  1196.   PktLInt(Pkt, Length(Reason) + 4, 4);  //Length of the following data
  1197.   PktLInt(Pkt, Length(Reason), 4);      //Length of the following string
  1198.   PktStr(Pkt, Reason);          //Following string
  1199.   EncryptPak(Pkt, Pkt^.Len, 8); //Encrypt packet
  1200.   Result := Seq; Inc(Seq);      //Inc Seq
  1201. end;
  1202. function CreatePEER_FILEINIT(Pkt: PRawPkt; Response: Boolean; FileDescription, FileName: String; Port: Word; FileLength: LongWord; var Seq: Word; Reason: String; Accept: Boolean): Word;
  1203. const
  1204.   StrCmd = 'File';
  1205. var
  1206.   lpkt: TRawPkt;
  1207. begin
  1208.   CreatePEER_HDR(Pkt, $da07, $1a00, Seq, Accept);
  1209.   if Accept then Reason := '';
  1210.   PktInt(Pkt, $0000, 2);        //Status
  1211.   if Length(Reason) = 0 then
  1212.   begin
  1213.     PktInt(Pkt, $01, 1);          //Flags
  1214.     PktInt(Pkt, $0000, 2);        //Unknown
  1215.   end else
  1216.   begin
  1217.     PktLInt(Pkt, Length(Reason) + 1, 2);
  1218.     PktStr(Pkt, Reason);
  1219.     PktInt(Pkt, $00, 1);
  1220.   end;
  1221.   PktInitRaw(@lpkt);                    //Init new packet for the feature concatination
  1222.   PktAddArrBuf(@lpkt, @FileSignature, 16);  //Signature
  1223.   PktInt(@lpkt, $0000, 2);              //Unknown
  1224.   PktLInt(@lpkt, Length(StrCmd), 4);    //Length of the text command
  1225.   PktStr(@lpkt, StrCmd);                //Text command
  1226.   PktInt(@lpkt, $00000100, 4);          //Unknown
  1227.   PktInt(@lpkt, $00010000, 4);          //Unknown
  1228.   PktInt(@lpkt, $00000000, 4);          //Unknown
  1229.   PktInt(@lpkt, $0000, 2);              //Unknown
  1230.   PktInt(@lpkt, $00, 1);                //Unknown
  1231.   PktLInt(Pkt, lpkt.Len, 2);            //Length of the message
  1232.   PktAddArrBuf(Pkt, @lpkt, lpkt.Len);   //Implode packets
  1233.   PktInitRaw(@lpkt);                    //Init new packet for the feature concatination
  1234.   PktLInt(@lpkt, Length(FileDescription), 4);   //Length of files description
  1235.   PktStr(@lpkt, FileDescription);       //Files description
  1236.   PktInt(@lpkt, Port, 2);               //Port
  1237.   if not Response then
  1238.     PktInt(@lpkt, $5401, 2)             //Seq
  1239.   else
  1240.     PktInt(@lpkt, $0000, 2);            //Seq
  1241.   PktLInt(@lpkt, Length(FileName) + 2, 2);      //Length of files description
  1242.   PktStr(@lpkt, FileName);              //Files description
  1243.   PktInt(@lpkt, $0000, 2);              //Null terminator
  1244.   PktLInt(@lpkt, FileLength, 4);        //Filelength
  1245.   PktLInt(@lpkt, Port, 4);              //Port
  1246.   PktLInt(Pkt, lpkt.Len, 4);            //Length of the following data
  1247.   PktAddArrBuf(Pkt, @lpkt, lpkt.Len);   //Implode packets
  1248.   EncryptPak(Pkt, Pkt^.Len, 8);         //Encrypt packet
  1249.   Result := Seq;                        //Inc Seq
  1250. end;
  1251. {This packet is a response to the incoming file transfer. It is sent as
  1252. a response to the PEER_FILE_INIT command.}
  1253. procedure CreatePEER_FILEINITACK(Pkt: PRawPkt; Speed: LongWord; Nick: String);
  1254. begin
  1255.   PktInitRaw(Pkt);                      //Initialize packet
  1256.   PktInt(Pkt, $01, 1);                  //The command: PEER_FILE_INITACK
  1257.   PktLInt(Pkt, Speed, 4);               //The receiver's speed. See PEER_FILE_INIT.
  1258.   PktLNTS(Pkt, Nick);                   //The receiver's nick.
  1259. end;
  1260. {The init packet sent within a new connection to the receiver given port
  1261. to initiate the file transfer. Note: the new connection is started with a
  1262. PEER_INIT/PEER_INITACK/PEER_INITACK2 sequence. Note: This is v6 of the
  1263. protocol.}
  1264. procedure CreatePEER_FILE_INIT2(Pkt: PRawPkt; Count, Bytes, Speed: LongWord);
  1265. begin
  1266.   PktInitRaw(Pkt);                      //Initialize packet
  1267.   PktInt(Pkt, $03, 1);                  //The command: PEER_FILE_INITACK2
  1268.   PktInt(Pkt, $00000000, 4);            //Unknown: empty.
  1269.   PktLInt(Pkt, Bytes, 4);               //Total bytes of all files to sent. 
  1270.   PktLInt(Pkt, Speed, 4);               //The sender's speed. See PEER_FILE_INIT.
  1271.   PktLInt(Pkt, Count, 4);               //Total number of files to be sent.
  1272. end;
  1273. {Create HTTP header.}
  1274. function CreateHTTP_Header(Method: String; URL, Host: String; DataLen: LongWord): String;
  1275. begin
  1276.   Result := Method + ' ' + URL + ' HTTP/1.1' + #13#10 +
  1277.             'user-agent: Mozilla/4.08 [en] (WinNT; U ;Nav)' + #13#10;
  1278.   if DataLen > 0 then
  1279.             Result := Result + 'content-length: ' + IntToStr(DataLen) + #13#10;
  1280.   Result := Result +
  1281.             'cache-control: no-store, no-cache' + #13#10 +
  1282.             'host: ' + Host + #13#10 +
  1283.             'connection: close' + #13#10 +
  1284.             'pragma: no-cache' + #13#10#13#10;
  1285. end;
  1286. {Write data headers in http proto.}
  1287. procedure CreateHTTP_DATA(Pkt: PRawPkt; PType: Word; Data: Pointer; DataLen: LongWord);
  1288. var
  1289.   lpkt: TRawPkt;
  1290. begin
  1291.   PktInitRaw(pkt);
  1292.   PktInitRaw(@lpkt);
  1293.   PktInt(@lpkt, $0443, 2);              //Version
  1294.   PktInt(@lpkt, PType, 2);              //Packet type
  1295.   PktInt(@lpkt, $00000000, 4);          //Unknown
  1296.   PktInt(@lpkt, $00000001, 4);          //Unknown
  1297.   PktAddArrBuf(@lpkt, Data, DataLen);   //Packet specific data
  1298.   PktInt(pkt, lpkt.Len, 2);             //Length of the following data
  1299.   PktAddArrBuf(pkt, @lpkt, lpkt.Len);   //Implode packets
  1300. end;
  1301. {First packet sent to proxy.}
  1302. function CreateHTTP_INIT: String;
  1303. begin
  1304.   Result := CreateHTTP_Header('GET', 'http://http.proxy.icq.com/hello', 'http.proxy.icq.com', 0);
  1305. end;
  1306. {Packet sent after packet was received from server.}
  1307. function CreateHTTP_RECV(Host, SID: String): String;
  1308. begin
  1309.   Result := CreateHTTP_Header('GET', 'http://' + Host + '/monitor?sid=' + SID, Host, 0);
  1310. end;
  1311. {Packet send as a response on HTTP_HELLO, ptype = 2.}
  1312. procedure CreateHTTP_LOGIN(Pkt: PRawPkt; Host: String; Port: Word);
  1313. var
  1314.   lpkt: TRawPkt;
  1315. begin
  1316.   PktInitRaw(@lpkt);
  1317.   PktWStr(@lpkt, Host);                 //ICQ server
  1318.   PktInt(@lpkt, Port, 2);               //Port
  1319.   CreateHTTP_DATA(Pkt, $0003, @lpkt, lpkt.Len);
  1320. end;
  1321. {Xorkeygen tabs}
  1322. const
  1323.   TAB0: array[0..63] of LongWord =
  1324.     ($00820200, $00020000, $80800000, $80820200,
  1325.      $00800000, $80020200, $80020000, $80800000,
  1326.      $80020200, $00820200, $00820000, $80000200,
  1327.      $80800200, $00800000, $00000000, $80020000,
  1328.      $00020000, $80000000, $00800200, $00020200,
  1329.      $80820200, $00820000, $80000200, $00800200,
  1330.      $80000000, $00000200, $00020200, $80820000,
  1331.      $00000200, $80800200, $80820000, $00000000,
  1332.      $00000000, $80820200, $00800200, $80020000,
  1333.      $00820200, $00020000, $80000200, $00800200,
  1334.      $80820000, $00000200, $00020200, $80800000,
  1335.      $80020200, $80000000, $80800000, $00820000,
  1336.      $80820200, $00020200, $00820000, $80800200,
  1337.      $00800000, $80000200, $80020000, $00000000,
  1338.      $00020000, $00800000, $80800200, $00820200,
  1339.      $80000000, $80820000, $00000200, $80020200);
  1340.   TAB1: array[0..63] of LongWord =
  1341.     ($10042004, $00000000, $00042000, $10040000,
  1342.      $10000004, $00002004, $10002000, $00042000,
  1343.      $00002000, $10040004, $00000004, $10002000,
  1344.      $00040004, $10042000, $10040000, $00000004,
  1345.      $00040000, $10002004, $10040004, $00002000,
  1346.      $00042004, $10000000, $00000000, $00040004,
  1347.      $10002004, $00042004, $10042000, $10000004,
  1348.      $10000000, $00040000, $00002004, $10042004,
  1349.      $00040004, $10042000, $10002000, $00042004,
  1350.      $10042004, $00040004, $10000004, $00000000,
  1351.      $10000000, $00002004, $00040000, $10040004,
  1352.      $00002000, $10000000, $00042004, $10002004,
  1353.      $10042000, $00002000, $00000000, $10000004,
  1354.      $00000004, $10042004, $00042000, $10040000,
  1355.      $10040004, $00040000, $00002004, $10002000,
  1356.      $10002004, $00000004, $10040000, $00042000);
  1357.   TAB2: array[0..63] of LongWord =
  1358.     ($41000000, $01010040, $00000040, $41000040,
  1359.      $40010000, $01000000, $41000040, $00010040,
  1360.      $01000040, $00010000, $01010000, $40000000,
  1361.      $41010040, $40000040, $40000000, $41010000,
  1362.      $00000000, $40010000, $01010040, $00000040,
  1363.      $40000040, $41010040, $00010000, $41000000,
  1364.      $41010000, $01000040, $40010040, $01010000,
  1365.      $00010040, $00000000, $01000000, $40010040,
  1366.      $01010040, $00000040, $40000000, $00010000,
  1367.      $40000040, $40010000, $01010000, $41000040,
  1368.      $00000000, $01010040, $00010040, $41010000,
  1369.      $40010000, $01000000, $41010040, $40000000,
  1370.      $40010040, $41000000, $01000000, $41010040,
  1371.      $00010000, $01000040, $41000040, $00010040,
  1372.      $01000040, $00000000, $41010000, $40000040,
  1373.      $41000000, $40010040, $00000040, $01010000);
  1374.   TAB3: array[0..63] of LongWord =
  1375.     ($00100402, $04000400, $00000002, $04100402,
  1376.      $00000000, $04100000, $04000402, $00100002,
  1377.      $04100400, $04000002, $04000000, $00000402,
  1378.      $04000002, $00100402, $00100000, $04000000,
  1379.      $04100002, $00100400, $00000400, $00000002,
  1380.      $00100400, $04000402, $04100000, $00000400,
  1381.      $00000402, $00000000, $00100002, $04100400,
  1382.      $04000400, $04100002, $04100402, $00100000,
  1383.      $04100002, $00000402, $00100000, $04000002,
  1384.      $00100400, $04000400, $00000002, $04100000,
  1385.      $04000402, $00000000, $00000400, $00100002,
  1386.      $00000000, $04100002, $04100400, $00000400,
  1387.      $04000000, $04100402, $00100402, $00100000,
  1388.      $04100402, $00000002, $04000400, $00100402,
  1389.      $00100002, $00100400, $04100000, $04000402,
  1390.      $00000402, $04000000, $04000002, $04100400);
  1391.   TAB4: array[0..63] of LongWord =
  1392.     ($02000000, $00004000, $00000100, $02004108,
  1393.      $02004008, $02000100, $00004108, $02004000,
  1394.      $00004000, $00000008, $02000008, $00004100,
  1395.      $02000108, $02004008, $02004100, $00000000,
  1396.      $00004100, $02000000, $00004008, $00000108,
  1397.      $02000100, $00004108, $00000000, $02000008,
  1398.      $00000008, $02000108, $02004108, $00004008,
  1399.      $02004000, $00000100, $00000108, $02004100,
  1400.      $02004100, $02000108, $00004008, $02004000,
  1401.      $00004000, $00000008, $02000008, $02000100,
  1402.      $02000000, $00004100, $02004108, $00000000,
  1403.      $00004108, $02000000, $00000100, $00004008,
  1404.      $02000108, $00000100, $00000000, $02004108,
  1405.      $02004008, $02004100, $00000108, $00004000,
  1406.      $00004100, $02004008, $02000100, $00000108,
  1407.      $00000008, $00004108, $02004000, $02000008);
  1408.   TAB5: array[0..63] of LongWord =
  1409.     ($20000010, $00080010, $00000000, $20080800,
  1410.      $00080010, $00000800, $20000810, $00080000,
  1411.      $00000810, $20080810, $00080800, $20000000,
  1412.      $20000800, $20000010, $20080000, $00080810,
  1413.      $00080000, $20000810, $20080010, $00000000,
  1414.      $00000800, $00000010, $20080800, $20080010,
  1415.      $20080810, $20080000, $20000000, $00000810,
  1416.      $00000010, $00080800, $00080810, $20000800,
  1417.      $00000810, $20000000, $20000800, $00080810,
  1418.      $20080800, $00080010, $00000000, $20000800,
  1419.      $20000000, $00000800, $20080010, $00080000,
  1420.      $00080010, $20080810, $00080800, $00000010,
  1421.      $20080810, $00080800, $00080000, $20000810,
  1422.      $20000010, $20080000, $00080810, $00000000,
  1423.      $00000800, $20000010, $20000810, $20080800,
  1424.      $20080000, $00000810, $00000010, $20080010);
  1425.   TAB6: array[0..63] of LongWord =
  1426.     ($00001000, $00000080, $00400080, $00400001,
  1427.      $00401081, $00001001, $00001080, $00000000,
  1428.      $00400000, $00400081, $00000081, $00401000,
  1429.      $00000001, $00401080, $00401000, $00000081,
  1430.      $00400081, $00001000, $00001001, $00401081,
  1431.      $00000000, $00400080, $00400001, $00001080,
  1432.      $00401001, $00001081, $00401080, $00000001,
  1433.      $00001081, $00401001, $00000080, $00400000,
  1434.      $00001081, $00401000, $00401001, $00000081,
  1435.      $00001000, $00000080, $00400000, $00401001,
  1436.      $00400081, $00001081, $00001080, $00000000,
  1437.      $00000080, $00400001, $00000001, $00400080,
  1438.      $00000000, $00400081, $00400080, $00001080,
  1439.      $00000081, $00001000, $00401081, $00400000,
  1440.      $00401080, $00000001, $00001001, $00401081,
  1441.      $00400001, $00401080, $00401000, $00001001);
  1442.   TAB7: array[0..63] of LongWord =
  1443.     ($08200020, $08208000, $00008020, $00000000,
  1444.      $08008000, $00200020, $08200000, $08208020,
  1445.      $00000020, $08000000, $00208000, $00008020,
  1446.      $00208020, $08008020, $08000020, $08200000,
  1447.      $00008000, $00208020, $00200020, $08008000,
  1448.      $08208020, $08000020, $00000000, $00208000,
  1449.      $08000000, $00200000, $08008020, $08200020,
  1450.      $00200000, $00008000, $08208000, $00000020,
  1451.      $00200000, $00008000, $08000020, $08208020,
  1452.      $00008020, $08000000, $00000000, $00208000,
  1453.      $08200020, $08008020, $08008000, $00200020,
  1454.      $08208000, $00000020, $00200020, $08008000,
  1455.      $08208020, $00200000, $08200000, $08000020,
  1456.      $00208000, $00008020, $08008020, $08200000,
  1457.      $00000020, $08208000, $00208020, $00000000,
  1458.      $08000000, $08200020, $00008000, $00208020);
  1459.   TAB8: array[0..63] of LongWord =
  1460.     ($00000000, $00000010, $20000000, $20000010,
  1461.      $00010000, $00010010, $20010000, $20010010,
  1462.      $00000800, $00000810, $20000800, $20000810,
  1463.      $00010800, $00010810, $20010800, $20010810,
  1464.      $00000020, $00000030, $20000020, $20000030,
  1465.      $00010020, $00010030, $20010020, $20010030,
  1466.      $00000820, $00000830, $20000820, $20000830,
  1467.      $00010820, $00010830, $20010820, $20010830,
  1468.      $00080000, $00080010, $20080000, $20080010,
  1469.      $00090000, $00090010, $20090000, $20090010,
  1470.      $00080800, $00080810, $20080800, $20080810,
  1471.      $00090800, $00090810, $20090800, $20090810,
  1472.      $00080020, $00080030, $20080020, $20080030,
  1473.      $00090020, $00090030, $20090020, $20090030,
  1474.      $00080820, $00080830, $20080820, $20080830,
  1475.      $00090820, $00090830, $20090820, $20090830);
  1476.   TAB9: array[0..63] of LongWord =
  1477.     ($00000000, $02000000, $00002000, $02002000,
  1478.      $00200000, $02200000, $00202000, $02202000,
  1479.      $00000004, $02000004, $00002004, $02002004,
  1480.      $00200004, $02200004, $00202004, $02202004,
  1481.      $00000400, $02000400, $00002400, $02002400,
  1482.      $00200400, $02200400, $00202400, $02202400,
  1483.      $00000404, $02000404, $00002404, $02002404,
  1484.      $00200404, $02200404, $00202404, $02202404,
  1485.      $10000000, $12000000, $10002000, $12002000,
  1486.      $10200000, $12200000, $10202000, $12202000,
  1487.      $10000004, $12000004, $10002004, $12002004,
  1488.      $10200004, $12200004, $10202004, $12202004,
  1489.      $10000400, $12000400, $10002400, $12002400,
  1490.      $10200400, $12200400, $10202400, $12202400,
  1491.      $10000404, $12000404, $10002404, $12002404,
  1492.      $10200404, $12200404, $10202404, $12202404);
  1493.   TABA: array[0..63] of LongWord =
  1494.     ($00000000, $00000001, $00040000, $00040001,
  1495.      $01000000, $01000001, $01040000, $01040001,
  1496.      $00000002, $00000003, $00040002, $00040003,
  1497.      $01000002, $01000003, $01040002, $01040003,
  1498.      $00000200, $00000201, $00040200, $00040201,
  1499.      $01000200, $01000201, $01040200, $01040201,
  1500.      $00000202, $00000203, $00040202, $00040203,
  1501.      $01000202, $01000203, $01040202, $01040203,
  1502.      $08000000, $08000001, $08040000, $08040001,
  1503.      $09000000, $09000001, $09040000, $09040001,
  1504.      $08000002, $08000003, $08040002, $08040003,
  1505.      $09000002, $09000003, $09040002, $09040003,
  1506.      $08000200, $08000201, $08040200, $08040201,
  1507.      $09000200, $09000201, $09040200, $09040201,
  1508.      $08000202, $08000203, $08040202, $08040203,
  1509.      $09000202, $09000203, $09040202, $09040203);
  1510.   TABB: array[0..63] of LongWord =
  1511.     ($00000000, $00100000, $00000100, $00100100,
  1512.      $00000008, $00100008, $00000108, $00100108,
  1513.      $00001000, $00101000, $00001100, $00101100,
  1514.      $00001008, $00101008, $00001108, $00101108,
  1515.      $04000000, $04100000, $04000100, $04100100,
  1516.      $04000008, $04100008, $04000108, $04100108,
  1517.      $04001000, $04101000, $04001100, $04101100,
  1518.      $04001008, $04101008, $04001108, $04101108,
  1519.      $00020000, $00120000, $00020100, $00120100,
  1520.      $00020008, $00120008, $00020108, $00120108,
  1521.      $00021000, $00121000, $00021100, $00121100,
  1522.      $00021008, $00121008, $00021108, $00121108,
  1523.      $04020000, $04120000, $04020100, $04120100,
  1524.      $04020008, $04120008, $04020108, $04120108,
  1525.      $04021000, $04121000, $04021100, $04121100,
  1526.      $04021008, $04121008, $04021108, $04121108);
  1527.   TABC: array[0..63] of LongWord =
  1528.     ($00000000, $10000000, $00010000, $10010000,
  1529.      $00000004, $10000004, $00010004, $10010004,
  1530.      $20000000, $30000000, $20010000, $30010000,
  1531.      $20000004, $30000004, $20010004, $30010004,
  1532.      $00100000, $10100000, $00110000, $10110000,
  1533.      $00100004, $10100004, $00110004, $10110004,
  1534.      $20100000, $30100000, $20110000, $30110000,
  1535.      $20100004, $30100004, $20110004, $30110004,
  1536.      $00001000, $10001000, $00011000, $10011000,
  1537.      $00001004, $10001004, $00011004, $10011004,
  1538.      $20001000, $30001000, $20011000, $30011000,
  1539.      $20001004, $30001004, $20011004, $30011004,
  1540.      $00101000, $10101000, $00111000, $10111000,
  1541.      $00101004, $10101004, $00111004, $10111004,
  1542.      $20101000, $30101000, $20111000, $30111000,
  1543.      $20101004, $30101004, $20111004, $30111004);
  1544.   TABD: array[0..63] of LongWord =
  1545.     ($00000000, $08000000, $00000008, $08000008,
  1546.      $00000400, $08000400, $00000408, $08000408,
  1547.      $00020000, $08020000, $00020008, $08020008,
  1548.      $00020400, $08020400, $00020408, $08020408,
  1549.      $00000001, $08000001, $00000009, $08000009,
  1550.      $00000401, $08000401, $00000409, $08000409,
  1551.      $00020001, $08020001, $00020009, $08020009,
  1552.      $00020401, $08020401, $00020409, $08020409,
  1553.      $02000000, $0A000000, $02000008, $0A000008,
  1554.      $02000400, $0A000400, $02000408, $0A000408,
  1555.      $02020000, $0A020000, $02020008, $0A020008,
  1556.      $02020400, $0A020400, $02020408, $0A020408,
  1557.      $02000001, $0A000001, $02000009, $0A000009,
  1558.      $02000401, $0A000401, $02000409, $0A000409,
  1559.      $02020001, $0A020001, $02020009, $0A020009,
  1560.      $02020401, $0A020401, $02020409, $0A020409);
  1561.   TABE: array[0..63] of LongWord =
  1562.     ($00000000, $00000100, $00080000, $00080100,
  1563.      $01000000, $01000100, $01080000, $01080100,
  1564.      $00000010, $00000110, $00080010, $00080110,
  1565.      $01000010, $01000110, $01080010, $01080110,
  1566.      $00200000, $00200100, $00280000, $00280100,
  1567.      $01200000, $01200100, $01280000, $01280100,
  1568.      $00200010, $00200110, $00280010, $00280110,
  1569.      $01200010, $01200110, $01280010, $01280110,
  1570.      $00000200, $00000300, $00080200, $00080300,
  1571.      $01000200, $01000300, $01080200, $01080300,
  1572.      $00000210, $00000310, $00080210, $00080310,
  1573.      $01000210, $01000310, $01080210, $01080310,
  1574.      $00200200, $00200300, $00280200, $00280300,
  1575.      $01200200, $01200300, $01280200, $01280300,
  1576.      $00200210, $00200310, $00280210, $00280310,
  1577.      $01200210, $01200310, $01280210, $01280310);
  1578.   TABF: array[0..63] of LongWord =
  1579.     ($00000000, $04000000, $00040000, $04040000,
  1580.      $00000002, $04000002, $00040002, $04040002,
  1581.      $00002000, $04002000, $00042000, $04042000,
  1582.      $00002002, $04002002, $00042002, $04042002,
  1583.      $00000020, $04000020, $00040020, $04040020,
  1584.      $00000022, $04000022, $00040022, $04040022,
  1585.      $00002020, $04002020, $00042020, $04042020,
  1586.      $00002022, $04002022, $00042022, $04042022,
  1587.      $00000800, $04000800, $00040800, $04040800,
  1588.      $00000802, $04000802, $00040802, $04040802,
  1589.      $00002800, $04002800, $00042800, $04042800,
  1590.      $00002802, $04002802, $00042802, $04042802,
  1591.      $00000820, $04000820, $00040820, $04040820,
  1592.      $00000822, $04000822, $00040822, $04040822,
  1593.      $00002820, $04002820, $00042820, $04042820,
  1594.      $00002822, $04002822, $00042822, $04042822);
  1595.   TABQ: array[0..15] of boolean =
  1596.     (FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  1597.      FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE);
  1598. type
  1599.   RTTabArray = array[0..31] of LongInt;
  1600. procedure TableGen(var t: RTTabArray; UIN: LongInt);
  1601. var u:     array[0..7] of Byte;
  1602.     ul:    array[0..1] of LongWord absolute u;
  1603.     v:     Byte;
  1604.     x:     Byte;
  1605.     l,h:   LongWord;
  1606.     a,b,c: LongWord;
  1607. begin
  1608.      {---- create UIN "hash" ----}
  1609.      v := ((UIN+9) shr 6) and 1;
  1610.      u[0] := ( ((trunc(sqrt(UIN*3+2)) and 1) or
  1611.                (((UIN shr 17) and 1) shl 1))  shl 2 ) or v;
  1612.      u[1] := ( (((trunc(sin(UIN)) shr 14) and 1) or
  1613.                 (((UIN shr 12) and 1) shl 1))  shl 2 ) or v;
  1614.      u[4] := ( (( (((UIN shr 7) and 1) or
  1615.                    (((UIN shr 12) and 1) shl 1))  shl 1 ) or
  1616.                 ((UIN shr 12) and 1))  shl 1 ) or
  1617.              ((UIN shr (UIN and 1)) and 1);
  1618.      u[6] := ( (( (((trunc(cos(UIN)) shr 8) and 1) or
  1619.                   (((UIN shr 5) and 1) shl 1))  shl 1 ) or
  1620.                 ((UIN shr 19) and 1))  shl 1 ) or
  1621.              ((UIN shr 18) and 1);
  1622.      u[3] := (( ((((UIN shr 9) and 1) shl 1) or
  1623.                  ((UIN shr 6) and 1))  shl 1 ) or
  1624.               (((UIN*5) shr 11) and 1))  shl 1;
  1625.      u[5] := ( (((trunc(sin(UIN)/cos(UIN){=tan(UIN)}) shr 4) and 1) or
  1626.                 (((UIN shr 11) and 1) shl 1))  shl 2 ) or
  1627.              ((UIN shr 2) and 1);
  1628.      u[2] := ( (((trunc(sqrt(UIN*3+2)) shr 13) and 1) or
  1629.                 (((UIN shr 10) and 1) shl 1))  shl 2 ) or v;
  1630.      u[7] := 0;
  1631.      {---- generate run-time encryption table ----}
  1632.      l := ul[0];
  1633.      h := ul[1];
  1634.      a := (l and $0F0F0F0F) xor ((h shr 4) and $0F0F0F0F);
  1635.      l := l xor a;
  1636.      h := h xor (a shl 4);
  1637.      a := (l and $CCCC0000) xor ((l and $FFFFF333) shl 18);
  1638.      l := l xor (a xor (a shr 18));
  1639.      a := (h and $CCCC0000) xor ((h and $FFFFF333) shl 18);
  1640.      h := h xor (a xor (a shr 18));
  1641.      a := (l and $55555555) xor ((h shr 1) and $55555555);
  1642.      l := l xor a;
  1643.      h := h xor (a shl 1);
  1644.      a := (h and $00FF00FF) xor ((l shr 8) and $00FF00FF);
  1645.      l := l xor (a shl 8);
  1646.      h := h xor a;
  1647.      a := (l and $55555555) xor ((h shr 1) and $55555555);
  1648.      l := l xor a;
  1649.      h := h xor (a shl 1);
  1650.      a := l and $0FFFFFFF;
  1651.      b := ( ((l and $F000000F) or ((h shr 12) and $00000FF0))  shr 4 ) or
  1652.           (h and $0000FF00) or ((h and $FF) shl 16);
  1653.      for x := 0 to 15 do
  1654.      begin
  1655.           if TABQ[x] then
  1656.           begin
  1657.                a := ((a and $3F) shl 26) or (a shr 2);
  1658.                b := ((b and $3F) shl 26) or (b shr 2);
  1659.           end
  1660.           else begin
  1661.                     a := ((a and $1F) shl 27) or (a shr 1);
  1662.                     b := ((b and $1F) shl 27) or (b shr 1);
  1663.                end;
  1664.           a := a and $0FFFFFFF;
  1665.           b := b and $0FFFFFFF;
  1666.           l := TABB[(( ((a and $00C00000) or
  1667.                        ((a shr 1) and $07000000))  shr 1 ) or
  1668.                      (a and $00100000))  shr 20] or
  1669.                TABA[((a and $0001E000) or
  1670.                      ((a shr 1) and $00060000))  shr 13] or
  1671.                TAB9[((a and $C0) or (l shr 1))  shr 6] or
  1672.                TAB8[a and 63];
  1673.           h := TABD[((b and $00000180) or
  1674.                      ((b shr 1) and $00001E00))  shr 7] or
  1675.                TABF[((b and $01E00000) or
  1676.                      ((b shr 1) and $06000000))  shr 21] or
  1677.                TABE[(b shr 15) and 63] or
  1678.                TABC[b and 63];
  1679.           c := (h and $FFFF0000) or (l shr 16);
  1680.           t[x*2+0] := (l and $0000FFFF) or (h shl 16);
  1681.           t[x*2+1] := (c shl 4) or (c shr 28);          { = ROL(c,4)}
  1682.      end;
  1683. end;
  1684. procedure XORKeyGen(var t: RTTabArray; var KeyLow, KeyHigh: LongInt);
  1685. var l, h,
  1686.     a, b: LongInt;
  1687.     x: Byte;
  1688. begin
  1689.   l := KeyLow;
  1690.   h := KeyHigh;
  1691.   a := (l and $0F0F0F0F) xor ((h shr 4) and $0F0F0F0F);
  1692.   l := l xor a;
  1693.   h := h xor (a shl 4);
  1694.   a := (h and $0000FFFF) xor (l shr 16);
  1695.   l := l xor (a shl 16);
  1696.   h := h xor a;
  1697.   a := (l and $33333333) xor ((h shr 2) and $33333333);
  1698.   l := l xor a;
  1699.   h := h xor (a shl 2);
  1700.   a := (h and $00FF00FF) xor ((l shr 8) and $00FF00FF);
  1701.   l := l xor (a shl 8);
  1702.   h := h xor a;
  1703.   a := (l and $55555555) xor ((h shr 1) and $55555555);
  1704.   l := l xor a;
  1705.   h := h xor (a shl 1);
  1706.   l := (l shl 1) or (l shr 31);                      {l = ROL(l,1)}
  1707.   h := (h shl 1) or (h shr 31);                      {h = ROL(h,1)}
  1708.   for x := 0 to 7 do
  1709.   begin
  1710.     a := t[x*4+0] xor l;
  1711.     b := t[x*4+1] xor l;
  1712.     b := (b shr 4) or (b shl 28);                 {b = ROR(b,4)}
  1713.     h := (h xor LongInt((TAB2[(a shr  8) and 63] or
  1714.     TAB3[(b shr  8) and 63] or
  1715.     TAB4[(a shr 16) and 63] or
  1716.     TAB5[(b shr 16) and 63] or
  1717.     TAB6[(a shr 24) and 63] or
  1718.     TAB7[(b shr 24) and 63] or
  1719.     TAB1[ b         and 63] or
  1720.     TAB0[ a         and 63])));
  1721.     a := t[x*4+2] xor h;
  1722.     b := t[x*4+3] xor h;
  1723.     b := (b shr 4) or (b shl 28);                 {b = ROR(b,4)}
  1724.     l := l xor LongInt((TAB2[(a shr  8) and 63] or
  1725.       TAB3[(b shr  8) and 63] or
  1726.       TAB4[(a shr 16) and 63] or
  1727.       TAB5[(b shr 16) and 63] or
  1728.       TAB6[(a shr 24) and 63] or
  1729.       TAB7[(b shr 24) and 63] or
  1730.       TAB1[ b         and 63] or
  1731.       TAB0[ a         and 63]));
  1732.   end;
  1733.   h := (h shr 1) or (h shl 31);                      {h = ROR(h,1)}
  1734.   l := (l shr 1) or (l shl 31);                      {l = ROR(l,1)}
  1735.   a := (h and $55555555) xor ((l shr 1) and $55555555);
  1736.   h := h xor a;
  1737.   l := l xor (a shl 1);
  1738.   a := (l and $00FF00FF) xor ((h shr 8) and $00FF00FF);
  1739.   h := h xor (a shl 8);
  1740.   l := l xor a;
  1741.   a := (h and $33333333) xor ((l shr 2) and $33333333);
  1742.   h := h xor a;
  1743.   l := l xor (a shl 2);
  1744.   a := (l and $0000FFFF) xor (h shr 16);
  1745.   l := l xor a;
  1746.   h := h xor (a shl 16);
  1747.   a := (h and $0F0F0F0F) xor ((l shr 4) and $0F0F0F0F);
  1748.   KeyLow  := h xor a;
  1749.   KeyHigh := l xor (a shl 4);
  1750. end;
  1751. {Xorkeygen by CoverD}
  1752. procedure GetXorKey(FUIN: LongWord; FCryptIV: LongWord; var XorKey: array of Byte);
  1753. var
  1754.   UIN:      LongInt;
  1755.   CryptIV:  LongInt;
  1756.   RTTab:    RTTabArray;
  1757.   l:        LongInt;
  1758.   h:        LongInt;
  1759.   key:      array[0..15] of Byte;
  1760.   keyl:     array[0..3] of LongInt absolute key;
  1761.   x:        byte;
  1762. begin
  1763.   UIN      := FUIN;
  1764.   CryptIV  := FCryptIV;
  1765.   TableGen(RTTab, UIN);      {create UIN-based run-time encryption table}
  1766.   l := CryptIV;
  1767.   h := 0;
  1768.   XORKeyGen(RTTab, l,h);     {generate first 8 bytes of XOR key}
  1769.   keyl[0] := l;
  1770.   keyl[1] := h;
  1771.   XORKeyGen(RTTab, l,h);     {generate next 8 bytes (first 3 are used)}
  1772.   keyl[2] := l;
  1773.   keyl[3] := h;
  1774.   for x := 0 to 10 do
  1775.     XorKey[x] := key[x];
  1776. end;
  1777. function Decrypt99bPassword(UIN, CryptIV: LongWord; const HexPass: String): String;
  1778. var
  1779.   XorKey,
  1780.   FBytePassw: array[0..15] of Byte;
  1781.   i, n: Word;
  1782. begin
  1783.   Result := '';
  1784.   if (UIN = 0) or (CryptIV = 0) or (Length(HexPass) = 0) then Exit;
  1785.   GetXorKey(UIN, CryptIV, XorKey);
  1786.   i := 0;
  1787.   for n := 1 to Length(HexPass) do
  1788.     if n mod 2 = 0 then
  1789.     begin
  1790.       FBytePassw[i] := HexToInt(Copy(HexPass, n - 1, 2));
  1791.       Inc(i);
  1792.     end;
  1793.   {First 2-bytes -- Length}
  1794.   for n := 2 to i - 2 do
  1795.     Result := Result + Chr(FBytePassw[n] xor XorKey[n]);
  1796. end;
  1797. function DecryptMirandaPassword(const Value: String): String;
  1798. var
  1799.   i: Word;
  1800. begin
  1801.   Result := '';
  1802.   if Length(Value) < 1 then Exit;
  1803.   for i := 1 to Length(Value) do
  1804.   begin
  1805.     Result := Result + Chr(Ord(Value[i]) - 5);
  1806.   end;
  1807. end;
  1808. end.