Cette page est en cours de rédaction.
Cet article est le second d'une série de trois dont le but est de vous présenter une solution permettant, en Perl, d'écrire un Bot IRC.
Au cours du premier article, nous avons vu comment écrire un petit script Perl, permettant, en quelques dizaines de lignes, de se connecter à un serveur IRC, de joindre un channel, d'y afficher un message, et de faire un echo vers une console de ce que les autres utilisateurs disaient.
Ce second article va nous permettre d'aller un peu plus loin dans le développement de notre Bot, puisque le point principal que nous aborderons est la réception, la reconnaissance, et l'exécution de commandes : nous allons rendre notre Bot interactif !
Avant de commencer, je vais reproduire deux paragraphes qui se trouvent déjà en introduction du premier article, à l'intention des lecteurs qui arriveraient sur cette page sans avoir lu la précédente ; si ce n'est pas votre cas, vous savez déjà ce que je vais dire :-)
Avant que nous ne nous lancions dans le vif du sujet, j'aimerais insister sur le fait que ces articles demandent de votre part quelques pré-requis. Notamment, je suppose que vous connaissez déjà assez bien le Perl, et ne ferai pas de rappel concernant les bases de ce langage de programmation.
Si vous ne connaissez pas le Perl, je ne peux que vous encourager à consulter un tutorial, tel celui de Sylvain Lhullier, intitulé Introduction à la programmation en Perl, qui est relativement complet, et somme toute assez facile à lire, ou alors, carrément, à trouver un livre traitant de Perl, ce qui n'est pas non plus une mauvaise idée.
Notez que cet article est rédigé en supposant que vous aviez déjà lu, et compris, le précédente ; si ce n'est pas le cas, vous pouvez le trouver à cette adresse : Ecrire un Bot IRC en Perl, première partie.
Encore une chose : comme tout programmeur Perl le sait (ou devrait le savoir ?), TMTOWTDI - "There's More Than One Way To Do It".
Ce que je veux dire par là, c'est qu'il existe 36 façons différentes de coder quelque chose... et 36 façons différentes d'écrire chacune de ces façons de coder...
Au cours des exemples que je donnerai, j'ai choisi à chaque fois une implémentation, en essayant de trouver un bon compromis entre efficacité et lisibilité : après tout, le but de mes exemples est qu'ils soient compréhensibles, même si ça ne les rend pas forcément agréables à regarder !
Sommaire
Introduction
I:\ Messages privés, et notice
A: Messages privés
B: Notice
C: Exécution
II:\ Recevoir des commandes
A: Reconnaître une commande
B: Et en pratique
1: Code source
2: Résultat à l'exécution
III:\ Recevoir des requêtes CTCP, et y répondre
A: me
B: ping, version, time, ...
1: Evenements CTCP
2: CTCP PING
3: CTCP TIME
4: CTCP VERSION
IV:\ S'identifier auprès du serveur
V:\ Code source complet
I:\ Messages privés, et notice
Nous avons vu au cours de la première partie de cette article comment développer un Bot IRC minimaliste, qui se connecte à un serveur, join un channel, et fait un écho sur la console de ce qui se dit en public sur ce channel.
Cela nous a permis de découvrir le principe de fonctionnement événementiel de la librairie Net::IRC.
A partir de là, il est relativement simple de développer de nouvelles fonctions, correspondant à d'autres types d'événements : nous agirons exactement comme nous l'avons fait pour l'événement 'public'.
A: Messages privés
Le protocole IRC permet aux utilisateurs de communiquer en "public", sur des channels où sont présentes plusieurs personnes, mais il permet aussi de dialoguer (à deux, donc), en "privé".
La réception d'un message privé correspond, pour la librairie Net::IRC, à l'événement 'msg'.
Nous allons assigner une fonction, que nous nommerons on_private, à cet événement, de façon à pouvoir effectuer une action lorsqu'il se produit. Pour cela, nous utilisons, comme nous l'avons fait précédemment, la fonction add_handler :
$conn->add_handler('msg', \&on_private);
Et, naturellement, nous devons définir cette fonction.
Ici, j'ai choisi d'effectuer un écho vers la console du message reçu en privé, comme nous l'avions fait au cours de la partie précédente pour les messages publics.
sub on_private
{
my ($conn, $event) = @_;
my $text = $event->{'args'}[0];
$conn->print("PRIVE<" . $event->nick() . ">\t| $text");
}
Nous ne faisons rien de plus que récupérer la connexion et l'événement, obtenir depuis celui-ci le texte qui lui correspond, et l'afficher sur la console, accompagné du nickname de la personne qui nous a envoyé le-dit message.
Pour savoir quelle est la structure d'un événement de type 'msg', nous avons utilisé Data::Dumper, comme expliqué en fin de première partie.
B: Notice
On peut aussi souhaiter avoir un affichage (ou un autre traitement, pourquoi pas !) des "notices".
En effet, certains serveurs les utilisent pour communiquer des informations - plus ou moins importantes - à leurs utilisateurs ; par exemple, sur worldnet, lorsque l'on se connecte avec un nick enregistré, le serveur envoie une série de notice pour nous informer qu'il faut s'authenfier pour pouvoir continuer à utiliser ce pseudonyme :
[18:13:52] NickServ [Services@Worldnet.Net]: This nickname is registered and protected. If it is your
[18:13:52] NickServ [Services@Worldnet.Net]: nick, type /msg NickServ IDENTIFY password. Otherwise,
[18:13:52] NickServ [Services@Worldnet.Net]: please choose a different nick.
[18:13:52] NickServ [Services@Worldnet.Net]: If you do not change within one minute, I will change your nick.
Voila la portion de code qui assigne à l'événement 'notice' la fonction on_notice :
$conn->add_handler('notice', \&on_notice);
Et voici le corps que j'ai choisi pour cette fonction :
sub on_notice
{
my ($conn, $event) = @_;
my $text = $event->{'args'}[0];
$conn->print("NOTICE<" . $event->nick() . ">\t| $text");
}
Ici encore, je me suis limité à un simple écho vers la console du message reçu, ainsi que du nickname de son expéditeur.
Nous aurons l'occasion un peu plus tard de voir que l'on peut, bien évidemment, effectuer des traitements plus riches.
C: Exécution
Comme un exemple parle mieux que la théorie, voyons à présent ce que l'on obtient à l'exécution de notre Bot, auquel ont été ajoutées les portions de code présentées juste au dessus.
Tout d'abord, une fois le Bot connecté, un utilisateur nommé 'squale92' écrit un message en public, puis lui envoit une notice :
/notice perlBot_v2 ceci est un notice
Et un message privé :
/msg perlBot_v2 et ceci un message privé
Ce qui donne, au sein de son client IRC, ceci :
[20:30:18] perlBot_v2 [~perlBot@home.squalenet.net] a rejoint #krypton
[20:30:18] <perlBot_v2> Salutations !
[20:30:27] <squale92> blah
[20:30:37] [NOTICE >>> perlBot_v2]: ceci est un notice
[20:30:46] [PRIVMSG >>> perlBot_v2]: et ceci un message privé
(Affichage obtenu avec le client KVirc, utilisable sous windows et sous Linux).
Et voici la sortie console obtenue suite aux affichages effectués par notre Bot :
NOTICE<Club.FR.Worldnet.Net> | *** Looking up your hostname...
NOTICE<Club.FR.Worldnet.Net> | *** Found your hostname, cached
NOTICE<Club.FR.Worldnet.Net> | *** Checking Ident
NOTICE<Club.FR.Worldnet.Net> | *** No Ident response
NOTICE<Club.FR.Worldnet.Net> | *** Notice -- motd was last changed at 24/2/2006 22:19
<perlBot_v2> | Salutations !
NOTICE<Club.FR.Worldnet.Net> | *** Notice -- This server runs an open proxy monitor to prevent abuse.
NOTICE<Club.FR.Worldnet.Net> | *** Notice -- If you see connections on various ports from Worldnet.Net
NOTICE<Club.FR.Worldnet.Net> | *** Notice -- please disregard them, as they are the monitor in action.
NOTICE<Club.FR.Worldnet.Net> | *** Notice -- For more information please visit http://www.irc.worldnet.net/
NOTICE<Global> | [Logon News - Mar 04 2004] If you see a connection on port 23, 1080, 3128 or 8080 from 213.41.84.205, this is NOT an attack! It's our insecure proxy detector.
NOTICE<Global> | [Logon News - Apr 07 2004] Use irc.worldnet.net to join our network, thanks | Dorenavant, utilisez irc.worldnet.net pour joindre notre reseau, merci.
NOTICE<Global> | [Logon News - Apr 18 2005] Salons officiels du reseau Worldnet : #help pour de l'aide sur IRC et l'informatique en general. #rockone La webradio Rock francophone. #wow-fr Le salon officiel de debat sur World of Warcraft et les MMORPGs.
NOTICE<Global> | [Random News - Apr 24 2004] Pour avoir les services en Français tapez /nickserv set language 2
<squale92> | blah
NOTICE<squale92> | ceci est un notice
PRIVE<squale92> | et ceci un message privé
Comme nous pouvons le constater, à la connexion, le serveur nous envoit une quantité non négligeable d'informations sous forme de notices ; plus ou moins utiles, je l'admet...
Un peu plus loin, nous aurons l'occasion d'exploiter les données reçues sous forme de messages privés ou de notices, en effectuant des traitements plus riches qu'un simple affichage, d'une part, et même, éventuellement, en renvoyant une valeur de retour à l'utilisateur qui a essayé de contacter notre programme...
II:\ Recevoir des commandes
Un bot IRC qui ne fait rien de plus qu'un écho de ce qui se dit, c'est, vous l'admettrez sans doute, somme toute assez peu utile... Nous allons donc rajouter un peu d'interactivité au notre, afin qu'il soit à même de recevoir des commandes, d'effectuer des traitements en fonction de celles-ci, et, au besoin, d'y répondre.
A: Reconnaître une commande
Nous savons comment obtenir le texte d'un message prononcé sur un channel en public, envoyé au bot sous forme d'une notice, ou écrit en privé ; à partir de ce message, il va nous falloir :
- Déterminer s'il s'agit d'une commande
- S'il s'agit d'une commande, déterminer de quelle commande il s'agit - si c'est une commande reconnue
- Selon la commande dont il s'agit, obtenir sa liste de paramètres, et vérifier leur validité
- Effectuer un traitement en fonction de ces paramètres
- Et, éventuellement, envoyer un résultat
En général, une commande est construite comme ceci :
- Un symbole '!' (point d'exclamation)
- Un mot : le nom de la commande à exécuter
- Eventuellement, une succession de mots : les paramètres de la commande
Par exemple, une commande demandant au Bot de dire bonjour à un utilisateur pourrait être appelée de la manière suivante :
!bonjour KindPerson
Et en réponse, le bot pourrait envoyer le message suivant (message affiché par un client IRC chez une personne connecté sur le channel où le message a été prononcé) :
[19:41:43] <perlBot_v2> Bonjour, KindPerson !
B: Et en pratique
1: Code source
En pratique, pour reconnaître une commande, on peut procéder de la manière suivante :
-
Déterminer si le texte reçu en public comme par un '!' :
if (substr($text, 0, 1) eq '!')
-
Extraire le premier mot de la ligne, suivant immédiatement le point d'exclamation ; il s'agira du nom de la commande :
my $commande = ($text =~ m/^!([^ ]*)/)[0];
-
S'assurer que le nom de la commande n'est pas vide (autrement dit, s'assurer qu'on avait un texte de la forme "!commande ...") :
if ($commande ne '')
-
Déterminer si le nom de commande identifié correspond à l'une des commandes que notre bot est à même de gérer :
if ($commande eq 'bonjour')
(Dans notre cas, vu que notre programme ne gère qu'une seule commande, nous n'entesterons pas d'autres ; mais dans un cas plus général, ce serait à prendre en compte)
-
Si la commande attend des paramètres, il nous faut à présent les obtenir.
Nous considérerons qu'un paramètre est un mot, et que les paramètres sont séparés par un ou plusieurs caractères d'espacement :
my @params = grep {!/^\s*$/} split(/\s+/, substr($text, length("!$commande")));
En deux mots, nous découpons le texte reçu en utilisant les caractères d'espacement comme séparateurs, à partir de la fin du nom de la commande (split), puis nous éliminons les paramètres vides (grep).
-
Enfin, il ne nous reste plus qu'à vérifier que les paramètres obligatoirement attendus par la commande ont bien été fournis :
if (defined($params[0]) && $params[0] ne '')
-
Si toutes ces conditions ont été vérifiées, il ne nous reste plus qu'à effectuer le traitement attendu :
$conn->privmsg($channel, "Bonjour $params[0] !");
$conn->print("<$nick>\t| Bonjour $params[0] !");
(En l'occurence, ici, le traitement de notre commande n'est pas des plus complexes)
Et voici la fonction on_public de notre bot en intégralité :
sub on_public
{
my ($conn, $event) = @_;
my $text = $event->{'args'}[0];
$conn->print("<" . $event->{'nick'} . ">\t| $text");
if (substr($text, 0, 1) eq '!')
{
my $commande = ($text =~ m/^!([^ ]*)/)[0];
if ($commande ne '')
{
if ($commande eq 'bonjour')
{
my @params = grep {!/^\s*$/} split(/\s+/, substr($text, length("!$commande")));
if (defined($params[0]) && $params[0] ne '')
{
$conn->privmsg($channel, "Bonjour $params[0] !");
$conn->print("<$nick>\t| Bonjour $params[0] !");
}
else
{
$conn->print("Un paramètre attendu");
}
}
else
{
$conn->print("Commande non reconnue");
}
}
else
{
$conn->print("Pas une commande");
}
}
}
Pour l'utiliser, il suffit de la placer au sein du bot que nous avons déjà développé, dont le code source est disponible en fin d'article précédent - nous ne le reproduirons pas ici en intégralité, ce serait trop long.
2: Résultat à l'exécution
Et maintenant, quelques exemples de ce qui se passe à l'éxecution du bot !
Je présenterai quatre exemples ; pour chaque, je commencerai par ce qui est visible au sein du client IRC d'un utilisateur ("squale92") du channel sur lequel est le bot, puis je reproduirai la sortie console effectuée par le programme.
Tout d'abord, voici un cas où l'utilisateur utilise la commande de la façon attendue ; le bot lui répondra donc aussi de la fçon attendue :
[20:05:52] <@squale92> !bonjour Utilisateur
[20:05:52] <perlBot_v2> Bonjour Utilisateur !
Côté bot, on voit qu'il a reçu la commande, et qu'il y répond, comme on pouvait s'y attendre après avoir vu la sortie cliente de l'utilisateur.
<squale92> | !bonjour Utilisateur
<perlBot_v2> | Bonjour Utilisateur !
Cela dit, il peut être bon de voir ce que donnent quelques cas d'erreur... Après tout, il serait dommage de constater une fois le bot lancé, qu'il est à même de planter dans n'importe quel cas simple !
Dans le cas où l'utilisateur saisi uniquement un point d'exclamation - c'est-à-dire un marqueur de début de commande...
[20:06:19] <@squale92> !
... Nous constatons l'utilité de vérifier que la commande reconnue est non vide.
<squale92> | !
Pas une commande
Notons que ceci correspond aussi aux cas où l'utilisateur saisi "! blah".
A présent, passons au cas où aucun paramètre n'a été passé à la fonction :
[20:06:35] <@squale92> !bonjour
Ce qui donne, côté console, affichage d'un message d'erreur :
<squale92> | !bonjour
Un paramètre attendu
Naturellement, nous aurions pu en profiter pour renvoyer à l'utilisateur (en privé, dans l'idéal, pour ne pas surcharger le channel) un message lui indiquant comment utiliser la commande...
Et enfin, voyons ce qu'il se passe si l'utilisateur fourni plus de paramètres que ce qui est attendu... en les séparant par quantité d'espaces :
[20:12:16] <@squale92> !bonjour Utilisateur glop
[20:12:16] <perlBot_v2> Bonjour Utilisateur !
Et côté console :
<squale92> | !bonjour Utilisateur glop
<perlBot_v2> | Bonjour Utilisateur !
Nous avons ici choisi d'ignorer les paramètres supplémentaires ; cela dit, dans d'autres cas, vous choisirez peut-être de considérer cette situation comme un cas d'erreur.
Notons tout de même une chose : si nous n'avions pas pensé à considérer comme séparateur les espaces multiples, ainsi qu'à éliminer les paramètres vides, nous aurions eu comme premier paramètre un paramètre vide... Ce qui, dans notre cas, n'est bien évidemment pas le comportement attendu.
III:\ Recevoir des requêtes CTCP, et y répondre
CTCP - Client-To-Client-Protocol
A: me
[21:45:27] squale92 dit bonjour
$conn->add_handler('caction', \&on_caction);
sub on_caction
{
my ($conn, $event) = @_;
use Data::Dumper;
print Data::Dumper->Dump([\$event], [qw(event)]);
}
$event = \bless( {
'to' => [
'#krypton'
],
'format' => 'caction',
'from' => 'squale92!~squale@home.squalenet.net',
'user' => '~squale',
'args' => [
'dit bonjour'
],
'nick' => 'squale92',
'type' => 'caction',
'userhost' => '~squale@home.squalenet.net',
'host' => 'home.squalenet.net'
}, 'Net::IRC::Event' );
sub on_caction
{
my ($conn, $event) = @_;
my $nick = $event->nick;
my $text = $event->{'args'}[0];
$conn->print("* $nick $text");
}
* squale92 dit Bonjour !
[00:50:49] squale92 dit Bonjour !
B: ping, version, time, ...
1: Evenements CTCP
$conn->add_handler('cversion', \&on_cversion);
$conn->add_handler('cping', \&on_cping);
$conn->add_handler('ctime', \&on_ctime);
$event = \bless( {
'to' => [
'perlBot_v2'
],
'format' => 'cping',
'from' => 'squale92!~squale@home.squalenet.net',
'user' => '~squale',
'args' => [
'1162415400.699022'
],
'nick' => 'squale92',
'type' => 'cping',
'userhost' => '~squale@home.squalenet.net',
'host' => 'home.squalenet.net'
}, 'Net::IRC::Event' );
$event = \bless( {
'to' => [
'perlBot_v2'
],
'format' => 'cversion',
'from' => 'squale92!~squale@home.squalenet.net',
'user' => '~squale',
'args' => [
'VERSION'
],
'nick' => 'squale92',
'type' => 'cversion',
'userhost' => '~squale@home.squalenet.net',
'host' => 'home.squalenet.net'
}, 'Net::IRC::Event' );
$event = \bless( {
'to' => [
'perlBot_v2'
],
'format' => 'ctime',
'from' => 'squale92!~squale@home.squalenet.net',
'user' => '~squale',
'args' => [
'TIME'
],
'nick' => 'squale92',
'type' => 'ctime',
'userhost' => '~squale@home.squalenet.net',
'host' => 'home.squalenet.net'
}, 'Net::IRC::Event' );
2: CTCP PING
sub on_cping
{
my ($conn, $event) = @_;
my $nick = $event->nick;
my $timestamp = $event->{'args'}[0];
$conn->ctcp_reply($nick, 'PING ' . $timestamp);
$conn->print("*** CTCP PING request de $nick");
}
[22:27:40] CTCP réponse de PING venant de perlBot_v2 [~perlBot@home.squalenet.net]: 0 sec 76 msec
*** CTCP PING request de squale92
3: CTCP TIME
[00:09:14] Réponse CTCP TIME venant de AZERTY [~xxxxx@XXXXXXXXXXXXXXXXXXX]: jeu. 2. nov. 00:09:20 2006
[00:09:36] Réponse CTCP TIME venant de QWERTY [~xxxxx@XXXXXXXXXXXXXXXXXXX]: Thu Nov 02 00:09:16 2006
[00:09:38] Réponse CTCP TIME venant de DVORAK [~xxxxx@XXXXXXXXXXXXXXXXXXX]: jeu nov 2 00:09:36 2006
sub on_ctime
{
my ($conn, $event) = @_;
my $date = localtime;
my $nick = $event->nick;
$conn->ctcp_reply($nick, 'TIME ' . $date);
$conn->print("*** CTCP TIME request de $nick");
}
[00:22:16] Réponse CTCP TIME venant de perlBot_v2 [~perlBot@home.squalenet.net]: Thu Nov 2 00:22:16 2006
sub on_ctime
{
my ($conn, $event) = @_;
use POSIX qw(strftime);
my $date = strftime "%a %b %e %H:%M:%S %Y", localtime;
my $nick = $event->nick;
$conn->ctcp_reply($nick, 'TIME ' . $date);
$conn->print("*** CTCP TIME request de $nick");
}
[00:22:32] Réponse CTCP TIME venant de perlBot_v2 [~perlBot@home.squalenet.net]: jeu nov 2 00:22:32 2006
4: CTCP VERSION
[00:40:42] Réponse CTCP VERSION venant de aaaa [xx@XXX]: mIRC v6.2 Khaled Mardam-Bey
[00:40:53] Réponse CTCP VERSION venant de cccc [xx@XXX]: irssi v0.8.10 - running on Linux i686
[00:41:00] Réponse CTCP VERSION venant de dddd [xx@XXX]: AZ2500 | kxX7wMWm | Azureus IRC Plugin 2.10
[00:41:04] Réponse CTCP VERSION venant de eeee [xx@XXX]: mIRC v6.17 Khaled Mardam-Bey
[00:41:05] Réponse CTCP VERSION venant de eeee [xx@XXX]: SysReset 2.53. Running Addons: KeepAlive 1.02 + WinAmp Scanner 1.17 + System Information 1.17 + GTSdll 1.2.1.2 + (big)
[00:41:13] Réponse CTCP VERSION venant de ffff [xx@XXX]: KVIrc 3.2.4 'Anomalies' 20060808 - build Sun Aug 13 02:36:30 UTC 2006 - i486-bcefikoprsAGTZ - Linux (2.6.17-10-generic) - QT Version: 3.3.6 - http://www.kvirc.net/
[00:41:20] Réponse CTCP VERSION venant de gggg [xx@XXX]: running mIRC32/6.16[winXP] - eXtreme v9.0 BETA (th/blue): t23?\ +1' [N_ -+17.+=
[00:41:23] Réponse CTCP VERSION venant de hhhh [xx@XXX]: xchat 2.6.4 Linux 2.6.18.m16a2 [i686/1.69GHz]
sub on_cversion
{
my ($conn, $event) = @_;
my $nick = $event->nick;
$conn->ctcp_reply($nick, 'VERSION ' . "ircPerlBot v $version, www.squalenet.net");
$conn->print("*** CTCP VERSION request de $nick");
}
*** CTCP VERSION request de squale92
[00:46:14] Réponse CTCP VERSION venant de perlBot_v2 [~perlBot@home.squalenet.net]: ircPerlBot v 2.0, www.squalenet.net
IV:\ S'identifier auprès du serveur
[20:43:20] Aurelie est Aurelie!~perlBot@home.squalenet.net
[20:43:20] Aurelie au nom réel : Bot IRC Perl
[20:43:20] Aurelie est sur : #krypton
[20:43:20] Aurelie est sur le serveur : Club.FR.Worldnet.Net - Club-Internet / T-Online France
[20:43:20] Aurelie à l'info : has identified for this nick
[20:43:20] Aurelie au temps d'inactivité : 0d 0h 0m 7s
[20:43:20] Aurelie s'est connecté le : jeu nov 2 20:43:05 2006
[20:43:20] Aurelie au WHOIS venant de Club.FR.Worldnet.Net
NOTICE<NickServ> | This nickname is registered and protected. If it is your
NOTICE<NickServ> | nick, type /msg NickServ IDENTIFY password. Otherwise,
NOTICE<NickServ> | please choose a different nick.
NOTICE<NickServ> | Password accepted - you are now recognized.
Identify : perlBot_v2 AZERTY
NOTICE<NickServ> | Your nick isn't registered.
my $nick = 'perlBot_v2';
my $pass = 'AZERTY';
$conn->privmsg('nickserv', 'IDENTIFY ' . $pass);
sub on_connect
{
my ($conn, $event) = @_;
$conn->join($channel);
$conn->privmsg($channel, 'Salutations !');
$conn->print("<$nick>\t| Salutations !");
$conn->{'connected'} = 1;
$conn->privmsg('nickserv', 'IDENTIFY ' . $pass);
$conn->print("Identify : $nick $pass");
}
V:\ Code source complet
Pour terminer, voici, en un seul morceau, le code source du Bot IRC que nous avons créé au cours de cet article ; il vous sera plus facile de l'exécuter ainsi, sans avoir à rassembler les différents morceaux présentés au sein de cet article.
Notez qu'il vous faudra sans doute apporter quelques modifications à ce programme, notamment pour permettre à votre Bot de s'identifier correctement.
use strict;
use warnings;
use diagnostics;
use Net::IRC;
my $server = 'irc.worldnet.net';
my $nick = 'perlBot_v2';
my $pass = 'AZERTY';
my $ircname = 'Bot IRC Perl';
my $username = 'perlBot';
my $version = '2.0';
my $channel = '#krypton';
my $irc = new Net::IRC;
my $conn = $irc->newconn(
'Server' => $server,
'Port' => 6667,
'Nick' => $nick,
'Ircname' => $ircname,
'Username' => $username
);
$conn->add_handler('endofmotd', \&on_connect);
$conn->add_handler('public', \&on_public);
$conn->add_handler('notice', \&on_notice);
$conn->add_handler('msg', \&on_private);
$conn->add_handler('caction', \&on_caction);
$conn->add_handler('cversion', \&on_cversion);
$conn->add_handler('cping', \&on_cping);
$conn->add_handler('ctime', \&on_ctime);
$irc->start();
sub on_connect
{
my ($conn, $event) = @_;
$conn->join($channel);
$conn->privmsg($channel, 'Salutations !');
$conn->print("<$nick>\t| Salutations !");
$conn->{'connected'} = 1;
$conn->privmsg('nickserv', 'IDENTIFY ' . $pass);
$conn->print("Identify : $nick $pass");
}
sub on_public
{
my ($conn, $event) = @_;
my $text = $event->{'args'}[0];
$conn->print("<" . $event->{'nick'} . ">\t| $text");
if (substr($text, 0, 1) eq '!')
{
my $commande = ($text =~ m/^!([^ ]*)/)[0];
if ($commande ne '')
{
if ($commande eq 'bonjour')
{
my @params = grep {!/^\s*$/} split(/\s+/, substr($text, length("!$commande")));
if (defined($params[0]) && $params[0] ne '')
{
$conn->privmsg($channel, "Bonjour $params[0] !");
$conn->print("<$nick>\t| Bonjour $params[0] !");
}
else
{
$conn->print("Un paramètre attendu");
}
}
else
{
$conn->print("Commande non reconnue");
}
}
else
{
$conn->print("Pas une commande");
}
}
}
sub on_notice
{
my ($conn, $event) = @_;
my $text = $event->{'args'}[0];
$conn->print("NOTICE<" . $event->nick() . ">\t| $text");
}
sub on_private
{
my ($conn, $event) = @_;
my $text = $event->{'args'}[0];
$conn->print("PRIVE<" . $event->nick() . ">\t| $text");
}
sub on_caction
{
my ($conn, $event) = @_;
my $nick = $event->nick;
my $text = $event->{'args'}[0];
$conn->print("* $nick $text");
}
sub on_cversion
{
my ($conn, $event) = @_;
my $nick = $event->nick;
$conn->ctcp_reply($nick, 'VERSION ' . "ircPerlBot v $version, www.squalenet.net");
$conn->print("*** CTCP VERSION request de $nick");
}
sub on_cping
{
my ($conn, $event) = @_;
my $nick = $event->nick;
my $timestamp = $event->{'args'}[0];
$conn->ctcp_reply($nick, 'PING ' . $timestamp);
$conn->print("*** CTCP PING request de $nick");
}
sub on_ctime
{
my ($conn, $event) = @_;
my $date = localtime;
my $nick = $event->nick;
$conn->ctcp_reply($nick, 'TIME ' . $date);
$conn->print("*** CTCP TIME request de $nick");
}
Exemple Complet
Nous voici arrivés à la fin de ce second article traitant de la création d'un Bot IRC en Perl... Je vous encourage à présent, si vous êtes curieux, à passer à la lecture de la troisième et dernière partie, qui nous emménera encore plus loin !