2 # xavierbot : an OCaml interpreter IRC bot.
3 # By Richard W.M. Jones <rich@annexia.org>.
4 # This code is in the Public Domain.
5 # $Id: xavierbot.pl,v 1.7 2007/06/29 07:55:47 rjones Exp $
8 use POE qw(Component::IRC Wheel::Run);
10 #----------------------------------------------------------------------
11 # Start of configuration.
13 my $nick = "xavierbot";
14 my $ircname = "Xavierbot"; # Printable name.
15 my $server = "chat.freenode.net";
16 #my $server = "devserv.devel.redhat.com";
18 my $channel = "#ocaml";
20 # End of configuration.
21 #----------------------------------------------------------------------
23 $ENV{PATH} = "/usr/bin:/bin";
25 POE::Session->create (
27 main => [ qw(_default _start irc_001 irc_public got_stdout got_sigchld) ],
36 my ($kernel, $heap) = @_[KERNEL,HEAP];
38 my $irc = POE::Component::IRC->spawn
44 ) or die "POE::Component::IRC->spawn failed: $!";
46 my $ocaml = start_toplevel ();
48 $kernel->sig(CHLD => qw(got_sigchld));
51 $heap->{ocaml} = $ocaml;
53 my $irc_session = $heap->{irc}->session_id ();
54 $kernel->post ($irc_session => register => "all");
55 $kernel->post ($irc_session => connect => { });
62 my ($kernel, $sender) = @_[KERNEL,SENDER];
64 my $poco_object = $sender->get_heap ();
65 print "Connected to ", $poco_object->server_name (), "\n";
67 $kernel->post ($sender => join => $channel);
73 my ($kernel, $sender, $who, $where, $what, $heap) =
74 @_[KERNEL,SENDER,ARG0,ARG1,ARG2,HEAP];
75 my $nick = (split /!/, $who)[0];
76 my $channel = $where->[0];
79 if (my ($stmt) = $what =~ /^\s*([^#].*;;)\s*$/) {
80 $heap->{ocaml}->put ("$stmt\n");
82 # XXX How to interpolate $nick into the patterns?
83 elsif ($what =~ /^\s*xavierbot\b.*\bhelp\b/) {
84 my $nick = (split /!/, $who)[0];
85 $kernel->post ($sender => privmsg => $channel =>
86 "$nick: expr ;; evaluate expr in OCaml toplevel");
87 $kernel->post ($sender => privmsg => $channel =>
88 "$nick: help help message");
89 $kernel->post ($sender => privmsg => $channel =>
90 "$nick: restart restart the toplevel");
92 elsif ($what =~ /^\s*xavierbot\b.*\brestart\b/) {
93 print STDOUT "got instruction to restart ...\n";
94 restart_toplevel ($heap->{ocaml});
101 my ($event, $args) = @_[ARG0 .. $#_];
102 my @output = ("$event: ");
104 foreach my $arg (@$args) {
105 if (ref ($arg) eq "ARRAY") {
106 push @output, "[" . join (" ,", @$arg) . "]";
108 push @output, "'$arg'";
111 print STDOUT join " ", @output, "\n";
115 #----------------------------------------------------------------------
117 # Toplevel wrote something.
121 my ($kernel,$heap, $input, $wheel_id) = @_[KERNEL,HEAP,ARG0,ARG1];
122 print "Child said: $input\n";
123 $kernel->post ($heap->{irc} => privmsg => $channel => "$input");
126 # Got a SIGCHLD, so start the bot up again.
130 my ($kernel, $heap) = @_[KERNEL,HEAP];
131 my $ocaml = start_toplevel ();
132 $heap->{ocaml} = $ocaml;
135 # Start up the toplevel (assumes it's not running).
139 return POE::Wheel::Run->new
141 Program => "./ocamlbotwrapper",
142 StdoutEvent => "got_stdout",
143 StderrEvent => "got_stdout",
144 ) or die "POE::Wheel::Run->new ./ocamlbotwrapper failed: $!";
147 # Restart the toplevel - kill the old one, and a new one
148 # will be spawned after we get the SIGCHLD signal.
150 # XXX Can't send signal to setuid child, so instead just close
158 $ocaml->shutdown_stdin;