ICQv7/8 (personal) protocol notes
_____________________________________
by Massimo Melina <rejetto@libero.it>
www.rejetto.com/icq
last update Jul 12, 2003
first release Sep 10, 2001
_____________________________________

---INTRODUCTION
These notes are about the protocol used by ICQ 2000+ for client-server
communication. Since version 2000 the protocol drastically changed. It was
over UDP, and now it is over TCP. ICQ2000 uses protocol version 7, ICQ2001
and ICQ2002 version 8, and ICQ lite version 9. A shorter name for the protocol
is ICQvX where X is the version.

---IMPORTANT NOTES
* THESE ARE ONLY _PERSONAL_ NOTES, USE THIS TEXT AT YOUR OWN RISK
* this doc is very bad written for several reasons i won't list here
* i don't earn money from this, i'm a student, i'm only having some fun
* a list of people who contributed to this doc is at bottom
* aside to this doc, it is a good idea to have a tcp sniffer
* if you need help subscribe the icq-devel mailing list
  www.d.kth.se/%7Ed95-mih/icq/icq-devel/
* if you want to tell me about additional info or wrong info in this file feel
  free to contact me
* AOL, ICQ inc, Mirabilis and (fill.the.blank) has no affiliation with
  this document
* SNAC family 13 is transaction incorrect

---DOC NOTES
* unk = unknown
* msg = message
* chars = characters
* FT = file transfer
* DC = direct connection
* p2p = peer-to-peer (that is, client to client)
* single quotes '' are used to enclose strings

---PROTO NOTES
* communication is over FLAP protocol, and where specified over SNAC
* password is xored with these bytes:
  F3,26,81,C4,39,86,DB,92,71,A3,B9,E6,53,7A,95,7C
  if your password is shorter then use less bytes
* AFAIK at the moment the server does not saves passwords longer than 8 chars
* at the moment i'm studying protocol with icq configured as
  "direct connections upon authorization"
* away messages, free for chat messages, etc use all the same method for
  exchanging, so i use a common name for them all: auto-messages.

---DATA FORMAT
* LE stands for little-endian
* BE stands for big-endian
* BYTE is a 8 bit integer
* WORD is a 2-byte integer (BE)
* DWORD is a 4-byte integer (BE)
* TIME_T is a DWORD, unix time format
* IPADDR is a quadruple of bytes A,B,C,D  where in dotted form is A.B.C.D
* COLOR is a quadruple of bytes: R,G,B,N  where N is not used (just set it zero)
* STRING is a succession of (ascii) chars without length-leading or
  null-char-ending
* UIN is a 4-byte integer (LE) that codifies the uin number
* B-UIN is a BYTE preceded STRING: the byte indicates the length of the string
  and the string report an uin number
* UINLIST is a raw succession of B-UINs
* NTS is a Null Termined String
* WNTS is a word (LE) preceeded NTS: the word indicates the length of the NTS,
  null char included (WNTS was LNTS, it has been renamed due to the large
  number of string formats)
* DS is a dword (LE) preceeded STRING:
  the dword indicates the length of the STRING, no null char
* BWS is a word (BE) preceeded STRING:
  the word indicates the length of the STRING
* WWNTS is a word (LE) preceeded WNTS:
  the word indicates the length of the WNTS
* FLAP is a 6-byte header, this layer describes the packet
    BYTE    2A
    BYTE    channel: 01 login, 02 SNACs, 03 errors, 04 logout, 05 keepalive
    WORD    sequence: an incrementing number
    WORD    data-length: length of the body of this FLAP packet
* SNAC is a 10-byte header, this layer describes functions
    WORD    family: in this doc SNAC XX,YY stands for family XX subtype YY
    WORD    subtype
    WORD    flags: use 0000 where not specified
    DWORD   request-id: used only for client-server requests
            it seems that the most significant bit has a special meaning,
            and if it is set the server disconnects you
  When bit15 is set in flags field, additional data is prefixed to the
  body (not the header) of the SNAC. This has been introduced with ICQv8.
  Here goes the structure
    WORD    N, number of following bytes (usually 6)
    WORD    unk (seen: 1)
    WORD    unk (seen: 2)
    WORD    unk (seen: 3 in snac-family 1, 2 in snac-family 13)
* strange-msg are sort of control messages sent by icq, purpose is unknown
  used values are: msg-type:01; priority:urgent;
  message body:empty; status:online;
* msg-type is a BYTE:
   CODE   FORMAT         MEANING
    01    plain          text-msg, rtf-msg, strange-msg
    02    ?              chat
    03    ?              file-req, file-ok
    04    url-msg        url
    06    FE-msg         authorization request
    07    plain          authorization denied
    08    empty          authorization given
    09    FE-msg         from Mirabilis
    0C    FE-msg         added-you (a contact added you to its contact list)
    0D    FE-msg         web pager (it has a leading
                         'Sender IP: xxx.xxx.xxx.xxx'0D0A in the body)
    0E    FE-msg         emailExpress
    13    contacts-msg   contacts
    1A    ?              descripted by a string
                         (used for contacts-req, greeting-card
    E8    plain          auto-msg, use this for away status
    E9    plain          auto-msg, use this for occupied status
    EA    plain          auto-msg, use this for N/A status
    EB    plain          auto-msg, use this for DND status
    EC    plain          auto-msg, use this for free4chat status

  note: E8-EC values are used for both request and reply
        requesting you have to refer to the status of the contact
        repling you have to refer to your own status

* msg-flags is a BYTE:
    00 = normal
    80 = multiple
    03 = special (used for auto-msg-req)
* error-code is a WORD:
    00 00   no error
    00 01   bad uin
    00 02   service unavailable
    00 04   bad password
    00 05   bad password
    00 07   "This ICQ number doesn't exist"
    00 08   "This ICQ number doesn't exist"
    00 14   unk
    00 15   too many clients from same ip
    00 16   too many clients from same ip
    00 18   rate exceeded
    00 1B   You are using an older version of ICQ. Upgrage
    00 1D   (probably) you're trying to reconnect too fast,
            wait a second and retry
    00 1E   Can't register on ICQ network. Please try again
* url-msg is a WNTS: msg FE url
* contacts-msg is a WNTS: contacts-number FE uin FE nick FE uin FE nick FE...
* FE-msg is a WNTS: nick FE first FE last FE email FE unk-char FE body
* gmt offset is a signed byte, specifies negative half hours from GMT 0
  (e.g. -3 = GMT+1:30)
* status codes is a double word: WORD flags WORD status
    WORD flags
      0001  webaware
      0002  show ip? (licq uses it on invisible state)
      0004  PFM
      0008  birthday flag
      0010  direct connection disabled
      0020  ICQ homepage
      0100  unk, seen on icq2go
      1000  direct connection upon authorization
      2000  direct connection only for contact list
    WORD status
      0000  online
      0001  away
      0002  dnd (also used: 0013)
      0004  n/a (also used: 0005)
      0010  occupied (also used: 0011)
      0020  free4chat
      0100  invisible
      0200  PFM (?) available (from LICQ source)
* accept-status codes
    0  normally accepted   (use this replying to auto-msg-req)
    1  file transfer denied
    9  not accepted, occupied
    A  not accepted, dnd
    4  accepted but away
    E  accepted but NA
    C  accepted to contact list (no blink in tray)
* priority codes
    00 00 = file-ok
    01 00 = normal, file-req
    02 00 = send urgent
    04 00 = send to contact list (don't blink in tray)
    21 00 = unk, seen in a greeting card and in an RTF msg
* direct-connection-info
    IPADDR  often second NIC ip, leave 0 for no DC
    DWORD   port where listening for connections, leave 0 for no DC
    BYTE    firewall details for the connection
              01 firewall/https
              02 SOCKS proxy
              04 normal
              06 unk, seen on icq2go
    WORD    p2p protocol version
              0004 icq98
              0006 icq99
              0007 icq2000
              0008 icq2001, icq2002, icq2003
              0009 icq lite
    4 BYTE  DC-cookie, the byte order is reversed in DC
    DWORD   web front port, usually 50
    DWORD   client features, usually 3
    TIME_T  last update?
    TIME_T  last info update?
    TIME_T  last status update?
    WORD    0
* 2001-short-info
    WNTS    nick
    WNTS    first
    WNTS    last
    WNTS    email
    3 BYTE  unk
* wp-short-request
    WNTS    first
    WNTS    last
    WNTS    nick
* wp-full-request
    wp-short-request-info
    WNTS    email
    WORD    (LE) minimum age, 0 if disabled
    WORD    (LE) maximum age, 0 if disabled
    BYTE    gender (0=disabled, other=see table)
    BYTE    language (0=disabled, other=see table)
    WNTS    city
    WNTS    state
    WORD    country (0=disabled, other=see table)
    WNTS    company-name
    WNTS    department
    WNTS    position
    BYTE    occupation field (0=disabled)
    WORD    past information category (0=disabled, other=see table)
    WNTS    desc
    WORD    interests-category (0=disabled, other=see table)
    WNTS    interests-specific (comma separated)
    WORD    affiliation/organization (0=disabled, other=see table)
    WNTS    desc
    WORD    homepage category
    WNTS    desc
    BYTE    only-online-users, (0=off, 1=on)
* wp-info
    WORD    length of this record, you can't rely on fields if record is shorter
    UIN     his uin
    WNTS    nick
    WNTS    first
    WNTS    last
    WNTS    email
    BYTE    auth (0=required, 1=always)
    BYTE    status (00 offline, 01 online, 02 not webaware)
    BYTE    unk, usually 0
    BYTE    gender
    BYTE    age
* main-home-info
    WNTS    nick
    WNTS    first
    WNTS    last
    WNTS    email
    WNTS    city
    WNTS    state
    WNTS    phone
    WNTS    fax
    WNTS    street
    WNTS    cellular (an ending ' SMS' is present if it's SMS-able)
    WNTS    zip
    WORD    country (LE)
    BYTE    gmt
    BYTE    publish email (00 yes, 01 no)
* work-info
    WNTS    city
    WNTS    state
    WNTS    phone
    WNTS    fax
    WNTS    street addres
    WNTS    zip
    WORD    country (LE)
    WNTS    company-name
    WNTS    company-dept
    WNTS    company-position
    WORD    unk, seen (0000, 0500)
    WNTS    company-web
* homepage-more-info
    BYTE    age
    BYTE    0
    BYTE    gender
    WNTS    homepage
    WORD    birth-year (LE)
    BYTE    birth-month
    BYTE    birth-day
    BYTE    lang1
    BYTE    lang2
    BYTE    lang3
* more-email-info
    BYTE    number (of addresses)
    for number times
      BYTE   publish email (00 yes, 01 no)
      WNTS   address
* personal-interests-in
    BYTE    N, number of categories to follow
     for N times
      WORD    category (see table)
      WNTS    specific
* past-backgrond-info
    WORD    category (see table)
    BYTE    unk
    WNTS    specific
    WORD    unk
    BYTE    unk
* capability is a 4 DWORD number
   4 capabilities are known
     1) 09461349 4C7F11D1 82224445 53540000  (auto-messages)
     2) 09461344 4C7F11D1 82224445 53540000  (unk)
     3) 97B12751 243C4334 AD22D6AB F73F1492  (RTF messages)
     4) 2E7A6475 FADF4DC8 886FEA35 95FDB6DF  (unk)
     5) 0946134E 4C7F11D1 82224445 53540000  (unk)
     6) 563FC809 0B6F41BD 9F794226 09DFA2F3  (unk)
     7) F2E7C7F4 FEAD4DFB B2353679 8BDF0000  (trillian only?)
* capability-info is a succession of capabilities
    note: icq2000   sends 1,2
          icq2001   sends 1,2,3,4
          icq2002   sends 1,3,2
          icq2003   sends 1,5,3,2
          licq      sends 2
          icq2go    sends 5,6
          icqlite   sends 6,1,5?,3,2
          trillian  sends 1,2,3,4,7
          "?" stands for not-always-present
* msg-data-1
	 TLV(0501)
	   BYTE    unk (seen: 01)
	 TLV(0101)
     4 BYTE  unk (seen: 0)
	   STRING  msg
* msg-data-4
   UIN    sender's uin
   BYTE   msg-type
   BYTE   msg-flags
   WNTS   msg
   if text-msg
     COLOR   foreground
     COLOR   background
   if contacts-req
     2 BYTE    39 00, it seems to be the number of following bytes
     18 BYTE   unk, 2A 0E 7D 46 76 76 D4 11 BC E6 00 04 AC 96 1E A6 02 00
     DS        Request For Contacts
     15 BYTE   00 00 00 00 00 01 00 00 00 00 00 00 00 00 00
     2 BYTE    11 00, it seems to be the number of following bytes
     2 BYTE    0
     DTS       request message
   if gcard
     gcard-data

* msg-data-2
   WORD       ??A    (0001 on abort request, 0002 on file-ack, else 0000)
   8 BYTE     same as msg-id
   16 BYTE    capability1
   if ??A = 0001
     TLV(B)      00 01 (present on abort requests)
   if ??A = 0000
     TLV(A)      00 02 for file-ok, file-ack, else 00 01
     TLV(5)      WORD, listening port (present on file-req, file-ok)
     TLV(3)      IPADDR, internal ip  (present on file-req, file-ok)
     TLV(F)      empty
     TLV(2711)
       -chuck1-
        WORD      number of following bytes (LE) usually 001B
        WORD      protocol version (LE)
        18 BYTE   0
                  i saw non-zero bytes in strange-msg:
                  10 CF 40 D1 4F E9 D3 11 BC D2 00 04 AC 96 DD 96 00 00
        DWORD     client features (LE) usually 3
        BYTE      firewall details? 04 on file-ok, file-req, text-msg, else 00
        WORD      ??D, seems to be a downcounter starting from FFFF
       -end-chunk1-
       -chunk2-
        WORD      number of following bytes (LE) usually 000E
        WORD      same as ??D
        12 BYTE   0
       -end-chunk2-
       BYTE      msg-type
       BYTE      msg-flags
       WORD      first word of my status-code (LE)  (0 for strange-msg)
       WORD      priority
       WNTS      msg  (7000 chars max)
       if msg-type = file-req
         4 BYTE    unk (seen: 9F CD D3 11, E0 1D E5 00, 00 00 00 00)
         WNTS      filename
         DWORD     filesize (LE)
         4 BYTE    unk (seen: 00 FD 81 01, 1D E0 00 00, 3E 03 00 00)
       if msg-type = file-ok
         WORD      listening port
         2 BYTE    0
         WNTS      ''
         4 BYTE    unk (seen: 5C 49 43 51, 00 00 00 00, 10 31 43 01)
         WORD      same listening port (LE)
         2 BYTE    0
       if msg-type = chat
         BYTE      01
         10 BYTE   0
       if msg-type = strange-msg
         6 BYTE    unk (seen: F0 02 BF 71 43, 10 18 06 70 54)
         16 BYTE   71 D3 11 8D D2 00 10 4B 06 46 2E 00 00 00 00 00 00
       if msg-type = text-msg
         COLOR     foreground
         COLOR     background
       if msg-type = rtf-msg
         COLOR     foreground
         COLOR     background
         DS        '{97B12751-243C-4334-AD22-D6ABF73F1492}'
       if msg-type = auto-msg-req
         empty
       if msg-type = greeting-card
         gcard-data
     if incoming file-ok, file-ack, file-req
 			 TLV(4)  IPADDR, external ip

* gcard-data
   -chunkGC-
   BYTE      unk (seen: 32 in v1.1,
                        2A in v1.2 for ICQ2001,
                        37 in v1.2 for ICQ2002)
   19 BYTE   unk (seen: 00 01 E5 3B 48 2A E4 D1 11 B6
                        79 00 60 97 E1 E2 94 00 00)
   DS        'Send Greeting card' in ICQ2002, else 'Greeting card'
   3 BYTE    unk (seen: 00 00 00)
   WORD      minor version (LE)
   WORD      major version (LE)
   -end-chunkGC-
   if version=1.2
     12 BYTE   unk, seen: 00 00 00 00 00 00 00 00 29 01 00 00,
                          00 00 00 00 00 00 00 00 42 01 00 00
   if version=1.1
     DWORD     seems a downcounter starting from 7F (LE)
   DS        version (seen: '1.2', '1.1')
   DS        theme (as 'Birthday','Anniversary', etc)
   DS        pre_title
   DS        design (seen: '37:215:318:13187:0:0:2008785')
   DS        title
   DS        recipient
   DS        text
   DS        sender
   WORD      major version (LE)
   WORD      minor version (LE)
   if version='1.2'
   DS        url

      note: the URL to open for v1.1 is (convert strings in URL format)
           'http://www.icq.americangreetings.com/icqorder.pd?'
           'mode=send'            ('mode=preview' for preview)
           '&design=' design
           '&pre_title=' pre_title
           '&title=' title
           '&recipient=' recipient
           '&text=' text
           '&sender=' sender

* xml-sms is a NTS
   '<icq_sms_message>'
   '<destination>' INTERNATIONAL NUMBER '</destination>'
   '<text>' TEXT-HTML '</text>'
   '<codepage>1252</codepage>'
   '<senders_UIN>' MYUIN '</senders_UIN>'
   '<senders_name>' MYNICK '</senders_name>'
   '<delivery_receipt>' YN-STRING '</delivery_receipt>'
   '<time>' GMT-STRING '</time>'
   '</icq_sms_message>'

* xml-sms-reply is a NTS
   '<sms_response>'
   '<source>' POWERED-BY '</source>'
   '<deliverable>' YN-STRING '</deliverable>'
   '<network>' DESTINATION-NETWORK '</network>'
   '<message_id>' NUM-NUM--NUM-NUM '</message_id>'
   '<messages_left>' NUM '</messages_left>'
   '</sms_response>'

 note: it can contain TAB chars (09) and LF chars (0A), just ignore them

* xml-sms-ack
   '<sms_delivery_receipt>'
   '<message_id>' NUM-NUM--NUM-NUM '</message_id>'
   '<destination>' INTERNATIONAL NUMBER '</destination>'
   '<delivered>' YN-STRING '</delivered>'
   '<submition_time>' GMT-STRING '</submition_time>'
   '<error_code>' NUM '</error_code>'
   '<error>'
   '<id>' NUM '</id>'
   '<params>'
   '<param>' NUM '</param>'
   '<param>' ERROR DESCRIPTION '</param>'
   '</params>'
   '</error>'
   '</sms_delivery_receipt>'

   TEXT-HTML  is simple text but with certain symbols mapped with ascii
              sequences. For a full list check an html reference.
   YN-STRING  is 'Yes' OR 'No'
   GMT-STRING is a string like 'Mon, 19 Nov 2001 08:23:38 GMT'
   NUM        is a succession of '0'..'9' chars

---LOGIN SESSION (connection to login.icq.com on port 5190)

server sends (1)      <- in parenthesis lies the FLAP channel
 4 BYTE   00 00 00 01

client sends (1)
 4 BYTE   00 00 00 01
 TLV(1)   STRING   my uin
 TLV(2)   STRING   encrypted password
 TLV(3)   STRING   client profile, example
                   (seen: 'ICQ Inc. - Product of ICQ (TM).2000b.4.63.1.3279.85')
 TLV(16)  WORD     unk, usually 01 0A
 TLV(17)  WORD     major version, 4 for icq2000, 5 for icq2001
 TLV(18)  WORD     minor version
 TLV(19)  WORD     lesser version
 TLV(1A)  WORD     build version
 TLV(14)  DWORD    dunno version
 TLV(0F)  STRING   language, 2 chars, usually 'en'
 TLV(0E)  STRING   country, 2 chars, usually 'us'

server sends (4)
 TLV(1)   STRING   my uin
 if all goes right
   TLV(5)   STRING   BOS-address:port
   TLV(6)   STRING   cookie
 else
   TLV(8)   error-code
   TLV(4)   STRING   url               // not always present
   TLV(C)   2 BYTE   unk (seen: 5F 65)

connection closed

---SERVICE SESSION (connection to service server specified in TLV(5))

server sends (1)
 4 BYTE   00 00 00 01

client sends (1)
 4 BYTE   00 00 00 01
 TLV(6)   STRING   cookie

---SNAC COMMANDS   (channel is always 2)

server sends       // error notification
 SNAC 1,01
 WORD   error-code
          000E  seen sending a bad 1,1E snac

client sends       // client ready
 SNAC 1,02
 follows a sequence of
   WORD    snac-family
   WORD    version required
   BYTE    01
   BYTE    ??A (seen: 10, 01)
   WORD    unk (seen: 028A for icq2000b, 047B for icq2001b)
 seen sequences of family/version/??A:
  icq2000 1,3,10;2,1,01;3,1,10;15,1,10;4,1,10;6,1,10;9,1,10;A,1,10
  icq2001 1,3,10;13,2,10;2,1,01;3,1,10;15,1,10;4,1,10;6,1,10;9,1,10;
          A,1,10;B,1,10

server sends       // Server is ready
 SNAC 1,03
 24 BYTE  00 01 00 02 00 03 00 04 00 06 00 08
          00 09 00 0A 00 0B 00 0C 00 13 00 15

client sends       // request rate
 SNAC 1,06
 empty

server sends       // response to 1,06
 SNAC 1,07
 181 BYTE  unk
 WORD      N, number of known messagges
 N DWORD   known messages, a known message is a words pair: FAMILY/SUBTYPE
 17 DWORD  unk, they seems messagge IDs too

client sends       // ack to 1,07
 SNAC 1,08
 10 BYTE   00 01 00 02 00 03 00 04 00 05

server sends       // warning: you're sending too fast
 SNAC 1,0A
 WORD     unk, (seen: 01, 02, 03)
 24 BYTE  00 01 00 00 00 50 00 00 09 C4 00 00
          07 D0 00 00 05 DC 00 00 03 20 00 00
 WORD     unk, maybe indicates the available space in the server queue and
          it is always under 2000dec. under 1500dec (5DChex) the first
          word is 3. over it is 2. note: 05DC appears in the 24 BYTE sequence.
 9 BYTE   00 00 17 70 00 00 00 00 01

server sends       // Server pause, you will be soon disconnected
 SNAC 1,0B
 empty

client sends       // Requests personal information.
 SNAC 1,0E
 empty

server sends       //  response to 1,0E
 SNAC 1,0F
 BUIN    my uin
 WORD    warning level
 WORD    N, number of following TLVs
 TLV(1)  WORD    unk, maybe sth about user class (seen: 00 00, 00 50)
 TLV(C)  direct-connection-info
 TLV(A)  IPADDR  my ip address
 TLV(4)  WORD    idle time, usually 00 00
 TLV(6)  DWORD   status code
 TLV(F)  DWORD   unk, it seems to be an incrementing value
 TLV(2)  TIME_T  member since
 TLV(3)  TIME_T  online since

client sends       // unk, usually sent after SNAC(1,1E)
 SNAC 1,11
 4 BYTE  0

server sends       // Message of the day
 SNAC 1,13
 2 BYTE   00 04
 TLV(B)   STRING message of the day, usually 'http://www.aol.com'

client sends       // protocol negotiation
 SNAC 1,17
 follows a sequence of
   WORD   snac-family
   WORD   version required
 (seen: ICQ 2000b sends couples: 1,3;13,2;2,1;3,1;15,1;4,1;6,1;9,1;A,1;B,1)

server sends       // these are my services, reply to SNAC(1,17)
 SNAC 1,18
 follows a sequence of
   WORD   snac-family
   WORD   version available
 (seen couples: 1,3;2,1;3,1;4,1;6,1;8,1;9,1;A,1;B,1;C,1;13,2;15,1)

client sends       // set status code
 SNAC 1,1E
 TLV(6)  status-code
 TLV(8)  error-code
 TLV(C)  direct-connection-info
 TLV(11) variable length, sent changing user info
         here some cases (they seems to be groups of 5 bytes)
         15 BYTE: 01 0A 19 0B 3B 01 2E 19 0B 3B 01 5E 19 0B 3B
          5 BYTE: 01 18 E5 CC 3B
          5 BYTE: 01 2C 35 FB 3B
 TLV(12) WORD  0  (sent changing user info)

client sends       // Request rights information for location service
 SNAC 2,02
   empty

server sends       // response to 2,02
 SNAC 2,03
 TLV(1)  04 00
 TLV(2)  00 10
 TLV(3)  00 0A

client sends       // set user info
 SNAC 2,04
 TLV(5) capability-info

client sends       // request user info?
 SNAC 2,05
 2 BYTE   00 02
 BUIN     my uin

server sends       // response to 2,05
 SNAC 2,06
 BUIN    uin requested
 WORD    0
 WORD    N, number of following TLVs
 TLV(1)  00 50
 TLV(C)  dc
 TLV(A)  ip address
 TLV(6)  status
 TLV(F)  DWORD   it seems a time in seconds
 TLV(2)  TIME_T  member since
 TLV(3)  TIME_T  online since

client sends       // Request rights information for buddy list
 SNAC 3,02
   empty

server sends       // response to 3,02
 SNAC 3,03
 TLV(1)  WORD   maximum number of contacts in your list (seen: 0258)
 TLV(2)  WORD   maximum number of watchers (seen: 2EE)
                 - a watcher is a contact with your uin in his list
 TLV(3)  WORD   unk (seen: 512)

client sends       // add to contact list
 SNAC 3,04
 UIN-LIST

client sends       // remove from contact list
 SNAC 3,05
 UIN-LIST

server sends       // rejected notification request (wtf?)
 SNAC 3,0A
 B-UIN

 note: there's no known way to prevent people from getting status notifications

server sends       // new status for user (not used offline)
 SNAC 3,0B
 B-UIN
 WORD    0
 WORD    N, number of following TLVs
 TLV(1)  WORD     unk (seen: 0050, 0070)
 TLV(C)  direct-connection-info
 TLV(A)  IPADDR
 TLV(11) 5 BYTE   unk (seen: 01 2C 35 FB 3B) seen with no TLVs 4,6
 TLV(4)  WORD     unk (seen: 0000, 0001)
 TLV(6)  status
 TLV(D)  capability-info
 TLV(F)  DWORD    it seems a time in seconds
 TLV(2)  TIME_T   member since
 TLV(3)  TIME_T   online since

server sends       // OFFgoing user (offline status)
 SNAC 3,0C
 B-UIN
 4 BYTE  00 00 00 01
 TLV(1)  00 00

server sends       // error notification
 SNAC 4,01
 WORD    error-code
          0004  type-2 messages to an offline client
          0009  type-2 messages to an old client?
          000A  too long message
          000E  invalid packet?

client sends       // Add ICBM parameter
 SNAC 4,02
 16 BYTE   00 00 00 00 00 03 1F 40 03 E7 03 E7 00 00 00 00

client sends       // Requests rights for ICBM (Instant Message) operations
 SNAC 4,04
   empty

server sends       // response to 4,04
 SNAC 4,05
 16 BYTE  00 02 00 00 00 03 02 00 03 E7 03 E7 00 00 03 E8

client sends       // send message
 SNAC 4,06
  8 BYTED  msg-id (ACKs should use same ID)
  WORD     msg-format
  B-UIN    recipient
  if msg-format=1           // simple message
       TLV(2)   msg-data-1
       TLV(6)   empty
     msg-format=2           // advanced message (only for ICQv7+ clients)
       TLV(5)   msg-data-2
       if ??A = 0000
         TLV(3) empty (ack request?)
     msg-format=4           // url or contacts or auth-reply or multi-send
       TLV(5)   msg-data-4
       TLV(6)   empty (ack request?)

server sends       // incoming message
 SNAC 4,07
 8 BYTE   msg-id
 WORD     msg-format
 B-UIN    sender's uin
 WORD     warning level? garbage of OSCAR protocol
 WORD     maybe the number of following TLVs, until msg-format dependant TLVs
          (seen: 00 05, 00 06)
 TLV(1)   WORD     unk (seen: 0050, 0070, 0004)
 TLV(4)   WORD     0
          (not present in file-req, file-ok, auto-msg-req, greeting-cards)
 TLV(6)   sender's status
 TLV(F)   DWORD    it seems a time in seconds
 TLV(2)   TIME_T   member since
 TLV(3)   TIME_T   online since
 if msg-format = 1    // message
   TLV(2)   msg-data-1
 if msg-format = 2    // advanced message
   TLV(5)   msg-data-2
 if msg-format = 4    // url or contacts or auth-req or added-you
   TLV(5)   msg-data-4

server sends            // message undelivered
  SNAC 4,0A
  2 BYTE   00 01
  B-UIN    sender's uin
  WORD     0
  WORD     number of following TLVs
  TLV(1)   00 50
  TLV(6)   sender's status
  TLV(F)   DWORD    it seems a time in seconds
  TLV(3)   TIME_T   online since
  WORD     number of undelivered messages
  WORD     error (0 invalid, 1 too large, 2 rate exceeded)

client or server sends    // ack to type-2 message, used for auto-msg too
  SNAC 4,0B
  10 BYTE   equals to first 10 BYTE of message
  BUIN      equals to message' uin
  2 BYTE    00 03
  chunk1 from TLV(2711) with zeroed firewall details
  chunk2 from TLV(2711)
  BYTE      msg-type
  BYTE      msg-flags
  BYTE      accept-status
  3 BYTE    0
  WNTS      message
  if text-msg
    8 BYTE    00 00 00 00 FF FF FF FF
  if auto-msg
    empty
  if greeting-card
    chunkGC
    4 BYTE    00 00 00 00
  if file-deny
    variable,
      seen: 11 BYTE   01 00 00 xx xx 00 00 xx xx 00 00
      seen: 15 BYTE   00 00 00 00 01 00 00 C8 06 C9 00 00 00 00 00

server sends       // server ack to type-2 messages
 SNAC 4,0C
 10 BYTE   equals to first 10 BYTE of message
 BUIN      equals to message' uin

client sends       // Requests BOS rights
 SNAC 9,02
   empty

server sends       // response to 9,02
 SNAC 9,03
 TLV(2)  00 A0
 TLV(1)  00 A0

client sends       // add to visible list
 SNAC 9,05
 UIN-LIST

client sends       // remove from visible list
 SNAC 9,06
 UIN-LIST

client sends       // add to invisible list
 SNAC 9,07
 UIN-LIST

client sends       // remove from invisible list
 SNAC 9,08
 UIN-LIST

client sends       / add to a sort of visible list
 SNAC 9,0A
 UIN-LIST

client sends       // remove from a sort of visible list
 SNAC 9,0B
 UIN-LIST

server sends       // Set minimum report interval?
 SNAC  B,02        // maybe related to the SNACs icq2001 sends periodically
 2 BYTE  04 B0

client sends       // ask server to ready UIN's database??
 SNAC 13,02
   empty

server sends       // reply to 13,02
 SNAC 13,03
 TLV(2)  unk, 00 FE
 TLV(3)  unk, 01 FC
 TLV(4)  unk, 02 58 00 33 00 80 00 80 00 01 00 01 00 32 00 00 00 00 00 03
              00 00 00 00 00 00 00 80 00 80 00 14 00 C8 00 01 00 00 00 01
 TLV(5)  unk, 00 00

client sends       // request saved roaster
 SNAC 13,05
 TIME_T  last saving time
 WORD    number of records your contact list has, counting vis, inv, ignore,
         then groups, and uins (all uins on ur list, including vis and inv)
         again, you can get this thru 13,06 server reply

server sends       // saved roaster (reply to 13,05)
 SNAC 13,06
 2 BYTE    0
 BYTE      number of records in the current 13,06 reply
 6 BYTE    0, present only in first 13,06
 TLV(1)    list of group-id where each element is
   TLV(C8) WORD      group-id
 for each user registered by you
   BYTE      0
   BUIN      other user
   2 BYTE    0
   2 BYTE    unk, (seen: 31 75, 50 70)
   4 BYTE    00 02 00 00
 if random(2)          // it seems to be present only in first SNAC(13,06)
   BWS       'Import Time'
   4 BYTE    00 00 00 01
   TLV(13)
     TLV(D4) TIME_T    import time, first time importing your list to server
 4 BYTE    0   (terminator?)
 2 BYTE    unk, (seen: 7F 5B)
 TLV(4)    TLV(CA)  BYTE   unk, (seen: 04, 03)
 if random(2)            // has anyone idea of when this section is present?
   for each user on your vis, inv, and ignore list
     WUIN      user uin
     2 BYTE    0
     2 BYTE    unk, not related to the later contact-id, but maybe unique
     1 BYTE    0
     1 BYTE    xx (02: vis, 03: inv, 0E ignore)
     2 BYTE    0
   BWS      'ICQTIC'
   4 BYTE   00 00 75 C8
   TLV(9) TLV(CD) STRING  unk (seen: '3097,0,0,0')
 for each group
   BWS      group name
   WORD     group-id
   2 BYTE   0
   TLV(1) TLV(C8) WORD    contact-id, list of contact-id where each element is
   for each uin under the current group
     BYTE      0
     BUIN      a contact of the group
     WORD      groupd-id (of the current group)
     TLV(0)
       2 BYTE    01 31
       BWS       nick
       if TLV(66) is present, we're waiting for auth from this contact
 TIME_T   last saving time, ZERO if this is not the last SNAC(13,06)
          used only for SNAC(13,05) requests

 note: you could get more than one SNAC of this kind

client sends       // ack to SNAC(13,06) ?
 SNAC 13,07
   empty

client sends       // add to a list
 SNAC 13,08
 BYTE   0
 BUIN   an uin
 if adding to visible list
   8 BYTE   00 00 2B 63 00 02 00 00
 if adding to contact list
   WORD     group-id
   WORD     contact-id
   TLV(0)
     2 BYTE   01 31
     BWS      nick
     if TLV(66) is present, we're waiting for auth from this contact
 if adding a group to the list (??)
   BWS      group name
   WORD     group-id
   2 BYTE   0

client sends       // update group (or add group too???)
 SNAC 13,09
 BWS      group name
 WORD     group-id
 2 BYTE   0
 TLV(1)
   TLV(C8) contact-ids of this group, can be empty

 note: server acks with last two byte as 0 (success?)

client sends       // remove from visible list
 SNAC 13,0A
 BYTE     0
 BUIN     an uin
 WORD     group-id
 if group-id = 0
   6 BYTE  seen: 22 64 00 02 00 00
 else
   WORD    uin-id
   TLV(0)
     2 BYTE   01 31
     BWS      nick
     if TLV(66) is present, we're waiting for auth from this contact

 variable, seen:
   8 BYTE   00 00 22 64 00 02 00 00
   16 BYTE  7F D1 0C 5C 00 00 00 08 01 31 00 00

server sends       // ack to SNACs 13
 SNAC 13,0E
 2 BYTE   unk, (seen: 00 00, 00 0E)

client sends       // begin editing roaster
 SNAC 13,11
 empty

client sends       // end editing roaster
 SNAC 13,12
 empty

client sends       // auth grant
 SNAC 13,14
 BUIN    recipient
 BWS     msg
 2 BYTE  0

client sends       // auth request
 SNAC 13,18
 BUIN    recipient
 BWS     msg
 2 BYTE  0

client sends       // unk
 SNAC 13,1B
 5 BYTE   01 00 00 00 00

client sends       // many purposes
 SNAC 15,02
 TLV(1)
   WORD   (LE) bytes remaining, useless
   UIN    my uin
   WORD   type
   WORD   req-id
   if type=3C00       // request offline messages
     nothing
   if type=3E00       // ack to offline messages
     nothing
   if type=D007
     WORD  subtype
     if subtype=9808  xml-stype in an WNTS
       WNTS    '<key>'name-of-required-data'</key>'
     if subtype=1F05       // request wp-info by UIN
       UIN     user to request info
     if subtype=6905       // request wp-info by UIN  (icq2001)
       4 BYTE  36 01 04 00
       UIN     user to request info
     if subtype=1505       // wp-short-request
       wp-short-request
     if subtype=3D05       // wp-short-request (wildcards support?)
       wp-short-request
     if subtype=3305       // wp-full-request
       wp-full-request
     if subtype=B204       // request full info
       UIN     user to request info
     if subtype=BA04       // request 2001-short-info
       UIN     user to request info
     if subtype=D004       // query my info
       UIN     my uin
     if subtype=EA03       // modify main-home-info
       main-home-info
     if subtype=FD03       // modify homepage-more-info
       homepage-more-info
     if subtype=0604       // modify about
       WNTS    about
     if subtype=F303       // modify work-info
       work-info
     if subtype=0B04       // add/set additional email addresses
       more-email-info
     if subtype=2E04       // change password
       WNTS    new password
     if subtype=C404       // remove user (warning!)
       UIN     uin to remove
       WNTS    password
     if subtype=2404       // set permissions?
       BYTE    authorization, 00 = required, 01 = not required
       BYTE    webaware, 00 = off, 01 = on
       2 BYTE  unk (seen: 01 00)
     if subtype=D70A       // unk (icq2001)
       empty
     if subtype=8214       // send sms
       4 BYTE   00 01 00 16
       18 BYTE  0
       WORD     length of the next string
       NTS      xml-sms
     if subtype=5F05       // search users by nick/first/last in 2001b
       2 BYTE  40 01
       LLTNS   first name
       2 BYTE  4A 01
       LLTNS   last name
       2 BYTE  54 01
       LWNTS   nick
     if subtype=7305     // search uin by email in 2001b
       2 BYTE  5E 01
       LLTNS   email
     if subtype=2905     // search by email
       LTNS    email

  note: with B204 you get several replies in SNAC(15,03), here is a list:
        C800, DC00, EB00, 0E01, D200, E600, F000, FA00

server sends       // many purposes
 SNAC 15,03 flag:000x
 TLV(1)  used for a lot of things
   WORD   (LE) bytes remaining, useless
   UIN    my uin
   WORD   type
   WORD   req-id
   if type = 4100                   // offline message
     UIN     his uin
     WORD    year (LE)
     BYTE    month (1=jan)
     BYTE    day
     BYTE    hour (GMT time)
     BYTE    minutes
     BYTE    msg-type
     BYTE    msg-flags
     WNTS    msg
     if greeting-card
       gcard-data
   if type = 4200                   // end of offline messages
     BYTE    unk, usually 0
   if type = D007
     2 BYTE  unk, usually 98 08
     WNTS    '<key>'field-type'</key>'
     if field-type = 'DataFilesIP'
       6 BYTE   unk, usually 2A 02 44 25 00 31
   if type = DA07
     WORD   subtype
     BYTE   result
     if result = 32 or 14 or 1E  // error: empty result or nonexistent user (14 and 32 = not found, 1E = readonly???)
       empty
     else
       if subtype=A208                //  where to get ads stuff
         WNTS     ip address  (a web server), usually '<value>205.188.250.25</value>' that is cb.icq.com
       if subtype=A401                //  reply to wp-full-request or find user
         wp-info
       if subtype=AE01                //  reply to wp-full-request or find user (the last)
         wp-info
         DWORD   lasting results (LE)
       if subtype=9001                //  reply to wp-short-request
         wp-result-info
       if subtype=9A01                //  reply to wp-short-request (the last) or by-uin
         wp-info
         DWORD   lasting results (LE)
       if subtype=6400                // ack to modify info (main/home)
         empty
       if subtype=7800                // ack to modify info (homepage/more)
         empty
       if subtype=8200                // ack to modify info (about)
         empty
       if subtype=6E00                // ack to modify info (work)
         empty
       if subtype=B400                // ack to remove user
         empty
       if subtype=AA00                // ack to change password
         empty
       if subtype=A000                // ack to 2404
         empty
       if subtype=1D03                // ack to D70A
         empty
       if subtype=8700                // ack to additional emails
       	 BYTE  unk, seen: 0A
       if subtype=0401                // reply to BA04
         2001-short-info
       if subtype=C800                // part of full-info
         main-home-info
         WORD    unk
       if subtype=DC00                // part of full-info
         homepage-more-info
         WORD    unk
       if subtype=EB00                // part of full-info
         more-email-info
       if subtype=0E01                // part of full-info
         WORD    0
       if subtype=D200                // part of full-info
         work-info
       if subtype=E600                // part of full-info
         WNTS    about
       if subtype=F000                // part of full-info
         personal-interests-info
       if subtype=FA00                // part of full-info
         past-background-info

server sends
 SNAC 17,03
 TLV(4)  STRING  message of the day, usually 'http://www.aol.com'
 TLV(8)  error-code
 TLV(C)  00 01

---DISCONNECTION

* to disconnect simply close the socket

server sends (4)
  TLV(9) WORD    disconnect reason
                 1 = another client is loggin with this uin
  TLV(B) STRING  additional info
         (seen: 'http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html')

----A (hopely) CORRECT LOGIN SEQUENCE
login packet (uin/password)
get the cookie and reconnect
send cookie
SNAC 1/3
SNAC 1/17
SNAC 1/6
SNAC 1/E
SNAC 2/2
SNAC 3/2
SNAC 4/4
SNAC 9/2
the server reply 1/7 to the 1/6, and then it goes:
SNAC 1/8
SNAC 4/2
SNAC 2/4
SNAC 3/4 with the contact list
if status = invisible SNAC 9/5 with visible list
SNAC 1/1E with status
SNAC 1/11
if status != invisible SNAC 9/7 with invisible list
SNAC 1/2
SNAC 15/2, to require offline messages


---RECEIVE A FILE TRANSFER REQUEST VIA SERVER
server:
 SNAC 4,07   (file-req)
client:
 SNAC 4,06   (file-ok)
  or
 SNAC 4,0B   (file-denied)
server:
 SNAC 4,07   (file-ack, with ??A=0002)

* after file-req a SNAC 4,07 (file-abort) could happen
* msg-id must be the same for all SNACs

---NEW UIN REGISTRATION  (a new connection is required to login.icq.com)

server sends (1)
 4 BYTE  00 00 00 01

client sends (1)
 4 BYTE  00 00 00 01

client sends
 SNAC  17,04
 3 BYTE  00 01 00
 BYTE    unk, (seen: 3B, 38)
 4 BYTE  0
 4 BYTE  28 00 03 00
 4 BYTE  0
 4 BYTE  0
 4 BYTE  ??A, unk, (seen: 03 46 00 00, B4 25 00 00)
 4 BYTE  same as ??A
 4 BYTE  0
 4 BYTE  0
 4 BYTE  0
 4 BYTE  0
 WNTS    chosen password
 4 BYTE  same as ??A
 4 BYTE  00 00 CF 01

server sends
 SNAC 17,05
 17 BYTE   00 01 00 32 30 00 00 00 00 00 2D 00 03 00 00 00 06
 BYTE      unk, (seen: 0F, 72)
 2 BYTE    3E 62
 2 BYTE    unk, (seen: E3 53, CD B5)
 2 BYTE    7E FF
 4 BYTE    unk, (seen: 14 18 03 46, 17 08 B4 25)
 18 BYTE   0
 UIN       new uin number
 2 BYTE    unk, (seen: 03 46, B4 25)
 2 BYTE    00 00

---PEOPLE WHO CONTRIBUTED TO THIS DOC (i decide the order, that is, random)
Jeff Hughes <valaxer@nwinet.com>
Filippov Joe <joe@idisys.iae.nsk.su>
Robin Fisher <robin@phase3solutions.com>
Daniel Wirtz <daniel@skywebs.net>
Alex Efros <powerman@sky.net.ua>
Vadim Pavlov <vadim@thesa.ru>
Olivier Crete <oliviercrete@videotron.ca>
Alexandr V. Shutko <avshutko@mail.khstu.ru>
Patrick Sung <phsung@ualberta.ca>
Zoe Smale <skyerat@hotmail.com>
Adam Fritzler <afritz@iname.com>
Peter Backes <rtc@gmx.de>