Rambler's Top100
Рейтинг@Mail.ru

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





































































 
    проект nICQ (урок №1) Шутка...
Назад Содержание Дальше
Для разбора конкретного примера возьмем ситуацию, когда мы запрашиваем у ICQ-сервера оффлайновые сообщения (т.е. те, которые накопились на сервере, пока нас не было в онлайне).

Запрос оффлайновых сообщений делаем с помощью SNAC(15,2), а ответ на него получим соответственно в SNAC(15,3). Оба этих SNACa имеют очень простой формат. Они содержат в себе только по одному TLV, а именно TLV(1). На первый взгляд все очень просто. Но... TLV(1), в свою очередь, имеет очень ветвистую структуру. (Такие особенности имеют и некоторые другие SNACи, например, SNAC(4,6) для передачи и SNAC(4,7) для приема сообщений).
В заметках к протоколу ICQv7 от Massimo Melina есть описание SNAC(15,2). Этот SNAC используется во множестве различных запросов. Я лишь выделю те строки, которые будут включены в наш запрос, а именно:
- заголовок самого SNAC(15,2);
- TLV(1), который включает в себя:
длину, следующих далее данных,
наш UIN,
тип запроса ($3С00),
cookie (по которому мы узнаем ответный SNAC(15,3) ).



В описании это находится вот здесь:
----- cut -----
SNAC 15,02
 TLV(1)
   WORD   (LE) bytes remaining, useless
   UIN    my uin
   WORD   type
   WORD   cookie
   type=3C00       // ask for offlines messages
     nothing
   type=3E00       // ack to offline messages, 
     nothing
type=D007 WORD subtype subtype=9808 xml-stype in an LNTS LNTS '<key>' name of required data '</key>' subtype=1F05 // simple query info UIN user to request info
subtype=B204 // query info about user UIN user to request info
subtype=D004 // query my info UIN my uin .............. .............. .............. ----- cut -----
В исходном коде это выглядит так:

  unit Main;
       // Get offline messages
// создаем FLAP-заголовок с Channel_ID=2 и SEQ++ tmp := CreatePacket(2,SEQ); // добавляем SNAC-заголовок SNAC(15,2) SNACAppend(tmp,$15,$2); // добавляем TLV(1) ($0001-Type, $000A-Length) PacketAppend32(tmp,dswap($0001000A)); // добавляем саму Value Для TLV(1) PacketAppend16(tmp, swap($0800));// бесполезная длина PacketAppend32(tmp, UIN); // наш UIN PacketAppend16(tmp, swap($3C00));// тип запроса PacketAppend16(tmp, swap($0200));// cookie PacketSend(tmp); M(Memo,'> Get offline messages');

Этот кусок кода сгенерирует следующий дамп:
2A 02 36 86 00 18 00 15
00 02 00 00 00 87 00 02
00 01 00 0A 08 00 XX XX
XX XX 3C 00 02 00 

Разпишем его в табличном виде для лучшего восприятия:

FLAP
Command Start 2A
Channel ID 02
Sequence Number 36 86
Data Field Length 00 18

SNAC (15, 02)
Family ID 00 15
SubType ID 00 02
Flags[0] 00
Flags[1] 00
Request ID 00 87 00 02

TLV (1)
Type 00 01
Length 00 0A
Value 08 00
 
XX XX XX XX наш UIN
3C 00 запрос на оффлайновые сообщения
02 00 cookie


Передадим пакет и от сервера получим FLAP-пакет с таким дампом:

2A 02 74 6D 00 4D 00 15 
00 03 00 01 00 87 00 02 
00 01 00 3F 3D 00 XX XX 
XX XX 41 00 02 00 F8 5F 
F1 08 D2 07 02 0C 10 12 
01 00 25 00 EF F0 E8 E2 
E5 F2 0D 0A FD F2 EE 20 
F2 E5 F1 F2 EE E2 EE E5 
20 F1 EE EE E1 F9 E5 ED 
E8 E5 20 21 21 21 0D 0A 
00 00 00
И снова распишем его в таблицу:

FLAP
Command Start 2A
Channel ID 02
Sequence Number 74 6D
Data Field Length 4D 00

SNAC (15, 03)
Family ID 00 15
SubType ID 00 03
Flags[0] 00
Flags[1] 01
Request ID 00 87 00 02 (такой же как и в запросе)

TLV (1)
Type 00 01
Length 00 3F
Value 3D 00
 
XX XX XX XX наш UIN
41 00 тип: оффлайновое сообщение
02 00 cookie (как и в запросе)
тело сообщения
XX XX XX XX его UIN
D2 07 год (2002)
02 месяц (февраль)
0C день (12)
10 час (16)
12 минуты (18)
01 под-тип сообщения
(обычное)
00 флаги сообщения (?)
25 00 длина сообщения (37)
EF F0 E8 E2 E5 F2 0D 0A FD F2 EE 20 F2 E5 F1 F2 EE E2 EE E5 20 F1 EE EE E1 F9 E5 ED E8 E5 20 21 21 21 0D 0A 00 текст сообщения:

"привет
это тестовое сообщение !!!"
00 00 присутствют, если сообщение единственное




В протокольных заметках я выделю ту часть описания SNAC(15,3), которая соответствует таблице:
----- cut -----
 SNAC 15,03
TLV(1)
WORD (LE) bytes remaining, useless
UIN my uin
WORD message-type
WORD cookie
message-type = 4100 // offline message
UIN his uin
WORD year (LE)
BYTE month (1=jan)
BYTE day
BYTE hour (GMT time)
BYTE minutes
BYTE msg-subtype
BYTE msg-flags
LNTS msg
WORD 0000, present only in single messages

message-type = 4200 // end of offline messages
BYTE unknown, usually 0
message-type = D007
2 BYTE unknown, usually 98 08
WORD length of the following NTS
NTS "<key>"field-type"</key>"
field-type = DataFilesIP
6 BYTE unk, usually 2A 02 44 25 00 31
message-type = DA07
3 BYTE subtype
subtype=A4010A // wp-full-request result
wp-result-info
.............. .............. .............. subtype=B4000A // ack to remove user
empty
subtype=AA000A // ack to change password
empty
----- cut -----
И "нарешти" - код для приема SNAC(15,3). Множественные комментарии, кажется тут уже излишни.

  unit Main;
procedure TForm1.SNAC_15_3(p:PPack);
var MessageType,Cookie : word;
    myUIN,hisUIN : longint;
    year,month,day,hour,minute,typemes,subtypemes,lenmes : word;
    tmp : PPack;
begin
     // просто пролетаем над началом TLV(1)
     PacketRead32(p);
     PacketRead16(p);

     // а дальше имена переменных объясняют больше, чем комментарии
     myUIN := PacketRead32(p);
     MessageType := swap(PacketRead16(p));
     Cookie := swap(PacketRead16(p));
     M(Memo,'< Cookie: $'+inttohex(Cookie,4));
     case MessageType of
     $4100: begin // OFFLINE MESSAGE
             hisUIN := PacketRead32(p); 
             M(Memo,'< Message-Type: $'+inttohex(MessageType,4));
             M(Memo,'< OFFLINE MESSAGE from UIN: '+s(hisUIN));
             year := PacketRead16(p);
             month := PacketRead8(p);
             day := PacketRead8(p);
             hour := PacketRead8(p);
             minute := PacketRead8(p);
             typemes := PacketRead8(p);
             subtypemes := PacketRead8(p);
             lenmes := PacketRead16(p);
             DoMsg(false,typemes,lenmes,PCharArray(@(p^.data[p^.cursor])),
                  hisUIN,UTC2LT(year,month,day,hour,minute));
            end;
      end;
end;


Тут можно на недельку передохнуть...

В скором времени я добавлю такие модули:
  •   передача сообщений (SendMess);
  •   прием сообщений (MessFrom);
  •   информация о пользователе (UserInfo);
  •   поиск пользователей по разным критериям (SearchUser);
...следите за обновлениями сайта
Назад Содержание Дальше