diff options
Diffstat (limited to 'scripts/chansearch.pl')
-rw-r--r-- | scripts/chansearch.pl | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/scripts/chansearch.pl b/scripts/chansearch.pl new file mode 100644 index 0000000..13831c2 --- /dev/null +++ b/scripts/chansearch.pl @@ -0,0 +1,300 @@ +#!/usr/bin/perl +# +# by Stefan 'tommie' Tomanek <stefan@pico.ruhr.de> + +use strict; + +use vars qw($VERSION %IRSSI); +$VERSION = '2.3'; +%IRSSI = ( + authors => 'Stefan \'tommie\' Tomanek, bw1', + contact => 'bw1@aol.at', + name => 'ChanSearch', + description => 'searches for specific channels', + license => 'GPLv2', + url => 'http://scripts.irssi.org/', + changed => $VERSION, + selfcheckcmd=> '/chansearch -check', +); + +my $help = << "END"; +%9Name%9 + $IRSSI{name} +%9Version%9 + $VERSION +%9Description%9 + $IRSSI{description} +%9Usage%9 + /chansearch [-network|-n <networkname>] [searchstring] + /chansearch -help|-h + /chansearch -check +%9Settings%9 + /set ChanSearch_default_network freenode + /set ChanSearch_max_results 50 + /set ChanSearch_max_columns 0 +%9See also%9 + https://netsplit.de/ +END + +use utf8; +use Irssi 20020324; +use open qw/:std :utf8/; +use LWP::UserAgent; +use LWP::Protocol::https; +use HTML::Entities; +use JSON::PP; +use Getopt::Long qw(GetOptionsFromString); +use POSIX; + +use vars qw($forked); + +$forked = 0; +my $footer; +my ($default_network, $max_results, $max_columns); +my ($max_columns2); +my (@results, $resultcount); + +# ! for the fork +my (@clist, $t, $rcount); + +sub draw_box ($$$$) { + my ($title, $text, $footer, $colour) = @_; + my $box = ''; + $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n"; + foreach (split(/\n/, $text)) { + $box .= '%R|%n '.$_."\n"; + } + $box .= '%R`--<%n'.$footer.'%R>->%n'; + $box =~ s/%.//g unless $colour; + return $box; +} + +sub dehtml { + my ($text) =@_; + $text =decode_entities($text); + $text =~ s/<.*?>//g; + return $text; +} + +sub get_entries_count { + $t =~ m/(\d+) matching results/; + return $1; +} + +sub html_to_list { + utf8::decode($t); + while (length($t) > 0) { + my %h; + if ($t =~ m#<span class="cs-channel">(.*?)</span>#p) { + $h{channel}= dehtml($1); + $' =~ m#<span class="cs-network">(.*?)</span>#p; + $h{network}= dehtml($1); + #$' =~ m#<span class="cs-users">(.*?)</span>#p; + #$' =~ m#<span class="cs-details">Chat Room.*?(\d+).*?</span>#p; + $' =~ m#<span class="cs-details">Chat Room - (\d+) users - </span>#p; + my $u=$1; + #$' =~ m#class="cs-time">.*?</span>(.*?)<span class="cs-category"#p; + $' =~ m#(current topic:|No topic)(.*?)<br>#p; + $t= $'; + $h{topic}=dehtml($2); + $u =~ m/(\d+)/; + $h{users}=$1; + push @clist, {%h}; + } else { + $t=''; + } + } +} + +sub fork_search { + my ($query,$net) = @_; + $footer="$net $query"; + my ($rh, $wh); + pipe($rh, $wh); + return if $forked; + my $pid = fork(); + $forked = 1; + if ($pid > 0) { + close($wh); + Irssi::pidwait_add($pid); + my $pipetag; + my @args = ($rh, \$pipetag); + $pipetag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, \@args); + print CLIENTCRAP "%R>>%n Please wait..."; + } else { + search_channels($query,$net); + #my $data = encode_json( \@clist ); + my $data = encode_json( { clist=>[ @clist ], rcount=>$rcount } ); + print($wh $data); + close($wh); + POSIX::_exit(1); + } +} + +sub pipe_input ($$) { + my ($rh, $pipetag) = @{$_[0]}; + my $data; + { + select($rh); + local $/; + select(CLIENTCRAP); + $data = <$rh>; + close($rh); + } + Irssi::input_remove($$pipetag); + return unless($data); + + my $res= decode_json( $data ); + @results = @{ $res->{clist} }; + $resultcount = $res->{rcount}; + + my $lnet=0; + my $lchan=0; + foreach (@results) { + $lnet =length($_->{network}) if ($lnet <length($_->{network})); + $lchan =length($_->{channel}) if ($lchan <length($_->{channel})); + } + $lnet++; + $lchan++; + + my $text; + foreach (@results) { + $text .= sprintf("%-".$lnet."s%-".$lchan."s %4i %s\n", + $_->{network}, $_->{channel}, $_->{users}, substr($_->{topic},0, + $max_columns2-$lnet-$lchan)); + } + + $forked = 0; + print CLIENTCRAP draw_box('ChanSearch', $text, $footer, 1); +} + +sub search_channels ($) { + my ($query,$net) = @_; + my $ua = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1,timeout => 30); + $ua->agent('Irssi Chansearch'); + # http://irc.netsplit.de/channels/?net=IRCnet&chat=linux&num=10 + my $num=''; + my $count=0; + do { + my $page = "http://irc.netsplit.de/channels/?net=$net&chat=$query$num"; + my $result = $ua->get($page); + return undef unless $result->is_success(); + $t = $result->content(); + $rcount = get_entries_count(); + html_to_list(); + $count += 10; + $num ="&num=$count"; + } while ( $count < $rcount && $count < $max_results ); +} + +sub cmd_chansearch ($$$) { + my ($args, $server, $witem) = @_; + my $net= $default_network; + my $help; + my ($re, $ar) = GetOptionsFromString($args, + 'network=s' => \$net, + 'n=s' => \$net, + 'help' => \$help, + 'h' => \$help, + 'check' => \&self_check_init, + ); + if ($max_columns==0) { + $max_columns2 = Irssi::active_win()->{width} -15; + } + if (!defined $help) { + fork_search($ar->[0], $net); + } else { + cmd_help($IRSSI{name}, $server, $witem); + } +} + +sub self_check_init { + $max_results=30; + fork_search('linux','Freenode'); + Irssi::timeout_add_once(5*1000, 'sig_self_check',''); +} + +sub self_check_quit { + my ( $s )=@_; + Irssi::command("selfcheckhelperscript $s"); +} + +sub sig_self_check { + my ($min, $max); + # min result + $min=20; + if ( scalar @results >= $min) { + print "Results: ",scalar @results," check"; + } else { + print "Results: ",scalar @results," <$min fail"; + self_check_quit("Error: self check fail (result)"); + } + # result more pages + if ( $resultcount == scalar @results || $max_results == scalar @results ) { + print "Resultscount: $resultcount check"; + } else { + print "Resultscount: $resultcount fail"; + self_check_quit("Error: self check fail (pages)"); + } + $max_results= Irssi::settings_get_int($IRSSI{name}.'_max_results'); + # topic + $min= 1000; + $max= 0; + foreach my $n ( @results ) { + my $l = length ( $n->{topic} ); + $min = $l if ($l < $min); + $max = $l if ($l > $max); + } + if ( $min != $max && $max >200 ) { + print "Topic min:$min max:$max check"; + } else { + print "Topic min:$min max:$max"; + self_check_quit("Error: self check fail (topic)"); + } + # users + $min= 10000; + $max= 0; + foreach my $n ( @results ) { + my $l = $n->{users} ; + $min = $l if ($l < $min); + $max = $l if ($l > $max); + } + if ( $min != $max && $max >200 ) { + print "Users min:$min max:$max check"; + } else { + print "Users min:$min max:$max"; + self_check_quit("Error: self check fail (users)"); + } + self_check_quit('ok'); +} + +sub sig_setup_changed { + $default_network= Irssi::settings_get_str($IRSSI{name}.'_default_network'); + $max_results= Irssi::settings_get_int($IRSSI{name}.'_max_results'); + $max_columns= Irssi::settings_get_int($IRSSI{name}.'_max_columns'); +} + +sub cmd_help { + my ($args, $server, $witem)=@_; + $args=~ s/\s+//g; + if (lc($IRSSI{name}) eq lc($args)) { + Irssi::print($help, MSGLEVEL_CLIENTCRAP); + Irssi::signal_stop(); + } +} + +Irssi::settings_add_str($IRSSI{name}, $IRSSI{name}.'_default_network', 'freenode' ); +Irssi::settings_add_int($IRSSI{name}, $IRSSI{name}.'_max_results', 50 ); +Irssi::settings_add_int($IRSSI{name}, $IRSSI{name}.'_max_columns', 0 ); + +Irssi::signal_add('setup changed', "sig_setup_changed"); + +Irssi::command_bind('chansearch', \&cmd_chansearch); +Irssi::command_set_options('chansearch', 'network check'); +Irssi::command_bind('help', \&cmd_help); + +sig_setup_changed(); + +print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded'; + +# vim:set sw=4 ts=8: |