Собственный ICQ бот на Перле

Категория: Perl , Чей-то софт Комментариев: 1

Всегда мечтали написать своего собственного ICQ-бота? Нет проблем.

Для работы с протоколом ICQ в Perl используется модуль Net::OSCAR. Взять его можно тут.
Для установки распакуйте архив, перейдите в получившуюся папку и от имени суперпользователя скомандуйте
perl Build.PL
perl Build
perl Build test
perl Build install

Создадим бота, который позволит выполнять удаленное администрирование нашего компьютера. В его задачи будут входить следующие:

  1. Выполнение системных комманд, получаемых по протоколу ICQ;
  2. Возврат отправителью результата выполения комманды;
  3. Выполнение комманд, отправленных только с определенного UIN'а (чтобы больше никто не смог что-то сделать на нашей машине);
  4. Ведение логов принятых комманд.

Первая и вторая задача заключаются в следующем: пользователь вводит какую-либо системную комманду (например df -h, ls, dmesg | tail, или даже rm -rf /), бот выполняет ее на машине, на которой он запущен, и возвращает результат выполнения пользователю.
Под третьей задачей понимается то, что бот должен выполнять комманды, отправленные только с определенного номера ICQ. Это условие не позволит администрировать нашу машину кому попало (мы-же не хотим, чтобы кто-то за нас выполнил rm -rf / ?)
Под четвертой задачей подразумевается, что все принимаемые комманды должны сохраняться в базе данных с временем приема, а также все попытки несанкционированного доступа к боту. Для этого мы будем использовать СУБД SQLite, о взаимодействии с которой я уже писал.

Приступим...

Первым делом необходимо подключить к нашей Perl-программе необходимые модули:
use DBI; # Поключаем модуль взаимодействия с БД
use Net::OSCAR; # Подключаем модуль работы с протоколом ICQ

Теперь определим необходимые настройки для нашего бота:
%conf = (
"b_uin" => "987654321", # UIN, на котором будет сидеть бот
"b_pass" => "12345", # пароль к UINу бота
"adm_uin" => "123456789", # UIN админа
"db_name" => "base.db" # имя файла базы данных для ведения логов
);

Далее подключаемся к базе данных и создаем таблицы для ведения логов.
$db_connection = DBI->connect("DBI:SQLite:dbname=".$conf{'db_name'}) or die("Невозможно подключиться к базе данных");
$db_connection->do("CREATE TABLE IF NOT EXISTS admin_logs (command text, date text)");
$db_connection->do("CREATE TABLE IF NOT EXISTS other_logs (uin text, command text, date text)");

для логов у нас будет две таблицы. В первую будут сохраняться логи выполненных администратором комманд, а во второй попыки несанкционированного доступа.
Первая будет содержать принятую комманду и дату передачи комманды, а вторая UIN, с которого была отправлена комманда, сама комманда и дата/время передачи комманды.

Теперь подключаемся к серверу ICQ:
$bot = Net::OSCAR->new(capabilities => [qw(extended_status typing_status)]); # Создаем новую сессию
$bot->signon($conf{"b_uin"},$conf{"b_pass"}) or die("Невозможно подключиться к серверу."); # Подключаемся к ICQ-серверу

Подключились, а что-же дальше? Как обрабатывать принимаемые сообщения? Теперь нужно написать обработчики ICQ-событий. Мы ограничимся событиями приема сообщения, оповещения о написании сообщения, удачного приема пользователем сообщения и обработки ошибок.
$bot->set_callback_im_in(\&im_in); # Устанавливаем функцию обработки входящих сообщений
$bot->set_callback_typing_status(\&typing_status); # Устанавливаем функцию обработки оповешения о написании сообщения.
$bot->set_callback_im_ok(\&im_ok); # Устанавливаем функцию обработки приема пользователем сообщения
$bot->set_callback_error(\&on_error); # Добавляем функцию обработки ошибок

Вот код этих функций:
# Функция обработки входящих сообщений
sub im_in{
local ($client, $uin, $msg) = @_; # В массиве @_ передается идентификатор сессии, UIN отправителя сообщения, и текст сообщения
local @time = localtime(time);
$strtime = "$time[3].$time[4].$time[5] $time[2]:$time[1]:$time[0]";
if ($uin ne $conf{'adm_uin'}){ # Если это не UIN администратора, то...
$db_connection->do("INSERT INTO other_logs VALUES ('$uin', '$msg', '$strtime')"); # ...добавляем запись в лог попыток несанкционированного доступа
}
else{
$db_connection->do("INSERT INTO admin_logs VALUES ('$msg', '$strtime')"); # Добавляем запись в администраторский лог
$command_reply = ` $msg`; # Выполняем введенную комманду и сохраняем вывод комманды в переменную
# Отображаем на экране комманду и ее ответ
print "\nАдминистраторская комманда: $msg\n";
print "Результат выполнения:\n" . $command_reply . "\n";
# ----------------------------------------
$client->send_typing_status(TYPINGSTATUS_STARTED); # Начинаем писать...
$client->send_im($uin, $command_reply); # Отправляем пользователю вывод выполненой программы
$client->send_typing_status(TYPINGSTATUS_FINISHED);
}
}

Здесь особое внимание следует уделить методу send_typing_status, который изменяет статус написания сообщения и методу send_im, который предназначен для отправки сообщения.
Методу send_typing_status можно передавать следующие значения:
TYPINGSTATUS_STARTED — Это означает, что пользователь начал писать, и написание сообщения в самом разгаре.
TYPINGSTATUS_TYPING — В поле ввода сообщения есть текст, но в данный момент пользователь больше не пишет.
TYPINGSTATUS_FINISHED — Пользователь перестал писать сообщение.

Для отправки сообщения необходимо методу send_im в качестве параметров передать UIN получателя сообщения и собственно текст сообщения. Выходными данными метода является идентификатор сообщения, который можно использовать в функции обработки приема пользователем сообщения

# Функция обработки приема пользователем сообщения
sub im_ok{
my ($client, $uin, $reqid) = @_; # В массиве @_ передается идентификатор сессии, UIN адресата и идентификатор сообщения
print "Сообщение получено пользователем " . $uin . "\n";
}

# Функция обработки статуса письма
sub typing_status{
my ($client, $uin, $status) = @_;
print $uin . " мне что-то пишет...\n";
}

# Функция обработки ошибок протокола ICQ
sub on_error{
my ($client, $connection, $error, $description, $fatal) = @_; # Получаем идентификатор сессии, где произошла ошибка, соединение с ошибкой, ошибку, ее описание и флаг, фатальна-ли она.
print "Произошла ошибка: " . $error . ", " . $description . ", " . $fatal . "\n";
}

Изменим видимость нашего бота и добавим сообщение для расширенного статуса:
$bot->set_visibility(VISMODE_DENYSOME); # Изменяем видимость UIN'а бота.
$bot->set_extended_status("Превед! Йа бод!"); # Добавляем расширенный статус

Методу set_visibility можно передавать следующие значения:
VISMODE_PERMITALL: Видим для всех
VISMODE_DENYALL: Невидим для всех
VISMODE_PERMITSOME: Видим только для списка видящих
VISMODE_DENYSOME: Невидим только для списка невидящих
VISMODE_PERMITBUDS: Видим только для контакт-листа.

Ну, попробуем включить...
Включился и выключился :'( А почему?
Потому, что теперь нужно запустить цикл, в котором будем производить итерацию бота:
while (1){ # Инициализируем бесконечный цикл, в котором...
$bot->do_one_loop; # Выполняем итерацию бота
}

Скачать готового бота можно тут.

Автор: Кто-то   @   2 мая 2009 Комментариев: 1
Метки : , ,

Поблагодарить автора

Webmoney Z163628999150, R617151845974

Комментариев: 1

Комментарии
мая 3, 2009
0:25
#1 Peter :

$msg не ескейпить перед вставкой в sql — это типическая скл-инжекция. Вообще, хорошо бы разносить это ->do () на prepare и execute, считается хорошим тоном.

оставить комментарий

Предыдущая запись
«
Следующая запись
»