# # Copyright (c) 2011/12 by Nils Görs # # will load/reload/unload script (language independent) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Development is currently hosted at # https://github.com/weechatter/weechat-scripts # # History: # 2012-08-14: nils_2 : # version 1.3: add: recognition of new script-plugin # 2012-03-24: nils_2 : # version 1.2: fix: invalid pointer for function infolist_get() # 2012-02-11: nils_2 : # version 1.1: fix: rephrase of text output # 2012-02-06: nils_2 : # version 1.0: complete rewrite of script. # : add: multi-script capability # 2012-01-29: nils_2 : # version 0.7: add; confirmation for auto(un)load option and error messages added # : fix: not installed script was loaded using option "unload" # : fix: script with full pathname wasn't loaded from a different path than homepath # 2012-01-17: nils_2 : # version 0.6: fix: a error message appeared when "autoload" was used with already installed script # 2011-11-05: nils_2 : # version 0.5: added: support for guile script # : added: option "force_reload" (default: off) # 2011-09-08: Banton & nils_2: # version 0.4: added: auto(un)load (by Banton) # : added: options autoload_load and autounload_unload # : added: plugin description # : WeeChat error message occurs twice when a script was loaded # : invalid command will be catched. # 2011-09-08: nils_2 : # version 0.3: added: command force_reload (idea by FiXato) # : script extension in function "list" added (idea by FlashCode) # 2011-09-06: Banton@freenode.#weechat: # version 0.2: added: completion for "/script load" # 2011-08-21: nils_2 : # version 0.1: proof-of-concept # # Development is currently hosted at # https://github.com/weechatter/weechat-scripts use strict; use File::Basename; my $PRGNAME = "script"; my $VERSION = "1.3"; my $AUTHOR = "Nils Görs "; my $LICENCE = "GPL3"; my $DESCR = "to load/reload/unload script (language independent) and also to create/remove symlink"; # internal values my $weechat_version = ""; my $home_dir = ""; my %script_suffix = ( "python_script" => ".py", "perl_script" => ".pl", "ruby_script" => ".rb", "tcl_script" => ".tcl", "lua_script" => ".lua", "guile_script" => ".scm", ); my %script_counter= ( "python_script" => 0, "perl_script" => 0, "ruby_script" => 0, "tcl_script" => 0, "lua_script" => 0, "guile_script" => 0, ); # default values my %options = ("autoload_load" => ["off","load script after a symlink was created (default: off)"], "autounload_unload" => ["off","unload script after a symlink was removed (default: off)"], "force_reload" => ["off","load the given script, if script is not installed and command \"reload\" is used (default: off)"], ); # -----------------------------[ main commands ]----------------------------------- sub list_scripts { my $str = ""; my $color1 = weechat::color(weechat::config_color(weechat::config_get("weechat.color.chat_buffer"))); my $color_reset = weechat::color("reset"); foreach my $script_suffix (keys %script_suffix){ $script_counter{$script_suffix} = 0; my $infolist = weechat::infolist_get($script_suffix,"",""); while (weechat::infolist_next($infolist)) { my $name = weechat::infolist_string($infolist, "name"); my $version = weechat::infolist_string($infolist, "version"); my $description = weechat::infolist_string($infolist, "description"); my $output = sprintf("%s %s%s %s %s - %s",$color1,$name,$script_suffix{$script_suffix},$color_reset,$version,$description); $script_counter{$script_suffix} ++; weechat::print("",$output); } weechat::infolist_free($infolist); } my $total = 0; while (my ($script,$count) = each (%script_counter)) { $total = $total + $count; $str .= $color1 . $script . ": " . $color_reset . $count . ", "; } weechat::print("","\n" . $str . $color1 . "total: " . $color_reset . $total); } sub load_script { my ($command,$script,$mute,$all) = ($_[0],$_[1],$_[2],$_[3]); my $short_script_name = check_if_script_is_installed($script); if ( $short_script_name eq "" ) # script not installed! { my $execute_command = script_loader($command,$script,$mute,$all); if ( $execute_command eq "" ) { weechat::print("",weechat::prefix("error")."$PRGNAME: \"$command\" error. script with name \"$script\" not found.") if ($mute ne "-mute"); return; } weechat::command("","/wait 1ms $execute_command"); }else { weechat::print("",weechat::prefix("error")."$PRGNAME: \"$command\" error. script with name \"$short_script_name\" already installed. use: /$PRGNAME reload $short_script_name") if ($mute ne "-mute"); } } sub reload_script { my ($command,$script,$mute,$all,$force) = ($_[0],$_[1],$_[2],$_[3],$_[4]); if ( $script eq "-all" or $all eq "-all") { script_re_unload_cb($command,"",$mute,$all); return; } my $short_script_name = check_if_script_is_installed($script); if ( $short_script_name eq "" ) # script not installed! { if ( $options{force_reload}[0] eq "on" or $force eq "-force") # use force_reload ?? { $command = "load"; my $execute_command = script_loader($command,$script,$mute,$all); if ( $execute_command ne "" ) { # weechat::print("","command: $command script: $script exe: $execute_command"); weechat::command("","/wait 1ms $execute_command"); }else { $short_script_name = $script if ( $short_script_name eq "" ); weechat::print("",weechat::prefix("error")."$PRGNAME: \"$command\" error. script with name \"$short_script_name\" not found."); } }else { weechat::print("",weechat::prefix("error")."$PRGNAME: \"$command\" error. script \"$script\" not loaded. You should either use \"/$PRGNAME load $script\" or use the \"-force\" argument."); } }else # reload script! { my $execute_command = script_re_unload_cb($command,$short_script_name,$mute,$all); if ( $execute_command ne "" ) { # weechat::print("","command_reload: $command script: $script exe: $execute_command"); weechat::command("","/wait 1ms $execute_command"); } } } sub unload_script { my ($command,$script,$mute,$all,$force) = ($_[0],$_[1],$_[2],$_[3],$_[4]); if ( $script eq "-all" or $all eq "-all") { script_re_unload_cb($command,"",$mute,$all); return; } my $short_script_name = check_if_script_is_installed($script); if ( $short_script_name eq "" ) # script not installed! { weechat::print("",weechat::prefix("error")."$PRGNAME: \"$command\" error. script \"$script\" not installed.") if ($mute ne "-mute"); }else { my $execute_command = script_re_unload_cb($command,$short_script_name,$mute,$all); if ( $execute_command ne "" ) { # weechat::print("","command_unload: $command script: $script exe: $execute_command"); weechat::command("","/wait 1ms $execute_command"); } } } sub autoload_script { my ($command,$script,$mute,$all) = ($_[0],$_[1],$_[2],$_[3]); my @files = get_all_scripts("autoload"); unless ( grep m/\/$script(.pl|.py|.rb|.tcl|.lua|.scm)$/ig, @files) { weechat::print("",weechat::prefix("error") . "$PRGNAME: \"$script\" not found.") if ($mute ne "-mute"); return; } foreach my $filename (@files) { if ($filename =~ /\/$script(.pl|.py|.rb|.tcl|.lua|.scm)/) { if ( $command eq "autoload" ) { my $suffix = ($filename =~ m{([^.]+)$} )[0]; # get suffix $suffix = ($filename =~ m{.*Logger$})[0] unless($suffix); my (undef,$path) = fileparse $filename; # remove path # if symlink don't exists, create one. unless (-e $path . "/autoload/" . $script . "." . $suffix) { weechat::print("",weechat::prefix("error") . "script: \"$script\" will be auto loaded.") if ($mute ne "-mute"); symlink($filename , $path . "/autoload/" . $script . "." . $suffix) } if ( $options{autoload_load}[0] eq "on" ) { my $execute_command = ""; my $short_script_name = check_if_script_is_installed($script); if ( $short_script_name eq "" ) # script not installed! { $execute_command = script_loader("load",$script,$mute,$all); } if ( $execute_command ne "" ) { weechat::command("","/wait 1ms $execute_command"); } } } } } } sub autounload_script { my ($command,$script,$mute,$all) = ($_[0],$_[1],$_[2],$_[3]); my @files = get_all_scripts("autounload"); unless ( grep m/\/$script(.pl|.py|.rb|.tcl|.lua|.scm)$/ig, @files) { weechat::print("",weechat::prefix("error") . "$PRGNAME: symlink for \"$script\" not found.") if ($mute ne "-mute"); return; } foreach my $filename (@files) { if ($filename =~ /\/$script(.pl|.py|.rb|.tcl|.lua|.scm)/) { if ( $command eq "autounload" ) { my $suffix = ($filename =~ m{([^.]+)$} )[0]; # get suffix $suffix = ($filename =~ m{.*Logger$})[0] unless($suffix); my (undef,$path) = fileparse $filename; # remove path # if symlink exists, delete it. if (-e $path . $script . "." . $suffix) { unlink $path . $script . "." . $suffix; weechat::print("",weechat::prefix("error") . "script \"$script\" will no longer be auto loaded.") if ($mute ne "-mute"); } if ( $options{autounload_unload}[0] eq "on" ) { my $execute_command = ""; my $short_script_name = check_if_script_is_installed($script); if ( $short_script_name ne "" ) # script installed! { unload_script("unload",$script,$mute,$all); # unload script } } } } } } # -----------------------------[ subroutines ]----------------------------------- sub get_all_scripts { my $command = $_[0]; my $path; my @files; while (my ($plugin,$suffix) = each (%script_suffix)) { ($plugin,undef) = split(/_/,$plugin); $path = $home_dir . "/" . $plugin . "/*" .$suffix if ($command eq "autoload"); $path = $home_dir . "/" . $plugin . "/autoload" . "/*" .$suffix if ($command eq "autounload"); my @files_glob = glob($path); if (@files_glob ne "") { foreach my $filename (@files_glob) { push(@files,$filename); } } } return @files; } sub check_if_script_is_installed { my ( $script ) = ($_[0]); my $path = ""; if (index($script,"/") >= 0) # /path/to/script given? { ($script,$path) = fileparse $script; # remove path } $script =~ s/\.[^.]+$// if (index($script,"/") == -1); # delete suffix from scriptname if no "/" in name # check if script is already installed. foreach my $plugin (keys %script_suffix) { my $infolist = weechat::infolist_get( $plugin, "", $script ); weechat::infolist_next($infolist); my $script_found = weechat::infolist_string( $infolist, "name" ) eq $script; weechat::infolist_free($infolist); if ( $script_found eq "1" ) { return $script; } } return ""; } sub script_loader{ my ($command,$script,$mute,$all) = ($_[0],$_[1],$_[2],$_[3]); my $execute_command = ""; my %script_suffix_bak = %script_suffix; # full script path given by user if (index($script,"/") >= 0) { while (my ($plugin,$suffix) = each (%script_suffix_bak)) { my ($plugin,undef) = split(/_/,$plugin); if ( index($script,$suffix) >= 0 ) { $execute_command = "/$plugin $command $script" if ($mute eq ""); $execute_command = "/mute $plugin $command $script" if ($mute eq "-mute"); return ($execute_command); } } }else { my @files; $script =~ s/\.[^.]+$//; # delete suffix while (my ($plugin,$suffix) = each (%script_suffix_bak)){ my ($plugin,undef) = split(/_/,$plugin); @files = glob($home_dir . "/" . $plugin . "/*" .$suffix); foreach my $file (@files) { if ( index($file,$script . $suffix) ne "-1" ) { $execute_command = "/$plugin $command $script"."$suffix" if ($mute eq ""); $execute_command = "/mute $plugin $command $script"."$suffix" if ($mute eq "-mute"); return ($execute_command); } } } } return $execute_command; } sub script_re_unload_cb { my ($command,$script,$mute,$all) = ($_[0],$_[1],$_[2],$_[3]); my $execute_command = ""; foreach my $script_suffix (keys %script_suffix) { my $infolist = weechat::infolist_get($script_suffix,"",""); while (weechat::infolist_next($infolist)){ my $name = weechat::infolist_string($infolist, "name"); if ( $all eq "-all"){ my ($plugin,undef) = split(/_/,$script_suffix); $execute_command = "/$plugin $command $name" if ($mute eq ""); $execute_command = "/mute $plugin $command $name" if ($mute eq "-mute"); # weechat::print("","/wait 1ms $execute_command"); weechat::command("","/wait 1ms $execute_command") if ( $execute_command ne ""); }elsif( lc($name) eq lc($script) ){ my ($plugin,undef) = split(/_/,$script_suffix); $execute_command = "/$plugin $command $name" if ($mute eq ""); $execute_command = "/mute $plugin $command $name" if ($mute eq "-mute"); last; } } weechat::infolist_free($infolist); } return $execute_command; } # -----------------------------[ command callback ]----------------------------------- sub my_command_cb { my ($getargs) = lc($_[2]); my $execute_command = ""; return weechat::WEECHAT_RC_OK if ($getargs eq ""); my @args=split(/ /, $getargs); my @commands = qw(list autoload autounload load reload unload); my $command = (grep /^$args[0]$/ig, @commands); # search for a command in first option # error checks... if ( $command == 0 ) { weechat::print("",weechat::prefix("error")."$PRGNAME: Yoda says: \"$args[0]\" is not a valid command. \“Do or do not... there is no try\”..."); return weechat::WEECHAT_RC_OK; } if ($args[0] eq "list") { list_scripts(); return weechat::WEECHAT_RC_OK; } if ( not defined $args[1] ) { weechat::print("",weechat::prefix("error")."$PRGNAME: \"$args[0]\" error. Obi-Wan says: You did not specified a script my young padawn..."); return weechat::WEECHAT_RC_OK; } # get additional options my $args_m = ""; my $args_a = ""; my $args_f = ""; $args_m = "-mute" if ( grep /^-mute$/i, @args ); $args_a = "-all" if ( grep /^-all$/i, @args ); $args_f = "-force" if ( grep /^-force$/i, @args ); my @script_array = grep !/(-all|-mute|-force)/, @args; # remove additional options from script list push @script_array, "-all" if ( $args_a eq "-all" ); my $i = 0; while ($i < $#script_array) { $i++; $args[1] = $script_array[$i]; $i = $#script_array if ( $args_a eq "-all" ); # load, unload, reload, autoload, autounload if ( $args[0] eq "load" ) { load_script($args[0],$args[1],$args_m,$args_a); }elsif ( $args[0] eq "reload" ) { reload_script($args[0],$args[1],$args_m,$args_a,$args_f); }elsif ( $args[0] eq "unload" ) { unload_script($args[0],$args[1],$args_m,$args_a,$args_f); }elsif ( $args[0] eq "autoload" ) { autoload_script($args[0],$args[1],$args_m,$args_a,$args_f); }elsif ( $args[0] eq "autounload" ) { autounload_script($args[0],$args[1],$args_m,$args_a,$args_f); } } return weechat::WEECHAT_RC_OK; } # -----------------------------[ completion callback ]----------------------------------- sub script_completion_cb { my ($data,$completion_item,$buffer,$completion) = ($_[0],$_[1],$_[2],$_[3]); my @files; while (my ($plugin,$suffix) = each (%script_suffix)){ my ($plugin,undef) = split(/_/,$plugin); @files = glob($home_dir . "/" . $plugin . "/*" .$suffix); foreach my $file (@files) { my $basename = basename($file, $suffix); weechat::hook_completion_list_add($completion, $basename, 0, weechat::WEECHAT_LIST_POS_SORT); } } return weechat::WEECHAT_RC_OK } # -----------------------------[ config ]----------------------------------- sub init_config { foreach my $option (keys %options){ if (!weechat::config_is_set_plugin($option)){ weechat::config_set_plugin($option, $options{$option}[0]); }else{ $options{$option}[0] = weechat::config_get_plugin($option); } if ( ($weechat_version ne "") && (weechat::info_get("version_number", "") >= 0x00030500) ){ weechat::config_set_desc_plugin($option, $options{$option}[1]); } } } sub toggle_config_by_set { my ($pointer, $name, $value) = @_; $name = substr($name, length("plugins.var.perl.$PRGNAME."), length($name)); $options{$name}[0] = lc($value); # insert a refresh here return weechat::WEECHAT_RC_OK; } # -------------------------------[ init ]------------------------------------- # first function called by a WeeChat-script. weechat::register($PRGNAME, $AUTHOR, $VERSION, $LICENCE, $DESCR, "", ""); $weechat_version = weechat::info_get("version_number", ""); $home_dir = weechat::info_get ("weechat_dir", ""); # check for script plugin... my $scrip_plugin = 0; my $infolist = weechat::infolist_get("plugin","","script"); weechat::infolist_next($infolist); $scrip_plugin = 1 if ( "script" eq weechat::infolist_string($infolist,"name")); weechat::infolist_free($infolist); if ($scrip_plugin == 1) { weechat::print("",weechat::prefix("error") . "script plugin is installed. No need to install script: $PRGNAME.pl. Script automatically removed..."); weechat::command("","/wait 1ms /script unload $PRGNAME".".pl"); } else { weechat::hook_command($PRGNAME, $DESCR, "load