скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

ICQ2000 сделай сам 5




Автор: Alexander Vaga
WEB-сайт: http://icq2000cc.hobi.ru

Лежат двое влюбленных в постели, утомленные первым бурным соитием.
Она:
- Милый, а ты помнишь, когда мы с тобой познакомились?
Он:
- Погоди... ща отдышусь и пойду хистори в аське посмотрю.

Перед рассмотрением работы обработчика AuthorizePart надо немного поговорить и о протоколе.

Перед тем, как подключиться к ICQ-серверу и начать работать мы должны пройти авторизацию на Authorization Server. Его адрес - login.icq.com:5190.

Необходимо:

  • соединиться с Authorization Server;
  • передать ему пакет с UINом и паролем;
  • получить от него IP-адрес и порт основного сервера и Cookie (256 байт случайных данных). Cookie - это будет наш пропуск при последующем (после авторизации) коннекте к основному рабочему серверу;
  • разьединиться с Authorization Server.

Именно к Authorization Server инициируется соединение в процедуре icq_Login.

Сервер отвечает нам маленьким пакетом:

FLAP
Command Start 2A
Channel ID 01
Sequence Number XX XX
Data Field Length 00 04
Data 00 00 00 01
 

В нем только лишь 00 00 00 01. Для нас - это сигнал начать передачу пакета с авторизационными данными (с UINом и паролем).

Сейчас уже пора разобраться и с форматом блока данных FLAP-пакета.

Можно сказать, что показанный выше пакет совсем не имеет никакой структуры: просто DWORD и все. В большинстве случаев в FLAP-пакете размещены данные, которые упакованы еще в один протокол: т.н. SNAC. В этом случае пакет данных выглядит так:

FLAP
Command Start 2A
Channel ID 02
Sequence Number word
Data Field Length word

SNAC
Family ID word
SubType ID word
Flags[0] byte
Flags[1] byte
Request ID dword
SNAC Data variable
 

 
SNAC
SNAC - это обычное содержимое блока данных FLAP-пакета в основной рабочей фазе соединения. Т.е. SNACи посылаются только через Сhannel ID = 2.

В любом FLAP-пакете может находиться только один пакет SNAC.

Прием (анализ) и передача SCACов - это то основное, что предстоит делать, чтобы реализовать все функции ICQ-клиента. Будь то передача списка контактов, или изменение нашего статуса, или получение и передача сообщений, или запрос информации о любом клиенте, для любого запроса и ответа на него есть свой SNAC (FamilyID, SubTypeID). Из сказанного видно, что вся смысловая информация помещена в SNACи. И UINы, и никнэймы, и и-мэйлы с хоумпэйджами. Конечно же они не просто так накиданы в SNACи. Они там размещены в юнитах, которые называются TLV.

TLV
TLV дословно означает - "Type, Length, Value" ("Тип, Длина, Значение"). Его структура такая:
TLV
(T)ype code word
(L)ength code word
(V)alue field variable length
 

В TLV упаковывается все, что используется в ICQ-протоколе: текстовые строки, байты, слова, двойные слова, другие массивы и т.д. и т.п.. На тип содеожимого TLV указывает Type code. Чаще всего TLV располагаются внутри SNACов, но это не является обязательным условием. Они могут также напрямую использоваться в блоке данных FLAP-пакета. Именно напрямую (т.е. без использования SNACов) TLV задействованы на этапе авторизации.

Этот механизм мы и рассмотрим именно сейчас, т.к. мы соединены уже с Authorization Server и получили от него добро в виде DWORD=00000001 на передачу нашего UINа и пароля.


procedure TForm1.AuthorizePart(p:PPack);
var ss : string;
    T : integer;
    tmp : PPack;
begin
     // позиционируемся на начало блока данных, пропустив заголовок
     PacketGoto(p,sizeof(FLAP_HDR));
     // если FLAP-данные содержат лишь 00000001,
     // то это самое начало сессии 
     if (swap(p^.Len)=4)and
        (swap(p^.SNAC.FamilyID)=0)and
        (swap(p^.SNAC.SubTypeID)=1) then begin
       M(Memo,'< Authorize Server CONNECT');
              // каждый раз, когда начинается новая TCP-сессия,
              // присваиваем SEQ случайное начальное значение
       SEQ := random($7FFF);       // в ответ надо передать пакет с UINом и паролем
       // создаем объект-пакет типа PPack: в нем формируется
       // FLAP-заголовок с Chanel_ID=1 
       tmp := CreatePacket(1,SEQ);
       // сначала надо вставить такой же DWORD=00000001
       // (еще надо помнить о порядке следования байтов в DWORD !!!)
       PacketAppend32(tmp,DSwap(1));
       // далее в поле данных добавляются несколько TLV
       // это наш UIN -  TLV(1)
       TLVAppendStr(tmp,$1,s(UIN));
       // и закодированный пароль - TLV(2) 
       TLVAppendStr(tmp,$2,Calc_Pass(PASSWORD));
       // описывать содержимое других TLV особого смысла нет
       TLVAppendStr(tmp,$3,
         'ICQ Inc. - Product of ICQ (TM).2000a.4.31.1.3143.85');
       TLVAppendWord(tmp,$16,$010A);
       TLVAppendWord(tmp,$17,$0004); // 4 - для ICQ2000a
       TLVAppendWord(tmp,$18,$001F);
       TLVAppendWord(tmp,$19,$0001);
       TLVAppendWord(tmp,$1A,$0C47);
       TLVAppendDWord(tmp,$14,$00000055);
       TLVAppendStr(tmp,$0F,'en');
       TLVAppendStr(tmp,$0E,'us');
       // посылаем пакет через  ClientSocket
       // (здесь tmp-пакет будет также и удален)
       PacketSend(tmp);
       M(Memo,'> Auth Request (Login)');

     end else  
     // на это сервер ответит так:
     // его ответ содержит TLV(1) - т.е. наш UIN
     if (TLVReadStr(p,ss)=1)and(ss=s(UIN))then begin
        // если это так, то считаем следующий TLV
        T := TLVReadStr(p,ss);
        case T of
          // если это TLV(5) - значит это адрес и порт основного сервера
          5: g>begin // BOS-IP:PORT
            M(Memo,'< Auth Responce (COOKIE)');
            // запоминаем и адрес и порт
            WorkAddress := copy(ss,1,pos(':',ss)-1);
            WorkPort := strtoint(copy(ss,pos(':',ss)+1,
                              length(ss)-pos(':',ss)));
            // за ними должен быть и TLV(6) - т.н. COOKIE (256 байт)
            // принимаем его прямо в переменную sCOOKIE
            // (он пригодится при коннекте к основному серверу)
            if (TLVReadStr(p,sCOOKIE)=6) then begin;
              // COOKIE получен и значит пора разъединяться
              // формируем пустой пакет с Channel_ID=4
              tmp:=CreatePacket(4,SEQ); // ChID=4
              // который и передаем
              PacketSend(tmp);
              // закрываем свой ClientSocket
              OfflineDiscconnect1Click(self);
              // говорим себе, что авторизация пройдена
              isAuth := false;
              // настраиваем ClientSocket на адрес:порт
              // основного (BOS) сервера
              CLI.Address := WorkAddress;
              CLI.Host := '';
              CLI.Port := WorkPort;
              M(Memo,'');
              M(Memo,'>>> Connecting to BOS: '+ss);
              // и коннектимся к нему
              CLI.Open;
{ ******************************************* }
{ в этом месте заканчивается этап авторизации }
{ ******************************************* }
            end;
          end;
          // а, например, в случае неверного UINа или пароля
          // мы получим TLV(4) и TLV(8)
          4,8: begin
               M(Memo,'< Auth ERROR');
               M(Memo,'TLV($'+inttohex(T,2)+') ERROR');
               M(Memo,'STRING: '+ss);
               if pos('http://',ss)>0 then begin
                 // и даже можем загрузить в браузер присланный нам URL
                 // с описанием ошибки
                 // Web.Navigate(ss); 
                 // {это навигатор с панели компонентов Делфи}
               end;
               TLVReadStr(p,ss); M(Memo,ss);
               // конечно же закрываем ClientSocket
               OfflineDiscconnect1Click(self);
               M(Memo,'');
             end;
        end;
     end;
end;

После успешного прохождения авторизации, мы подключаемся к основному рабочему серверу ICQ. Т.к. флажек isAuth уже сброшен, то диспетчер MainTTimer все пакеты будет направлять на обработчик WorkPart. Его построение во многом схоже с только, что рассмотренным обработчиком AuthorizePart.

В таком случае продолжим...






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook