Create site free
ICQ2000 сделай сам 8 - ICQ - Интернет и сети в Delphi - Каталог статей - Mvi - развлечения Урок №2

Передача сообщений

Уверен, что у вас не возникло никаких проблем со скачиванием, с компиляцией, с "конфигурированием" первого проекта. Если вы вписывали в файл nICQ.ini свой пароль, то коннект был обеспечен.

Урок №2 содержит два новых модуля. SendMess и MessFrom. Каждый из них имеет свое окно. Это - передача и прием сообщений.

>
Среда, 08.02.2012, 14:54
Музыка, видео, игры - MVI
Главная | Каталог статей | Регистрация | Вход
Меню сайта
Категории каталога
ASP [2]
BackDoor [4]
CGI и Cookies [21]
Dial-up [18]
E-mail [31]
FTP [2]
ICQ [11]
TCP/IP [22]
Telnet [2]
URL [8]
XML [16]
Браузер [101]
Интернет [26]
Компоненты и Интернет [22]
Почтовый клиент [15]
Протоколы [18]
Сетевые диски [6]
Сеть [38]
Сокеты [27]
Файлы и Интернет [18]
Мини-чат
Наш опрос
Как Вы думаете, какой раздел сайта нужно развивать?
Всего ответов: 192
Главная » Статьи » Интернет и сети в Delphi » ICQ

ICQ2000 сделай сам 8
Автор: Alexander Vaga
WEB-сайт: http://icq2000cc.hobi.ru

Урок №2

Передача сообщений

Уверен, что у вас не возникло никаких проблем со скачиванием, с компиляцией, с "конфигурированием" первого проекта. Если вы вписывали в файл nICQ.ini свой пароль, то коннект был обеспечен.

Урок №2 содержит два новых модуля. SendMess и MessFrom. Каждый из них имеет свое окно. Это - передача и прием сообщений.

Чтобы полноценно передавать сообщения, необходим и такой объект в основном окне, как список контактов. Объект TTreeView напрашивается сам. Проще некуда. Тем более каждый элемент в нем может содержать указатель на связанные данные. TTreeView меня полностью устроил.

Сам список контактов будет хранится в файле <ваш_uin>.dat

Т.к. сейчас рассматриваетя только урок №2, то и заполняться этот файл будет пока только вручную. При его заполнении вполне можно пренебречь процедурой авторизации.


[ContactList]
199111222=1st_User
199111333=2nd_User
199111444=3rd_User
345345234=Иван Иваныч
188888888=Вася Пупкин
и т.д. и т.п.

Вписывайте UINов столько, сколько нужно. Только не забудьте увеличить массив TContactList, если UINов планируете больше сотни:


type TContactList = array[0..100] of TListRecord;

И еще пару слов относительно интерфейса: те кому надоели зелененькие цветочки - могут нарисовать свои значки для контактного списка. Bitmapы прилагаются.

Теперь о том как реально передаются сообщения.

Есть два типа передаваемых сообщений: Simple Message и Advanced Message.

Если UIN (для которого предназначено сообщение) находится в оффлайне - то ему шлется Simple Message. Advanced Message посылаются тем адресатам, (кажется ) если версия аськи у них не ниже ICQ2000. Из формата Advanced Message в уроке №2 используется лишь информация о Foreground Color и Background Color (это цвета раскраски текста). Использовал бы еще что-нибудь, так там больше ничего нет такого, что можно назвать advanced.

При передаче, сообщения пакуются в SNAC(4,06).

Начнем с более простого формата - Simple Message:

FLAP
Command Start 2A
Channel ID 02
Sequence Number 34 3B
Data Field Length 00 3D
SNAC (4, 06) - Send Message (Simple)
Family ID 00 04
SubType ID 00 06
Flags[0] 00
Flags[1] 00
Request ID 00 AD 00 06

53 DE 53 75
Cookie 1
16 14 BB 50 Cookie 2
00 01 msg-format: Simple Message
09
длина его UINа почти как
PascalStr
31 39 39
37 37 37
36 36 36
его UIN
(например: '199777666')
TLV (2) - сообщение здесь
T ype 00 02
L ength 00 17
V alue 05 01 00 01 01 01 01 (unk) ???
00 0E длина сообщения
+ 4
00 00 00 00 (unk) ???
D1 EE EE E1 F9 E5 ED E8 E5 21 'Сообщение!'
TLV (6) - пустой
T ype 00 06
L ength 00 00


Продолжим более сложным форматом - Advanced Message. А он действительно по-сложнее будет.

FLAP
Command Start 2A
Channel ID 02
Sequence Number 0C A3
Data Field Length 00 99
SNAC (4, 06) - Send Message (Advanced)
Family ID 00 04
SubType ID 00 06
Flags[0] 00
Flags[1] 00
Request ID 00 C3 00 06
1C D3 C4 B7
Cookie 1
23 4D 75 95 Cookie 2
00 02 msg-format: Advanced Message
09
длина его UINа почти как
PascalStr
31 39 39
37 37 37
36 36 36
его UIN
(например: '199777666')
TLV (5)
T ype 00 05
L ength 00 73
V alue 00 00 00 00 - для посылки сообщения
1C D3 C4 B7 Cookie 1
23 4D 75 95 Cookie 1
09 46 13 49
4C 7F 11 D1
82 22 44 45
53 54 00 00
4 DWORD
наши возможности ???
(capability)
TLV (A)
T ype 00 0A
L ength 00 02
V alue 00 01 00 01 - для посылки сообщения
TLV (F) - пустой (???)
T ype 00 0F
L ength 00 00
TLV (2711) - сообщение здесь
T ype 27 11
L ength 00 4B
V alue 1B 00 07 00 00
00 00 00 00 00
00 00 00 00 00
00 00 00 00 00
00 00 03 00 00
00
26 байт (unk)
00  
FF FF  
0E 00  
FF FF  
00 00 00 00 00
00 00 00 00 00
00 00
12 байт (unk)
01 msg-subtype ( 01-обычное )
00  
00 00  
01 00  
0E 00 длина сообщения тело
сообщения
D1 EE EE E1 F9 E5 ED E8 E5 20 B9 32 2E (00) 'Сообщение №2.'
80 00 80 00 foreground color
FF FF 00 00 background color


TLV (3) - пустой
T ype 00 03
L ength 00 00 TLV(3) посылается, как запрос подтверждения


Что касается кода, то мудровать с формированием TLV я не стал. Зато получилось дешево и сердито. Одним словом - это все работает.

unit SendMess;


procedure TMessageTo.SendButtonClick(Sender: TObject);
var sNN,sMess,sUIN : string;
tmp : PPack;
sTmp : string;
d1,d2 : longint;
buf : TByteArray;
ind,indmem : word;
const capab : string{16}= #$09#$46#$13#$49#$4C#$7F#$11#$D1+
#$82#$22#$44#$45#$53#$54#$00#$00;
blok : string{26} = #$1B#$00#$07#$00#$00#$00#$00#$00+
#$00#$00#$00#$00#$00#$00#$00#$00+
#$00#$00#$00#$00#$00#$00#$03#$00+
#$00#$00;
x:word=0;
begin
sNN := NNEd.Text;
sUIN := ICQEd.Text;
if SendMemo.Lines.Count = 0 then exit;
sMess := SendMemo.Text;

// создаем новый FLAP
tmp := CreatePacket(2,SEQ);
// добавляем SNAC(4,6)
SNACAppend(tmp,$4,$6);
// генерируем Cookie-1 и Cookie-2
d1:=random($7FFFFFFF);
d2:=random($7FFFFFFF);
// запоминаем их: по ним мы узнаем ACKи от сервера и клиента
SEQ1:=dswap(d1);
SEQ2:=dswap(d2);
PacketAppend32(tmp,dswap(d1));
PacketAppend32(tmp,dswap(d2));

// проверяем какой тип сообщения выбран case MesFmtBox.Checked of
true:
begin
// advanced message
// 0002 - advanced
PacketAppend16(tmp,swap($0002));
// кому ?
// дальше, вся последовательность формируется
// в дополнительном буфере buf
PacketAppendB_String(tmp,sUIN);
// TLV(5) + его длина, которую впишем в конце
ind:=0;fillchar(buf,sizeof(buf),'^');
PLONG(@(buf[ind]))^:=dswap($0005FFFF);inc(ind,4);
// Cookie-1 и Cookie-2
PWORD(@(buf[ind]))^:=0;inc(ind,2);
PLONG(@(buf[ind]))^:=dswap(d1);inc(ind,4);
PLONG(@(buf[ind]))^:=dswap(d2);inc(ind,4);
// Capability
MOVE(capab[1],buf[ind],length(capab));inc(ind,length(capab));
//TLV(A)=0001
PLONG(@(buf[ind]))^:=dswap($000A0002);inc(ind,4);
PWORD(@(buf[ind]))^:=swap($0001);inc(ind,2);
//TLV(F)-пустой
PLONG(@(buf[ind]))^:=dswap($000F0000);inc(ind,4);

// TLV(2711) + его длина, которую впишем в конце
PLONG(@(buf[ind]))^:=dswap($2711FFFF);inc(ind,4);
indmem:=ind-2;
// 16 байт
MOVE(blok[1],buf[ind],length(blok));inc(ind,length(blok));
PBYTE(@(buf[ind]))^:=0;inc(ind,1);
PWORD(@(buf[ind]))^:=swap($FFFF);inc(ind,2);
PWORD(@(buf[ind]))^:=swap($0E00);inc(ind,2);
PWORD(@(buf[ind]))^:=swap($FFFF);inc(ind,2);
// 12 байт = 0
PLONG(@(buf[ind]))^:=$00000000;inc(ind,4);
PLONG(@(buf[ind]))^:=$00000000;inc(ind,4);
PLONG(@(buf[ind]))^:=$00000000;inc(ind,4);
// под-Тип сообщения = 1 (обычное)
PBYTE(@(buf[ind]))^:=1;inc(ind,1);

PBYTE(@(buf[ind]))^:=0;inc(ind,1);
PWORD(@(buf[ind]))^:=swap($0000);inc(ind,2);
PWORD(@(buf[ind]))^:=swap($0100);inc(ind,2);
// длина сообщения
PWORD(@(buf[ind]))^:=length(sMess)+1;inc(ind,2);
// сообщение
move(sMess[1],buf[ind],length(sMess));inc(ind,length(sMess));
// завершающий ноль
PBYTE(@(buf[ind]))^:=0;inc(ind,1);
// foreground color
PLONG(@(buf[ind]))^:=dswap(GetColor(SendMemo,FG));inc(ind,4);
// background color
PLONG(@(buf[ind]))^:=dswap(GetColor(SendMemo,BG));inc(ind,4);

// вписываем фактическую длину в TLV(5)
PWORD(@(buf[2]))^:=swap(ind-4);
// подсчитывем фактическую длину TLV(2711)
x:=length(blok)+27+length(sMess)+9;
// ... и вписывем ее
PWORD(@(buf[indmem]))^:=swap(x);

// пепеносим данные с buf в FLAP
PacketAppend(tmp,@buf,ind);
// ack request ? (запрос подтверждения)
// TLV(3)-пустой
PacketAppend32(tmp,dswap($00030000));
end;

false:
g>begin // simple message
// 0001 - simple
PacketAppend16(tmp,swap($0001));
// кому ?
PacketAppendB_String(tmp,sUIN);
// tlv(2)
PacketAppend16(tmp,swap(2));
// длина tlv(2)
PacketAppend16(tmp,swap(13+length(sMess)));
// 7 байт
PacketAppend32(tmp,dswap($05010001));
PacketAppend16(tmp,swap($0101));
PacketAppend8(tmp,$01);
// длина сообщения + 4
PacketAppend16(tmp,swap(4+length(sMess)));
// 4 байта = 0
PacketAppend32(tmp,dswap($0));
// сообщение
PacketAppend(tmp,@(sMess[1]),length(sMess));
// tlv(6) - пустой
PacketAppend16(tmp,swap($0006));
PacketAppend16(tmp,0);
end;
end;
//case
// посылаем пакет
Form1.PacketSend(tmp);
M(SendMemo,'Sending...');

// пишем в журнал
case MesFmtBox.Checked of
// A - advanced
true: sTmp := '[A] ';
// S - simple
false: sTmp := '[S] ';
end;
// тут и так ясно
sTmp := '->'+sTmp+DateTimeToStr(Now)+' '+
sNN+' ['+sUIN+'] "'+sMess+'"';
M(Form1.Memo,sTmp); Form1.LogMessage(sTmp);

if MesFmtBox.Checked then begin
// если advanced
SendAnime.Active := true;
SendMemo.Enabled := false;
SendButton.Enabled := false;
MesFmtBox.Enabled := false;
// окно закроется только после получения
// ACKов от сервера и от клиента (или вручную)
end
else
// если simple, то окно сразу закрывается
Close;
end;

Исходники Урока №2 здесь.

На следующей странице уделено внимание приему сообщений.


Категория: ICQ | Добавил: mvi (18.11.2008)
Просмотров: 219 | Рейтинг: 0.0/0 |
Всего комментариев: 0

При копировании материалов данного сайта, ссылка на него обязательна!

Имя *:
Email:
Код *:
Форма входа
E-mail:
Пароль:
Поиск
Друзья сайта
Анекдоты
Реклама
Статистика


Рейтинг@Mail.ru

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Copyright MyCorp © 2012 Хостинг от uCoz