I do almost the same for our local irc channel, but connections are based only on number of directly addressed (=~ /^$nick/) messages. And GraphViz helps to avoid writing .DOT files.
#!/usr/bin/perl -w
use strict;
use Net::IRC;
use Storable;
use Data::Dumper;
use GraphViz;
use vars qw/$myself $version $channel $network_file $format_version
$admin_nick $output_file $output_url %users $network $aliases
@topic_log/;
do 'octopus.config.pl'
or die "Cannot read config: err= $!, evalerr= $@\n";
$network_file = "chan.$channel.8pus.$format_version";
my $nick_re = qr/[A-Za-z](?:[A-Za-z0-9_`\\\]\[^}{-])+/;
sub save {
store [$network, $aliases], $network_file;
print "Saved network\n";
my $nnetwork; # normalized as per $aliases
foreach my $from (keys %$network) {
my $real_from = $aliases->{$from} || $from;
foreach my $to (keys %{$network->{$from}}) {
my $real_to = $aliases->{$to} || $to;
$nnetwork->{$real_from}->{$real_to} += $network->{$from}->
+{$to};
}
}
my $g = new GraphViz
layout => 'dot',
concentrate => 1,
directed => 0;
foreach my $from (keys %$nnetwork) {
$g->add_node($from);
foreach my $to (keys %{$nnetwork->{$from}}) {
$g->add_node($to);
$g->add_edge($from, $to, weight => $nnetwork->{$from}->{$t
+o});
}
}
open CHART, ">$output_file";
binmode CHART;
print CHART $g->as_png;
close CHART;
}
sub on_connect {
my $self = shift;
print "Joining $channel...\n";
$self->join($channel);
$self->privmsg($channel, "Hi from the Deep.");
eval { ($network, $aliases) = @{retrieve($network_file)} };
$network ||= {};
$aliases ||= {};
}
sub on_public_msg {
my $self = shift;
my $event = shift;
my $message = ($event->args)[0];
print $event->nick . " says: '" . $message . "'\n";
if ($message =~ /^$myself/o) {
# to me
if ($message =~ /\bhi\b/i) {
$self->privmsg($channel, "Hi, (?:wo)?man. I\'m an 8pus v.$
+version reading $channel");
} elsif ($message =~ /\bwhere\b/) {
$self->privmsg($channel, "Look at $output_url");
} elsif ($message =~ /help/) {
$self->privmsg($channel, "Available commands: hi, where, h
+elp, topiclog");
}
}
for my $user (keys %users) {
if ($message =~ /^$user\b/) {
$network->{$event->nick}->{$user}++;
}
}
}
sub on_msg {
my $self = shift;
my $event = shift;
my $message = ($event->args)[0];
print $event->nick . " privately says: '" . $message . "'\n";
if ($message =~ /save/) {
save;
$self->privmsg($event->nick, 'Ok, saved');
} elsif ($message =~ /dump/) {
for my $line (split "\n", Dumper($network)) {
$self->privmsg($event->nick, $line);
}
} elsif ($event->nick eq $admin_nick && $message =~ /($nick_re)\s+
+aka\s+($nick_re)/o) {
$aliases->{$2} = $1;
$self->privmsg($event->nick, "'$2' is now an alias for '$1', a
+h ok...");
}
}
sub on_names {
my ($self, $event) = @_;
my @args = $event->args;
%users = map { $_ => 1 } map { s/^[@+]//; $_ } split ' ', $args[3]
+;
print "Users online: " . join (', ', keys %users) . "\n";
}
sub on_part {
my ($self, $event) = @_;
delete $users{$event->nick};
}
sub on_join {
my ($self, $event) = @_;
$users{$event->nick} = 1;
}
my $irc = new Net::IRC;
my $conn = newconn $irc
Nick => $myself,
Server => 'irc.server',
Port => 6667,
Username=> '8pus',
Ircname => 'Octopus Vulgaris';
$conn->add_handler(376 => \&on_connect);
$conn->add_handler(public => \&on_public_msg);
$conn->add_handler(msg => \&on_msg);
$conn->add_handler(353 => \&on_names);
$conn->add_handler('join' => \&on_join);
$conn->add_handler(part => \&on_part);
$irc->start;
save;
Config file looks like this:
$myself = 'Octopus';
$version = '0.5';
$channel = '#free_tibet';
$format_version = 'III';
$admin_nick = 'kappa';
$channel =~ /^#(.+)$/ and do {
$output_file = "charts/chan.$1.net.png";
$output_url = "http://my.web.site/octopus/chan.$1.net.png";
}