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

Delphi控件源码

开发平台:

Delphi

  1. unit ICQWorks {TICQClient, TICQDb contants & procedures};
  2. {(C) Alex Demchenko(alex@ritlabs.com)}
  3. {$R-}                           //Remove range checking
  4. {$DEFINE USE_ASM}               //Remove this line to use pascal code instead of assembler (where it's possible)
  5. interface
  6. uses
  7.   Windows, Classes;
  8. const
  9.   MAX_DATA_LEN = 8192;          //Maximum packet size
  10.   //Online statuses
  11.   S_ONLINE      = $00000000;    //Online
  12.   S_INVISIBLE   = $00000100;    //Invisible
  13.   S_AWAY        = $00000001;    //Away
  14.   S_NA          = $00000005;    //N/A
  15.   S_OCCUPIED    = $00000011;    //Occupied
  16.   S_DND         = $00000013;    //Do Not Disturb
  17.   S_FFC         = $00000020;    //Free For Chat
  18.   //Flags used with statuses
  19.   S_SHOWIP      = $00020000;    //show ip (for older clients), IP edit removed in ICQ2000a+ :)
  20.   S_WEBAWARE    = $00030000;    //do not show status from the www
  21.   S_ALLOWDCONN  = $00000000;    //allow direct connection with everyone
  22.   S_ALLOWDAUTH  = $10000000;    //allow direct connection upon authorization
  23.   S_ALLOWDLIST  = $20000000;    //allow direct connection with users in contact list
  24.   //Message types
  25.   M_PLAIN         = $01;        //Plain message
  26.   M_CHAT          = $02;        //Chat request
  27.   M_FILE          = $03;        //File request
  28.   M_URL           = $04;        //URL
  29.   M_AUTH_REQ      = $06;        //Auth request
  30.   M_AUTH_DENIED   = $07;        //Deny auth
  31.   M_AUTH_GIVEN    = $08;        //Authorize
  32.   M_WEB_PAGE      = $0D;
  33.   M_EMAIL_EXPRESS = $0E;
  34.   M_CONTACTS      = $13;
  35.   M_ADVANCED      = $1A;        //Seems to be an advanced-msg type (contacts, file requests, etc)
  36.   //Genders
  37.   GEN_FEMALE    = 1;            //Gender: Female
  38.   GEN_MALE      = 2;            //Gender: Male
  39.   //CLI_TOICQSRV commands
  40.   CMD_ACKOFFMSG = $3E;
  41.   CMD_REQOFFMSG = $3C;
  42.   CMD_REQINFO   = $7D0;
  43.   TFLAPSZ: Word = 6;            //Size of FLAP header
  44.   TSNACSZ: Word = 10;           //Size of SNAC header
  45.   //SRV UIN Flags
  46.   U_NORMAL         = $0000;     //Normal list entry
  47.   U_VISIBLE_LIST   = $0002;     //User in visible list
  48.   U_INVISIBLE_LIST = $0003;     //User in invisible list
  49.   U_IGNORE_LIST    = $000e;     //User in ignore list
  50.   ACC_NORMAL      = $0;         //Normally accepted
  51.   ACC_NO_OCCUPIED = $9;         //Not accepted, occupied
  52.   ACC_NO_DND      = $A;         //Not accepted, dnd
  53.   ACC_AWAY        = $4;         //Accepted but away
  54.   ACC_NA          = $E;         //Accepted but NA
  55.   ACC_CONTACTLST  = $C;         //Accepted to contact list (no blink in tray)
  56.   //Auto message requests
  57.   GET_AWAY        = $E8;        //Get away message
  58.   GET_OCCUPIED    = $E9;        //Get occupied message
  59.   GET_NA          = $EA;        //Get N/A message
  60.   GET_DND         = $EB;        //Get DND message
  61.   GET_FFC         = $EC;        //Get FFC(Free For Chat) message
  62.   //Buddy types
  63.   BUDDY_NORMAL    = $0000;      //A normal contact list entry
  64.   BUDDY_GROUP     = $0001;      //A larger group header
  65.   BUDDY_IGNORE    = $000e;      //A contact on the ignore list
  66.   BUDDY_INVISIBLE = $0003;      //A contact on the invisible list
  67.   BUDDY_VISIBLE   = $0002;      //A contact on the visible list
  68.   //SSL errors
  69.   ERRSSL_NOTFOUND = $0002;      //User not found
  70.   ERRSSL_EXISTS   = $0003;      //Added buddy already exists
  71.   ERRSSL_AUTH     = $000e;      //User not authorized
  72.   ERRSSL_OTHER    = $000a;      //Other SSL error
  73.   ERRSSL_NOERROR  = $0000;      //No error (changed successfully)
  74.   ICQClientVer_Major = 1;       //Major version of component
  75.   ICQClientVer_Minor = 18;      //Minor version of component
  76. type
  77.   //File request record
  78.   TFTRequestRec = record
  79.     ReqType: Byte;
  80.     ITime, IRandomID: LongWord;
  81.     UIN: LongWord;
  82.     Description: String;
  83.     FileName: String;
  84.     FileSize: LongWord;
  85.     Seq: Word;
  86.     Port: Word;
  87.   end;
  88.   //File start record
  89.   TFTStartRec = record
  90.     UIN: LongWord;
  91.     FilesCount: LongWord;
  92.     Speed: LongWord;
  93.   end;
  94.   //Error types
  95.   TErrorType = (ERR_SOCKET, ERR_INTERNAL, ERR_WARNING, ERR_PROXY, ERR_PROTOCOL, ERR_CONNTIMEOUT, ERR_LOGIN);
  96.   //Proxy types
  97.   TProxyType = (P_NONE, P_SOCKS4, P_SOCKS5{, P_HTTP});
  98.   //Info types
  99.   TInfoType = (INFO_GENERAL, INFO_MORE, INFO_ABOUT, INFO_PASSWORD);
  100.   //Database types, used in ICQDb.pas
  101.   TDbType = (DB_ICQ, DB_MIRANDA);
  102.   //Flap header
  103.   PFlapHdr = ^TFlapHdr;
  104.   TFlapHdr = record
  105.     Ident: Byte;
  106.     ChID: Byte;
  107.     Seq: Word;
  108.     DataLen: Word;
  109.   end;
  110.   //Snac header
  111.   PSnacHdr = ^TSnacHdr;
  112.   TSnacHdr = record
  113.     Family: Word;
  114.     SubType: Word;
  115.     Flags: array[0..1] of Byte;
  116.     ReqID: LongWord;
  117.   end;
  118.   //Raw packet
  119.   PRawPkt = ^TRawPkt;
  120.   TRawPkt = record
  121.     Data: array[0..MAX_DATA_LEN - 1] of Byte;
  122.     Len: Word;
  123.   end;
  124.   //Filetransfer init call back function
  125.   TOnFTInit = procedure(Sender: TObject; UIN: LongWord; FileCount, TotalBytes, Speed: LongWord; NickName: String) of object;
  126.   TOnFTStart = procedure(Sender: TObject; StartRec: TFTStartRec; FileName: String; FileSize, Speed: LongWord) of object;
  127.   TOnFTFileData = procedure(Sender: TObject; UIN: LongWord; Data: Pointer; DataLen: LongWord; LastPacket: Boolean) of object;  
  128. function IntToStr(Value: Int64): String;
  129. function StrToInt(const Value: String): LongWord;
  130. function IntToHex(Int: Int64; IntSize: Byte): String;
  131. function HexToInt(Value: String): LongWord;
  132. procedure ICQEncryptPass(SrcBuf: Pointer; BufLen: LongWord);
  133. procedure ICQEncryptPassStr(var Pass: String);
  134. function Swap16(Value: Word): Word;
  135. function Swap32(Value: LongWord): LongWord;
  136. {Low-level functions}
  137. {-- Adding data --}
  138. procedure PktAddData(Pkt: PRawPkt; Data: Pointer; DataLen: LongWord);
  139. procedure PktAddArrBuf(Pkt: PRawPkt; Data: Pointer; DataLen: LongWord);
  140. procedure PktInit(Pkt: PRawPkt; Channel: Byte; var Seq: Word);
  141. procedure PktInitRaw(Pkt: PRawPkt);
  142. procedure PktFinal(Pkt: PRawPkt);
  143. procedure PktSnac(Pkt: PRawPkt; Family, SubType: Word; ID: LongWord; Flags: Word);
  144. procedure PktInt(Pkt: PRawPkt; Value: LongWord; IntSize: Byte);
  145. procedure PktLInt(Pkt: PRawPkt; Value: LongWord; IntSize: Byte);
  146. procedure PktStr(Pkt: PRawPkt; const S: String);
  147. procedure PktLStr(Pkt: PRawPkt; const S: String); overload;
  148. procedure PktLStr(Pkt: PRawPkt; S: LongWord); overload;
  149. procedure PktWStr(Pkt: PRawPkt; const S: String);
  150. procedure PktDWStr(Pkt: PRawPkt; const S: String);
  151. procedure PktLNTS(Pkt: PRawPkt; const S: String);
  152. procedure PktLLNTS(Pkt: PRawPkt; const S: String);
  153. procedure PktTLV(Pkt: PRawPkt; T, L: Word; V: LongWord); overload;
  154. procedure PktTLV(Pkt: PRawPkt; T: Word; const V: String); overload;
  155. procedure PktTLV(Pkt: PRawPkt; T, L: Word; V: Pointer); overload;
  156. {-- Extracting data --}
  157. function GetInt(Pkt: PRawPkt; IntSize: Byte): LongWord;
  158. function GetLInt(Pkt: PRawPkt; IntSize: Byte): LongWord;
  159. function GetStr(Pkt: PRawPkt; StrLen: Word): String;
  160. function GetTLVStr(Pkt: PRawPkt; var T: Word): String;
  161. function GetTLVInt(Pkt: PRawPkt; var T: Word): LongWord;
  162. procedure GetSnac(Pkt: PRawPkt; var Snac: TSnacHdr);
  163. function GetLStr(Pkt: PRawPkt): String;
  164. function GetWStr(Pkt: PRawPkt): String;
  165. function GetDWStr(Pkt: PRawPkt): String;
  166. function GetLNTS(Pkt: PRawPkt): String;
  167. {High-level functions}
  168. function StrToLanguageI(const Value: String): Word;
  169. function StrToCountryI(const Value: String): Word;
  170. function StrToInterestI(const Value: String): Word;
  171. function StrToOccupationI(const Value: String): Word;
  172. function StrToPastI(const Value: String): Word;
  173. function StrToOrganizationI(const Value: String): Word;
  174. procedure ParseContacts(Value: String; var List: TStringList);
  175. function MakeContactsStr(Contacts: TStringList): String;
  176. {Packet creation functions}
  177. procedure CreateCLI_IDENT(Pkt: PRawPkt; UIN: LongWord; Password: String; var Seq: Word);
  178. procedure CreateCLI_COOKIE(Pkt: PRawPkt; const Cookie: String; var Seq: Word);
  179. procedure CreateCLI_FAMILIES(Pkt: PRawPkt; var Seq: Word);
  180. procedure CreateCLI_RATESREQUEST(Pkt: PRawPkt; var Seq: Word);
  181. procedure CreateCLI_ACKRATES(Pkt: PRawPkt; var Seq: Word);
  182. procedure CreateCLI_REQINFO(Pkt: PRawPkt; var Seq: Word);
  183. procedure CreateCLI_REQUNKNOWN(Pkt: PRawPkt; var Seq: Word);
  184. procedure CreateCLI_REQROSTER(Pkt: PRawPkt; var Seq: Word);
  185. procedure CreateCLI_CHECKROSTER(Pkt: PRawPkt; var Seq: Word);
  186. procedure CreateCLI_REQLOCATION(Pkt: PRawPkt; var Seq: Word);
  187. procedure CreateCLI_REQBUDDY(Pkt: PRawPkt; var Seq: Word);
  188. procedure CreateCLI_REQICBM(Pkt: PRawPkt; var Seq: Word);
  189. procedure CreateCLI_SETSTATUS(Pkt: PRawPkt; Status: LongWord; IP: LongInt; Port: Word; Cookie: LongWord; ProxyType: TProxyType; var Seq: Word);
  190. procedure CreateCLI_SETSTATUS_SHORT(Pkt: PRawPkt; Status: LongWord; var Seq: Word);
  191. procedure CreateCLI_REQBOS(Pkt: PRawPkt; var Seq: Word);
  192. procedure CreateCLI_SETUSERINFO(Pkt: PRawPkt; var Seq: Word);
  193. procedure CreateCLI_SETICBM(Pkt: PRawPkt; var Seq: Word);
  194. procedure CreateCLI_READY(Pkt: PRawPkt; var Seq: Word);
  195. procedure CreateCLI_TOICQSRV(Pkt: PRawPkt; UIN: LongWord; Command: Word; Data: Pointer; DataLen: LongWord; var Seq, Seq2: Word);
  196. procedure CreateCLI_ADDCONTACT(Pkt: PRawPkt; UIN: String; var Seq: Word);
  197. procedure CreateCLI_REMOVECONTACT(Pkt: PRawPkt; UIN: LongWord; var Seq: Word);
  198. procedure CreateCLI_ADDVISIBLE(Pkt: PRawPkt; UINs: TStrings; var Seq: Word);
  199. procedure CreateCLI_REMVISIBLE(Pkt: PRawPkt; UIN: LongWord; var Seq: Word);
  200. procedure CreateCLI_ADDINVISIBLE(Pkt: PRawPkt; UINs: TStrings; var Seq: Word);
  201. procedure CreateCLI_REMINVISIBLE(Pkt: PRawPkt; UIN: LongWord; var Seq: Word);
  202. procedure CreateCLI_ACKOFFLINEMSGS(Pkt: PRawPkt; UIN: LongWord; var Seq, Seq2: Word);
  203. procedure CreateCLI_SENDMSG(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; const Msg: String; var Seq: Word);
  204. procedure CreateCLI_SENDURL(Pkt: PRawPkt; ITime, IRandom, MyUIN, UIN: LongWord; const URL, Description: String; var Seq: Word);
  205. procedure CreateCLI_AUTHORIZE(Pkt: PRawPkt; UIN: LongWord; Auth: Byte; Reason: String; var Seq: Word);
  206. procedure CreateCLI_METAREQINFO(Pkt: PRawPkt; UIN, dUIN: LongWord; var Seq, Seq2: Word);
  207. procedure CreateCLI_SEARCHBYMAIL(Pkt: PRawPkt; UIN: LongWord; const Email: String; var Seq, Seq2: Word);
  208. procedure CreateCLI_SEARCHBYUIN(Pkt: PRawPkt; UIN: LongWord; DUIN: LongWord; var Seq, Seq2: Word);
  209. procedure CreateCLI_SEARCHBYNAME(Pkt: PRawPkt; UIN: LongWord; const FirstName, LastName, NickName, Email: String; var Seq, Seq2: Word);
  210. procedure CreateCLI_SEARCHRANDOM(Pkt: PRawPkt; UIN: LongWord; Group: Word; var Seq, Seq2: Word);
  211. procedure CreateCLI_SEARCHWP(Pkt: PRawPkt; UIN: LongWord; First, Last, Nick, Email: String; MinAge, MaxAge: Word; Gender: Byte; Language: Byte; City: String; Country: Word; Company, Department, Position: String; Occupation: Byte; Organization: Word; OrganKeyWords: String; Affiliation: Word; AffiKeyWords, KeyWord: String; Online: Byte; var Seq, Seq2: Word);
  212. procedure CreateCLI_METASETMORE(Pkt: PRawPkt; UIN: LongWord; Age: Word; Gender: Byte; HomePage: String; BirthYear: Word; BirthMonth, BirthDay, Lang1, Lang2, Lang3: Byte; var Seq, Seq2: Word);
  213. procedure CreateCLI_METASETGENERAL(Pkt: PRawPkt; UIN: LongWord; const NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip: String; Country: Word; TimeZone: Byte; PublishEmail: Boolean; var Seq, Seq2: Word);
  214. procedure CreateCLI_METASETABOUT(Pkt: PRawPkt; UIN: LongWord; const About: String; var Seq, Seq2: Word);
  215. procedure CreateCLI_SENDSMS(Pkt: PRawPkt; UIN: LongWord; const Destination, Text: String; CodePage: Word; const Time: String; var Seq, Seq2: Word);
  216. procedure CreateCLI_SENDMSG_ADVANCED(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; const Msg: String; RTFFormat: Boolean; var Seq: Word);
  217. procedure CreateCLI_SENDMSG_FILEACK(Pkt: PRawPkt; FFSeq: Word; ITime, IRandom, UIN, FileSize: LongWord; const FileDesc, FileName: String; Port: Word; var Seq: Word);
  218. procedure CreateCLI_SENDMSG_FILEDECLINE(Pkt: PRawPkt; FFSeq: Word; ITime, IRandom, UIN, FileSize: LongWord; const FileDesc, FileName, Reason: String; Port: Word; var Seq: Word);
  219. procedure CreateCLI_HELLO(Pkt: PRawPkt; var Seq: Word);
  220. procedure CreateCLI_GOODBYE(Pkt: PRawPkt; var Seq: Word);
  221. procedure CreateCLI_REGISTERUSER(Pkt: PRawPkt; const Password: String; var Seq: Word);
  222. procedure CreateCLI_REQAWAYMSG(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; Status: Byte; var Seq: Word);
  223. procedure CreateCLI_SENDCONTACTS(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; Contacts: TStringList; var Seq: Word);
  224. procedure CreateCLI_SENDCONTACTS_REQ(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; Reason: String; var Seq: Word);
  225. procedure CreateCLI_UNREGUIN(Pkt: PRawPkt; UIN: LongWord; const Password: String; var Seq, Seq2: Word);
  226. procedure CreateCLI_METASETPASS(Pkt: PRawPkt; UIN: LongWord; const Password: String; Buffer: Pointer; BufLen: Word; var Seq, Seq2: Word);
  227. procedure CreateCLI_METASETPERMISSIONS(Pkt: PRawPkt; UIN: LongWord; AuthorizationRequired, WebAware: Boolean; var Seq, Seq2: Word);
  228. procedure CreateCLI_METAREQINFO_SHORT(Pkt: PRawPkt; UIN, DestUIN: LongWord; var Seq, Seq2: Word);
  229. procedure CreateCLI_REQAUTH(Pkt: PRawPkt; UIN: LongWord; Msg: String; var Seq: Word);
  230. procedure CreateCLI_KEEPALIVE(Pkt: PRawPkt; var Seq: Word);
  231. procedure CreateCLI_ADDSTART(Pkt: PRawPkt; FirstUpload: Boolean; var Seq: Word);
  232. procedure CreateCLI_ADDEND(Pkt: PRawPkt; var Seq: Word);
  233. procedure CreateCLI_UPDATEGROUP(Pkt: PRawPkt; Name: String; Tag: Word; IDs: TStringList; var Seq: Word);
  234. procedure CreateCLI_UPDATEBUDDY(Pkt: PRawPkt; UIN, Name, SMSNumber: String; Tag, ID: Word; BuddyType: Word; NotAuthorized: Boolean; var Seq: Word);
  235. procedure CreateCLI_ADDBUDDY(Pkt: PRawPkt; UIN, Name, SMSNumber: String; Tag, ID: Word; BuddyType: Word; NotAuthorized: Boolean; var Seq: Word);
  236. procedure CreateCLI_DELETEBUDDY(Pkt: PRawPkt; UIN, Name, SMSNumber: String; Tag, ID: Word; BuddyType: Word; NotAuthorized, IsGroup: Boolean; var Seq: Word);
  237. {Misc functions}
  238. function SnacToStr(Family, SubType: Word): String;
  239. function SrvMetaToStr(V1, V2: Word): String;
  240. function PeerCmdToStr(Cmd: Byte): String;
  241. function DumpPacket(Buffer: Pointer; BufLen: Word): String;
  242. function Rtf2Txt(const Value: String): String;
  243. function StatusToStr(Value: LongWord): String;
  244. function CountryToStr(Value: Word): String;
  245. function LanguageToStr(Value: Byte): String;
  246. function OccupationToStr(Value: Word): String;
  247. function InterestToStr(Value: Word): String;
  248. function PastToStr(Value: Word): String;
  249. function AffiliationToStr(Value: Word): String;
  250. function LoadPacketRaw(Pkt: PRawPkt; const FName: String): Boolean;
  251. function LoadPacket(Pkt: PRawPkt; const FName: String; var Flap: TFlapHdr; var Snac: TSnacHdr): Boolean;
  252. function FileExists(const FileName: String): Boolean;
  253. function FileSize(const FName: String): LongWord;
  254. procedure LogText(const FName, Text: String);
  255. procedure ShowMessage(const Value: String); overload;
  256. procedure ShowMessage(Value: LongWord); overload;
  257. function ExtractName(const Value: String): String;
  258. function ExtractValue(const Value: String): String;
  259. function UTF8ToStr(Value: String): String;
  260. function UTF8ToStrSmart(Value: String): String;
  261. function GetXMLEntry(const Tag, Msg: String): String;
  262. {SMS functions}
  263. function StrToUTF8(Value: String): String;
  264. function STime: String;
  265. function GetSMSTime: String;
  266. function DecryptPak(Pak: Pointer; Size: LongWord; Ver: Byte): Boolean;
  267. procedure EncryptPak(Pak: Pointer; Size: LongWord; Ver: Byte);
  268. {Peer packet functions}
  269. procedure CreatePEER_INIT(Pkt: PRawPkt; Cookie, DestUIN, SrcUIN, SrcPort, SrcIPExt, SrcIPInt: LongWord; ProxyType: TProxyType);
  270. procedure CreatePEER_INIT2(Pkt: PRawPkt; Ack: Boolean);
  271. procedure CreatePEER_ACK(Pkt: PRawPkt);
  272. function CreatePEER_MSG(Pkt: PRawPkt; const Msg: String; RTFFormat: Boolean; var Seq: Word): Word;
  273. procedure CreatePEER_MSGACK(Pkt: PRawPkt; Seq: Word);
  274. procedure CreatePEER_AUTOMSG_ACK(Pkt: PRawPkt; Answer: String; Status, Seq: Word);
  275. function CreatePEER_CONTACTS(Pkt: PRawPkt; Contacts: TStringList; var Seq: Word): Word;
  276. function CreatePEER_CONTACTREQ(Pkt: PRawPkt; const Reason: String; var Seq: Word): Word;
  277. function CreatePEER_FILEINIT(Pkt: PRawPkt; Response: Boolean; FileDescription, FileName: String; Port: Word; FileLength: LongWord; var Seq: Word; Reason: String; Accept: Boolean): Word;
  278. procedure CreatePEER_FILEINITACK(Pkt: PRawPkt; Speed: LongWord; Nick: String);
  279. procedure CreatePEER_FILE_INIT2(Pkt: PRawPkt; Count, Bytes, Speed: LongWord);
  280. function CreateHTTP_Header(Method: String; URL, Host: String; DataLen: LongWord): String;
  281. procedure CreateHTTP_DATA(Pkt: PRawPkt; PType: Word; Data: Pointer; DataLen: LongWord);
  282. function CreateHTTP_INIT: String;
  283. function CreateHTTP_RECV(Host, SID: String): String;
  284. procedure CreateHTTP_LOGIN(Pkt: PRawPkt; Host: String; Port: Word);
  285. function Decrypt99bPassword(UIN, CryptIV: LongWord; const HexPass: String): String;
  286. function DecryptMirandaPassword(const Value: String): String;
  287. //Text constants
  288. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  289. //------------------------------------------------------------------------------------------------------------
  290. const
  291.   Countries: array[0..242] of record Ident: Word; Value: String end =
  292.     ((Ident: 1; Value: 'USA'),
  293.     (Ident: 7; Value: 'Russia'),
  294.     (Ident: 20; Value: 'Egypt'),
  295.     (Ident: 27; Value: 'South Africa'),
  296.     (Ident: 30; Value: 'Greece'),
  297.     (Ident: 31; Value: 'Netherlands'),
  298.     (Ident: 32; Value: 'Belgium'),
  299.     (Ident: 33; Value: 'France'),
  300.     (Ident: 34; Value: 'Spain'),
  301.     (Ident: 36; Value: 'Hungary'),
  302.     (Ident: 39; Value: 'Italy'),
  303.     (Ident: 40; Value: 'Romania'),
  304.     (Ident: 41; Value: 'Switzerland'),
  305.     (Ident: 42; Value: 'Czech Republic'),
  306.     (Ident: 43; Value: 'Austria'),
  307.     (Ident: 44; Value: 'United Kingdom'),
  308.     (Ident: 45; Value: 'Denmark'),
  309.     (Ident: 46; Value: 'Sweden'),
  310.     (Ident: 47; Value: 'Norway'),
  311.     (Ident: 48; Value: 'Poland'),
  312.     (Ident: 49; Value: 'Germany'),
  313.     (Ident: 51; Value: 'Peru'),
  314.     (Ident: 52; Value: 'Mexico'),
  315.     (Ident: 53; Value: 'Cuba'),
  316.     (Ident: 54; Value: 'Argentina'),
  317.     (Ident: 55; Value: 'Brazil'),
  318.     (Ident: 56; Value: 'Chile'),
  319.     (Ident: 57; Value: 'Colombia'),
  320.     (Ident: 58; Value: 'Venezuela'),
  321.     (Ident: 60; Value: 'Malaysia'),
  322.     (Ident: 61; Value: 'Australia'),
  323.     (Ident: 62; Value: 'Indonesia'),
  324.     (Ident: 63; Value: 'Philippines'),
  325.     (Ident: 64; Value: 'New Zealand'),
  326.     (Ident: 65; Value: 'Singapore'),
  327.     (Ident: 66; Value: 'Thailand'),
  328.     (Ident: 81; Value: 'Japan'),
  329.     (Ident: 82; Value: 'Korea (Republic of)'),
  330.     (Ident: 84; Value: 'Vietnam'),
  331.     (Ident: 86; Value: 'China'),
  332.     (Ident: 90; Value: 'Turkey'),
  333.     (Ident: 91; Value: 'India'),
  334.     (Ident: 92; Value: 'Pakistan'),
  335.     (Ident: 93; Value: 'Afghanistan'),
  336.     (Ident: 94; Value: 'Sri Lanka'),
  337.     (Ident: 95; Value: 'Myanmar'),
  338.     (Ident: 98; Value: 'Iran'),
  339.     (Ident: 101; Value: 'Anguilla'),
  340.     (Ident: 102; Value: 'Antigua'),
  341.     (Ident: 103; Value: 'Bahamas'),
  342.     (Ident: 104; Value: 'Barbados'),
  343.     (Ident: 105; Value: 'Bermuda'),
  344.     (Ident: 106; Value: 'British Virgin Islands'),
  345.     (Ident: 107; Value: 'Canada'),
  346.     (Ident: 108; Value: 'Cayman Islands'),
  347.     (Ident: 109; Value: 'Dominica'),
  348.     (Ident: 110; Value: 'Dominican Republic'),
  349.     (Ident: 111; Value: 'Grenada'),
  350.     (Ident: 112; Value: 'Jamaica'),
  351.     (Ident: 113; Value: 'Montserrat'),
  352.     (Ident: 114; Value: 'Nevis'),
  353.     (Ident: 115; Value: 'St. Kitts'),
  354.     (Ident: 116; Value: 'St. Vincent and the Grenadines'),
  355.     (Ident: 117; Value: 'Trinidad and Tobago'),
  356.     (Ident: 118; Value: 'Turks and Caicos Islands'),
  357.     (Ident: 120; Value: 'Barbuda'),
  358.     (Ident: 121; Value: 'Puerto Rico'),
  359.     (Ident: 122; Value: 'Saint Lucia'),
  360.     (Ident: 123; Value: 'United States Virgin Islands'),
  361.     (Ident: 212; Value: 'Morocco'),
  362.     (Ident: 213; Value: 'Algeria'),
  363.     (Ident: 216; Value: 'Tunisia'),
  364.     (Ident: 218; Value: 'Libya'),
  365.     (Ident: 220; Value: 'Gambia'),
  366.     (Ident: 221; Value: 'Senegal Republic'),
  367.     (Ident: 222; Value: 'Mauritania'),
  368.     (Ident: 223; Value: 'Mali'),
  369.     (Ident: 224; Value: 'Guinea'),
  370.     (Ident: 225; Value: 'Ivory Coast'),
  371.     (Ident: 226; Value: 'Burkina Faso'),
  372.     (Ident: 227; Value: 'Niger'),
  373.     (Ident: 228; Value: 'Togo'),
  374.     (Ident: 229; Value: 'Benin'),
  375.     (Ident: 230; Value: 'Mauritius'),
  376.     (Ident: 231; Value: 'Liberia'),
  377.     (Ident: 232; Value: 'Sierra Leone'),
  378.     (Ident: 233; Value: 'Ghana'),
  379.     (Ident: 234; Value: 'Nigeria'),
  380.     (Ident: 235; Value: 'Chad'),
  381.     (Ident: 236; Value: 'Central African Republic'),
  382.     (Ident: 237; Value: 'Cameroon'),
  383.     (Ident: 238; Value: 'Cape Verde Islands'),
  384.     (Ident: 239; Value: 'Sao Tome and Principe'),
  385.     (Ident: 240; Value: 'Equatorial Guinea'),
  386.     (Ident: 241; Value: 'Gabon'),
  387.     (Ident: 242; Value: 'Congo'),
  388.     (Ident: 243; Value: 'Dem. Rep. of the Congo'),
  389.     (Ident: 244; Value: 'Angola'),
  390.     (Ident: 245; Value: 'Guinea-Bissau'),
  391.     (Ident: 246; Value: 'Diego Garcia'),
  392.     (Ident: 247; Value: 'Ascension Island'),
  393.     (Ident: 248; Value: 'Seychelle Islands'),
  394.     (Ident: 249; Value: 'Sudan'),
  395.     (Ident: 250; Value: 'Rwanda'),
  396.     (Ident: 251; Value: 'Ethiopia'),
  397.     (Ident: 252; Value: 'Somalia'),
  398.     (Ident: 253; Value: 'Djibouti'),
  399.     (Ident: 254; Value: 'Kenya'),
  400.     (Ident: 255; Value: 'Tanzania'),
  401.     (Ident: 256; Value: 'Uganda'),
  402.     (Ident: 257; Value: 'Burundi'),
  403.     (Ident: 258; Value: 'Mozambique'),
  404.     (Ident: 260; Value: 'Zambia'),
  405.     (Ident: 261; Value: 'Madagascar'),
  406.     (Ident: 262; Value: 'Reunion Island'),
  407.     (Ident: 263; Value: 'Zimbabwe'),
  408.     (Ident: 264; Value: 'Namibia'),
  409.     (Ident: 265; Value: 'Malawi'),
  410.     (Ident: 266; Value: 'Lesotho'),
  411.     (Ident: 267; Value: 'Botswana'),
  412.     (Ident: 268; Value: 'Swaziland'),
  413.     (Ident: 269; Value: 'Mayotte Island'),
  414.     (Ident: 290; Value: 'St. Helena'),
  415.     (Ident: 291; Value: 'Eritrea'),
  416.     (Ident: 297; Value: 'Aruba'),
  417.     (Ident: 298; Value: 'Faeroe Islands'),
  418.     (Ident: 299; Value: 'Greenland'),
  419.     (Ident: 350; Value: 'Gibraltar'),
  420.     (Ident: 351; Value: 'Portugal'),
  421.     (Ident: 352; Value: 'Luxembourg'),
  422.     (Ident: 353; Value: 'Ireland'),
  423.     (Ident: 354; Value: 'Iceland'),
  424.     (Ident: 355; Value: 'Albania'),
  425.     (Ident: 356; Value: 'Malta'),
  426.     (Ident: 357; Value: 'Cyprus'),
  427.     (Ident: 358; Value: 'Finland'),
  428.     (Ident: 359; Value: 'Bulgaria'),
  429.     (Ident: 370; Value: 'Lithuania'),
  430.     (Ident: 371; Value: 'Latvia'),
  431.     (Ident: 372; Value: 'Estonia'),
  432.     (Ident: 373; Value: 'Moldova'),
  433.     (Ident: 374; Value: 'Armenia'),
  434.     (Ident: 375; Value: 'Belarus'),
  435.     (Ident: 376; Value: 'Andorra'),
  436.     (Ident: 377; Value: 'Monaco'),
  437.     (Ident: 378; Value: 'San Marino'),
  438.     (Ident: 379; Value: 'Vatican City'),
  439.     (Ident: 380; Value: 'Ukraine'),
  440.     (Ident: 381; Value: 'Yugoslavia'),
  441.     (Ident: 385; Value: 'Croatia'),
  442.     (Ident: 386; Value: 'Slovenia'),
  443.     (Ident: 387; Value: 'Bosnia and Herzegovina'),
  444.     (Ident: 389; Value: 'F.Y.R.O.M. (Former Yugoslav Republic of Macedonia)'),
  445.     (Ident: 500; Value: 'Falkland Islands'),
  446.     (Ident: 501; Value: 'Belize'),
  447.     (Ident: 502; Value: 'Guatemala'),
  448.     (Ident: 503; Value: 'El Salvador'),
  449.     (Ident: 504; Value: 'Honduras'),
  450.     (Ident: 505; Value: 'Nicaragua'),
  451.     (Ident: 506; Value: 'Costa Rica'),
  452.     (Ident: 507; Value: 'Panama'),
  453.     (Ident: 508; Value: 'St. Pierre and Miquelon'),
  454.     (Ident: 509; Value: 'Haiti'),
  455.     (Ident: 590; Value: 'Guadeloupe'),
  456.     (Ident: 591; Value: 'Bolivia'),
  457.     (Ident: 592; Value: 'Guyana'),
  458.     (Ident: 593; Value: 'Ecuador'),
  459.     (Ident: 594; Value: 'French Guiana'),
  460.     (Ident: 595; Value: 'Paraguay'),
  461.     (Ident: 596; Value: 'Martinique'),
  462.     (Ident: 597; Value: 'Suriname'),
  463.     (Ident: 598; Value: 'Uruguay'),
  464.     (Ident: 599; Value: 'Netherlands Antilles'),
  465.     (Ident: 670; Value: 'Saipan Island'),
  466.     (Ident: 671; Value: 'Guam'),
  467.     (Ident: 672; Value: 'Christmas Island'),
  468.     (Ident: 673; Value: 'Brunei'),
  469.     (Ident: 674; Value: 'Nauru'),
  470.     (Ident: 675; Value: 'Papua New Guinea'),
  471.     (Ident: 676; Value: 'Tonga'),
  472.     (Ident: 677; Value: 'Solomon Islands'),
  473.     (Ident: 678; Value: 'Vanuatu'),
  474.     (Ident: 679; Value: 'Fiji Islands'),
  475.     (Ident: 680; Value: 'Palau'),
  476.     (Ident: 681; Value: 'Wallis and Futuna Islands'),
  477.     (Ident: 682; Value: 'Cook Islands'),
  478.     (Ident: 683; Value: 'Niue'),
  479.     (Ident: 684; Value: 'American Samoa'),
  480.     (Ident: 685; Value: 'Western Samoa'),
  481.     (Ident: 686; Value: 'Kiribati Republic'),
  482.     (Ident: 687; Value: 'New Caledonia'),
  483.     (Ident: 688; Value: 'Tuvalu'),
  484.     (Ident: 689; Value: 'French Polynesia'),
  485.     (Ident: 690; Value: 'Tokelau'),
  486.     (Ident: 691; Value: 'Micronesia, Federated States of'),
  487.     (Ident: 692; Value: 'Marshall Islands'),
  488.     (Ident: 705; Value: 'Kazakhstan'),
  489.     (Ident: 706; Value: 'Kyrgyz Republic'),
  490.     (Ident: 708; Value: 'Tajikistan'),
  491.     (Ident: 709; Value: 'Turkmenistan'),
  492.     (Ident: 711; Value: 'Uzbekistan'),
  493.     (Ident: 800; Value: 'International Freephone Service'),
  494.     (Ident: 850; Value: 'Korea (North)'),
  495.     (Ident: 852; Value: 'Hong Kong'),
  496.     (Ident: 853; Value: 'Macau'),
  497.     (Ident: 855; Value: 'Cambodia'),
  498.     (Ident: 856; Value: 'Laos'),
  499.     (Ident: 870; Value: 'INMARSAT'),
  500.     (Ident: 871; Value: 'INMARSAT (Atlantic-East)'),
  501.     (Ident: 872; Value: 'INMARSAT (Pacific)'),
  502.     (Ident: 873; Value: 'INMARSAT (Indian)'),
  503.     (Ident: 874; Value: 'INMARSAT (Atlantic-West)'),
  504.     (Ident: 880; Value: 'Bangladesh'),
  505.     (Ident: 886; Value: 'Taiwan, Republic of China'),
  506.     (Ident: 960; Value: 'Maldives'),
  507.     (Ident: 961; Value: 'Lebanon'),
  508.     (Ident: 962; Value: 'Jordan'),
  509.     (Ident: 963; Value: 'Syria'),
  510.     (Ident: 964; Value: 'Iraq'),
  511.     (Ident: 965; Value: 'Kuwait'),
  512.     (Ident: 966; Value: 'Saudi Arabia'),
  513.     (Ident: 967; Value: 'Yemen'),
  514.     (Ident: 968; Value: 'Oman'),
  515.     (Ident: 971; Value: 'United Arab Emirates'),
  516.     (Ident: 972; Value: 'Israel'),
  517.     (Ident: 973; Value: 'Bahrain'),
  518.     (Ident: 974; Value: 'Qatar'),
  519.     (Ident: 975; Value: 'Bhutan'),
  520.     (Ident: 976; Value: 'Mongolia'),
  521.     (Ident: 977; Value: 'Nepal'),
  522.     (Ident: 994; Value: 'Azerbaijan'),
  523.     (Ident: 995; Value: 'Georgia'),
  524.     (Ident: 2691; Value: 'Comoros'),
  525.     (Ident: 4101; Value: 'Liechtenstein'),
  526.     (Ident: 4201; Value: 'Slovak Republic'),
  527.     (Ident: 5399; Value: 'Guantanamo Bay'),
  528.     (Ident: 5901; Value: 'French Antilles'),
  529.     (Ident: 6101; Value: 'Cocos-Keeling Islands'),
  530.     (Ident: 6701; Value: 'Rota Island'),
  531.     (Ident: 6702; Value: 'Tinian Island'),
  532.     (Ident: 6721; Value: 'Australian Antarctic Territory'),
  533.     (Ident: 6722; Value: 'Norfolk Island'),
  534.     (Ident: 9999; Value: 'Unknown'));
  535.   Languages: array[0..72] of record Ident: Byte; Value: String end =
  536.     ((Ident: 1; Value: 'Arabic'),
  537.     (Ident: 2; Value: 'Bhojpuri'),
  538.     (Ident: 3; Value: 'Bulgarian'),
  539.     (Ident: 4; Value: 'Burmese'),
  540.     (Ident: 5; Value: 'Cantonese'),
  541.     (Ident: 6; Value: 'Catalan'),
  542.     (Ident: 7; Value: 'Chinese'),
  543.     (Ident: 8; Value: 'Croatian'),
  544.     (Ident: 9; Value: 'Czech'),
  545.     (Ident: 10; Value: 'Danish'),
  546.     (Ident: 11; Value: 'Dutch'),
  547.     (Ident: 12; Value: 'English'),
  548.     (Ident: 13; Value: 'Esperanto'),
  549.     (Ident: 14; Value: 'Estonian'),
  550.     (Ident: 15; Value: 'Farci'),
  551.     (Ident: 16; Value: 'Finnish'),
  552.     (Ident: 17; Value: 'French'),
  553.     (Ident: 18; Value: 'Gaelic'),
  554.     (Ident: 19; Value: 'German'),
  555.     (Ident: 20; Value: 'Greek'),
  556.     (Ident: 21; Value: 'Hebrew'),
  557.     (Ident: 22; Value: 'Hindi'),
  558.     (Ident: 23; Value: 'Hungarian'),
  559.     (Ident: 24; Value: 'Icelandic'),
  560.     (Ident: 25; Value: 'Indonesian'),
  561.     (Ident: 26; Value: 'Italian'),
  562.     (Ident: 27; Value: 'Japanese'),
  563.     (Ident: 28; Value: 'Khmer'),
  564.     (Ident: 29; Value: 'Korean'),
  565.     (Ident: 30; Value: 'Lao'),
  566.     (Ident: 31; Value: 'Latvian'),
  567.     (Ident: 32; Value: 'Lithuanian'),
  568.     (Ident: 33; Value: 'Malay'),
  569.     (Ident: 34; Value: 'Norwegian'),
  570.     (Ident: 35; Value: 'Polish'),
  571.     (Ident: 36; Value: 'Portuguese'),
  572.     (Ident: 37; Value: 'Romanian'),
  573.     (Ident: 38; Value: 'Russian'),
  574.     (Ident: 39; Value: 'Serbo-Croatian'),
  575.     (Ident: 40; Value: 'Slovak'),
  576.     (Ident: 41; Value: 'Slovenian'),
  577.     (Ident: 42; Value: 'Somali'),
  578.     (Ident: 43; Value: 'Spanish'),
  579.     (Ident: 44; Value: 'Swahili'),
  580.     (Ident: 45; Value: 'Swedish'),
  581.     (Ident: 46; Value: 'Tagalog'),
  582.     (Ident: 47; Value: 'Tatar'),
  583.     (Ident: 48; Value: 'Thai'),
  584.     (Ident: 49; Value: 'Turkish'),
  585.     (Ident: 50; Value: 'Ukrainian'),
  586.     (Ident: 51; Value: 'Urdu'),
  587.     (Ident: 52; Value: 'Vietnamese'),
  588.     (Ident: 53; Value: 'Yiddish'),
  589.     (Ident: 54; Value: 'Yoruba'),
  590.     (Ident: 55; Value: 'Afrikaans'),
  591.     (Ident: 56; Value: 'Bosnian'),
  592.     (Ident: 57; Value: 'Persian'),
  593.     (Ident: 58; Value: 'Albanian'),
  594.     (Ident: 59; Value: 'Armenian'),
  595.     (Ident: 60; Value: 'Punjabi'),
  596.     (Ident: 61; Value: 'Chamorro'),
  597.     (Ident: 62; Value: 'Mongolian'),
  598.     (Ident: 63; Value: 'Mandarin'),
  599.     (Ident: 64; Value: 'Taiwanese'),
  600.     (Ident: 65; Value: 'Macedonian'),
  601.     (Ident: 66; Value: 'Sindhi'),
  602.     (Ident: 67; Value: 'Welsh'),
  603.     (Ident: 68; Value: 'Azerbaijani'),
  604.     (Ident: 69; Value: 'Kurdish'),
  605.     (Ident: 70; Value: 'Gujarati'),
  606.     (Ident: 71; Value: 'Tamil'),
  607.     (Ident: 72; Value: 'Belorussian'),
  608.     (Ident: 255; Value: 'Unknown'));
  609.   Occupations: array[1..17] of record Ident: Byte; Value: String end =
  610.     ((Ident: 1; Value: 'Academic'),
  611.     (Ident: 2; Value: 'Administrative'),
  612.     (Ident: 3; Value: 'Art/Entertainment'),
  613.     (Ident: 4; Value: 'College Student'),
  614.     (Ident: 5; Value: 'Computers'),
  615.     (Ident: 6; Value: 'Community & Social'),
  616.     (Ident: 7; Value: 'Education'),
  617.     (Ident: 8; Value: 'Engineering'),
  618.     (Ident: 9; Value: 'Financial Services'),
  619.     (Ident: 10; Value: 'Government'),
  620.     (Ident: 11; Value: 'High School Student'),
  621.     (Ident: 12; Value: 'Home'),
  622.     (Ident: 13; Value: 'ICQ - Providing Help'),
  623.     (Ident: 14; Value: 'Law'),
  624.     (Ident: 15; Value: 'Managerial'),
  625.     (Ident: 16; Value: 'Manufacturing'),
  626.     (Ident: 17; Value: 'Medical/Health'));
  627.   Interests: array[100..150] of record Ident: Byte; Value: String end =
  628.     ((Ident: 100; Value: 'Art'),
  629.     (Ident: 101; Value: 'Cars'),
  630.     (Ident: 102; Value: 'Celebrity Fans'),
  631.     (Ident: 103; Value: 'Collections'),
  632.     (Ident: 104; Value: 'Computers'),
  633.     (Ident: 105; Value: 'Culture & Literature'),
  634.     (Ident: 106; Value: 'Fitness'),
  635.     (Ident: 107; Value: 'Games'),
  636.     (Ident: 108; Value: 'Hobbies'),
  637.     (Ident: 109; Value: 'ICQ - Providing Help'),
  638.     (Ident: 110; Value: 'Internet'),
  639.     (Ident: 111; Value: 'Lifestyle'),
  640.     (Ident: 112; Value: 'Movies/TV'),
  641.     (Ident: 113; Value: 'Music'),
  642.     (Ident: 114; Value: 'Outdoor Activities'),
  643.     (Ident: 115; Value: 'Parenting'),
  644.     (Ident: 116; Value: 'Pets/Animals'),
  645.     (Ident: 117; Value: 'Religion'),
  646.     (Ident: 118; Value: 'Science/Technology'),
  647.     (Ident: 119; Value: 'Skills'),
  648.     (Ident: 120; Value: 'Sports'),
  649.     (Ident: 121; Value: 'Web Design'),
  650.     (Ident: 122; Value: 'Nature and Environment'),
  651.     (Ident: 123; Value: 'News & Media'),
  652.     (Ident: 124; Value: 'Government'),
  653.     (Ident: 125; Value: 'Business & Economy'),
  654.     (Ident: 126; Value: 'Mystics'),
  655.     (Ident: 127; Value: 'Travel'),
  656.     (Ident: 128; Value: 'Astronomy'),
  657.     (Ident: 129; Value: 'Space'),
  658.     (Ident: 130; Value: 'Clothing'),
  659.     (Ident: 131; Value: 'Parties'),
  660.     (Ident: 132; Value: 'Women'),
  661.     (Ident: 133; Value: 'Social science'),
  662.     (Ident: 134; Value: '60''s'),
  663.     (Ident: 135; Value: '70''s'),
  664.     (Ident: 136; Value: '80''s'),
  665.     (Ident: 137; Value: '50''s'),
  666.     (Ident: 138; Value: 'Finance and corporate'),
  667.     (Ident: 139; Value: 'Entertainment'),
  668.     (Ident: 140; Value: 'Consumer electronics'),
  669.     (Ident: 141; Value: 'Retail stores'),
  670.     (Ident: 142; Value: 'Health and beauty'),
  671.     (Ident: 143; Value: 'Media'),
  672.     (Ident: 144; Value: 'Household products'),
  673.     (Ident: 145; Value: 'Mail order catalog'),
  674.     (Ident: 146; Value: 'Business services'),
  675.     (Ident: 147; Value: 'Audio and visual'),
  676.     (Ident: 148; Value: 'Sporting and athletic'),
  677.     (Ident: 149; Value: 'Publishing'),
  678.     (Ident: 150; Value: 'Home automation'));
  679.   RandGroups: array[1..11] of record Ident: Byte; Value: String end =
  680.     ((Ident: 1; Value: 'General'),
  681.     (Ident: 2; Value: 'Romance'),
  682.     (Ident: 3; Value: 'Games'),
  683.     (Ident: 4; Value: 'Students'),
  684.     (Ident: 5; Value: '20 something'),
  685.     (Ident: 6; Value: '30 something'),
  686.     (Ident: 7; Value: '40 something'),
  687.     (Ident: 8; Value: '50+'),
  688.     (Ident: 9; Value: 'Romance'),
  689.     (Ident: 10; Value: 'Man requesting woman'),
  690.     (Ident: 11; Value: 'Woman requesting man'));
  691.   Organizations: array[0..19] of record Ident: Word; Value: String end =
  692.     ((Ident: 200; Value: 'Alumni Org.'),
  693.     (Ident: 201; Value: 'Charity Org.'),
  694.     (Ident: 202; Value: 'Club/Social Org.'),
  695.     (Ident: 203; Value: 'Community Org.'),
  696.     (Ident: 204; Value: 'Cultural Org.'),
  697.     (Ident: 205; Value: 'Fan Clubs'),
  698.     (Ident: 206; Value: 'Fraternity/Sorority'),
  699.     (Ident: 207; Value: 'Hobbyists Org.'),
  700.     (Ident: 208; Value: 'International Org.'),
  701.     (Ident: 209; Value: 'Nature and Environment Org.'),
  702.     (Ident: 210; Value: 'Professional Org.'),
  703.     (Ident: 211; Value: 'Scientific/Technical Org.'),
  704.     (Ident: 212; Value: 'Self Improvement Group'),
  705.     (Ident: 213; Value: 'Spiritual/Religious Org.'),
  706.     (Ident: 214; Value: 'Sports Org.'),
  707.     (Ident: 215; Value: 'Support Org.'),
  708.     (Ident: 216; Value: 'Trade and Business Org.'),
  709.     (Ident: 217; Value: 'Union'),
  710.     (Ident: 218; Value: 'Volunteer Org.'),
  711.     (Ident: 299; Value: 'Other'));
  712.   Pasts: array[0..7] of record Ident: Word; Value: String end =
  713.     ((Ident: 300; Value: 'Elementary School'),
  714.     (Ident: 301; Value: 'High School'),
  715.     (Ident: 302; Value: 'College'),
  716.     (Ident: 303; Value: 'University'),
  717.     (Ident: 304; Value: 'Military'),
  718.     (Ident: 305; Value: 'Past Work Place'),
  719.     (Ident: 306; Value: 'Past Organization'),
  720.     (Ident: 399; Value: 'Other'));
  721. //------------------------------------------------------------------------------------------------------------
  722. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  723. implementation
  724. const
  725.   FileSignature: array[0..15] of Byte = ($f0, $2d, $12, $d9, $30, $91, $d3, $11,
  726.                                          $8d, $d7, $00, $10, $4b, $06, $46, $2e);
  727.   ContactsSignature: array[0..15] of Byte = ($2a, $0e, $7d, $46, $76, $76, $d4, $11,
  728.                                              $bc, $e6, $00, $04, $ac, $96, $1e, $a6);
  729. function IntToStr(Value: Int64): String;
  730. begin
  731.   Str(Value, Result);
  732. end;
  733. function StrToInt(const Value: String): LongWord;
  734. var
  735.   nCode: Integer;
  736. begin
  737.   Val(Value, Result, nCode);
  738. end;
  739. const
  740.   HexChars: array[0..15] of Char = ('0', '1', '2', '3', '4', '5',
  741.                                     '6', '7', '8', '9', 'a', 'b',
  742.                                     'c', 'd', 'e', 'f');
  743. function IntToHex(Int: Int64; IntSize: Byte): String;
  744. var
  745.   n: Byte;
  746. begin
  747.   Result := '';
  748.   for n := 0 to IntSize - 1 do
  749.   begin
  750.     Result := HexChars[Int and $F] + Result;
  751.     Int := Int shr $4;
  752.   end;
  753. end;
  754. function HexToInt(Value: String): LongWord;
  755. const
  756.   HexStr: String = '0123456789abcdef';
  757. var
  758.   i: Word;
  759. begin
  760.   Result := 0;
  761.   if Value = '' then Exit;
  762.   for i := 1 to Length(Value) do
  763.     Inc(Result, (Pos(Value[i], HexStr) - 1) shl ((Length(Value) - i) shl 2));
  764. end;
  765. const
  766.   TXorData: array[0..15] of Byte = (
  767.     $F3, $26, $81, $C4, $39, $86, $DB, $92,
  768.     $71, $A3, $B9, $E6, $53, $7A, $95, $7C
  769.   );
  770. procedure ICQEncryptPass(SrcBuf: Pointer; BufLen: LongWord); assembler;
  771. asm
  772.   or    edx,edx
  773.   jz    @@end
  774. @@loop:
  775.   mov   cl,byte ptr[eax + edx - 1]
  776.   xor   cl,byte ptr[TXorData + edx - 1]
  777.   mov   byte ptr[eax + edx - 1],cl
  778.   dec   edx
  779.   jnz   @@loop
  780. @@end:
  781. end;
  782. procedure ICQEncryptPassStr(var Pass: String);
  783. var
  784.   i: Word;
  785. begin
  786.   for i := 1 to Length(Pass) do
  787.     Pass[i] := Chr(Ord(Pass[i]) xor TXorData[i - 1]);
  788. end;
  789. function Swap16(Value: Word): Word; assembler;
  790. asm
  791.   rol   ax,8
  792. end;
  793. function Swap32(Value: LongWord): LongWord; assembler;
  794. asm
  795.   bswap eax
  796. end;
  797. {----------------------------------------------}
  798. //Adding data in reverse order
  799. procedure PktAddData(Pkt: PRawPkt; Data: Pointer; DataLen: LongWord);
  800. var
  801.   i: Word;
  802. begin
  803.   if DataLen = 0 then Exit;
  804.   for i := 0 to DataLen - 1 do
  805.     PByte(LongWord(Pkt) + Pkt^.Len + i)^ := PByte(LongWord(Data) + DataLen - i - 1)^;
  806.   Inc(Pkt^.Len, DataLen);
  807. end;
  808. //Adding data in direct order(local arrays, merging 2 or more packets)
  809. procedure PktAddArrBuf(Pkt: PRawPkt; Data: Pointer; DataLen: LongWord);
  810. begin
  811.   if DataLen = 0 then Exit;
  812.   Move(Data^, Ptr(LongWord(Pkt) + Pkt^.Len)^, DataLen);
  813.   Inc(Pkt^.Len, DataLen);
  814. end;
  815. procedure PktInt(Pkt: PRawPkt; Value: LongWord; IntSize: Byte);
  816. begin
  817.   PktAddData(Pkt, @Value, IntSize);
  818. end;
  819. procedure PktLInt(Pkt: PRawPkt; Value: LongWord; IntSize: Byte);
  820. begin
  821.   PktAddArrBuf(Pkt, @Value, IntSize);
  822. end;
  823. procedure PktStr(Pkt: PRawPkt; const S: String);
  824. begin
  825.   if Length(S) = 0 then Exit;
  826.   Move(PChar(S)^, Ptr(LongWord(Pkt) + Pkt.Len)^, Length(S));
  827.   Inc(Pkt^.Len, Length(S));
  828. end;
  829. procedure PktLStr(Pkt: PRawPkt; const S: String); overload;
  830. begin
  831.   PktInt(Pkt, Length(S), 1);
  832.   PktStr(Pkt, S);
  833. end;
  834. procedure PktLStr(Pkt: PRawPkt; S: LongWord); overload;
  835. begin
  836.   PktLStr(Pkt, IntToStr(S));
  837. end;
  838. procedure PktWStr(Pkt: PRawPkt; const S: String);
  839. begin
  840.   if Length(S) = 0 then
  841.   begin
  842.     PktInt(Pkt, 0, 2);
  843.     Exit;
  844.   end;
  845.   PktInt(Pkt, Length(S), 2);
  846.   PktStr(Pkt, S);
  847. end;
  848. procedure PktDWStr(Pkt: PRawPkt; const S: String);
  849. begin
  850.   PktLInt(Pkt, Length(S), 4);
  851.   PktStr(Pkt, S);
  852. end;
  853. procedure PktLNTS(Pkt: PRawPkt; const S: String);
  854. begin
  855.   if Length(S) = 0 then
  856.   begin
  857.     PktInt(Pkt, 0, 2);
  858.     Exit;
  859.   end;
  860.   PktLInt(Pkt, Length(S) + 1, 2);
  861.   PktStr(Pkt, S);
  862.   PktInt(Pkt, 0, 1);
  863. end;
  864. procedure PktLLNTS(Pkt: PRawPkt; const S: String);
  865. begin
  866.   if Length(S) = 0 then
  867.   begin
  868.     PktInt(Pkt, 0, 2);
  869.     Exit;
  870.   end;
  871.   PktLInt(Pkt, Length(S) + 3, 2);
  872.   PktLNTS(Pkt, S);
  873. end;
  874. {--}
  875. function GetInt(Pkt: PRawPkt; IntSize: Byte): LongWord;
  876. var
  877.   i: Word;
  878. begin
  879.   Result := 0;
  880.   if IntSize = 0 then Exit;
  881.   if Pkt^.Len > 8100 then Exit;
  882.   for i := Pkt^.Len to Pkt^.Len + IntSize - 1 do
  883.     Inc(Result, PByte(LongWord(Pkt) + i)^ shl ((Pkt^.Len + IntSize - 1 - i) * 8));
  884.   Inc(Pkt^.Len, IntSize);
  885. end;
  886. function GetLInt(Pkt: PRawPkt; IntSize: Byte): LongWord;
  887. var
  888.   i, c: Word;
  889. begin
  890.   Result := 0; c := 0;
  891.   if IntSize = 0 then Exit;
  892.   if Pkt^.Len > 8100 then Exit;
  893.   for i := Pkt^.Len to Pkt^.Len + IntSize - 1 do
  894.   begin
  895.     Inc(Result, PByte(LongWord(Pkt) + Pkt^.Len + IntSize - c - 1)^ shl ((Pkt^.Len + IntSize - 1 - i) * 8));
  896.     Inc(c);
  897.   end;
  898.   Inc(Pkt^.Len, IntSize);
  899. end;
  900. function GetStr(Pkt: PRawPkt; StrLen: Word): String;
  901. begin
  902.   Result := '';
  903.   while StrLen > 0 do
  904.   begin
  905.     Result := Result + PChar(LongWord(Pkt) + Pkt^.Len)^;
  906.     Inc(Pkt^.Len);
  907.     Dec(StrLen);
  908.     if Pkt^.Len > 8100 then Exit;
  909.   end;
  910. end;
  911. function GetTLVStr(Pkt: PRawPkt; var T: Word): String;
  912. var
  913.   ISize: Word;
  914. begin
  915.   T := GetInt(Pkt, 2);          //Get type
  916.   ISize := GetInt(Pkt, 2);      //Get data length
  917.   Result := GetStr(Pkt, ISize); //Get data
  918. end;
  919. function GetTLVInt(Pkt: PRawPkt; var T: Word): LongWord;
  920. var
  921.   ISize: Word;
  922. begin
  923.   T := GetInt(Pkt, 2);          //Get type
  924.   ISize := GetInt(Pkt, 2);      //Get data length
  925.   Result := GetInt(Pkt, ISize); //Get data
  926. end;
  927. procedure GetSnac(Pkt: PRawPkt; var Snac: TSnacHdr);
  928. begin
  929.   Snac := PSnacHdr(LongWord(Pkt) + Pkt^.Len)^;
  930.   Snac.Family := Swap16(Snac.Family);
  931.   Snac.SubType := Swap16(Snac.SubType);
  932.   Snac.ReqID := Swap32(Snac.ReqID);
  933.   Inc(Pkt^.Len, TSNACSZ);
  934. end;
  935. function GetLStr(Pkt: PRawPkt): String;
  936. begin
  937.   Result := GetStr(Pkt, GetInt(Pkt, 1));
  938. end;
  939. function GetWStr(Pkt: PRawPkt): String;
  940. begin
  941.   Result := GetStr(Pkt, GetInt(Pkt, 2));
  942. end;
  943. function GetDWStr(Pkt: PRawPkt): String;
  944. begin
  945.   Result := GetStr(Pkt, GetLInt(Pkt, 4));
  946. end;
  947. function GetLNTS(Pkt: PRawPkt): String;
  948. begin
  949.   Result := GetStr(Pkt, GetLInt(Pkt, 2) - 1);
  950.   Inc(Pkt^.Len, 1);
  951. end;
  952. {--------}
  953. procedure PktTLV(Pkt: PRawPkt; T, L: Word; V: LongWord); overload;
  954. begin
  955.   PktInt(Pkt, T, 2);  //Add type
  956.   PktInt(Pkt, L, 2);  //Add length
  957.   PktInt(Pkt, V, L);  //Add value
  958. end;
  959. procedure PktTLV(Pkt: PRawPkt; T: Word; const V: String); overload;
  960. begin
  961.   PktInt(Pkt, T, 2);            //Add type
  962.   PktInt(Pkt, Length(V), 2);    //Add length
  963.   PktStr(Pkt, V);               //Add value
  964. end;
  965. procedure PktTLV(Pkt: PRawPkt; T, L: Word; V: Pointer); overload; //for arrays
  966. begin
  967.   PktInt(Pkt, T, 2);            //Add type
  968.   PktInt(Pkt, L, 2);            //Add length
  969.   PktAddArrBuf(Pkt, V, L);      //Add value
  970. end;
  971. procedure PktInit(Pkt: PRawPkt; Channel: Byte; var Seq: Word);
  972. begin
  973.   Pkt^.Len := 0;                //Starting size of packet to 0
  974.   PktInt(Pkt, $2A, 1);          //Ident, always $2A
  975.   PktInt(Pkt, Channel, 1);      //Channel
  976.   PktInt(Pkt, SEQ, 2); Inc(SEQ);//Seq
  977.   PktInt(Pkt, 0, 2);            //Reserved for size
  978. end;
  979. {$IFDEF USE_ASM}
  980. procedure PktInitRaw(Pkt: PRawPkt); assembler;
  981. asm
  982.   mov   word ptr[eax + MAX_DATA_LEN], 0         //Default size of the packet
  983. end;
  984. {$ELSE}
  985. procedure PktInitRaw(Pkt: PRawPkt);
  986. begin
  987.   Pkt^.Len := 0;                                //Default size of the packet
  988. end;
  989. {$ENDIF}
  990. //Used with PktInit only
  991. {$IFDEF USE_ASM}
  992. procedure PktFinal(Pkt: PRawPkt); assembler;
  993. asm
  994.   mov   cx,word ptr[eax + MAX_DATA_LEN]
  995.   sub   cx,TFLAPSZ
  996.   rol   cx,8
  997.   mov   word ptr[eax + 4], cx   //Store the packet size (without flap header size)
  998. end;
  999. {$ELSE}
  1000. procedure PktFinal(Pkt: PRawPkt);
  1001. begin
  1002.   PWord(LongWord(Pkt) + 4)^ := Swap16(Pkt.Len - TFLAPSZ); //Store the packet size (without flap header size)
  1003. end;
  1004. {$ENDIF}
  1005. procedure PktSnac(Pkt: PRawPkt; Family, SubType: Word; ID: LongWord; Flags: Word);
  1006. begin
  1007.   PktInt(Pkt, Family, 2);       //Snac family
  1008.   PktInt(Pkt, SubType, 2);      //Snac subtype
  1009.   PktInt(Pkt, Flags, 2);        //Snac flags
  1010.   PktInt(Pkt, ID, 4);           //Snac reference
  1011. end;
  1012. {@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}
  1013. function StrToLanguageI(const Value: String): Word;
  1014. var
  1015.   i: Word;
  1016. begin
  1017.   for i := Low(Languages) to High(Languages) do
  1018.     if Languages[i].Value = Value then
  1019.     begin
  1020.       Result := Languages[i].Ident;
  1021.       Exit;
  1022.     end;
  1023.   Result := 0;
  1024. end;
  1025. function StrToCountryI(const Value: String): Word;
  1026. var
  1027.   i: Word;
  1028. begin
  1029.   for i := Low(Countries) to High(Countries) do
  1030.     if Countries[i].Value = Value then
  1031.     begin
  1032.       Result := Countries[i].Ident;
  1033.       Exit;
  1034.     end;
  1035.   Result := 0;
  1036. end;
  1037. function StrToInterestI(const Value: String): Word;
  1038. var
  1039.   i: Word;
  1040. begin
  1041.   for i := Low(Interests) to High(Interests) do
  1042.     if Interests[i].Value = Value then
  1043.     begin
  1044.       Result := Interests[i].Ident;
  1045.       Exit;
  1046.     end;
  1047.   Result := 0;
  1048. end;
  1049. function StrToOccupationI(const Value: String): Word;
  1050. var
  1051.   i: Word;
  1052. begin
  1053.   for i := Low(Occupations) to High(Occupations) do
  1054.     if Occupations[i].Value = Value then
  1055.     begin
  1056.       Result := Occupations[i].Ident;
  1057.       Exit;
  1058.     end;
  1059.   Result := 0;
  1060. end;
  1061. function StrToPastI(const Value: String): Word;
  1062. var
  1063.   i: Word;
  1064. begin
  1065.   for i := Low(Pasts) to High(Pasts) do
  1066.     if Pasts[i].Value = Value then
  1067.     begin
  1068.       Result := Pasts[i].Ident;
  1069.       Exit;
  1070.     end;
  1071.   Result := 0;
  1072. end;
  1073. function StrToOrganizationI(const Value: String): Word;
  1074. var
  1075.   i: Word;
  1076. begin
  1077.   for i := Low(Organizations) to High(Organizations) do
  1078.     if Organizations[i].Value = Value then
  1079.     begin
  1080.       Result := Organizations[i].Ident;
  1081.       Exit;
  1082.     end;
  1083.   Result := 0;
  1084. end;
  1085. {Parse contacts responses.}
  1086. procedure ParseContacts(Value: String; var List: TStringList);
  1087. var
  1088.   i, l: Word;
  1089.   FName, FUIN: String;
  1090. begin
  1091.   l := 0; FName := ''; FUIN := '';
  1092.   if Length(Value) > Pos(#$fe, Value) + 1 then
  1093.     for i := Pos(#$fe, Value) + 1 to Length(Value) do
  1094.     begin
  1095.       if Value[i] = #$fe then
  1096.         Inc(l)
  1097.       else
  1098.       begin
  1099.         if l mod 2 = 0 then
  1100.           FName := FName + Value[i]
  1101.         else
  1102.           FUIN := FUIN + Value[i];
  1103.       end;
  1104.       if l = 2 then
  1105.       begin
  1106.         if (FName <> '') and (FUIN <> '') then
  1107.           List.Add(FName + '=' + FUIN);
  1108.         FName := '';
  1109.         FUIN := '';
  1110.         l := 0;
  1111.       end;
  1112.     end;
  1113. end;
  1114. {Create string representation of list with contacts.}
  1115. function MakeContactsStr(Contacts: TStringList): String;
  1116. var
  1117.   i, count: Word;
  1118.   S: String;
  1119. begin
  1120.   count := 0;
  1121.   S := '';
  1122.   if Contacts.Count > 0 then
  1123.     for i := 0 to Contacts.Count - 1 do
  1124.     begin
  1125.       if ExtractName(Contacts.Strings[i]) <> '' then
  1126.       begin
  1127.         S := S + ExtractName(Contacts.Strings[i]) + #$fe;
  1128.         if ExtractValue(Contacts.Strings[i]) = '' then
  1129.           S := S + ExtractName(Contacts.Strings[i]) + #$fe
  1130.         else
  1131.           S := S + ExtractValue(Contacts.Strings[i]) + #$fe;
  1132.         Inc(count);
  1133.       end;
  1134.     end;
  1135.   Result := IntToStr(count) + #$fe + S;
  1136. end;
  1137. {-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=}
  1138. {The first packet sent by the client after connecting and receiving
  1139. the SRV_HELLO packet from the server. The packet basiclly identifies
  1140. what kind and version of client is connecting along with the user's
  1141. UIN and password.}
  1142. procedure CreateCLI_IDENT(Pkt: PRawPkt; UIN: LongWord; Password: String; var Seq: Word);
  1143. begin
  1144.   PktInit(Pkt, 1, Seq);                         //Channel 1
  1145.   PktInt(Pkt, 1, 4);                            //00 00 00 01
  1146.   PktTLV(Pkt, 1, IntToStr(UIN));                //Adding user's UIN
  1147.   ICQEncryptPassStr(Password);                  //Encrypt password
  1148.   PktTLV(Pkt, 2, Password);                     //Adding encrypted password
  1149.   PktTLV(Pkt, 3, 'ICQ Inc. - Product of ICQ (TM).2001b.5.15.1.3634.85');   //Cookie
  1150.   //Uknowns
  1151.   PktInt(Pkt, $00160002, 4); PktInt(Pkt, $010a, 2);
  1152.   PktInt(Pkt, $00170002, 4); PktInt(Pkt, $0005, 2);
  1153.   PktInt(Pkt, $00180002, 4); PktInt(Pkt, $000f, 2);
  1154.   PktInt(Pkt, $00190002, 4); PktInt(Pkt, $0001, 2);
  1155.   PktInt(Pkt, $001a0002, 4); PktInt(Pkt, $0e32, 2);
  1156.   PktInt(Pkt, $00140004, 4); PktInt(Pkt, $00000055, 4);
  1157.   PktTLV(Pkt, $000f, 'en');
  1158.   PktTLV(Pkt, $000e, 'us');
  1159.   PktFinal(Pkt);                                //Finalize packet
  1160. end;
  1161. {Sent as the first packet after the client has logged in
  1162. to the second server and received the SRV_HELLO packet.}
  1163. procedure CreateCLI_COOKIE(Pkt: PRawPkt; const Cookie: String; var Seq: Word);
  1164. begin
  1165.   PktInit(Pkt, 1, Seq);                         //Channel 1
  1166.   PktInt(Pkt, 1, 4);                            //00 00 00 01
  1167.   PktTLV(Pkt, 6, Cookie);                       //TLV(06) Cookie
  1168.   PktFinal(Pkt);                                //Finalize packet
  1169. end;
  1170. {This packet is a response to SNAC(1,3), SRV_FAMILIES. This tells
  1171. the server which SNAC families and their corresponding versions
  1172. which the client understands. This also seems to identify the client
  1173. as an ICQ vice AIM client to the server.}
  1174. procedure CreateCLI_FAMILIES(Pkt: PRawPkt; var Seq: Word);
  1175. begin
  1176.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1177.   PktSnac(Pkt, 1, $17, 0, 0);                   //Snac: Type x01/x17, ID x0000, Flags 0
  1178.   PktInt(Pkt, $00010003, 4);                    //Family x01 is Version x03
  1179.   PktInt(Pkt, $00130002, 4);                    //Family x13 at Version x02
  1180.   PktInt(Pkt, $00020001, 4);                    //Family x02 at Version x01
  1181.   PktInt(Pkt, $00030001, 4);                    //Family x03 at Version x01
  1182.   PktInt(Pkt, $00150001, 4);                    //Family x15 at Version x01
  1183.   PktInt(Pkt, $00040001, 4);                    //Family x04 at Version x01
  1184.   PktInt(Pkt, $00060001, 4);                    //Family x06 at Version x01
  1185.   PktInt(Pkt, $00090001, 4);                    //Family x09 at Version x01
  1186.   PktInt(Pkt, $000A0001, 4);                    //Family x0A at Version x01
  1187.   PktInt(Pkt, $000B0001, 4);                    //Family x0B at Version x01
  1188.   PktFinal(Pkt);                                //Finalize packet
  1189. end;
  1190. {This packet requests from the server several bits of information most
  1191. likely regarding how fast certain packets can be sent to the server and
  1192. possibly a maximum packet size as well.}
  1193. procedure CreateCLI_RATESREQUEST(Pkt: PRawPkt; var Seq: Word);
  1194. begin
  1195.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1196.   PktSnac(Pkt, $01, $06, 0, 0);                 //Snac: Type x01/x06, ID x0000, Flags 0
  1197.   PktFinal(Pkt);                                //Finalize packet
  1198. end;
  1199. {This packet is sent in response to the SRV_RATES SNAC(1,7). This
  1200. packet contains the same group numbers as was in the SRV_RATES
  1201. packet and is an acknowledgement of their receipt.}
  1202. procedure CreateCLI_ACKRATES(Pkt: PRawPkt; var Seq: Word);
  1203. begin
  1204.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1205.   PktSnac(Pkt, $01, $08, 0, 0);                 //Type x01/x08, ID x0000, Flags 0
  1206.   PktInt(Pkt, $0001, 2);                        //Group1 - 0x0001
  1207.   PktInt(Pkt, $0002, 2);                        //Group2 - 0x0002
  1208.   PktInt(Pkt, $0003, 2);                        //Group3 - 0x0003
  1209.   PktInt(Pkt, $0004, 2);                        //Group4 - 0x0004
  1210.   PktInt(Pkt, $0005, 2);                        //Group5 - 0x0005
  1211.   PktFinal(Pkt);                                //Finalize packet
  1212. end;
  1213. {This command requests from the server certain information
  1214. about the client that is stored on the server}
  1215. procedure CreateCLI_REQINFO(Pkt: PRawPkt; var Seq: Word);
  1216. begin
  1217.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1218.   PktSnac(Pkt, $01, $0E, 0, 0);                 //Snac: Type x01/x0E, ID x0000, Flags 0
  1219.   PktFinal(Pkt);                                //Finalize packet
  1220. end;
  1221. {Unknown}
  1222. procedure CreateCLI_REQUNKNOWN(Pkt: PRawPkt; var Seq: Word);
  1223. begin
  1224.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1225.   PktSnac(Pkt, $13, $02, 0, 0);                 //Snac: Type x13/x02, ID x0000, Flags 0
  1226.   PktFinal(Pkt);                                //Finalize packet
  1227. end;
  1228. {This command, like CLI_CHECKROSTER, requests the server side contact list.
  1229. The difference between CLI_REQROSTER and CLI_CHECKROSTER is that CLI_REQROSTER
  1230. has no parameters, and always causes SRV_REPLYROSTER (rather than
  1231. SRV_REPLYROSTEROK). My guess is that CLI_REQROSTER is sent instead of
  1232. CLI_CHECKROSTER when the client does not have a cached copy of the contact
  1233. list; ie, the first time a user logs in with a particular client.}
  1234. procedure CreateCLI_REQROSTER(Pkt: PRawPkt; var Seq: Word);
  1235. begin
  1236.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1237.   PktSnac(Pkt, $13, $04, $00010004, 0);         //Snac: Type x13/x04, ID x00010004, Flags 0
  1238.   PktFinal(Pkt);                                //Finalize packet
  1239. end;
  1240. {Synchronizes the server side contact list with the client's.
  1241. If the passed values match those on the server, SNAC(13,F)
  1242. SRV_REPLYROSTEROK will be returned. If the values are older
  1243. than what is on the server then SNAC(13,6) SRV_REPLYROSTER will
  1244. be returned.}
  1245. procedure CreateCLI_CHECKROSTER(Pkt: PRawPkt; var Seq: Word);
  1246. begin
  1247.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1248.   PktSnac(Pkt, $13, $05, $00010005, 0);         //Snac: Type x13/x05, ID x00010005, Flags 0
  1249.   PktInt(Pkt, $3C36D709, 4);                    //time(NULL), The last modification time of the server side contact list.
  1250.   PktInt(Pkt, $0000, 2);                        //Size of server side contact list.
  1251.   PktFinal(Pkt);                                //Finalize packet
  1252. end;
  1253. {Request rights information for location service. This is from
  1254. the OSCAR document.}
  1255. procedure CreateCLI_REQLOCATION(Pkt: PRawPkt; var Seq: Word);
  1256. begin
  1257.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1258.   PktSnac(Pkt, $02, $02, 0, 0);                 //Snac: Type x02/x02, ID x0000, Flags 0
  1259.   PktFinal(Pkt);                                //Finalize packet
  1260. end;
  1261. {Request rights information for buddy service. This from the OSCAR document.}
  1262. procedure CreateCLI_REQBUDDY(Pkt: PRawPkt; var Seq: Word);
  1263. begin
  1264.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1265.   PktSnac(Pkt, $03, $02, 0, 0);                 //Snac: Type x03/x02, ID x0000, Flags 0
  1266.   PktFinal(Pkt);                                //Finalize packet
  1267. end;
  1268. {Request rights information for ICBM (instant messages) operations. This
  1269. from the OSCAR document.}
  1270. procedure CreateCLI_REQICBM(Pkt: PRawPkt; var Seq: Word);
  1271. begin
  1272.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1273.   PktSnac(Pkt, $04, $04, 0, 0);                 //Snac: Type x04/x04, ID x0000, Flags 0
  1274.   PktFinal(Pkt);                                //Finalize packet
  1275. end;
  1276. {Request BOS rights. This from the OSCAR document.}
  1277. procedure CreateCLI_REQBOS(Pkt: PRawPkt; var Seq: Word);
  1278. begin
  1279.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1280.   PktSnac(Pkt, $09, $02, 0, 0);                 //Snac: Type x09/x02, ID x0000, Flags 0
  1281.   PktFinal(Pkt);                                //Finalize packet
  1282. end;
  1283. {This packet sends the client's capabilities information to the server.}
  1284. procedure CreateCLI_SETUSERINFO(Pkt: PRawPkt; var Seq: Word);
  1285. const
  1286.   caps: array[0..$40 - 1] of Byte = (
  1287.     $09, $46, $13, $49, $4C, $7F, $11, $D1, $82, $22, $44, $45, $53, $54, $00, $00,
  1288.     $97, $B1, $27, $51, $24, $3C, $43, $34, $AD, $22, $D6, $AB, $F7, $3F, $14, $92,
  1289.     $2E, $7A, $64, $75, $FA, $DF, $4D, $C8, $88, $6F, $EA, $35, $95, $FD, $B6, $DF,
  1290.     $09, $46, $13, $44, $4C, $7F, $11, $D1, $82, $22, $44, $45, $53, $54, $00, $00
  1291.   );
  1292. begin
  1293.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1294.   PktSnac(Pkt, $02, $04, 0, 0);                 //Snac: Type x02/x04, ID x0000, Flags 0
  1295.   PktTLV(Pkt, 5, Length(caps), @caps);          //Client's capabilities
  1296.   PktFinal(Pkt);                                //Finalize packet
  1297. end;
  1298. {This packet seems to change some of the values passed from the server
  1299. in SRV_REPLYICBM SNAC(4,5).}
  1300. procedure CreateCLI_SETICBM(Pkt: PRawPkt; var Seq: Word);
  1301. begin
  1302.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1303.   PktSnac(Pkt, $04, $02, 0, 0);                 //Snac: Type x04/x02, ID x0000, Flags 0
  1304.   PktInt(Pkt, 0, 4);                            //0, Unknown; Numbers similar to x04/x05
  1305.   PktInt(Pkt, $0003, 2);                        //3, Unknown
  1306.   PktInt(Pkt, $1F40, 2);                        //8000, Unknown
  1307.   PktInt(Pkt, $03E7, 2);                        //999, Unknown
  1308.   PktInt(Pkt, $03E7, 2);                        //999, Unknown
  1309.   PktInt(Pkt, 0, 4);                            //0, Unknown
  1310.   PktFinal(Pkt);                                //Finalize packet
  1311. end;
  1312. {This sets the clients online status code and some other direct client
  1313. to client information as well. Used in login sequence.}
  1314. procedure CreateCLI_SETSTATUS(Pkt: PRawPkt; Status: LongWord; IP: LongInt; Port: Word; Cookie: LongWord; ProxyType: TProxyType; var Seq: Word);
  1315. var
  1316.   lpkt: TRawPkt;
  1317. begin
  1318.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1319.   PktSnac(Pkt, $01, $1E, 0, 0);                 //Snac: Type x01/x1E, ID x0000, Flags 0
  1320.   PktTLV(Pkt, $06, 4, Status);                  //TLV(06) Status
  1321.   PktTLV(Pkt, $08, 2, 0);                       //TLV(08) Error code
  1322.   PktInitRaw(@lpkt);
  1323.   //{$R-}
  1324.   PktInt(@lpkt, Swap32(IP), 4);                 //The client computer's local IP address.(internal)
  1325.   //{$R+}
  1326.   PktInt(@lpkt, Port, 4);                       //This is the port to connect with when making client to client connections.
  1327.   if ProxyType = P_NONE then
  1328.     PktInt(@lpkt, $04, 1)                       //01 = Firewall (or HTTPS proxy); 02 = SOCKS4/5 proxy; 04 = 'normal' connection
  1329.   else if (ProxyType = P_SOCKS4) or (ProxyType = P_SOCKS5) then
  1330.     PktInt(@lpkt, $02, 1);
  1331.   PktInt(@lpkt, $0008, 2);                      //The highest client to client protocol version this client uses.
  1332.   PktInt(@lpkt, Cookie, 4);                     //Probably a direct client to client connection cookie.
  1333.   PktInt(@lpkt, $0000, 2);                      //0, Unknown
  1334.   PktInt(@lpkt, $0050, 2);                      //80, Unknown
  1335.   PktInt(@lpkt, $0000, 2);                      //0, Unknown
  1336.   PktInt(@lpkt, $0003, 2);                      //Count: 3
  1337.     //Theese are used in miranda-icq
  1338.     //PktInt(@lpkt, $FFFFFFFF, 4);                  //time(NULL): Wed Sep 19 13:53:51 2001
  1339.     //PktInt(@lpkt, $00010201, 4);                  //time(NULL): Thu Nov 08 22:54:27 2001
  1340.     //PktInt(@lpkt, $3B7248ED, 4);                  //time(NULL): Thu Nov 08 22:49:54 2001
  1341.   PktInt(@lpkt, $00000000, 4);                  //time(NULL)
  1342.   PktInt(@lpkt, $00000000, 4);                  //time(NULL)
  1343.   PktInt(@lpkt, $00000000, 4);                  //time(NULL)
  1344.   PktInt(@lpkt, $0000, 2);                      //0, Unknown
  1345.   PktTLV(Pkt, $0C, lpkt.len, @lpkt.Data);       //TLV(0C)
  1346.   PktFinal(Pkt);                                //Finalize packet
  1347. end;
  1348. {Set client's online status after login.}
  1349. procedure CreateCLI_SETSTATUS_SHORT(Pkt: PRawPkt; Status: LongWord; var Seq: Word);
  1350. begin
  1351.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1352.   PktSnac(Pkt, $01, $1E, 0, 0);                 //Snac: Type x01/x1E, ID x0000, Flags 0
  1353.   PktTLV(Pkt, $06, 4, Status);                  //TLV(06) Status
  1354.   PktFinal(Pkt);                                //Finalize packet
  1355. end;
  1356. {This packet seems to pass the SNAC Families and their versions
  1357. along with some unknown other information back to the server.}
  1358. procedure CreateCLI_READY(Pkt: PRawPkt; var Seq: Word);
  1359. const
  1360.   buf: array[0..79] of Byte = (
  1361.     $00, $01, $00, $03, $01, $10, $04, $7B,
  1362.     $00, $13, $00, $02, $01, $10, $04, $7B,
  1363.     $00, $02, $00, $01, $01, $01, $04, $7B,
  1364.     $00, $03, $00, $01, $01, $10, $04, $7B,
  1365.     $00, $15, $00, $01, $01, $10, $04, $7B,
  1366.     $00, $04, $00, $01, $01, $10, $04, $7B,
  1367.     $00, $06, $00, $01, $01, $10, $04, $7B,
  1368.     $00, $09, $00, $01, $01, $10, $04, $7B,
  1369.     $00, $0A, $00, $01, $01, $10, $04, $7B,
  1370.     $00, $0B, $00, $01, $01, $10, $04, $7B
  1371.   );
  1372. begin
  1373.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1374.   PktSnac(Pkt, $01, $02, 0, 0);                 //Snac: Type x01/x02, ID x0000, Flags 0
  1375.   PktAddArrBuf(Pkt, @buf, SizeOf(buf));         //Number sequence matches SNAC(x01/x17)
  1376.   PktFinal(Pkt);                                //Finalize packet
  1377. end;
  1378. {This packet seems to act as an interface between the AIM OSCAR-based server
  1379. and the old original ICQ server database.}
  1380. procedure CreateCLI_TOICQSRV(Pkt: PRawPkt; UIN: LongWord; Command: Word; Data: Pointer; DataLen: LongWord; var Seq, Seq2: Word);
  1381. var
  1382.   lpkt: TRawPkt;
  1383.   len: Word;
  1384. begin
  1385.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1386.   if Seq2 = 2 then
  1387.     PktSnac(Pkt, $15, $02, $00010002, 0)        //Snac: Type x15/x02, ID x00010002, Flags 0
  1388.   else
  1389.     PktSnac(Pkt, $15, $02, $00000000, 0);       //Snac: Type x15/x02, ID x00000000, Flags 0
  1390.   PktInitRaw(@lpkt);
  1391.   Inc(lpkt.Len, 2);
  1392.   PktInt(@lpkt, Swap32(UIN), 4);
  1393.   PktInt(@lpkt, Swap16(Command), 2);
  1394.   PktInt(@lpkt, Swap16(Seq2), 2);
  1395.   PktAddArrBuf(@lpkt, Data, DataLen);
  1396.   //Store remaining size
  1397.   len := lpkt.Len;
  1398.   lpkt.Len := 0;
  1399.   PktLInt(@lpkt, len - 2, 2);
  1400.   lpkt.Len := len;
  1401.   //--
  1402.   PktTLV(Pkt, 1, lpkt.Len, @lpkt);
  1403.   PktFinal(Pkt);
  1404.   Inc(Seq2);
  1405. end;
  1406. {This is sent at login and when you add a new user to your
  1407. contact list. It contains a list of all the uin's in you're
  1408. contact list. ****May be repeated multiple times****}
  1409. procedure CreateCLI_ADDCONTACT(Pkt: PRawPkt; UIN: String; var Seq: Word);
  1410. begin
  1411.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1412.   PktSnac(Pkt, $03, $04, 0, 0);                 //Snac: Type x03/x04, ID x0000, Flags 0
  1413.   PktLStr(Pkt, UIN);                            //UIN
  1414.   PktFinal(Pkt);                                //Finalize packet
  1415. end;
  1416. {Sent to remove contacts from contact list.}
  1417. procedure CreateCLI_REMOVECONTACT(Pkt: PRawPkt; UIN: LongWord; var Seq: Word);
  1418. begin
  1419.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1420.   PktSnac(Pkt, $03, $05, 0, 0);                 //Snac: Type x03/x05, ID x0000, Flags 0
  1421.   PktLStr(Pkt, IntToStr(UIN));                  //List of UINs to remove from contact list.
  1422.   PktFinal(Pkt);                                //Finalize packet
  1423. end;
  1424. {Add UINs to your visible list.}
  1425. procedure CreateCLI_ADDVISIBLE(Pkt: PRawPkt; UINs: TStrings; var Seq: Word);
  1426. var
  1427.   i: Word;
  1428. begin
  1429.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1430.   PktSnac(Pkt, $09, $05, 0, 0);                 //Snac: Type x09/x05, ID x0000, Flags 0
  1431.   if UINs.Count > 0 then
  1432.     for i := 0 to UINs.Count - 1 do
  1433.       PktLStr(Pkt, UINs.Strings[i]);
  1434.   PktFinal(Pkt);                                //Finalize packet
  1435. end;
  1436. {Remove UINs from your visible list.}
  1437. procedure CreateCLI_REMVISIBLE(Pkt: PRawPkt; UIN: LongWord; var Seq: Word);
  1438. begin
  1439.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1440.   PktSnac(Pkt, $09, $06, 0, 0);                 //Snac: Type x09/x05, ID x0000, Flags 0
  1441.   PktLStr(Pkt, IntToStr(UIN));                  //The UINs to remove from your invisible list.
  1442.   PktFinal(Pkt);                                //Finalize packet
  1443. end;
  1444. {List of UINs to add to invisible list. ****May be repeated multiple times****}
  1445. procedure CreateCLI_ADDINVISIBLE(Pkt: PRawPkt; UINs: TStrings; var Seq: Word);
  1446. var
  1447.   i: Word;
  1448. begin
  1449.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1450.   PktSnac(Pkt, $09, $07, 0, 0);                 //Snac: Type x09/x05, ID x0000, Flags 0
  1451.   if UINs.Count > 0 then
  1452.     for i := 0 to UINs.Count - 1 do
  1453.       PktLStr(Pkt, UINs.Strings[i]);
  1454.   PktFinal(Pkt);                                //Finalize packet
  1455. end;
  1456. {Remove UINs from your invisible list...}
  1457. procedure CreateCLI_REMINVISIBLE(Pkt: PRawPkt; UIN: LongWord; var Seq: Word);
  1458. begin
  1459.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1460.   PktSnac(Pkt, $09, $08, 0, 0);                 //Snac: Type x09/x05, ID x0000, Flags 0
  1461.   PktLStr(Pkt, IntToStr(UIN));                  //The UINs to remove from your invisible list.
  1462.   PktFinal(Pkt);                                //Finalize packet
  1463. end;
  1464. {Acknowledge the receipt of all offline messages.}
  1465. procedure CreateCLI_ACKOFFLINEMSGS(Pkt: PRawPkt; UIN: LongWord; var Seq, Seq2: Word);
  1466. begin
  1467.   CreateCLI_TOICQSRV(Pkt, UIN, CMD_ACKOFFMSG, nil, 0, Seq, Seq2);
  1468. end;
  1469. {Send a message.}
  1470. procedure CreateCLI_SENDMSG(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; const Msg: String; var Seq: Word);
  1471. var
  1472.   lpkt: TRawPkt;
  1473.   pmsg: TRawPkt;
  1474. begin
  1475.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1476.   PktSnac(Pkt, $04, $06, 0, 0);                 //Snac: Type x04/x06, ID x0000, Flags 0
  1477.   PktInt(Pkt, ITime, 4);                        //MID
  1478.   PktInt(Pkt, IRandom, 4);                      //MID
  1479.   PktInt(Pkt, 1, 2);                            //type, 1 - text messages
  1480.   PktLStr(Pkt, UIN);                            //The UIN to send the message to.
  1481.   PktInitRaw(@lpkt);                            //Allocate packet for incapsulated TLV(02)
  1482.   PktTLV(@lpkt, 1281, 1, 1);                    //Unknown: 0x1 = 1.
  1483.   PktInitRaw(@pmsg);                            //Allocate packet for incapsulated TLV(257)
  1484.   PktInt(@pmsg, 0, 4);                          //Unknown: empty. vICQ uses 00 00 ff ff.
  1485.   PktStr(@pmsg, Msg);                           //Finally, the message to send.
  1486.   PktTLV(@lpkt, 257, pmsg.Len, @pmsg);          //Add TLV(257)
  1487.   PktTLV(Pkt, 2, lpkt.Len, @lpkt);              //Add TLV(2)
  1488.   PktTLV(Pkt, 6, 0, 0);                         //Always present empty TLV.
  1489.   PktFinal(Pkt);                                //Finalize packet
  1490. end;
  1491. {Send an URL.}
  1492. procedure CreateCLI_SENDURL(Pkt: PRawPkt; ITime, IRandom, MyUIN, UIN: LongWord; const URL, Description: String; var Seq: Word);
  1493. var
  1494.   lpkt: TRawPkt;
  1495.   S: String;
  1496. begin
  1497.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1498.   PktSnac(Pkt, $04, $06, 0, 0);                 //Snac: Type x04/x06, ID x0000, Flags 0
  1499.   PktInt(Pkt, ITime, 4);                        //MID
  1500.   PktInt(Pkt, IRandom, 4);                      //MID
  1501.   PktInt(Pkt, 4, 2);                            //type, 1 - url etc messages
  1502.   PktLStr(Pkt, UIN);                            //The UIN to sent the message to.
  1503.   PktInitRaw(@lpkt);                            //Allocate packet for incapsulated TLV(5)
  1504.   PktLInt(@lpkt, MyUIN, 4);                     //My UIN.
  1505.   PktInt(@lpkt, 4, 1);                          //The message type as in the old protocol.
  1506.   PktInt(@lpkt, 0, 1);                          //Unknown flags; possibly the message flags.
  1507.   S := Description + #$fe + URL;                //Concatinate: Decription + 0xFE + URL
  1508.   PktLNTS(@lpkt, S);                            //Finally the URL to send.
  1509.   PktTLV(Pkt, 5, lpkt.Len, @lpkt);              //Add TLV(5)
  1510.   PktTLV(Pkt, 6, 0, 0);                         //Always present empty TLV.
  1511.   PktFinal(Pkt);                                //Finalize packet
  1512. end;
  1513. {Grant another user's request for authorization (in response to SRV_AUTH_REQ).}
  1514. procedure CreateCLI_AUTHORIZE(Pkt: PRawPkt; UIN: LongWord; Auth: Byte; Reason: String; var Seq: Word);
  1515. begin
  1516.   if Auth = 1 then Reason := '';
  1517.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1518.   PktSnac(Pkt, $13, $1A, 0, 0);                 //Snac: Type x13/x1A, ID x0000, Flags 0
  1519.   PktLStr(Pkt, UIN);                            //UIN of the user to authorize.
  1520.   PktInt(Pkt, Auth, 1);                         //Decline or authorize the contact add request: 00 - decline, 01 - authorize
  1521.   PktInt(Pkt, Length(Reason), 2);               //Length of the following reason; always 0 for authorize.
  1522.   PktStr(Pkt, Reason);                          //Reason for declining authorization as ASCII string.
  1523.   PktInt(Pkt, 0, 2);                            //Unknown: empty.
  1524.   PktFinal(Pkt);                                //Finalize packet
  1525. end;
  1526. {Request information about another user.}
  1527. procedure CreateCLI_METAREQINFO(Pkt: PRawPkt; UIN, dUIN: LongWord; var Seq, Seq2: Word);
  1528. var
  1529.   lpkt: TRawPkt;
  1530. begin
  1531.   PktInitRaw(@lpkt);
  1532.   PktLInt(@lpkt, $04b2, 2); //CLI_METAREQINFO 0x04d0, ICQ 2002a sends 0xb204
  1533.   PktLInt(@lpkt, dUIN, 4);
  1534.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2);
  1535. end;
  1536. {Searches user by email.}
  1537. procedure CreateCLI_SEARCHBYMAIL(Pkt: PRawPkt; UIN: LongWord; const Email: String; var Seq, Seq2: Word);
  1538. var
  1539.   lpkt: TRawPkt;
  1540. begin
  1541.   PktInitRaw(@lpkt);
  1542.   PktInt(@lpkt, $7305, 2); //CLI_SEARCHBYMAIL
  1543.   PktInt(@lpkt, $5e01, 2); //The key to search for: 0x15e = 350 = email address
  1544.   PktLLNTS(@lpkt, Email);  //The email address to search for.
  1545.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1546. end;
  1547. {Searches user by UIN.}
  1548. procedure CreateCLI_SEARCHBYUIN(Pkt: PRawPkt; UIN: LongWord; DUIN: LongWord; var Seq, Seq2: Word);
  1549. var
  1550.   lpkt: TRawPkt;
  1551. begin
  1552.   PktInitRaw(@lpkt);
  1553.   PktInt(@lpkt, $6905, 2); //CLI_SEARCHBYUIN
  1554.   PktInt(@lpkt, $3601, 2); //The key to search for: 0x15e = 350 = email address
  1555.   PktInt(@lpkt, $0400, 2); //Length of the following data
  1556.   PktInt(@lpkt, Swap32(DUIN), 4); //UIN
  1557.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1558. end;
  1559. {Search for a user by most common options.}
  1560. procedure CreateCLI_SEARCHBYNAME(Pkt: PRawPkt; UIN: LongWord; const FirstName, LastName, NickName, Email: String; var Seq, Seq2: Word);
  1561. var
  1562.   lpkt: TRawPkt;
  1563. begin
  1564.   PktInitRaw(@lpkt);
  1565.   PktInt(@lpkt, $5F05, 2);      //CLI_SEARCHBYNAME
  1566.   if Length(FirstName) <> 0 then
  1567.   begin
  1568.     PktInt(@lpkt, $4001, 2);    //The key to search for: 0x140 = 320 = first name.
  1569.     PktLLNTS(@lpkt, FirstName); //The first name to search for.
  1570.   end;
  1571.   if Length(LastName) <> 0 then
  1572.   begin
  1573.     PktInt(@lpkt, $4a01, 2);    //The key to search for: 0x14a = 330 = last name.
  1574.     PktLLNTS(@lpkt, LastName);  //The last name to search for.
  1575.   end;
  1576.   if Length(NickName) <> 0 then
  1577.   begin
  1578.     PktInt(@lpkt, $5401, 2);    //The key to search for: 0x154 = 340 = nick.
  1579.     PktLLNTS(@lpkt, NickName);  //The nick name to search for.
  1580.   end;
  1581.   if Length(Email) <> 0 then
  1582.   begin
  1583.     PktInt(@lpkt, $5e01, 2);    //The key to search for: 0x15e = 350 = email address.
  1584.     PktLLNTS(@lpkt, Email);     //The email address to search for.
  1585.   end;
  1586.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1587. end;
  1588. {Ask for a random UIN from a user in given chat group.}
  1589. procedure CreateCLI_SEARCHRANDOM(Pkt: PRawPkt; UIN: LongWord; Group: Word; var Seq, Seq2: Word);
  1590. var
  1591.   lpkt: TRawPkt;
  1592. begin
  1593.   PktInitRaw(@lpkt);
  1594.   PktInt(@lpkt, $4E07, 2); //CLI_SEARCHRANDOM Channel: 2, SNAC(21,2) 2000/1870
  1595.   PktInt(@lpkt, Swap16(Group), 2); //The random chat group to request a UIN from.
  1596.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1597. end;
  1598. {Do an extensive search for a user.}
  1599. procedure CreateCLI_SEARCHWP(Pkt: PRawPkt; UIN: LongWord; First, Last, Nick, Email: String; MinAge, MaxAge: Word;
  1600.   Gender: Byte; Language: Byte; City: String; Country: Word; Company, Department, Position: String;
  1601.   Occupation: Byte; Organization: Word; OrganKeyWords: String; Affiliation: Word; AffiKeyWords,
  1602.   KeyWord: String; Online: Byte; var Seq, Seq2: Word);
  1603. var
  1604.   lpkt: TRawPkt;
  1605. begin
  1606.   if (Gender <> GEN_MALE) and (Gender <> GEN_FEMALE) then
  1607.     Gender := 0;                        //Don't care about gender
  1608.   PktInitRaw(@lpkt);                    //Initialize temporary packet
  1609.   PktInt(@lpkt, $5F05, 2);              //CLI_SEARCHBYPERSINF, Channel: 2, SNAC(21,2) 2000/1375
  1610.   if First <> '' then begin PktInt(@lpkt, $4001, 2); PktLLNTS(@lpkt, First); end;                                       //Fist Name
  1611.   if Last <> '' then begin PktInt(@lpkt, $4a01, 2); PktLLNTS(@lpkt, Last); end;                                         //Last Name
  1612.   if Nick <> '' then begin PktInt(@lpkt, $5401, 2); PktLLNTS(@lpkt, Nick); end;                                         //Nick Name
  1613.   if Email <> '' then begin PktInt(@lpkt, $5e01, 2); PktLLNTS(@lpkt, Email); end;                                       //Email
  1614.   if Gender <> 0 then begin PktInt(@lpkt, $7c01, 2); PktInt(@lpkt, $0100, 2); PktInt(@lpkt, Gender, 1);  end;           //Gender
  1615.   if (MinAge <> 0) and (MaxAge <> 0) then begin PktInt(@lpkt, $6801, 2); PktInt(@lpkt, $0400, 2); PktLInt(@lpkt, MinAge, 2); PktLInt(@lpkt, MaxAge, 2); end;      //Age
  1616.   if City <> '' then begin PktInt(@lpkt, $9001, 2); PktLLNTS(@lpkt, City); end;                                         //City/State
  1617.   if Country <> 0 then begin PktInt(@lpkt, $a401, 2); PktInt(@lpkt, $0200, 2); PktLInt(@lpkt, Country, 2); end;         //Country
  1618.   if Language <> 0 then begin PktInt(@lpkt, $8601, 2); PktInt(@lpkt, $0200, 2); PktLInt(@lpkt, Language, 2); end;       //Language
  1619.   if Company <> '' then begin PktInt(@lpkt, $ae01, 2); PktLLNTS(@lpkt, Company); end;                                   //Company
  1620.   if Department <> '' then begin PktInt(@lpkt, $b801, 2); PktLLNTS(@lpkt, Department); end;                             //Department
  1621.   if Occupation <> 0 then begin PktInt(@lpkt, $cc01, 2); PktInt(@lpkt, $0200, 2); PktLInt(@lpkt, Occupation, 2); end;   //Occupation
  1622.   if Position <> '' then begin PktInt(@lpkt, $c201, 2); PktLLNTS(@lpkt, Position); end;
  1623.   if Affiliation <> 0 then begin PktInt(@lpkt, $d601, 2); PktInt(@lpkt, 3 + Length(AffiKeyWords), 2); PktLInt(@lpkt, Affiliation, 2); PktLNTS(@lpkt, AffiKeyWords); end;     //Affiliation
  1624.   if Organization <> 0 then begin PktInt(@lpkt, $fe01, 2); PktInt(@lpkt, 3 + Length(OrganKeyWords), 2); PktLInt(@lpkt, Organization, 2); PktLNTS(@lpkt, OrganKeyWords); end; //Organization
  1625.   if KeyWord <> '' then begin PktInt(@lpkt, $2602, 2); PktLLNTS(@lpkt, KeyWord); end;                                   //Search by KeyWord
  1626.   if Online = 1 then begin PktInt(@lpkt, $3002, 2); PktInt(@lpkt, $0100, 2); PktInt(@lpkt, $01, 1); end;                //Search only online users
  1627.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1628. end;
  1629. {Set more information about yourself.}
  1630. procedure CreateCLI_METASETMORE(Pkt: PRawPkt; UIN: LongWord; Age: Word; Gender: Byte; HomePage: String; BirthYear: Word; BirthMonth, BirthDay, Lang1, Lang2, Lang3: Byte; var Seq, Seq2: Word);
  1631. var
  1632.   lpkt: TRawPkt;
  1633. begin
  1634.   if (Gender <> GEN_MALE) and (Gender <> GEN_FEMALE) then
  1635.     Gender := 0;                //Gender not specified.
  1636.   PktInitRaw(@lpkt);            //Initialize packet
  1637.   PktInt(@lpkt, $FD03, 2);      //CLI_METASETMORE Channel: 2, SNAC(21,2) 2000/1021
  1638.   PktLInt(@lpkt, Age, 2);       //Your age.
  1639.   PktInt(@lpkt, Gender, 1);     //Your gender.
  1640.   PktLNTS(@lpkt, HomePage);     //Your personal home page.
  1641.   PktLInt(@lpkt, BirthYear, 2); //Your year of birth.
  1642.   PktInt(@lpkt, BirthMonth, 1); //Your month of birth.
  1643.   PktInt(@lpkt, BirthDay, 1);   //Your day of birth.
  1644.   PktInt(@lpkt, Lang1, 1);      //Your first language. Numbers according to a table.
  1645.   PktInt(@lpkt, Lang2, 1);      //Your second language. Numbers according to a table.
  1646.   PktInt(@lpkt, Lang3, 1);      //Your third language. Numbers according to a table.
  1647.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1648. end;
  1649. {Set general information about yourself.}
  1650. procedure CreateCLI_METASETGENERAL(Pkt: PRawPkt; UIN: LongWord; const NickName, FirstName, LastName, Email, City, State, Phone, Fax, Street, Cellular, Zip: String; Country: Word; TimeZone: Byte; PublishEmail: Boolean; var Seq, Seq2: Word);
  1651. var
  1652.   lpkt: TRawPkt;
  1653. begin
  1654.   PktInitRaw(@lpkt);
  1655.   PktInt(@lpkt, $EA03, 2);      //CLI_METASETGENERAL Channel: 2, SNAC(21,2) 2000/1002
  1656.   PktLNTS(@lpkt, NickName);     //The nick of the user.
  1657.   PktLNTS(@lpkt, FirstName);    //The first name of the user.
  1658.   PktLNTS(@lpkt, LastName);     //The last name of the user.
  1659.   PktLNTS(@lpkt, Email);        //The email address of the user.
  1660.   PktLNTS(@lpkt, City);         //The city the user lives in.
  1661.   PktLNTS(@lpkt, State);        //The state the user lives in.
  1662.   PktLNTS(@lpkt, Phone);        //The phone number of the user.
  1663.   PktLNTS(@lpkt, Fax);          //The fax number of the user.
  1664.   PktLNTS(@lpkt, Street);       //The street the user lives in.
  1665.   PktLNTS(@lpkt, Cellular);     //The cell phone number of the user.
  1666.   PktLNTS(@lpkt, Zip);          //The zip code of the user.
  1667.   PktLInt(@lpkt, Country, 2);   //The country the user lives in according to a table.
  1668.   PktInt(@lpkt, TimeZone, 1);   //The timezone the user lives in, as multiples of 30minutes relative to UTC.
  1669.   PktInt(@lpkt, Ord(PublishEmail), 1); //Publush email: 1 = yes, 0 = no. 
  1670.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1671. end;
  1672. {Set the about string.}
  1673. procedure CreateCLI_METASETABOUT(Pkt: PRawPkt; UIN: LongWord; const About: String; var Seq, Seq2: Word);
  1674. var
  1675.   lpkt: TRawPkt;
  1676. begin
  1677.   PktInitRaw(@lpkt);
  1678.   PktInt(@lpkt, $0604, 2);      //CLI_METASETABOUT Channel: 2, SNAC(21,2) 2000/1030
  1679.   PktLNTS(@lpkt, About);        //The about information string to set.
  1680.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1681. end;
  1682. {Send SMS message.}
  1683. procedure CreateCLI_SENDSMS(Pkt: PRawPkt; UIN: LongWord; const Destination, Text: String; CodePage: Word; const Time: String; var Seq, Seq2: Word);
  1684. var
  1685.   lpkt: TRawPkt;
  1686.   S: String;
  1687. begin
  1688.   PktInitRaw(@lpkt);
  1689.   PktInt(@lpkt, $8214, 2);      //CLI_SENDSMS Channel: 2, SNAC(21,2) 2000/5250
  1690.   PktInt(@lpkt, $0001, 2);      //Unknown: 0x1 = 1.
  1691.   PktInt(@lpkt, $0016, 2);      //Unknown: 0x16 = 22.
  1692.   PktInt(@lpkt, 0, 4);
  1693.   PktInt(@lpkt, 0, 4);
  1694.   PktInt(@lpkt, 0, 4);
  1695.   PktInt(@lpkt, 0, 4);
  1696.   //Format message
  1697.   S := '<icq_sms_message>' +
  1698.        '<destination>' + Destination + '</destination>' +
  1699.        '<text>' + StrToUTF8(Text) + '</text>' +
  1700.        '<codepage>' + IntToStr(CodePage) + '</codepage>' +
  1701.        '<senders_UIN>' + IntToStr(UIN) + '</senders_UIN>' +
  1702.        '<senders_name>TICQClient</senders_name>' +
  1703.        '<delivery_receipt>Yes</delivery_receipt>' +
  1704.        '<time>' + Time + '</time>' +
  1705.        '</icq_sms_message>';
  1706.   PktTLV(@lpkt, 0, S);          //The message as a XML entity
  1707.   CreateCLI_TOICQSRV(Pkt, UIN, $07D0, @lpkt, lpkt.Len, Seq, Seq2); //Incapsulate in CLI_TOICQSRV
  1708. end;
  1709. {Sends a messaged/request with advanced options}
  1710. procedure CreateCLI_SENDADVMSG_CUSTOM(Pkt: PRawPkt; FFSeq: Word; ITime, IRandom, UIN: LongWord; CMD, MSGTYPE: Byte; ACMD: Word; const Msg: String; Data: Pointer; DataLen: LongWord; RTFFormat: Boolean; var Seq: Word; Accept: Boolean = True);
  1711. var
  1712.   lpTLV05: TRawPkt;
  1713.   lpTLV2711: TRawPkt;
  1714. const
  1715.   StrGuid: String = '{97B12751-243C-4334-AD22-D6ABF73F1492}';
  1716.   Capabilities: array[0..15] of Byte = ($09, $46, $13, $49, $4C, $7F, $11, $D1,
  1717.                                         $82, $22, $44, $45, $53, $54, $00, $00);
  1718. begin
  1719.   PktInit(Pkt, 2, Seq);                         //Channel 2
  1720.   PktSnac(Pkt, $04, $06, 0, 0);                 //Snac: Type x04/x06, ID x0000, Flags 0
  1721.   PktInt(Pkt, ITime, 4);                        //Seems to be a time stamp in 1/1500 sec since 8am of that Sunday.
  1722.   PktInt(Pkt, IRandom, 2);                      //A seemingly random ID generated for each message.
  1723.   PktInt(Pkt, $00000002, 4);                    //The message type used
  1724.   PktLStr(Pkt, UIN);                            //Destination UIN.
  1725.   PktInitRaw(@lpTLV2711);                       //TLV(2711)
  1726.   PktInt(@lpTLV2711, $1b, 1);                   //If this value is not present, this is not a message packet.
  1727.   PktInt(@lpTLV2711, $0008, 2);                 //This is the version of the TCP protocol that the sending client uses.
  1728.   PktInt(@lpTLV2711, $00, 1);                   //Unknown
  1729.   PktInt(@lpTLV2711, $00000000, 4);             //Caps, empty
  1730.   PktInt(@lpTLV2711, $00000000, 4);             //Caps, empty
  1731.   PktInt(@lpTLV2711, $00000000, 4);             //Caps, empty
  1732.   PktInt(@lpTLV2711, $00000000, 4);             //Caps, empty
  1733.   PktInt(@lpTLV2711, $0000, 2);                 //Unknown
  1734.   PktInt(@lpTLV2711, $03, 1);                   //Unknown
  1735.   PktInt(@lpTLV2711, $00000000, 4);             //0 = normal message, 4 = file ok or file request.
  1736.   PktInt(@lpTLV2711, FFSeq, 2);                 //SEQ1
  1737.   PktInt(@lpTLV2711, $0e00, 2);                 //Unknown, seen: 0x1200 and 0x0e00.
  1738.   PktInt(@lpTLV2711, FFSeq, 2);                 //SEQ1
  1739.   PktInt(@lpTLV2711, $00000000, 4);             //Unknown, always zero.
  1740.   PktInt(@lpTLV2711, $00000000, 4);             //Unknown, always zero.
  1741.   PktInt(@lpTLV2711, $00000000, 4);             //Unknown, always zero.
  1742.   PktInt(@lpTLV2711, CMD, 1);                   //0x01 - normal message, 0x1a - filerequest/response, contacts
  1743.   PktInt(@lpTLV2711, MSGTYPE, 1);               //00 - normal message 80 - multiple recipients 03 - auto reply message request.
  1744.   PktInt(@lpTLV2711, $0000, 2);                 //Usually 0, seen 0x2000.
  1745.   PktInt(@lpTLV2711, $0000, 2);                 //Usually 0, seen 0x0002 in information request messages.
  1746.   if Length(Msg) = 0 then
  1747.   begin
  1748.     PktLInt(@lpTLV2711, $0001, 2);              //Length of the message
  1749.     PktInt(@lpTLV2711, $00, 1);                 //The message should always have null terminator, event if it's empty
  1750.   end else
  1751.     PktLNTS(@lpTLV2711, Msg);                   //The message!
  1752.   if CMD = $01 then
  1753.   begin
  1754.     PktInt(@lpTLV2711, $00000000, 4);           //Only present in actual real messages, this will be the background color of the text box in RGB0 format.
  1755.     PktInt(@lpTLV2711, $FFFFFF00, 4);           //Only present in actual real messages, this will be the text color of the message in RGB0 format.
  1756.   end else
  1757.     PktAddArrBuf(@lpTLV2711, Data, DataLen);    //Add packet specific data
  1758.   if RTFFormat then                             //If we are using RTF format, then add GUID
  1759.   begin
  1760.     PktLInt(@lpTLV2711, 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.
  1761.     PktStr(@lpTLV2711, 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.
  1762.   end;
  1763.   PktInitRaw(@lpTLV05);                         //TLV(05)
  1764.   PktInt(@lpTLV05, $0000, 2);                   //0x0000 - normal message
  1765.   PktInt(@lpTLV05, ITime, 4);                   //Seems to be a time stamp in 1/1500 sec since 8am of that Sunday.
  1766.   PktInt(@lpTLV05, IRandom, 2);                 //A seemingly random ID generated for each message.
  1767.   PktInt(@lpTLV05, $0000, 2);                   //Unknown: 0.
  1768.   PktAddArrBuf(@lpTLV05, @Capabilities, 16);    //One of the capabilities sent in CLI_SETUSERINFO
  1769.   PktTLV(@lpTLV05, $000a, 2, ACMD);             //0x0001 - normal message 0x0002 - file ack or file ok
  1770.   PktTLV(@lpTLV05, $000f, 0, $00);              //Unknown, empty.
  1771.   //PktTLV(@lpTLV05, $0003, $0004, $c0a86516);    //Timestamp
  1772.   //PktTLV(@lpTLV05, $0005, $0002, $5d3c);        //Unknown
  1773.   PktTLV(@lpTLV05, $2711, lpTLV2711.Len, @lpTLV2711); //Incapsulate TLV2711 into TLV05
  1774.   PktTLV(Pkt, $05, lpTLV05.Len, @lpTLV05);      //Incapsulate TLV05 into Pkt
  1775.   PktTLV(Pkt, $0003, 0, 0);                     //Unknown, empty TLV(03)
  1776.   PktFinal(Pkt);                                //Finalize packet
  1777. end;
  1778. {Sends a messaged with advanced options}
  1779. procedure CreateCLI_SENDMSG_ADVANCED(Pkt: PRawPkt; ITime, IRandom, UIN: LongWord; const Msg: String; RTFFormat: Boolean; var Seq: Word);
  1780. begin
  1781.   CreateCLI_SENDADVMSG_CUSTOM(Pkt, $FFFF, ITime, IRandom, UIN, $01, $00, $0001, Msg, nil, 0, RTFFormat, Seq, True);
  1782. end;
  1783. {Sends an ack  with advanced options}
  1784. procedure CreateCLI_SENDMSG_FILEACK(Pkt: PRawPkt; FFSeq: Word; ITime, IRandom, UIN, FileSize: LongWord; const FileDesc, FileName: String; Port: Word; var Seq: Word);
  1785. var