Bienvenue sur Squalenet.Net ! - Nous sommes le 24/10/2017 ; il est 00:47
Connecté : 1 inconnu
Votre Compte

Login :
Password :

S'inscrirePassword Oublié
Statistiques

Perl::IRC - 2/3

Ecrire un bot IRC en Perl

Perl::IRC - 1/3   Perl::IRC - 3/3
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); # En privé

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");
} # Fin on_private

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); # En 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");
} # Fin on_notice

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 :

En général, une commande est construite comme ceci :

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 :

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 '!')
    { # $text commence par un '!' => il s'agit probablement d'une commande
        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 '')
                { # Un paramètre (non vide) a été passé à la commande
                  # => On va pouvoir l'utiliser
                    $conn->privmsg($channel, "Bonjour $params[0] !"); # Salutation sur le channel
                    $conn->print("<$nick>\t| Bonjour $params[0] !");  # Et echo sur la console
                }
                else
                { # Un paramètre attendu n'a pas été fourni à la commande...
                    $conn->print("Un paramètre attendu");
                }
            }
            else
            { # La commande n'a pas été reconnue...
                $conn->print("Commande non reconnue");
            }
        }
        else
        { # On avait un ! en début de ligne, mais non suivi d'un nom de commande
            $conn->print("Pas une commande");
        }
    }
   
} # Fin on_public

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);          # /me

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);    # Demande de version
$conn->add_handler('cping', \&on_cping);          # Demande de PING
$conn->add_handler('ctime', \&on_ctime);          # Demande de time

$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';    # A configurer !
my $pass = 'AZERTY';        # A configurer !

$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");
   
} # Fin on_connect

 

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.

#!/usr/bin/perl

use strict;
use warnings;
use diagnostics;

# On utilise la librairie Net::IRC pour se connecter à IRC
use Net::IRC;

# Vous utiliserez peut-être Data::Dumper pour le debug, pour savoir de quoi sont composés certains événements...
# use Data::Dumper;



# Configuration des options de connexion (serveur, login) :
my $server = 'irc.worldnet.net';
my $nick = 'perlBot_v2';    # A configurer !
my $pass = 'AZERTY';        # A configurer !


# Informations concernant le Bot :
my $ircname = 'Bot IRC Perl';
my $username = 'perlBot';
my $version = '2.0';


# Channel sur lequel on veut que le Bot aille :
my $channel = '#krypton';


# On crée l'objet qui nous permet de nous connecter à IRC :
my $irc = new Net::IRC;


# On crée l'objet de connexion à IRC :
my $conn = $irc->newconn(
    'Server'      => $server,
    'Port'        => 6667,
    'Nick'        => $nick,
    'Ircname'    => $ircname,
    'Username'    => $username
);


# On installe les fonctions de Hook :
$conn->add_handler('endofmotd', \&on_connect);    # Fin du MOTD => on est connecté
$conn->add_handler('public', \&on_public);        # Sur le chan
$conn->add_handler('notice', \&on_notice);        # En notice
$conn->add_handler('msg', \&on_private);          # En privé
$conn->add_handler('caction', \&on_caction);      # /me
$conn->add_handler('cversion', \&on_cversion);    # Demande de version
$conn->add_handler('cping', \&on_cping);          # Demande de PING
$conn->add_handler('ctime', \&on_ctime);          # Demande de time

# On lance la connexion et la boucle de gestion des événements :
$irc->start();





## Les fonctions de gestion des événements :

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");
   
} # Fin on_connect


sub on_public
{
    my ($conn, $event) = @_;
    my $text = $event->{'args'}[0];
    $conn->print("<" . $event->{'nick'} . ">\t| $text");
   
    if (substr($text, 0, 1) eq '!')
    { # $text commence par un '!' => il s'agit probablement d'une commande
        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 '')
                { # Un paramètre (non vide) a été passé à la commande
                  # => On va pouvoir l'utiliser
                    $conn->privmsg($channel, "Bonjour $params[0] !"); # Salutation sur le channel
                    $conn->print("<$nick>\t| Bonjour $params[0] !");  # Et echo sur la console
                }
                else
                { # Un paramètre attendu n'a pas été fourni à la commande...
                    $conn->print("Un paramètre attendu");
                }
            }
            else
            { # La commande n'a pas été reconnue...
                $conn->print("Commande non reconnue");
            }
        }
        else
        { # On avait un ! en début de ligne, mais non suivi d'un nom de commande
            $conn->print("Pas une commande");
        }
    }
} # Fin on_public


sub on_notice
{
    my ($conn, $event) = @_;
    my $text = $event->{'args'}[0];
    $conn->print("NOTICE<" . $event->nick() . ">\t| $text");
} # Fin on_notice


sub on_private
{
    my ($conn, $event) = @_;
    my $text = $event->{'args'}[0];
    $conn->print("PRIVE<" . $event->nick() . ">\t| $text");
} # Fin on_private


sub on_caction
{
    my ($conn, $event) = @_;
    my $nick = $event->nick;
    my $text = $event->{'args'}[0];
    $conn->print("* $nick $text");
} # Fin on_caction


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");
} # Fin on_cversion


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");
} # Fin on_cping


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");
} # Fin on_ctime
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 !

Perl::IRC - 1/3   Perl::IRC - 3/3