<?php
// © Navigator, 2005-2006
// icq: 117886
// при
распространении ссылка на меня обязательна
//
// скрипт позволяет работать
с протоколом icq из php. реализованы
// только базовые функции, такие как
подключение к сети, приём и отправка
// сообщений. возможно также добавление
своих функций.
ignore_user_abort(true);
error_reporting(E_ALL);
set_time_limit(0);
$uin = "uin"; //
номер
$pass =
EncDecPassWord("password"); // пароль к
номеру
/********/
function EncDecPassWord($pass)
{
$enc = "\xF3\x26\x81\xC4\x39\x86\xDB\x92\x71\xA3\xB9\xE6\x53\x7A\x95\x7C";
$ret
= "";
for ($i
= 0; $i <
strlen($pass); $i++)
$ret .= chr(ord($pass{$i}) ^ ord($enc{$i
% 16}));
return $ret;
}
function hexDump($raw)
{
$raw = (string)$raw;
$len
= strlen($raw);
$raz
= ceil($len /
16);
$i
= 0;
$ret
= "Length:
$len\n";
while ($i++ < $raz)
{
$tempHex = "";
$tempRaw = "";
$tempStr = substr($raw, 16
* ($i - 1),
16);
$j = -1;
while
($j++ < 16)
{
if
(!isset($tempStr{$j}))
break;
$ord = dechex(ord($tempStr{$j}));
if
(strlen((string)$ord) < 2)
$ord = "0$ord";
$tempHex .= $ord."
";
$tempRaw .= ($tempStr{$j} >= "
") ? $tempStr{$j} :
".";
}
if
(strlen($tempHex) < 48) while (strlen($tempHex) < 48) $tempHex
.= " ";
if
(strlen($tempRaw) < 16) while (strlen($tempRaw) < 16) $tempRaw
.= " ";
$ret .= "$tempHex| $tempRaw |\n";
}
return
$ret;
}
$charmap =
"%u0402%u0403%u201A%u0453%u201E%u2026%u2020%u2021%u20AC%u2030%u0409%u2039%u040A%u040C%u040B%u040F".
"%u0452%u2018%u2019%u201C%u201D%u2022%u2013%u2014%u0000%u2122%u0459%u203A%u045A%u045C%u045B%u045F".
"%u00A0%u040E%u045E%u0408%u00A4%u0490%u00A6%u00A7%u0401%u00A9%u0404%u00AB%u00AC%u00AD%u00AE%u0407".
"%u00B0%u00B1%u0406%u0456%u0491%u00B5%u00B6%u00B7%u0451%u2116%u0454%u00BB%u0458%u0405%u0455%u0457";
function ucs2win($str)
{
global $charmap;
$ret
= "";
if (strlen($str) % 2
!= 0) return "";
for ($i
= 1; $i <
strlen($str); $i++)
{
$first_char = ord($str{$i++}) & 0xff;
$i++;
$second_char = ord($str{$i++}) & 0xff;
$char = ($first_char << 8) | $second_char;
if
(($char >= 0x0410) && ($char <= 0x044f))
{
$ret .= chr($char
- 0x0350);
}
else
if ($char <
128)
{
$ret .= chr($char
& 0x7f);
}
else
{
if
(($pos = strpos($charmap, sprintf("%%u%04X", $char))) != false)
{
$ret .= chr(128
+ ($pos / 6));
}
else
{
$ret .= chr($char
& 0xff);
}
}
}
return
$ret;
}
function
utf2ucs($utf8)
{
$ret
= "";
for ($i = 0; $i
< strlen($utf8);
$i++)
{
$charcode = 0;
$first = ord($utf8{$i});
if
(($first &
0x80) == 0)
{
$charcode = $first;
}
else
{
if
((($first &
224) != 192) | !isset($utf8{$i++})) return false;
$second = ord($utf8{$i});
if
(($second &
192) != 0x80) return false;
if
(($first &
240) == 224)
{
if
(!isset($utf8{$i++})) return false;
$third = ord($utf8{$i});
if
(($third &
192) != 0x80) return false;
$charcode = (($first & 0x0F) << 12) | (($second & 0x3F) << 6) | ($third
& 0x3F);
}
else
{
$charcode = ($first & 0x1F) << 6 | ($second
& 0x3F);
}
}
$ret .= pack("n", $charcode);
}
return
$ret;
}
function
getW($str, $pos, $le
= false)
{
$ret
= 0;
if ($le)
{
$ret = ((ord($str{$pos
+ 1}) & 0xFF) << 8) | (ord($str{$pos})
& 0xFF);
}
else
{
$ret = ((ord($str{$pos}) & 0xFF) << 8) | (ord($str{$pos
+ 1}) & 0xFF);
}
return
$ret;
}
function
readSRV()
{
global $serv;
$data
= fread($serv,6);
if (!$data)
{
//print "No answer from
server.\n";
return "";
}
if
($data{0} != "*")
{
print
"Bad server answer:\n";
print
hexDump($data);
return
false;
}
$channel_id = ord($data{1});
$seqid
= getW($data,
2);
$len
= getW($data,
4);
$content
= $len > 0 ?
fread($serv,$len) : "";
print
hexDump($data.$content);
return
array(
'CHANNEL_ID' => $channel_id,
'SEQ' => $seqid,
'LENGTH' => $len,
'DATA' => $content
);
}
function sndFLAP($channel,$raw="") {
static
$id;
global $serv;
if
(!is_integer($id)) $id
= (int)rand(0,0x7fff);
$to_send
= "*";
$to_send
.= chr($channel);
$to_send
.= pack("n",$id);
$to_send
.= pack("n",strlen($raw));
$to_send
.= $raw;
$id++;
$id
&= 0x7fff;
print hexDump($to_send);
return fwrite($serv,$to_send,strlen($to_send));
}
function
splitTLVS($raw)
{
$i = -1;
$na
= 0;
$result
= array();
while
($i++ < strlen($raw))
{
if (!isset($raw{$i}))
break;
$unp = substr($raw,$i,2);
$unp = unpack("n",$unp);
$tlv_id = $unp[1];
$unp = substr($raw,$i+2,2);
$unp = unpack("n",$unp);
$tlv_len = $unp[1];
$tlv_data = substr($raw,$i+4,$tlv_len);
if
(isset($result[$tlv_id]))
$na++;
$result[isset($result[$tlv_id]) ? dechex($tlv_id)."_$na" : $tlv_id] = $tlv_data;
$i += $tlv_len + 3;
}
return
$result;
}
function sendMSG($to,$what="",$canBeOffline=false)
{
global $ads, $serv;
static $cnt;
$cnt++;
$what
= trim($what);
$stlv
= "\x05\x01\x00\x02\x01\x01\x01\x01";
$stlv
.= pack("n",strlen($what)+4);
$stlv
.= "\x00\x00\x00\x00";
$stlv
.= $what;
$return
= "\x00\x04\x00\x06\x00\x00\x00\x01\x00\x06";
$return
.= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
$return
.= chr(strlen($to)).$to."\x00\x02".pack("n",strlen($stlv)).$stlv .
($canBeOffline ?
"\x00\x06\x00\x00" :
"");
sndFLAP(2,$return);
usleep(1250);
}
function recieveMSG($data) {
if
(getW($data, 0) == 4
&& getW($data, 2) == 7)
{
$msg_channel = ord($data{19});
$msg_sender_screenname_len =
ord($data{20});
$msg_sender_screenname = substr($data,21,$msg_sender_screenname_len);
$msg_tlvs = splitTLVS(substr($data,25+$msg_sender_screenname_len));
$decodeUCS = false;
if
($msg_channel ==
1)
{
$msg_inttlvs = splitTLVS($msg_tlvs[2]);
$tlvx101 = $msg_inttlvs[0x0101];
$charset = getW($tlvx101, 0);
$msg_text = substr($tlvx101, 4);
if
(preg_match('#[^\x01-\x7f]#x', $msg_text))
{
$utf2ucs = utf2ucs($msg_text);
if
($utf2ucs != false)
{
$msg_text = $utf2ucs;
$decodeUCS = true;
$utf2ucs = null;
}
else
{
$decodeUCS = ($charset == 2);
}
if
($decodeUCS) $msg_text = ucs2win($msg_text);
}
}
else
if ($msg_channel ==
4)
{
$tlv5 = $msg_tlvs[5];
if
(getW($tlv5, 4) != 0x0101)
return;
$len = getW($tlv5, 6, true);
$msg_text = substr($tlv5, 8, $len
- 1);
if
(preg_match('#[^\x01-\x7f]#x', $msg_text))
{
$utf2ucs = utf2ucs($msg_text);
if
($utf2ucs != false)
{
$msg_text = ucs2win($utf2ucs);
$utf2ucs = null;
}
}
}
else
{
print
"Unknown MSG channel. Ignoring . . .\n\n";
return;
}
print
"RECIEVED MESSAGE.\n";
print
"MESSAGE TYPE: $msg_channel\n";
print
"FROM: $msg_sender_screenname\n";
print
"MESSAGE:\n";
print
"$msg_text\n\n";
// тут обрабатываем пришедшее сообщение так, как нам
нужно
}
}
function LogIn()
{
global $serv, $uin,
$pass;
print "Connecting . . .\n";
$serv
= fsockopen("login.icq.com", "5190");
readSRV();
print "Authentication . . .\n";
sndFLAP(1,"\x00\x00\x00\x01\x00\x01\x00".chr(strlen($uin)).$uin."\x00\x02\x00".chr(strlen($pass)).$pass);
print "Recieving auth data . . .\n";
if (!($data = readSRV()))
{
print "Connection failed.\n";
fclose($serv);
print
"Reconnecting after 1 sec. . .\n";
sleep(1);
LogIn();
return;
}
$tlv = splitTLVS($data['DATA']);
print "Server name: {$tlv[5]}.
Disconnecting from login.icq.com . . .\n";
sndFLAP(4);
fclose($serv);
print "Connecting to {$tlv[5]} . .
.\n";
$connect
= explode(':',$tlv[5]);
$serv
= fsockopen($connect[0],isset($connect[1]) ?
$connect[1] : "5190");
readSRV();
socket_set_blocking($serv, false);
print "Authentication . . .\n";
sndFLAP(1,"\x00\x00\x00\x01\x00\x06".pack("n",strlen($tlv[6])).$tlv[6]);
print
"Sending CLI_SETUSERINFO . . .\n";
$caps = pack("H*", "0946134D4C7F11D18222444553540000");
$caps
.= pack("H*",
"0946134E4C7F11D18222444553540000");
sndFLAP(2,"\x00\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x05".pack("n",
strlen($caps)).$caps);
print "Set status to Online . . .\n";
sndFLAP(2,"\x00\x01\x00\x1e\x00\x00\x00\x00\x00\x00".implode(array(
"\x00", "\x06", "\x00", "\x04", "\x10", "\x10", "\x00", "\x00",
"\x00", "\x0C", "\x00", "\x25",
"\x00", "\x00", "\x00", "\x00",
"\x00", "\x00", "\x00", "\x00",
"\x00",
"\x00", "\x06",
"\x00", "\x00", "\x00", "\x00",
"\x00", "\x00",
"\x00", "\x50",
"\x00", "\x00",
"\x00", "\x03",
"\x35", "\x66", "\x66", "\x66",
"\x00", "\x00", "\x00", "\x00",
"\x00", "\x00", "\x00", "\x00",
"\x00", "\x00"
)));
print "Sending CLI_SETICBM packets . . .\n";
sndFLAP(2, pack("H*", "00040002000000000002") . pack("H*", "000100000001FFFF03E703E700000000"));
sndFLAP(2, pack("H*", "00040002000000000002") . pack("H*", "00020000000000000000000000000000"));
sndFLAP(2, pack("H*", "00040002000000000002") . pack("H*", "000400000001FFFF03E703E700000000"));
print "Sending CLI_READY . . .\n";
sndFLAP(2,"\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00".implode(array(
"\x00", "\x01", "\x00", "\x03",
"\x01", "\x10", "\x04", "\x7B",
"\x00", "\x13", "\x00", "\x02",
"\x01", "\x10", "\x04", "\x7B",
"\x00", "\x02", "\x00", "\x01",
"\x01", "\x01", "\x04", "\x7B",
"\x00", "\x03", "\x00", "\x01",
"\x01", "\x10", "\x04", "\x7B",
"\x00", "\x15", "\x00", "\x01",
"\x01", "\x10", "\x04", "\x7B",
"\x00", "\x04", "\x00", "\x01",
"\x01", "\x10", "\x04", "\x7B",
"\x00", "\x06", "\x00", "\x01",
"\x01", "\x10", "\x04", "\x7B",
"\x00", "\x09", "\x00", "\x01",
"\x01", "\x10", "\x04", "\x7B",
"\x00", "\x0A", "\x00", "\x01",
"\x01", "\x10", "\x04", "\x7B",
"\x00", "\x0B", "\x00", "\x01",
"\x01", "\x10", "\x04", "\x7B"
)));
print "Connected.\n";
}
LogIn();
while (1) // в этом цикле, собственно, и
работает бот
{
usleep(1);
if
($data = readSRV())
{
if ($data['CHANNEL_ID'] == 3)
{
fclose($serv);
LogIn();
}
if
($data['CHANNEL_ID'] == 2)
{
$data = $data['DATA'];
switch
(getW($data, 0))
{
case
4:
recieveMSG($data);
break;
}
}
}
}
?>