From 7a2a97ead43f07fbeb25bca43f40c7f994cc77ab Mon Sep 17 00:00:00 2001 From: Ralf Ertzinger Date: Fri, 4 Jul 2008 16:07:16 +0200 Subject: [PATCH] Initial checkin --- quotesite.pl | 360 +++++++++++++++++++++++++++++++++++++++++ quotesite/Base.pm | 140 ++++++++++++++++ quotesite/BashOrgGrabber.pm | 70 ++++++++ quotesite/GermanBashGrabber.pm | 71 ++++++++ quotesite/GrabberBase.pm | 61 +++++++ 5 files changed, 702 insertions(+) create mode 100644 quotesite.pl create mode 100644 quotesite/Base.pm create mode 100644 quotesite/BashOrgGrabber.pm create mode 100644 quotesite/GermanBashGrabber.pm create mode 100644 quotesite/GrabberBase.pm diff --git a/quotesite.pl b/quotesite.pl new file mode 100644 index 0000000..5385055 --- /dev/null +++ b/quotesite.pl @@ -0,0 +1,360 @@ +# autodisplay quotes from quotesites +# +# (c) 2007-2008 by Ralf Ertzinger +# licensed under GNU GPL v2 + +use strict; +use Irssi 20020324 qw (command_bind command_runsub signal_add_first signal_add_last); +use vars qw($VERSION %IRSSI); +use XML::Simple; +use Data::Dumper; +use File::Spec; + +my @grabbers; +my $conf; +my $conffile = File::Spec->catfile(Irssi::get_irssi_dir(), 'quotesite.xml'); +my $plugindir = File::Spec->catfile(Irssi::get_irssi_dir(), 'scripts', 'quotesite'); + +my $PARAMS = { +}; + + +# activate debug here +my $debug = 1; + +# "message public", SERVER_REC, char *msg, char *nick, char *address, char *target +signal_add_last("message public" => sub {check_for_link(\@_,1,4,2,0);}); +# "message own_public", SERVER_REC, char *msg, char *target +signal_add_last("message own_public" => sub {check_for_link(\@_,1,2,-1,0);}); + +# "message private", SERVER_REC, char *msg, char *nick, char *address +signal_add_last("message private" => sub {check_for_link(\@_,1,-1,2,0);}); +# "message own_private", SERVER_REC, char *msg, char *target, char *orig_target +signal_add_last("message own_private" => sub {check_for_link(\@_,1,2,-1,0);}); + +# "message irc action", SERVER_REC, char *msg, char *nick, char *address, char *target +signal_add_last("message irc action" => sub {check_for_link(\@_,1,4,2,0);}); +# "message irc own_action", SERVER_REC, char *msg, char *target +signal_add_last("message irc own_action" => sub {check_for_link(\@_,1,2,-1,0);}); + +sub write_irssi { + my $witem = shift; + my @text = @_; + + $text[0] = 'quotesite: ' . $text[0]; + + if (defined $witem) { + $witem->print(sprintf(shift(@text), @text), MSGLEVEL_CLIENTCRAP); + } else { + Irssi::print(sprintf(shift(@text), @text)); + } + +} + +sub write_debug { + if ($debug) { + write_irssi(shift, @_); + } +} + +sub check_for_link { + my ($signal,$parammessage,$paramchannel,$paramnick,$paramserver) = @_; + my $server = $signal->[$paramserver]; + my $target = $signal->[$paramchannel]; + my $message = ($parammessage == -1) ? '' : $signal->[$parammessage]; + my $g; + my $m; + my $p; + + + my $witem; + if (defined $server) { + $witem = $server->window_item_find($target); + } else { + $witem = Irssi::window_item_find($target); + } + + # Look if we should ignore this line + if ($message =~ m,(?:\s|^)/nosave(?:\s|$),) { + return; + } + + study($message); + + # Offer the message to all Grabbers in turn + foreach $g (@grabbers) { + ($m, $p) = $g->get($message); + while (defined($m)) { + write_irssi($witem, '%%R>>> %%Y%s%%N %%G%s', $m->{'SOURCE'}, $m->{'ID'}); + + foreach (split(/[\n\r]+/, $m->{'CONTENT'})) { + write_irssi($witem, ' %%g%s', $_); + } + + # Remove the matched part from the message and try again (there may be + # more!) + $message =~ s/$p//; + study($message); + + ($m, $p) = $g->get($message); + } + } +} + +sub cmd_save { + + eval { + open(CONF, '>'.$conffile) or die 'Could not open config file'; + print CONF XML::Simple::XMLout($conf, KeepRoot => 1, KeyAttr => {'config' => 'module', 'option' => 'key'}); + close(CONF); + }; + if ($@) { + write_irssi(undef, 'Could not save config to %s: %s', ($conffile, $@)); + } else { + write_irssi(undef, 'configuration saved to %s', $conffile); + } +} + +sub cmd_set { + my $target = shift; + my $key = shift; + my $val = shift; + my $p; + + foreach $p (@grabbers) { + if ($p->{'NAME'} eq $target) { + $p->setval($key, $val); + return; + } + } + write_irssi(undef, 'No such module'); +} + + +sub cmd_enable { + my $target = shift; + my $p; + + foreach $p (@grabbers) { + if ($p->{'NAME'} eq $target) { + $p->enable(); + return; + } + } + write_irssi(undef, 'No such module'); +} + + +sub cmd_disable { + my $target = shift; + my $p; + + foreach $p (@grabbers) { + if ($p->{'NAME'} eq $target) { + $p->disable(); + return; + } + } + write_irssi(undef, 'No such module'); +} + + +sub cmd_show { + my $target = shift; + my $p; + my $e; + + if (defined($target)) { + foreach $p (@grabbers) { + if ($p->{'NAME'} eq $target) { + write_irssi(undef, $p->getconfstr()); + return; + } + } + write_irssi(undef, 'No such module'); + } else { + write_irssi(undef, 'Loaded grabbers (* denotes enabled modules):'); + foreach $p (@grabbers) { + $e = $p->_getval('enabled'); + write_irssi(undef, ' %s%s', $p->{'NAME'}, $e?'*':''); + }; + } +} + +sub cmd_help { + my $target = shift; + my $p; + + if (defined($target)) { + foreach $p (@grabbers) { + if ($p->{'NAME'} eq $target) { + write_irssi(undef, $p->gethelpstr()); + return; + } + } + write_irssi(undef, 'No such module'); + } else { + write_irssi(undef, <<'EOT'); +Supported commands: + save: Save the current configuration + help [modulename]: Display this help, or module specific help + show [modulename]: Show loaded modules, or the current parameters of a module + set modulename parameter value: set a module parameter to a new value + enable [modulename]: enable the usage of this module (grabbers only) + disable [modulename]: disable the usage of this module (grabbers only) + reload: reload all modules (this is somewhat experimental) + debug: enable debugging messages + nodebug: disable debugging messages +EOT + } +} + +# save on unload +sub sig_command_script_unload { + my $script = shift; + if ($script =~ /(.*\/)?quotesite(\.pl)?$/) { + cmd_save(); + } +} + +sub ploader { + + my $dir = shift; + my $pattern = shift; + my $type = shift; + my @list; + my $p; + my $g; + my @g = (); + + opendir(D, $dir) || return (); + @list = grep {/$pattern/ && -f File::Spec->catfile($dir, $_) } readdir(D); + closedir(D); + + foreach $p (@list) { + write_debug(undef, "Trying to load $p:"); + $p =~ s/\.pm$//; + eval qq{ require $p; }; + if ($@) { + write_debug(undef, "Failed to load plugin: $@"); + next; + } + + $g = eval $p.q{->new();}; + if ($@) { + write_debug(undef, "Failed to instanciate: $@"); + delete($INC{$p}); + next; + } + + write_debug(undef, "found $g->{'TYPE'} $g->{'NAME'}"); + if ($type eq $g->{'TYPE'}) { + push(@g, $g); + $g->setio(sub {Irssi::print(shift)}); + } else { + write_irssi(undef, '%s has wrong type (got %s, expected %s)', $p, $g->{'TYPE'}, $type); + delete($INC{$p}); + } + } + + write_debug(undef, "Loaded %d plugins", $#g+1); + + return @g; +} + +sub _load_modules($) { + + my $path = shift; + + foreach (keys(%INC)) { + if ($INC{$_} =~ m|^$path|) { + write_debug(undef, "Removing %s from \$INC", $_); + delete($INC{$_}); + } + } + @grabbers = ploader($path, '.*Grabber\.pm$', 'grabber'); +} + + +sub init_quotesite { + + my $bindings = shift; + my $p; + + unless(-r $conffile && defined($conf = XML::Simple::XMLin($conffile, ForceArray => ['config', 'option'], KeepRoot => 1, KeyAttr => {'config' => 'module', 'option' => 'key'}))) { + # No config, start with an empty one + write_debug(undef, 'No config found, using defaults'); + $conf = { 'quotesite' => { }}; + } + foreach (keys(%{$PARAMS})) { + unless (exists($conf->{'quotesite'}->{$_})) { + $conf->{'quotesite'}->{$_} = $PARAMS->{$_}; + } + } + + _load_modules($plugindir); + + unless (defined(@grabbers)) { + write_irssi(undef, 'No grabbers found, can not proceed.'); + return; + } + + + # Loop through all plugins and load the config + foreach $p (@grabbers) { + $conf->{'quotesite'}->{'config'}->{$p->{'NAME'}} = $p->mergeconfig($conf->{'quotesite'}->{'config'}->{$p->{'NAME'}}); + } + + if ($bindings) { + + Irssi::signal_add_first('command script load', 'sig_command_script_unload'); + Irssi::signal_add_first('command script unload', 'sig_command_script_unload'); + Irssi::signal_add('setup saved', 'cmd_save'); + + + Irssi::command_bind('quotesite' => \&cmdhandler); + } + + write_irssi(undef, 'quotesite initialized'); +} + +sub cmdhandler { + my ($data, $server, $item) = @_; + my @params = split(/\s+/, $data); + + if ($params[0] eq 'save') { + cmd_save(); + } elsif ($params[0] eq 'set') { + shift(@params); + cmd_set(@params); + } elsif ($params[0] eq 'show') { + shift(@params); + cmd_show(@params); + } elsif ($params[0] eq 'help') { + shift(@params); + cmd_help(@params); + } elsif ($params[0] eq 'enable') { + shift(@params); + cmd_enable(@params); + } elsif ($params[0] eq 'disable') { + shift(@params); + cmd_disable(@params); + } elsif ($params[0] eq 'reload') { + init_quotesite(0); + } elsif ($params[0] eq 'debug') { + $debug = 1; + foreach (@grabbers) { + $_->setdebug(1); + } + write_irssi(undef, 'Enabled debugging'); + } elsif ($params[0] eq 'nodebug') { + $debug = 0; + foreach (@grabbers) { + $_->setdebug(0); + } + write_irssi(undef, 'Disabled debugging'); + } +} + +unshift(@INC, $plugindir); +init_quotesite(1); diff --git a/quotesite/Base.pm b/quotesite/Base.pm new file mode 100644 index 0000000..d8a4e98 --- /dev/null +++ b/quotesite/Base.pm @@ -0,0 +1,140 @@ +# (c) 2007 by Ralf Ertzinger +# licensed under GNU GPL v2 + +package Base; + +use strict; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {'_DEBUG' => 0, '_OUT' => sub {print shift}}; + + bless($self, $class); + + $self->_prepare_parameters(); + + return $self; +} + +sub error { + my $self = shift; + my $t; + + $t = sprintf(shift(@_), @_); + $t =~ s/%/%%/g; + $self->{'_OUT'}($t); +} + +sub debug { + my $self = shift; + my @data = @_; + + $data[0] = "DEBUG: " . $data[0]; + if ($self->{'_DEBUG'} != 0) {$self->error(@data)}; +} + +sub mergeconfig { + my $self = shift; + my $c = shift; + my $o; + + return $self->{'_CONFIG'} unless defined($c); + + foreach $o (keys(%{$c->{'option'}})) { + if (exists($self->{'_CONFIG'}->{'option'}->{$o})) { + $self->{'_CONFIG'}->{'option'}->{$o}->{'content'} = $c->{'option'}->{$o}->{'content'}; + } + } + + return $self->{'_CONFIG'}; +} + +sub _prepare_parameters { + my $self = shift; + my $p; + + $self->{'_CONFIG'} = {'option' => {'enabled' => {'content' => '1'}}}; + + foreach $p (keys(%{$self->{'_PARAMS'}})) { + $self->{'_CONFIG'}->{'option'}->{$p}->{'content'} = $self->{'_PARAMS'}->{$p}->[0]; + } +} + +sub _getval { + my $self = shift; + my $key = shift; + my $val; + + $val = $self->{'_CONFIG'}->{'option'}->{$key}->{'content'}; + $self->debug('Returning %s=%s', $key, $val); + + return $val; +} + +sub setval { + my $self = shift; + my $key = shift; + my $val = shift; + + if (exists($self->{'_CONFIG'}->{'option'}->{$key})) { + $self->{'_CONFIG'}->{'option'}->{$key}->{'content'} = $val; + } else { + $self->error('Module %s does not have a parameter named %s', $self->{'NAME'}, $key); + } +} + +sub setio { + my $self = shift; + my $io = shift; + + $self->{'_OUT'} = $io; +} + +sub getconfstr { + my $self = shift; + my $s = 'Options for ' . $self->{'NAME'} . ":\n"; + my $k; + my $p; + + foreach $k (keys(%{$self->{'_CONFIG'}->{'option'}})) { + $p = $self->{'_CONFIG'}->{'option'}->{$k}->{'content'}; + $p =~ s/%/%%/g; + $s .= sprintf(" %s: %s", $k, $p); + if ($self->{'_CONFIG'}->{'option'}->{$k}->{'content'} eq $self->{'_PARAMS'}->{$k}->[0]) { + $s .= " (default)\n"; + } else { + $s .= "\n"; + } + } + + return $s; +} + +sub gethelpstr { + my $self = shift; + my $s = 'Help for ' . $self->{'NAME'} . ":\n"; + my $k; + my $p; + + if (exists($self->{'DESC'})) { + $s .= "Description:\n " . $self->{'DESC'}; + } + + $s .= " Options:\n"; + foreach $k (keys(%{$self->{'_CONFIG'}->{'option'}})) { + $p = $self->{'_PARAMS'}->{$k}->[0]; + $p =~ s/%/%%/g; + $s .= sprintf(" %s: %s (default: %s)\n", $k, $self->{'_PARAMS'}->{$k}->[1], $p); + } + + return $s; +} + +sub setdebug { + my $self = shift; + + $self->{'_DEBUG'} = shift; +} + +1; diff --git a/quotesite/BashOrgGrabber.pm b/quotesite/BashOrgGrabber.pm new file mode 100644 index 0000000..7f0d197 --- /dev/null +++ b/quotesite/BashOrgGrabber.pm @@ -0,0 +1,70 @@ +# (c) 2007 by Ralf Ertzinger +# licensed under GNU GPL v2 +# +# Grabber for bash.org + +package BashOrgGrabber; + +use GrabberBase; +@ISA = qw(GrabberBase); + +use LWP::Simple qw(!get); +use HTML::TokeParser; +use Data::Dumper; + +use strict; + +sub new { + my $class = shift; + my $self = $class->SUPER::new(); + + $self->{'NAME'} = 'bash.org'; + $self->{'PATTERNS'} = ['(http://(?:[-a-zA-Z0-9_.]+\.)*bash\.org/\?(\d+))']; + + bless($self, $class); + $self->_prepare_parameters(); + + return $self; +} + +sub _parse { + my $self = shift; + my $url = shift; + my $pattern = shift; + my $content; + my $metadata = {}; + my $p; + my $t; + + $url =~ m|$pattern|; + $url = $1; + + $metadata->{'URL'} = $url; + $metadata->{'ID'} = $2; + $metadata->{'TYPE'} = 'quote'; + $metadata->{'SOURCE'} = $self->{'NAME'}; + $metadata->{'CONTENT'} = undef; + + # Get the HTML file containing the quote + unless(defined($content = LWP::Simple::get(sprintf('http://bash.org/?%s', $2)))) { + $self->error('Could not download quote'); + return undef; + } + + $p = HTML::TokeParser->new(\$content); + + while ($t = $p->get_tag('p')) { + if (exists($t->[1]->{'class'}) && ($t->[1]->{'class'} eq 'qt')) { + $metadata->{'CONTENT'} = $p->get_text('/p'); + } + } + + unless(defined($metadata->{'CONTENT'})) { + $self->error('Could not extract quote content'); + return undef; + } + + return $metadata; +} + +1; diff --git a/quotesite/GermanBashGrabber.pm b/quotesite/GermanBashGrabber.pm new file mode 100644 index 0000000..3fb4e63 --- /dev/null +++ b/quotesite/GermanBashGrabber.pm @@ -0,0 +1,71 @@ +# (c) 2007 by Ralf Ertzinger +# licensed under GNU GPL v2 +# +# Grabber for german-bash.org + +package GermanBashGrabber; + +use GrabberBase; +@ISA = qw(GrabberBase); + +use LWP::Simple qw(!get); +use HTML::TokeParser; +use Data::Dumper; + +use strict; + +sub new { + my $class = shift; + my $self = $class->SUPER::new(); + + $self->{'NAME'} = 'germanbash'; + $self->{'PATTERNS'} = ['(http://(?:[-a-zA-Z0-9_.]+\.)*german-bash\.org/(\d+))']; + + bless($self, $class); + $self->_prepare_parameters(); + + return $self; +} + +sub _parse { + my $self = shift; + my $url = shift; + my $pattern = shift; + my $content; + my $metadata = {}; + my $p; + my $t; + + $url =~ m|$pattern|; + $url = $1; + + $metadata->{'URL'} = $url; + $metadata->{'ID'} = $2; + $metadata->{'TYPE'} = 'quote'; + $metadata->{'SOURCE'} = $self->{'NAME'}; + $metadata->{'CONTENT'} = undef; + + # Get the HTML file containing the quote + unless(defined($content = LWP::Simple::get(sprintf('http://german-bash.org/%s', $2)))) { + $self->error('Could not download quote'); + return undef; + } + + $p = HTML::TokeParser->new(\$content); + + while ($t = $p->get_tag('div')) { + if (exists($t->[1]->{'class'}) && ($t->[1]->{'class'} eq 'zitat')) { + $metadata->{'CONTENT'} = $p->get_text('/div'); + $metadata->{'CONTENT'} =~ s/^\s*//mg; + } + } + + unless(defined($metadata->{'CONTENT'})) { + $self->error('Could not extract quote content'); + return undef; + } + + return $metadata; +} + +1; diff --git a/quotesite/GrabberBase.pm b/quotesite/GrabberBase.pm new file mode 100644 index 0000000..6a1c70a --- /dev/null +++ b/quotesite/GrabberBase.pm @@ -0,0 +1,61 @@ +# (c) 2007 by Ralf Ertzinger +# licensed under GNU GPL v2 + +package GrabberBase; +use Base; +@ISA = qw(Base); + +use strict; + +sub new { + my $class = shift; + my $self = $class->SUPER::new(); + + $self = {%{$self}, + NAME => 'FlashGrab', + TYPE => 'grabber', + PATTERNS => [], + }; + return bless($self, $class); +} + +sub get($$) { + my $self = shift; + my $url = shift; + my $pattern; + + return undef unless $self->_getval('enabled'); + + foreach $pattern (@{$self->{'PATTERNS'}}) { + $self->debug("Matching %s against %s", $pattern, $url); + if ($url =~ m|$pattern|) { + $self->debug("Match"); + return wantarray?($self->_parse($url, $pattern), $pattern):$self->_parse($url, $pattern); + } + } + + return undef; +} + +sub enable { + my $self = shift; + + $self->debug('Enabling %s grabber', $self->{'NAME'}); + $self->setval('enabled', '1'); +} + +sub disable { + my $self = shift; + + $self->debug('Disabling %s grabber', $self->{'NAME'}); + $self->setval('enabled', '0'); +} + +sub _parse { + my $self = shift; + my $url = shift; + + return undef; +} + +1; -- 1.8.3.1