1 # by Stefan "tommie" Tomanek
8 use vars
qw($VERSION %IRSSI);
9 $VERSION = '2003020803';
11 authors => 'Stefan \'tommie\' Tomanek',
12 contact => 'stefan@pico.ruhr.de',
13 name => 'scriptassist',
14 description => 'keeps your scripts on the cutting edge',
16 url => 'http://irssi.org/scripts/',
18 modules => 'Data::Dumper LWP::UserAgent (GnuPG)',
19 commands => "scriptassist"
22 use vars qw($forked %remote_db $have_gpg);
29 # GnuPG is not always needed
30 use vars qw($have_gpg @complist);
32 eval "use GnuPG qw(:algo :trust);";
33 $have_gpg = 1 if not ($@);
36 my $help = "scriptassist
$VERSION
38 Check all loaded scripts
for new available versions
39 /scriptassist update
<script
|all
>
40 Update the selected
or all script to the newest version
41 /scriptassist search
<query
>
42 Search the script database
43 /scriptassist info
<scripts
>
44 Display information about
<scripts
>
45 /scriptassist ratings
<scripts
>
46 Retrieve the average ratings of the the scripts
47 /scriptassist top
<num
>
48 Retrieve the first
<num
> top rated scripts
49 /scriptassist new
<num
>
50 Display the newest
<num
> scripts
51 /scriptassist rate
<script
> <stars
>
52 Rate the script with a number of stars ranging from
0-5
53 /scriptassist contact
<script
>
54 Write an email to the author of the script
56 /scriptassist cpan
<module
>
57 Visit CPAN to look
for missing Perl modules
59 /scriptassist install
<script
>
60 Retrieve
and load the script
61 /scriptassist autorun
<script
>
62 Toggles automatic loading of
<script
>
65 foreach (split(/\n/, $help)) {
66 $_ =~ s/^\/(.*)$/%9\/$1%9/;
69 print CLIENTCRAP &draw_box("ScriptAssist
", $text, "scriptassist help
", 1);
70 #theme_box("ScriptAssist
", $text, "scriptassist help
", 1);
73 sub theme_box ($$$$) {
74 my ($title, $text, $footer, $colour) = @_;
75 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'box_header', $title);
76 foreach (split(/\n/, $text)) {
77 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'box_inside', $_);
79 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'box_footer', $footer);
83 my ($title, $text, $footer, $colour) = @_;
85 $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n";
86 foreach (split(/\n/, $text)) {
87 $box .= '%R|%n '.$_."\n";
88 } $box .= '%R`--<%n'.$footer.'%R>->%n';
89 $box =~ s/%.//g unless $colour;
93 sub call_openurl ($) {
96 # check for a loaded openurl
97 if (defined %{ "Irssi
::Script
::openurl
::" }) {
98 &{ "Irssi
::Script
::openurl
::launch_url
" }($url);
100 print CLIENTCRAP "%R>>%n Please install openurl
.pl
";
110 print CLIENTCRAP "%R>>%n Please
wait until your earlier request has been finished
.";
116 print CLIENTCRAP "%R>>%n Please
wait...";
118 Irssi::pidwait_add($pid);
120 my @args = ($rh, \$pipetag, $func);
121 $pipetag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, \@args);
124 my @items = split(/ /, $func);
126 my $ts1 = $remote_db{timestamp};
127 my $xml = get_scripts();
128 my $ts2 = $remote_db{timestamp};
129 if (not($ts1 eq $ts2) && Irssi::settings_get_bool('scriptassist_cache_sources')) {
130 $result{db} = $remote_db{db};
131 $result{timestamp} = $remote_db{timestamp};
133 if ($items[0] eq 'check') {
134 $result{data}{check} = check_scripts($xml);
135 } elsif ($items[0] eq 'update') {
137 $result{data}{update} = update_scripts(\@items, $xml);
138 } elsif ($items[0] eq 'search') {
140 #$result{data}{search}{-foo} = 0;
142 $result{data}{search}{$_} = search_scripts($_, $xml);
144 } elsif ($items[0] eq 'install') {
146 $result{data}{install} = install_scripts(\@items, $xml);
147 } elsif ($items[0] eq 'debug') {
149 $result{data}{debug} = debug_scripts(\@items);
150 } elsif ($items[0] eq 'ratings') {
152 @items = @{ loaded_scripts() } if $items[0] eq "all
";
153 #$result{data}{rating}{-foo} = 1;
154 my %ratings = %{ get_ratings(\@items, '') };
155 foreach (keys %ratings) {
156 $result{data}{rating}{$_}{rating} = $ratings{$_}->[0];
157 $result{data}{rating}{$_}{votes} = $ratings{$_}->[1];
159 } elsif ($items[0] eq 'rate') {
160 #$result{data}{rate}{-foo} = 1;
161 $result{data}{rate}{$items[1]} = rate_script($items[1], $items[2]);
162 } elsif ($items[0] eq 'info') {
164 $result{data}{info} = script_info(\@items);
165 } elsif ($items[0] eq 'echo') {
166 $result{data}{echo} = 1;
167 } elsif ($items[0] eq 'top') {
168 my %ratings = %{ get_ratings([], $items[1]) };
169 foreach (keys %ratings) {
170 $result{data}{rating}{$_}{rating} = $ratings{$_}->[0];
171 $result{data}{rating}{$_}{votes} = $ratings{$_}->[1];
173 } elsif ($items[0] eq 'new') {
174 my $new = get_new($items[1]);
175 $result{data}{new} = $new;
176 } elsif ($items[0] eq 'unknown') {
178 $result{data}{unknown}{$cmd} = get_unknown($cmd, $xml);
180 my $dumper = Data::Dumper->new([\%result]);
181 $dumper->Purity(1)->Deepcopy(1)->Indent(0);
182 my $data = $dumper->Dump;
190 sub get_unknown ($$) {
192 foreach (keys %$db) {
193 next unless defined $db->{$_}{commands};
194 foreach my $item (split / /, $db->{$_}{commands}) {
195 return { $_ => $db->{$_} } if ($item =~ /^$cmd$/i);
201 sub script_info ($) {
205 my $xml = get_scripts();
206 foreach (@{$scripts}) {
207 next unless (defined $xml->{$_.".pl
"} || (defined %{ 'Irssi::Script::'.$_.'::' } && defined %{ 'Irssi::Script::'.$_.'::IRSSI' }));
208 $result{$_}{version} = get_remote_version($_, $xml);
209 my @headers = ('authors', 'contact', 'description', 'license', 'source');
210 foreach my $entry (@headers) {
211 $result{$_}{$entry} = ${ 'Irssi::Script::'.$_.'::IRSSI' }{$entry};
212 if (defined $xml->{$_.".pl
"}{$entry}) {
213 $result{$_}{$entry} = $xml->{$_.".pl
"}{$entry};
216 if ($xml->{$_.".pl
"}{signature_available}) {
217 $result{$_}{signature_available} = 1;
219 if (defined $xml->{$_.".pl
"}{modules}) {
220 my $modules = $xml->{$_.".pl
"}{modules};
221 #$result{$_}{modules}{-foo} = 1;
222 foreach my $mod (split(/ /, $modules)) {
223 my $opt = ($mod =~ /\((.*)\)/)? 1 : 0;
225 $result{$_}{modules}{$mod}{optional} = $opt;
226 $result{$_}{modules}{$mod}{installed} = module_exist($mod);
228 } elsif (defined ${ 'Irssi::Script::'.$_.'::IRSSI' }{modules}) {
229 my $modules = ${ 'Irssi::Script::'.$_.'::IRSSI' }{modules};
230 foreach my $mod (split(/ /, $modules)) {
231 my $opt = ($mod =~ /\((.*)\)/)? 1 : 0;
233 $result{$_}{modules}{$mod}{optional} = $opt;
234 $result{$_}{modules}{$mod}{installed} = module_exist($mod);
237 if (defined $xml->{$_.".pl
"}{depends}) {
238 my $depends = $xml->{$_.".pl
"}{depends};
239 foreach my $dep (split(/ /, $depends)) {
240 $result{$_}{depends}{$dep}{installed} = 1; #(defined ${ 'Irssi::Script::'.$dep });
247 sub rate_script ($$) {
248 my ($script, $stars) = @_;
249 my $ua = LWP::UserAgent->new(env_proxy=>1, keep_alive=>1, timeout=>30);
250 $ua->agent('ScriptAssist/'.$VERSION);
251 my $request = HTTP::Request->new('GET', 'http://ratings.irssi.de/irssirate.pl?&stars='.$stars.'&mode=rate&script='.$script);
252 my $response = $ua->request($request);
253 unless ($response->is_success() && $response->content() =~ /You already rated this script/) {
260 sub get_ratings ($$) {
261 my ($scripts, $limit) = @_;
262 my $ua = LWP::UserAgent->new(env_proxy=>1, keep_alive=>1, timeout=>30);
263 $ua->agent('ScriptAssist/'.$VERSION);
264 my $script = join(',', @{$scripts});
265 my $request = HTTP::Request->new('GET', 'http://ratings.irssi.de/irssirate.pl?script='.$script.'&sort=rating&limit='.$limit);
266 my $response = $ua->request($request);
268 if ($response->is_success()) {
269 foreach (split /\n/, $response->content()) {
270 if (/<tr><td><a href=".*?
">(.*?)<\/a>/) {
272 if (/"><\
/td
><td
>([0-9.]+)<\
/td><td>(.*?)<\/td
><td
>/) {
273 $result{$entry} = [$1, $2];
284 my $xml = get_scripts
();
285 foreach (sort {$xml->{$b}{last_modified
} cmp $xml->{$a}{last_modified
}} keys %$xml) {
286 my %entry = %{ $xml->{$_} };
287 $result->{$_} = \
%entry;
293 sub module_exist
($) {
295 $module =~ s/::/\//g
;
297 return 1 if (-e
$_."/".$module.".pm");
302 sub debug_scripts
($) {
305 foreach (@
{$scripts}) {
306 my $xml = get_scripts
();
307 if (defined $xml->{$_.".pl"}{modules
}) {
308 my $modules = $xml->{$_.".pl"}{modules
};
309 foreach my $mod (split(/ /, $modules)) {
310 my $opt = ($mod =~ /\((.*)\)/)?
1 : 0;
312 $result{$_}{$mod}{optional
} = $opt;
313 $result{$_}{$mod}{installed
} = module_exist
($mod);
320 sub install_scripts
($$) {
321 my ($scripts, $xml) = @_;
324 my $dir = Irssi
::get_irssi_dir
()."/scripts/";
325 foreach (@
{$scripts}) {
326 if (get_local_version
($_) && (-e
$dir.$_.".pl")) {
327 $success{$_}{installed
} = -2;
329 $success{$_} = download_script
($_, $xml);
335 sub update_scripts
($$) {
336 my ($list, $database) = @_;
337 $list = loaded_scripts
() if ($list->[0] eq "all" || scalar(@
$list) == 0);
341 my $local = get_local_version
($_);
342 my $remote = get_remote_version
($_, $database);
343 next if $local eq '' || $remote eq '';
344 if (compare_versions
($local, $remote) eq "older") {
345 $status{$_} = download_script
($_, $database);
347 $status{$_}{installed
} = -2;
349 $status{$_}{remote
} = $remote;
350 $status{$_}{local} = $local;
355 sub search_scripts
($$) {
356 my ($query, $database) = @_;
358 #$result{-foo} = " ";
359 foreach (sort keys %{$database}) {
360 my %entry = %{$database->{$_}};
362 $string .= $entry{description
} if defined $entry{description
};
363 if ($string =~ /$query/i) {
366 if (defined $entry{description
}) {
367 $result{$name}{desc
} = $entry{description
};
369 $result{$name}{desc
} = "";
371 if (defined $entry{authors
}) {
372 $result{$name}{authors
} = $entry{authors
};
374 $result{$name}{authors
} = "";
376 if (get_local_version
($name)) {
377 $result{$name}{installed
} = 1;
379 $result{$name}{installed
} = 0;
387 my ($rh, $pipetag) = @
{$_[0]};
390 Irssi
::input_remove
($$pipetag);
392 my $text = join("", @lines);
394 print CLIENTCRAP
"%R<<%n Something weird happend";
398 my $incoming = eval("$text");
399 if ($incoming->{db
} && $incoming->{timestamp
}) {
400 $remote_db{db
} = $incoming->{db
};
401 $remote_db{timestamp
} = $incoming->{timestamp
};
403 unless (defined $incoming->{data
}) {
404 print CLIENTCRAP
"%R<<%n Something weird happend";
407 my %result = %{ $incoming->{data
} };
409 if (defined $result{new
}) {
410 print_new
($result{new
});
411 push @complist, $_ foreach keys %{ $result{new
} };
413 if (defined $result{check
}) {
414 print_check
(%{$result{check
}});
415 push @complist, $_ foreach keys %{ $result{check
} };
417 if (defined $result{update
}) {
418 print_update
(%{ $result{update
} });
419 push @complist, $_ foreach keys %{ $result{update
} };
421 if (defined $result{search
}) {
422 foreach (keys %{$result{search
}}) {
423 print_search
($_, %{$result{search
}{$_}});
424 push @complist, keys(%{$result{search
}{$_}});
427 if (defined $result{install
}) {
428 print_install
(%{ $result{install
} });
429 push @complist, $_ foreach keys %{ $result{install
} };
431 if (defined $result{debug
}) {
432 print_debug
(%{ $result{debug
} });
434 if (defined $result{rating
}) {
435 print_ratings
(%{ $result{rating
} });
436 push @complist, $_ foreach keys %{ $result{rating
} };
438 if (defined $result{rate
}) {
439 print_rate
(%{ $result{rate
} });
441 if (defined $result{info
}) {
442 print_info
(%{ $result{info
} });
444 if (defined $result{echo
}) {
447 if ($result{unknown
}) {
448 print_unknown
($result{unknown
});
453 sub print_unknown
($) {
455 foreach my $cmd (keys %$data) {
456 print CLIENTCRAP
"%R<<%n No script provides '/$cmd'" unless $data->{$cmd};
457 foreach (keys %{ $data->{$cmd} }) {
458 my $text .= "The command '/".$cmd."' is provided by the script '".$data->{$cmd}{$_}{name
}."'.\n";
459 $text .= "This script is currently not installed on your system.\n";
460 $text .= "If you want to install the script, enter\n";
461 my ($name) = /(.*?)\.pl$/;
462 $text .= " %U/script install ".$name."%U ";
463 my $output = draw_box
("ScriptAssist", $text, "'".$_."' missing", 1);
464 print CLIENTCRAP
$output;
469 sub check_autorun
($) {
471 my $dir = Irssi
::get_irssi_dir
()."/scripts/";
472 if (-e
$dir."/autorun/".$script.".pl") {
473 if (readlink($dir."/autorun/".$script.".pl") eq "../".$script.".pl") {
483 foreach my $line (@array) {
484 for (0..scalar(@
$line)-1) {
488 $width[$_] = length($l) if $width[$_]<length($l);
492 foreach my $line (@array) {
493 for (0..scalar(@
$line)-1) {
495 $text .= $line->[$_];
498 $text .= " "x
($width[$_]-length($l)+1) unless ($_ == scalar(@
$line)-1);
509 foreach my $script (sort keys(%data)) {
510 my ($local, $autorun);
511 if (get_local_version
($script)) {
513 $local = get_local_version
($script);
518 if (defined $local || check_autorun
($script)) {
520 $autorun = "yes" if check_autorun
($script);
524 $line .= "%9".$script."%9\n";
525 $line .= " Version : ".$data{$script}{version
}."\n";
526 $line .= " Source : ".$data{$script}{source
}."\n";
527 $line .= " Installed : ".$local."\n" if defined $local;
528 $line .= " Autorun : ".$autorun."\n" if defined $autorun;
529 $line .= " Authors : ".$data{$script}{authors
};
530 $line .= " %Go-m signed%n" if $data{$script}{signature_available
};
532 $line .= " Contact : ".$data{$script}{contact
}."\n";
533 $line .= " Description: ".$data{$script}{description
}."\n";
534 $line .= "\n" if $data{$script}{modules
};
535 $line .= " Needed Perl modules:\n" if $data{$script}{modules
};
537 foreach (sort keys %{$data{$script}{modules
}}) {
538 if ( $data{$script}{modules
}{$_}{installed
} == 1 ) {
539 $line .= " %g->%n ".$_." (found)";
541 $line .= " %r->%n ".$_." (not found)";
543 $line .= " <optional>" if $data{$script}{modules
}{$_}{optional
};
546 #$line .= " Needed Irssi scripts:\n";
547 $line .= " Needed Irssi Scripts:\n" if $data{$script}{depends
};
548 foreach (sort keys %{$data{$script}{depends
}}) {
549 if ( $data{$script}{depends
}{$_}{installed
} == 1 ) {
550 $line .= " %g->%n ".$_." (loaded)";
552 $line .= " %r->%n ".$_." (not loaded)";
554 #$line .= " <optional>" if $data{$script}{depends}{$_}{optional};
558 print CLIENTCRAP draw_box
('ScriptAssist', $line, 'info', 1) ;
564 foreach my $script (sort keys(%data)) {
565 if ($data{$script}) {
566 $line .= "%go%n %9".$script."%9 has been rated";
568 $line .= "%ro%n %9".$script."%9 : Already rated this script";
571 print CLIENTCRAP draw_box
('ScriptAssist', $line, 'rating', 1) ;
574 sub print_ratings
(%) {
577 foreach my $script (sort {$data{$b}{rating
}<=>$data{$a}{rating
}} keys(%data)) {
579 if (get_local_version
($script)) {
584 push @line, "%9".$script."%9";
585 push @line, $data{$script}{rating
};
586 push @line, "[".$data{$script}{votes
}." votes]";
589 print CLIENTCRAP draw_box
('ScriptAssist', array2table
(@table), 'ratings', 1) ;
595 foreach (sort {$list->{$b}{last_modified
} cmp $list->{$a}{last_modified
}} keys %$list) {
597 my ($name) = /^(.*?)\.pl$/;
598 if (get_local_version
($name)) {
603 push @line, "%9".$name."%9";
604 push @line, $list->{$_}{last_modified
};
607 print CLIENTCRAP draw_box
('ScriptAssist', array2table
(@table), 'new scripts', 1) ;
610 sub print_debug
(%) {
613 foreach my $script (sort keys %data) {
614 $line .= "%ro%n %9".$script."%9 failed to load\n";
615 $line .= " Make sure you have the following perl modules installed:\n";
616 foreach (sort keys %{$data{$script}}) {
617 if ( $data{$script}{$_}{installed
} == 1 ) {
618 $line .= " %g->%n ".$_." (found)";
620 $line .= " %r->%n ".$_." (not found)\n";
621 $line .= " [This module is optional]\n" if $data{$script}{$_}{optional
};
622 $line .= " [Try /scriptassist cpan ".$_."]";
626 print CLIENTCRAP draw_box
('ScriptAssist', $line, 'debug', 1) ;
630 sub load_script
($) {
632 Irssi
::command
('script load '.$script);
635 sub print_install
(%) {
638 my ($crashed, @installed);
639 foreach my $script (sort keys %data) {
641 if ($data{$script}{installed
} == 1) {
643 if ($have_gpg && Irssi
::settings_get_bool
('scriptassist_use_gpg')) {
644 if ($data{$script}{signed
} >= 0) {
645 load_script
($script) unless (lc($script) eq lc($IRSSI{name
}));
650 load_script
($script) unless (lc($script) eq lc($IRSSI{name
}));
652 if (get_local_version
($script) && not lc($script) eq lc($IRSSI{name
})) {
653 $line .= "%go%n %9".$script."%9 installed\n";
654 push @installed, $script;
655 } elsif (lc($script) eq lc($IRSSI{name
})) {
656 $line .= "%yo%n %9".$script."%9 installed, please reload manually\n";
658 $line .= "%Ro%n %9".$script."%9 fetched, but unable to load\n";
659 $crashed .= $script." " unless $hacked;
661 if ($have_gpg && Irssi
::settings_get_bool
('scriptassist_use_gpg')) {
662 foreach (split /\n/, check_sig
($data{$script})) {
663 $line .= " ".$_."\n";
666 } elsif ($data{$script}{installed
} == -2) {
667 $line .= "%ro%n %9".$script."%9 already loaded, please try \"update\"\n";
668 } elsif ($data{$script}{installed
} <= 0) {
669 $line .= "%ro%n %9".$script."%9 not installed\n";
670 foreach (split /\n/, check_sig
($data{$script})) {
671 $line .= " ".$_."\n";
674 $line .= "%Ro%n %9".$script."%9 not found on server\n";
678 # Inspect crashed scripts
679 bg_do
("debug ".$crashed) if $crashed;
680 print CLIENTCRAP draw_box
('ScriptAssist', $text, 'install', 1);
681 list_sbitems
(\
@installed);
684 sub list_sbitems
($) {
687 foreach (@
$scripts) {
689 next unless defined %{ "Irssi::Script::${_}::" };
690 next unless defined %{ "Irssi::Script::${_}::IRSSI" };
691 my %header = %{ "Irssi::Script::${_}::IRSSI" };
692 next unless $header{sbitems
};
693 $text .= '%9"'.$_.'"%9 provides the following statusbar item(s):'."\n";
694 $text .= ' ->'.$_."\n" foreach (split / /, $header{sbitems
});
698 $text .= "Enter '/statusbar window add <item>' to add an item.";
699 print CLIENTCRAP draw_box
('ScriptAssist', $text, 'sbitems', 1);
705 my %trust = ( -1 => 'undefined',
711 if ($sig->{signed
} == 1) {
712 $line .= "Signature found from ".$sig->{sig
}{user
}."\n";
713 $line .= "Timestamp : ".$sig->{sig
}{date
}."\n";
714 $line .= "Fingerprint: ".$sig->{sig
}{fingerprint
}."\n";
715 $line .= "KeyID : ".$sig->{sig
}{keyid
}."\n";
716 $line .= "Trust : ".$trust{$sig->{sig
}{trust
}}."\n";
717 } elsif ($sig->{signed
} == -1) {
718 $line .= "%1Warning, unable to verify signature%n\n";
719 } elsif ($sig->{signed
} == 0) {
720 $line .= "%1No signature found%n\n" unless Irssi
::settings_get_bool
('scriptassist_install_unsigned_scripts');
725 sub print_search
($%) {
726 my ($query, %data) = @_;
728 foreach (sort keys %data) {
730 $line .= "%go%n" if $data{$_}{installed
};
731 $line .= "%yo%n" if not $data{$_}{installed
};
732 $line .= " %9".$_."%9 ";
733 $line .= $data{$_}{desc
};
734 $line =~ s/($query)/%U$1%U/gi;
735 $line .= ' ('.$data{$_}{authors
}.')';
736 $text .= $line." \n";
738 print CLIENTCRAP draw_box
('ScriptAssist', $text, 'search: '.$query, 1) ;
741 sub print_update
(%) {
745 my $verbose = Irssi
::settings_get_bool
('scriptassist_update_verbose');
746 foreach (sort keys %data) {
748 if ($data{$_}{installed
} == 1) {
749 my $local = $data{$_}{local};
750 my $remote = $data{$_}{remote
};
751 push @table, ['%yo%n', '%9'.$_.'%9', 'upgraded ('.$local.'->'.$remote.')'];
752 foreach (split /\n/, check_sig
($data{$_})) {
753 push @table, ['', '', $_];
755 if (lc($_) eq lc($IRSSI{name
})) {
756 push @table, ['', '', "%R%9Please reload manually%9%n"];
760 } elsif ($data{$_}{installed
} == 0 || $data{$_}{installed
} == -1) {
761 push @table, ['%yo%n', '%9'.$_.'%9', 'not upgraded'];
762 foreach (split /\n/, check_sig
($data{$_})) {
763 push @table, ['', '', $_];
765 } elsif ($data{$_}{installed
} == -2 && $verbose) {
766 my $local = $data{$_}{local};
767 push @table, ['%go%n', '%9'.$_.'%9', 'already at the latest version ('.$local.')'];
770 $text = array2table
(@table);
771 print CLIENTCRAP draw_box
('ScriptAssist', $text, 'update', 1) ;
774 sub contact_author
($) {
777 return unless defined %{ "Irssi::Script::${script}::" };
778 my %header = %{ "Irssi::Script::${script}::IRSSI" };
779 if (defined $header{contact
}) {
780 my @ads = split(/ |,/, $header{contact
});
781 my $address = $ads[0];
782 $address .= '?subject='.$script;
783 $address .= '_'.get_local_version
($script) if defined get_local_version
($script);
784 call_openurl
($address);
789 my $ua = LWP
::UserAgent
->new(env_proxy
=>1, keep_alive
=>1, timeout
=>30);
790 $ua->agent('ScriptAssist/'.$VERSION);
792 my @mirrors = split(/ /, Irssi
::settings_get_str
('scriptassist_script_sources'));
796 foreach my $site (@mirrors) {
797 my $request = HTTP
::Request
->new('GET', $site);
798 if ($remote_db{timestamp
}) {
799 $request->if_modified_since($remote_db{timestamp
});
801 my $response = $ua->request($request);
802 next unless $response->is_success;
804 my $data = $response->content();
806 if ($site =~ /(.*\/).+\
.(.+)/) {
811 #my @header = ('name', 'contact', 'authors', 'description', 'version', 'modules', 'last_modified');
812 if ($type eq 'dmp') {
814 my $new_db = eval "$data";
815 foreach (keys %$new_db) {
816 if (defined $sites_db{script
}{$_}) {
817 my $old = $sites_db{$_}{version
};
818 my $new = $new_db->{$_}{version
};
819 next if (compare_versions
($old, $new) eq 'newer');
821 #foreach my $key (@header) {
822 foreach my $key (keys %{ $new_db->{$_} }) {
823 next unless defined $new_db->{$_}{$key};
824 $sites_db{$_}{$key} = $new_db->{$_}{$key};
826 $sites_db{$_}{source
} = $src;
835 foreach (keys %{$remote_db{db
}}) {
836 foreach my $site (@sources) {
837 if ($remote_db{db
}{$_}{source
} eq $site) {
838 delete $remote_db{db
}{$_};
843 $remote_db{db
}{$_} = $sites_db{$_} foreach (keys %sites_db);
844 $remote_db{timestamp
} = time();
846 return $remote_db{db
};
849 sub get_remote_version
($$) {
850 my ($script, $database) = @_;
851 return $database->{$script.".pl"}{version
};
854 sub get_local_version
($) {
857 return unless defined %{ "Irssi::Script::${script}::" };
858 my $version = ${ "Irssi::Script::${script}::VERSION" };
862 sub compare_versions
($$) {
863 my ($ver1, $ver2) = @_;
864 my @ver1 = split /\./, $ver1;
865 my @ver2 = split /\./, $ver2;
866 #if (scalar(@ver2) != scalar(@ver1)) {
870 ### Special thanks to Clemens Heidinger
871 $cmp ||= $ver1[$_] <=> $ver2[$_] || $ver1[$_] cmp $ver2[$_] for 0..scalar(@ver2);
872 return 'newer' if $cmp == 1;
873 return 'older' if $cmp == -1;
880 foreach (sort grep(s/::$//, keys %Irssi::Script
::)) {
881 #my $name = ${ "Irssi::Script::${_}::IRSSI" }{name};
882 #my $version = ${ "Irssi::Script::${_}::VERSION" };
883 push @modules, $_;# if $name && $version;
892 #$versions{-foo} = 1;
893 foreach (@
{loaded_scripts
()}) {
894 my $remote = get_remote_version
($_, $data);
895 my $local = get_local_version
($_);
897 if ($local && $remote) {
898 $state = compare_versions
($local, $remote);
900 $state = 'noversion';
908 $versions{$_}{state} = $state;
909 $versions{$_}{remote
} = $remote;
910 $versions{$_}{local} = $local;
916 sub download_script
($$) {
917 my ($script, $xml) = @_;
919 my $site = $xml->{$script.".pl"}{source
};
920 $result{installed
} = 0;
922 my $dir = Irssi
::get_irssi_dir
();
923 my $ua = LWP
::UserAgent
->new(env_proxy
=> 1,keep_alive
=> 1,timeout
=> 30);
924 $ua->agent('ScriptAssist/'.$VERSION);
925 my $request = HTTP
::Request
->new('GET', $site.'/scripts/'.$script.'.pl');
926 my $response = $ua->request($request);
927 if ($response->is_success()) {
928 my $file = $response->content();
929 mkdir $dir.'/scripts/' unless (-e
$dir.'/scripts/');
931 open(F
, '>'.$dir.'/scripts/'.$script.'.pl.new');
934 if ($have_gpg && Irssi
::settings_get_bool
('scriptassist_use_gpg')) {
935 my $ua2 = LWP
::UserAgent
->new(env_proxy
=> 1,keep_alive
=> 1,timeout
=> 30);
936 $ua->agent('ScriptAssist/'.$VERSION);
937 my $request2 = HTTP
::Request
->new('GET', $site.'/signatures/'.$script.'.pl.asc');
938 my $response2 = $ua->request($request2);
939 if ($response2->is_success()) {
941 my $sig_dir = $dir.'/scripts/signatures/';
942 mkdir $sig_dir unless (-e
$sig_dir);
943 open(S
, '>'.$sig_dir.$script.'.pl.asc');
944 my $file2 = $response2->content();
949 # FIXME gpg needs two rounds to load the key
950 my $gpg = new GnuPG
();
952 $sig = $gpg->verify( file
=> $dir.'/scripts/'.$script.'.pl.new', signature
=> $sig_dir.$script.'.pl.asc' );
955 if (defined $sig->{user
}) {
956 $result{installed
} = 1;
958 $result{sig
}{$_} = $sig->{$_} foreach (keys %{$sig});
961 $result{installed
} = 0;
962 $result{signed
} = -1;
966 $result{installed
} = -1;
967 $result{installed
} = 1 if Irssi
::settings_get_bool
('scriptassist_install_unsigned_scripts');
971 $result{installed
} = -1;
972 $result{installed
} = 1 if Irssi
::settings_get_bool
('scriptassist_install_unsigned_scripts');
975 if ($result{installed
}) {
976 my $old_dir = "$dir/scripts/old/";
977 mkdir $old_dir unless (-e
$old_dir);
978 rename "$dir/scripts/$script.pl", "$old_dir/$script.pl.old" if -e
"$dir/scripts/$script.pl";
979 rename "$dir/scripts/$script.pl.new", "$dir/scripts/$script.pl";
984 sub print_check
(%) {
988 foreach (sort keys %data) {
989 my $state = $data{$_}{state};
990 my $remote = $data{$_}{remote
};
991 my $local = $data{$_}{local};
992 if (Irssi
::settings_get_bool
('scriptassist_check_verbose')) {
993 push @table, ['%go%n', '%9'.$_.'%9', 'Up to date. ('.$local.')'] if $state eq 'equal';
995 push @table, ['%mo%n', '%9'.$_.'%9', "No version information available on network."] if $state eq "noversion";
996 push @table, ['%mo%n', '%9'.$_.'%9', 'No header in script.'] if $state eq "noheader";
997 push @table, ['%bo%n', '%9'.$_.'%9', "Your version is newer (".$local."->".$remote.")"] if $state eq "newer";
998 push @table, ['%ro%n', '%9'.$_.'%9', "A new version is available (".$local."->".$remote.")"] if $state eq "older";;
1000 $text = array2table
(@table);
1001 print CLIENTCRAP draw_box
('ScriptAssist', $text, 'check', 1) ;
1004 sub toggle_autorun
($) {
1006 my $dir = Irssi
::get_irssi_dir
()."/scripts/";
1007 mkdir $dir."autorun/" unless (-e
$dir."autorun/");
1008 return unless (-e
$dir.$script.".pl");
1009 if (check_autorun
($script)) {
1010 if (readlink($dir."/autorun/".$script.".pl") eq "../".$script.".pl") {
1011 if (unlink($dir."/autorun/".$script.".pl")) {
1012 print CLIENTCRAP
"%R>>%n Autorun of ".$script." disabled";
1014 print CLIENTCRAP
"%R>>%n Unable to delete link";
1017 print CLIENTCRAP
"%R>>%n ".$dir."/autorun/".$script.".pl is not a correct link";
1020 symlink("../".$script.".pl", $dir."/autorun/".$script.".pl");
1021 print CLIENTCRAP
"%R>>%n Autorun of ".$script." enabled";
1025 sub sig_script_error
($$) {
1026 my ($script, $msg) = @_;
1027 return unless Irssi
::settings_get_bool
('scriptassist_catch_script_errors');
1028 if ($msg =~ /Can't locate (.*?)\.pm in \@INC \(\@INC contains:(.*?) at/) {
1030 $module =~ s/\//::/g
;
1031 missing_module
($module);
1035 sub missing_module
($$) {
1038 $text .= "The perl module %9".$module."%9 is missing on your system.\n";
1039 $text .= "Please ask your administrator about it.\n";
1040 $text .= "You can also check CPAN via '/scriptassist cpan ".$module."'.\n";
1041 print CLIENTCRAP
&draw_box
('ScriptAssist', $text, $module, 1);
1044 sub cmd_scripassist
($$$) {
1045 my ($arg, $server, $witem) = @_;
1046 my @args = split(/ /, $arg);
1047 if ($args[0] eq 'help' || $args[0] eq '-h') {
1049 } elsif ($args[0] eq 'check') {
1051 } elsif ($args[0] eq 'update') {
1053 bg_do
("update ".join(' ', @args));
1054 } elsif ($args[0] eq 'search' && defined $args[1]) {
1056 bg_do
("search ".join(" ", @args));
1057 } elsif ($args[0] eq 'install' && defined $args[1]) {
1059 bg_do
("install ".join(' ', @args));
1060 } elsif ($args[0] eq 'contact' && defined $args[1]) {
1061 contact_author
($args[1]);
1062 } elsif ($args[0] eq 'ratings' && defined $args[1]) {
1064 bg_do
("ratings ".join(' ', @args));
1065 } elsif ($args[0] eq 'rate' && defined $args[1] && defined $args[2]) {
1067 bg_do
("rate ".join(' ', @args)) if ($args[2] >= 0 && $args[2] < 6);
1068 } elsif ($args[0] eq 'info' && defined $args[1]) {
1070 bg_do
("info ".join(' ', @args));
1071 } elsif ($args[0] eq 'echo') {
1073 } elsif ($args[0] eq 'top') {
1074 my $number = defined $args[1] ?
$args[1] : 10;
1075 bg_do
("top ".$number);
1076 } elsif ($args[0] eq 'cpan' && defined $args[1]) {
1077 call_openurl
('http://search.cpan.org/search?mode=module&query='.$args[1]);
1078 } elsif ($args[0] eq 'autorun' && defined $args[1]) {
1079 toggle_autorun
($args[1]);
1080 } elsif ($args[0] eq 'new') {
1081 my $number = defined $args[1] ?
$args[1] : 5;
1082 bg_do
("new ".$number);
1086 sub sig_command_script_load
($$$) {
1087 my ($script, $server, $witem) = @_;
1089 $script = $2 if $script =~ /(.*\/)?
(.*?
)\
.pl
$/;
1090 if (defined %{ "Irssi::Script::${script}::" }) {
1091 if (defined &{ "Irssi::Script::${script}::pre_unload" }) {
1092 print CLIENTCRAP
"%R>>%n Triggering pre_unload function of $script...";
1093 &{ "Irssi::Script::${script}::pre_unload" }();
1098 sub sig_default_command
($$) {
1099 my ($cmd, $server) = @_;
1100 return unless Irssi
::settings_get_bool
("scriptassist_check_unknown_commands");
1101 bg_do
('unknown '.$cmd);
1104 sub sig_complete
($$$$$) {
1105 my ($list, $window, $word, $linestart, $want_space) = @_;
1106 return unless $linestart =~ /^.script(assist)? (install|rate|ratings|update|check|contact|info|autorun)/;
1109 foreach (@complist) {
1110 if ($_ =~ /^(\Q$str\E.*)?$/) {
1114 foreach (@
{loaded_scripts
()}) {
1115 push @newlist, $_ if /^(\Q$str\E.*)?$/;
1118 push @
$list, $_ foreach @newlist;
1119 Irssi
::signal_stop
();
1123 Irssi
::settings_add_str
($IRSSI{name
}, 'scriptassist_script_sources', 'http://www.irssi.org/scripts/scripts.dmp');
1124 Irssi
::settings_add_bool
($IRSSI{name
}, 'scriptassist_cache_sources', 1);
1125 Irssi
::settings_add_bool
($IRSSI{name
}, 'scriptassist_update_verbose', 1);
1126 Irssi
::settings_add_bool
($IRSSI{name
}, 'scriptassist_check_verbose', 1);
1127 Irssi
::settings_add_bool
($IRSSI{name
}, 'scriptassist_catch_script_errors', 1);
1129 Irssi
::settings_add_bool
($IRSSI{name
}, 'scriptassist_install_unsigned_scripts', 1);
1130 Irssi
::settings_add_bool
($IRSSI{name
}, 'scriptassist_use_gpg', 1);
1131 Irssi
::settings_add_bool
($IRSSI{name
}, 'scriptassist_integrate', 1);
1132 Irssi
::settings_add_bool
($IRSSI{name
}, 'scriptassist_check_unknown_commands', 1);
1134 Irssi
::signal_add_first
("default command", \
&sig_default_command
);
1135 Irssi
::signal_add_first
('complete word', \
&sig_complete
);
1136 Irssi
::signal_add_first
('command script load', \
&sig_command_script_load
);
1137 Irssi
::signal_add_first
('command script unload', \
&sig_command_script_load
);
1139 if (defined &Irssi
::signal_register
) {
1140 Irssi
::signal_register
({ 'script error' => [ 'Irssi::Script', 'string' ] });
1141 Irssi
::signal_add_last
('script error', \
&sig_script_error
);
1144 Irssi
::command_bind
('scriptassist', \
&cmd_scripassist
);
1146 Irssi
::theme_register
(['box_header', '%R,--[%n$*%R]%n',
1147 'box_inside', '%R|%n $*',
1148 'box_footer', '%R`--<%n$*%R>->%n',
1151 foreach my $cmd ( ( 'check', 'install', 'update', 'contact', 'search', '-h', 'help', 'ratings', 'rate', 'info', 'echo', 'top', 'cpan', 'autorun', 'new') ) {
1152 Irssi
::command_bind
('scriptassist '.$cmd => sub {
1153 cmd_scripassist
("$cmd ".$_[0], $_[1], $_[2]); });
1154 if (Irssi
::settings_get_bool
('scriptassist_integrate')) {
1155 Irssi
::command_bind
('script '.$cmd => sub {
1156 cmd_scripassist
("$cmd ".$_[0], $_[1], $_[2]); });
1160 print CLIENTCRAP
'%B>>%n '.$IRSSI{name
}.' '.$VERSION.' loaded: /scriptassist help for help';