#!/usr/bin/perl use warnings; use strict; use POE qw( Component::IRC ); # Gleichbedeutend mit: # use POE; # use POE::Component::IRC; # Das ist also nur als Abkürzung. # Nun benutzen wir PoCo::IRC, um einen einfachen IRC-Bot zu schreiben. # Zuerst einmal erzeugen wir ne neue Session für uns. POE::Session->create( # Hier definieren wir, welche Handler für welche Events aufgerufen werden # sollen. inline_states => { # _start ist der Handler, der aufgerufen wird, sobald die Session erzeugt # ist. Hier werden wir PoCo::IRC initialisieren. _start => sub { warn "Up and running.\n"; # Als Parameter erwartet PoCo::IRC::new nur einen Namen, der dann als # Alias verwendet wird. POE kennt diese Unter-Session, also die # IRC-Verbindung, ab dann unter dem Namen "bot". Wir brauchen den Namen, # um ihr Befehle schicken zu können. Wichtig: PoCo::IRC::new return()ed # kein Objekt oder so. POE::Component::IRC->new("bot"); # Also der Bot ist jetzt startbereit. Nun müssen wir ihm sagen, welche # IRC-Events uns interessieren. Das ist in diesem Fall 376 (End Of MOTD, # also die Antwort auf die Frage "Sind wir eingeloggt?") und public # (Irgendjemand hat irgendwas in irgendeinen Channel geschrieben.). # POE::Kernel::post erwartet als ersten Parameter eine Session (also ein # Alias für eine Session. Wir ham unsere PoCo::IRC-Session "bot" genannt, # also müssen wir das hier ihm auch sagen.). Dann kommt der Name des # Events, den unser Bot empfangen soll. Und danach kommen alle Argumente. # Kurz: Die nächste Zeile sendet unserem Bot den Event "register" mit den # Parametern "376" und "public". POE::Kernel->post(bot => "register", qw( 376 public )); # Ok, verbinden wir uns. POE::Kernel->post(bot => "connect", { # Welchen Server? -- Ich hab nen eigenen IRC-Server bei mir laufen, zum # Testen und so. Du solltest das in irc.gnu.org oder so ändern. Server => "thestars", # 6667 ist der Standard-IRC-Port. Port => 6667, Nick => "dapoebot", }); # Wichtig: Jetzt, zu diesem Zeitpunkt, wir noch gar nix verbunden. # Verbunden wir erst, wenn PoCo::IRC den Event wirklich erhält. Und das # kann frühestens dann sein, wenn unser Event-Handler (also diese Subref # hier jetzt grad) vorbei ist. Weil: POE ist auch nur nen normales # Perl-Modul, was jetzt nicht irgendwie perl selbst ändert, dass es # (z.B.) nach jedem Statement schaut, ob da neue Events da sind oder so. }, # Nun ja, egal, schreiben wir unsere anderen Event-Handler. # irc_376 wird von "bot" getriggered, wenn er die Meldung End of MOTD # erhält, das ist also kurz nach dem Einloggen. (Wenn deine Firewall Port # 113 DROPed (statt REJECTed), kann es relativ lange dauern (2 min), bis # der Server und wirklich reinlässt.) irc_376 => sub { warn "Connected.\n"; # Nun wollen wir unseren Test-Channel, #poerulez, joinen. # Wieder das gleiche Spielchen mit POE::Kernel::post: Wir senden der # Session "bot" den Event "join" mit dem Parameter "#poerulez". PoCo::IRC # wird dann daraufhin dem Server folgendes schicken (aber das ist egal, # PoCo::IRC abstrahiert ja für uns): # JOIN #poerulez # Wir müssen uns nicht darum kümmern, wie IRC (das Protokoll) das # wirklich erwartet (um z.B. jemanden ne Nachricht zu schicken, müssten # wir (raw) schicken: # PRIVMSG nick :Hallo # Ja, genau, in der Form. Aber wie gesagt, PoCo::IRC abstrahiert für # uns.). # Auch kümmert sich PoCo::IRC darum, dass wir nicht zu viele Befehle auf # einmal senden (dann würde uns der Server mit "Excess Flood"-Meldung # KILLen. PoCo::IRC tut alle Befehle in ne Warteschlange, und führt sie # erst dann aus, wenn es auch wirklich sicher ist. POE::Kernel->post(bot => "join", "#poerulez"); }, # Unser letzter Event, irc_public. PoCo::IRC triggered unseren irc_public, # wenn in irgendeinem Channel was gesprochen wurde. # perldoc POE::Component::IRC verrät uns: # irc_public # Sent whenever you receive a PRIVMSG command that was sent to a channel. ARG0 # is the nick!hostmask of the sender. ARG1 is an array reference containing the # channel name(s) of the recipients. ARG2 is the text of the message. irc_public => sub { # ARG0, ARG1, ARG2 sind alles Konstanten (wie bei HEAP und so auch). # $_[ARG0] enthält also das erste Argument. my ($nickmask, $dest, $text) = @_[ARG0, ARG1, ARG2]; # Wir hätten auch schreiben können: # my ($nickmask, $dest, $text) = @_[ARG0..$#_]; # Weil: Alle "echten" Argumente (also nicht HEAP und so) sind immer am # Ende. ARG0 gibt die Position des ersten Argumentes an, $#_ damit die # des letzten. # $nickmask sieht z.B. so aus: "iblech!~iblech@223.8-dial.augustakom.net" # Uns interessiert nur den Nickname, also: $nickmask =~ /^([^!]+)/ or return; # Wenn die Regex fehlschlägt, dann gabs keinen Nickname (also dann wars # z.B. der Server der war gesagt hat oder so, interessiert uns nicht ==> # return). my $nick = $1; # $dest ist ne Arrayref, wir derefenzieren uns geben aus: warn "@$dest: <$nick> $text\n"; }, }, ); # Wir sind fertig! Dein erster Bot ;-) # Und das, mit Kommentaren, in 124 Zeilen, ohne Kommentare: 43 Zeilen!! # POE::Kernel ablaufen lassen. POE::Kernel->run; exit;