ICQ2000 сделай сам 10
|
Одиночество - это когда контакт лист icq грохнулся.
|
Урок №3
Запрос информации о клиенте,
Поиск клиентов по различным критериям и др.
Итак... Передавать и принимать сообщения уже умеем. На очереди - получение информации о клиентах, которые находятся в списке контактов; а также поиск новых клиентов по различным критериям. Такие запросы к серверу посылаются с помощью все тех же SNAC(15,2). Вспомните, как производится запрос оффлайновых сообщений.
Точно также SNAC(15,2) с типом запроса равным D007 применяется:
- при всех операциях с Инфо клиентов ( и получение, и обновление своего);
- при поиске клиентов по имени, по UINу, по E-mailу;
- при изменении пароля;
- при удалении UINа из реестра ICQ;
- при многих других операциях.
Каждая из перечисленных операций определяется подтипом запроса. Приведу обобщенную таблицу SNAC(15,2) для некоторых запросов:
FLAP |
Command Start |
2A |
Channel ID |
02 |
Sequence Number |
XX XX |
Data Field Length |
XX XX |
SNAC (15,
02) |
Family ID |
00 15 |
SubType ID |
00 02 |
Flags[0] |
00 |
Flags[1] |
00 |
Request ID |
00 XX 00 02 (по
ним можно опознать ответ) |
TLV
(1) |
Type |
00 01 |
Length |
XX XX |
Value |
Length-2
|
(и что
оно тут делает ?) |
XX XX XX XX |
наш UIN
|
D0 07 |
тип
запроса |
XX 00 |
cookie (по
нему можно/нужно опознавать ответ) |
B2 04 |
подтип
запроса (B204 - запрос инфо
клиента) |
Это переменная часть
зпроса. Она определяется
подтипом
запроса.
Например:
При запросе инфо клиента
(B2 04)
или при поиске клиента по
UINу (1F05) здесь следует
разместить запрашиваемый UIN.
При поиске клиента по E-mail
(2905) здесь будет помещена строка с
искомым адресом.
При поиске по NickName, FirstName,
LastName (1505) сюда помещаются
соответственно три стоки.
При смене пароля
(2E04) здесь будет лишь строка с паролем,
а наш UIN сервер и так
знает.
|
| |
| |
Теперь к Delphi-проекту добавлены еще два модуля: UInfo и SUser (User Info & Search User).
Очередные исходники 3-его урока здесь. Т.к. все рассмотренные више запросы практически однотипные, то приведу комментарии только к одному из них. Это будет поиск по NickName, FirstName, LastName:
unit SUser;
procedure TSearchUser.META_Search_User(NN,FN,LN : string);
var p : PPack;
// промежуточный массив.
// в нем накапливаются данные TLV(1)
b : TByteArray;
i : integer;
begin
if (NN='')and(FN='')and(LN='') then exit;
EndOfSearch := false;
// word(b[0]) - тут будет ненужная длина
// (но ее надо потом корректно заполнить)
// а пока переходим к 3-у елементу
i:=2;
// вписываем UIN (только СВОЙ - укажем явно,что из модуля Main.pas)
PLONG(@(b[i]))^ := main.UIN; inc(i,4);
// ТИП запроса
PWORD(@(b[i]))^ := swap($D007); inc(i,2);
// придумаем себе COOKIE
// (можно и по-проще, но в настоящей аське
// COOKIE имеет такой вид XX00)
Cookie := random($FF) shl 8;
PWORD(@(b[i]))^ := swap(Cookie); inc(i,2);
// ПОДТИП запроса
PWORD(@(b[i]))^ := swap($1505); inc(i,2);
// добавляем три текстовые строки (First, Last, Nick)
// у AOL новый тип строк наверное :)
// впереди - длина строки, а в конце #0
// (что-то одно из них убрали бы)
// длина строки
PWORD(@(b[i]))^ := length(FN)+1; inc(i,2);
// сама строка FirstName
MOVE(FN[1],b[i],length(FN)); inc(i,Length(FN));
// завершающий #0
PBYTE(@(b[i]))^ := 0; inc(i,1);
// LastName
PWORD(@(b[i]))^ := length(LN)+1; inc(i,2);
MOVE(LN[1],b[i],length(LN)); inc(i,Length(LN));
PBYTE(@(b[i]))^ := 0; inc(i,1);
// NickName
PWORD(@(b[i]))^ := length(NN)+1; inc(i,2);
MOVE(NN[1],b[i],length(NN)); inc(i,Length(NN));
PBYTE(@(b[i]))^ := 0; inc(i,1);
// дозаполним "ненужную" длину в начале массива
PWORD(@(b[0]))^ := i-2;
// создаем FLAP-пакет
P:=CreatePacket(2,SEQ);
// добавляем SNAC(15,2)
SNACAppend(p,$15,$2);
// добавляем TLV(1) с данными из промежуточного массива
TLVAppend(p,1,i,@b);
// шлем запрос
Form1.PacketSend(p);
// пишем в Memo
M(Form1.Memo,'> Search Detail: Nick:'+NN+
' First:'+FN+
' Last:'+LN+' '+
'Cookie:$'+inttohex(Cookie,4));
end;
|
Запросы других подтипов передаются аналогично. С небольшими вариациями. Оновременно можем передавать на сервер много запросов. Сервер разберется. Ведь в каждом нашем запросе есть уникальное(ый) Cookie (а также и RequestID в SNAC-заголовке). Сервер пометит свои пакеты-ответы этими же опознавательными знаками.
Я лично делаю проверку(сверку) только по Cookie. Выдавая запрос, запоминаю Cookie. А когда приходит ответ от сервера, то процедура-обработчик SNAC_15_3 просто использует WinAPI функцию PostMessage для передачи ответа окну, которое выдало запрос. В параметрах PostMessage указан Cookie из ответа сервера. Какое окно его опознает - значит тому окну и предназначен ответ.
Работа процедуры-обработчика SNAC_15_3 уже ранее рассматривалась. Сейчас она просто дополнена новыми блоками, обрабатывающими новые ответы сервера. Следует упомянуть, что на один (единственный) наш запрос сервер присылает сразу целый массив из SNAC-ответов. Это типичная ситуация.
Например: запрашиваем Инфо о клиенте SNAC(15,2) [подтип запроса B204].
В ответ получим сразу восемь SNAC-ответов.
Вот их краткие названия-описания:
- main-home-info
- homepage-more-info
- more-email-info
- additional-info
- work-info
- about
- personal-interests
- past-background
Все полученные данные теперь сохраняются в файле .dat
|