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));
// кому ?
PacketAppendB_String(tmp,sUIN); // дальше, вся последовательность формируется // в дополнительном буфере buf
ind:=0;fillchar(buf,sizeof(buf),'^'); // TLV(5) + его длина, которую впишем в конце
PLONG(@(buf[ind]))^:=dswap($0005FFFF);inc(ind,4);
PWORD(@(buf[ind]))^:=0;inc(ind,2); // Cookie-1 и Cookie-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:
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
true: sTmp := '[A] '; // A - advanced
false: sTmp := '[S] '; // S - simple
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 Close; // если simple, то окно сразу закрывается
end;
|