From 7e7aa928072775240ff70ca61f2dd0e8a09242d8 Mon Sep 17 00:00:00 2001 From: Johannes Löthberg Date: Sun, 2 Feb 2014 20:35:42 +0100 Subject: (Let's pretend that this is the) initial commit --- weechat/perl/autoload/buffers.pl | 1 + weechat/perl/autoload/highmon.pl | 1 + weechat/perl/autoload/iset.pl | 1 + weechat/perl/autoload/stalker.pl | 1 + weechat/perl/autoload/yaurls.pl | 1 + weechat/perl/buffers.pl | 1200 ++++++++++++++++++++++++++++++++ weechat/perl/highmon.pl | 1064 ++++++++++++++++++++++++++++ weechat/perl/iset.pl | 1394 +++++++++++++++++++++++++++++++++++++ weechat/perl/stalker.pl | 1408 ++++++++++++++++++++++++++++++++++++++ weechat/perl/yaurls.pl | 301 ++++++++ 10 files changed, 5372 insertions(+) create mode 120000 weechat/perl/autoload/buffers.pl create mode 120000 weechat/perl/autoload/highmon.pl create mode 120000 weechat/perl/autoload/iset.pl create mode 120000 weechat/perl/autoload/stalker.pl create mode 120000 weechat/perl/autoload/yaurls.pl create mode 100644 weechat/perl/buffers.pl create mode 100644 weechat/perl/highmon.pl create mode 100644 weechat/perl/iset.pl create mode 100644 weechat/perl/stalker.pl create mode 100644 weechat/perl/yaurls.pl (limited to 'weechat/perl') diff --git a/weechat/perl/autoload/buffers.pl b/weechat/perl/autoload/buffers.pl new file mode 120000 index 0000000..445dc3c --- /dev/null +++ b/weechat/perl/autoload/buffers.pl @@ -0,0 +1 @@ +../buffers.pl \ No newline at end of file diff --git a/weechat/perl/autoload/highmon.pl b/weechat/perl/autoload/highmon.pl new file mode 120000 index 0000000..2eb5e1e --- /dev/null +++ b/weechat/perl/autoload/highmon.pl @@ -0,0 +1 @@ +../highmon.pl \ No newline at end of file diff --git a/weechat/perl/autoload/iset.pl b/weechat/perl/autoload/iset.pl new file mode 120000 index 0000000..2746e0d --- /dev/null +++ b/weechat/perl/autoload/iset.pl @@ -0,0 +1 @@ +../iset.pl \ No newline at end of file diff --git a/weechat/perl/autoload/stalker.pl b/weechat/perl/autoload/stalker.pl new file mode 120000 index 0000000..28bb788 --- /dev/null +++ b/weechat/perl/autoload/stalker.pl @@ -0,0 +1 @@ +../stalker.pl \ No newline at end of file diff --git a/weechat/perl/autoload/yaurls.pl b/weechat/perl/autoload/yaurls.pl new file mode 120000 index 0000000..c7dbf0c --- /dev/null +++ b/weechat/perl/autoload/yaurls.pl @@ -0,0 +1 @@ +../yaurls.pl \ No newline at end of file diff --git a/weechat/perl/buffers.pl b/weechat/perl/buffers.pl new file mode 100644 index 0000000..e315f80 --- /dev/null +++ b/weechat/perl/buffers.pl @@ -0,0 +1,1200 @@ +# +# Copyright (C) 2008-2012 Sebastien Helleu +# Copyright (C) 2011-2012 Nils G +# +# 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 . +# +# +# Display sidebar with list of buffers. +# +# History: +# +# 2012-10-18, nils_2@freenode.#weechat: +# v3.8: add option "mark_inactive", to mark buffers you are not in (idea by xrdodrx) +# : add wildcard "*" for immune_detach_buffers (idea by StarWeaver) +# : add new options "detach_query" and "detach_free_content" (idea by StarWeaver) +# 2012-10-06, Nei : +# v3.7: call menu on right mouse if menu script is loaded. +# 2012-10-06, nils_2 : +# v3.6: add new option "hotlist_counter" (idea by torque). +# 2012-06-02, nils_2 : +# v3.5: add values "server|channel|private|all|keepserver|none" to option "hide_merged_buffers" (suggested by dominikh). +# 2012-05-25, nils_2 : +# v3.4: add new option "show_lag". +# 2012-04-07, Sebastien Helleu : +# v3.3: fix truncation of wide chars in buffer name (option name_size_max) (bug #36034) +# 2012-03-15, nils_2 : +# v3.2: add new option "detach"(weechat >= 0.3.8) +# add new option "immune_detach_buffers" (requested by Mkaysi) +# add new function buffers_whitelist add|del|reset (suggested by FiXato) +# add new function buffers_detach add|del|reset +# 2012-03-09, Sebastien Helleu : +# v3.1: fix reload of config file +# 2012-01-29, nils_2 : +# v3.0: fix: buffers did not update directly during window_switch (reported by FiXato) +# 2012-01-29, nils_2 : +# v2.9: add options "name_size_max" and "name_crop_suffix" +# 2012-01-08, nils_2 : +# v2.8: fix indenting for option "show_number off" +# fix unset of buffer activity in hotlist when buffer was moved with mouse +# add buffer with free content and core buffer sorted first (suggested by nyuszika7h) +# add options queries_default_fg/bg and queries_message_fg/bg (suggested by FiXato) +# add clicking with left button on current buffer will do a jump_previously_visited_buffer (suggested by FiXato) +# add clicking with right button on current buffer will do a jump_next_visited_buffer +# add additional informations in help texts +# add default_fg and default_bg for whitelist channels +# internal changes (script is now 3Kb smaller) +# 2012-01-04, Sebastien Helleu : +# v2.7: fix regex lookup in whitelist buffers list +# 2011-12-04, nils_2 : +# v2.6: add own config file (buffers.conf) +# add new behavior for indenting (under_name) +# add new option to set different color for server buffers and buffers with free content +# 2011-10-30, nils_2 : +# v2.5: add new options "show_number_char" and "color_number_char", +# add help-description for options +# 2011-08-24, Sebastien Helleu : +# v2.4: add mouse support +# 2011-06-06, nils_2 : +# v2.3: added: missed option "color_whitelist_default" +# 2011-03-23, Sebastien Helleu : +# v2.2: fix color of nick prefix with WeeChat >= 0.3.5 +# 2011-02-13, nils_2 : +# v2.1: add options "color_whitelist_*" +# 2010-10-05, Sebastien Helleu : +# v2.0: add options "sort" and "show_number" +# 2010-04-12, Sebastien Helleu : +# v1.9: replace call to log() by length() to align buffer numbers +# 2010-04-02, Sebastien Helleu : +# v1.8: fix bug with background color and option indenting_number +# 2010-04-02, Helios : +# v1.7: add indenting_number option +# 2010-02-25, m4v : +# v1.6: add option to hide empty prefixes +# 2010-02-12, Sebastien Helleu : +# v1.5: add optional nick prefix for buffers like IRC channels +# 2009-09-30, Sebastien Helleu : +# v1.4: remove spaces for indenting when bar position is top/bottom +# 2009-06-14, Sebastien Helleu : +# v1.3: add option "hide_merged_buffers" +# 2009-06-14, Sebastien Helleu : +# v1.2: improve display with merged buffers +# 2009-05-02, Sebastien Helleu : +# v1.1: sync with last API changes +# 2009-02-21, Sebastien Helleu : +# v1.0: remove timer used to update bar item first time (not needed any more) +# 2009-02-17, Sebastien Helleu : +# v0.9: fix bug with indenting of private buffers +# 2009-01-04, Sebastien Helleu : +# v0.8: update syntax for command /set (comments) +# 2008-10-20, Jiri Golembiovsky : +# v0.7: add indenting option +# 2008-10-01, Sebastien Helleu : +# v0.6: add default color for buffers, and color for current active buffer +# 2008-09-18, Sebastien Helleu : +# v0.5: fix color for "low" level entry in hotlist +# 2008-09-18, Sebastien Helleu : +# v0.4: rename option "show_category" to "short_names", +# remove option "color_slash" +# 2008-09-15, Sebastien Helleu : +# v0.3: fix bug with priority in hotlist (var not defined) +# 2008-09-02, Sebastien Helleu : +# v0.2: add color for buffers with activity and config options for +# colors, add config option to display/hide categories +# 2008-03-15, Sebastien Helleu : +# v0.1: script creation +# +# Help about settings: +# display all settings for script (or use iset.pl script to change settings): +# /set buffers* +# show help text for option buffers.look.whitelist_buffers: +# /help buffers.look.whitelist_buffers +# +# Mouse-support (standard key bindings): +# left mouse-button: +# - click on a buffer to switch to selected buffer +# - click on current buffer will do action jump_previously_visited_buffer +# - drag a buffer and drop it on another position will move the buffer to position +# right mouse-button: +# - click on current buffer will do action jump_next_visited_buffer +# - moving buffer to the left/right will close buffer. +# + +use strict; +use Encode qw( decode encode ); +# -------------------------------[ internal ]------------------------------------- +my $version = "3.8"; + +my $BUFFERS_CONFIG_FILE_NAME = "buffers"; +my $buffers_config_file; +my $cmd_buffers_whitelist= "buffers_whitelist"; +my $cmd_buffers_detach = "buffers_detach"; + +my %mouse_keys = ("\@item(buffers):button1*" => "hsignal:buffers_mouse", # catch all left mouse button gestures + "\@item(buffers):button2*" => "hsignal:buffers_mouse"); # catch all right mouse button gestures +my %options; +my %hotlist_level = (0 => "low", 1 => "message", 2 => "private", 3 => "highlight"); +my @whitelist_buffers = (); +my @immune_detach_buffers= (); +my @buffers_focus = (); +my %buffers_timer = (); +my %Hooks = (); + +# --------------------------------[ init ]-------------------------------------- +weechat::register("buffers", "Sebastien Helleu ", $version, + "GPL3", "Sidebar with list of buffers", "", ""); +my $weechat_version = weechat::info_get("version_number", "") || 0; + +buffers_config_init(); +buffers_config_read(); + +weechat::bar_item_new("buffers", "build_buffers", ""); +weechat::bar_new("buffers", "0", "0", "root", "", "left", "horizontal", + "vertical", "0", "0", "default", "default", "default", "1", + "buffers"); +weechat::hook_signal("buffer_*", "buffers_signal_buffer", ""); +weechat::hook_signal("window_switch", "buffers_signal_buffer", ""); +weechat::hook_signal("hotlist_*", "buffers_signal_hotlist", ""); +weechat::hook_signal("window_switch", "buffers_signal_buffer", ""); +#weechat::hook_command_run("/input switch_active_*", "buffers_signal_buffer", ""); +weechat::bar_item_update("buffers"); +if ($weechat_version >= 0x00030600) +{ + weechat::hook_focus("buffers", "buffers_focus_buffers", ""); + weechat::hook_hsignal("buffers_mouse", "buffers_hsignal_mouse", ""); + weechat::key_bind("mouse", \%mouse_keys); +} + +weechat::hook_command( $cmd_buffers_whitelist, + "add/del current buffer to/from buffers whitelist", + "[add] || [del] || [reset]", + + " add: add current buffer in configuration file\n". + " del: delete current buffer from configuration file\n". + "reset: reset all buffers from configuration file (no confirmation!)\n\n". + "Examples:\n". + "/$cmd_buffers_whitelist add\n", + "add %-||". + "del %-||". + "reset %-", + "buffers_cmd_whitelist", ""); +weechat::hook_command( $cmd_buffers_detach, + "add/del current buffer to/from buffers detach", + "[add] || [del] || [reset]", + + " add: add current buffer in configuration file\n". + " del: delete current buffer from configuration file\n". + "reset: reset all buffers from configuration file (no confirmation!)\n\n". + "Examples:\n". + "/$cmd_buffers_detach add\n", + "add %-||". + "del %-||". + "reset %-", + "buffers_cmd_detach", ""); + +if ($weechat_version >= 0x00030800) +{ + weechat::hook_config("buffers.look.detach", "hook_timer_detach", ""); +} + + weechat::hook_config("buffers.look.show_lag", "hook_timer_lag", ""); + +# -------------------------------- [ command ] -------------------------------- +sub buffers_cmd_whitelist +{ +my ( $data, $buffer, $args ) = @_; + $args = lc($args); + my $buffers_whitelist = weechat::config_string( weechat::config_get("buffers.look.whitelist_buffers") ); + return weechat::WEECHAT_RC_OK if ( $buffers_whitelist eq "" and $args eq "del" or $buffers_whitelist eq "" and $args eq "reset" ); + my @buffers_list = split( /,/, $buffers_whitelist ); + # get buffers name + my $infolist = weechat::infolist_get("buffer", weechat::current_buffer(), ""); + weechat::infolist_next($infolist); + my $buffers_name = weechat::infolist_string($infolist, "name"); + weechat::infolist_free($infolist); + return weechat::WEECHAT_RC_OK if ( $buffers_name eq "" ); # should never happen + + if ( $args eq "add" ) + { + return weechat::WEECHAT_RC_OK if ( grep /^$buffers_name$/, @buffers_list ); # check if buffer already in list + push @buffers_list,( $buffers_name ); + my $buffers_list = &create_whitelist(\@buffers_list); + weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), $buffers_list,1 ); + weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" added to buffers whitelist"); + } + elsif ( $args eq "del" ) + { + return weechat::WEECHAT_RC_OK unless ( grep /^$buffers_name$/, @buffers_list ); # check if buffer is in list + @buffers_list = grep {$_ ne $buffers_name} @buffers_list; # delete entry + my $buffers_list = &create_whitelist(\@buffers_list); + weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), $buffers_list,1 ); + weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" deleted from buffers whitelist"); + } + elsif ( $args eq "reset" ) + { + return weechat::WEECHAT_RC_OK if ( $buffers_whitelist eq "" ); + weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), "",1 ); + weechat::print(weechat::current_buffer(), "buffers whitelist is empty, now..."); + } + return weechat::WEECHAT_RC_OK; +} +sub buffers_cmd_detach +{ +my ( $data, $buffer, $args ) = @_; + $args = lc($args); + my $immune_detach_buffers = weechat::config_string( weechat::config_get("buffers.look.immune_detach_buffers") ); + return weechat::WEECHAT_RC_OK if ( $immune_detach_buffers eq "" and $args eq "del" or $immune_detach_buffers eq "" and $args eq "reset" ); + my @buffers_list = split( /,/, $immune_detach_buffers ); + # get buffers name + my $infolist = weechat::infolist_get("buffer", weechat::current_buffer(), ""); + weechat::infolist_next($infolist); + my $buffers_name = weechat::infolist_string($infolist, "name"); + weechat::infolist_free($infolist); + return weechat::WEECHAT_RC_OK if ( $buffers_name eq "" ); # should never happen + + if ( $args eq "add" ) + { + return weechat::WEECHAT_RC_OK if ( grep /^$buffers_name$/, @buffers_list ); # check if buffer already in list + push @buffers_list,( $buffers_name ); + my $buffers_list = &create_whitelist(\@buffers_list); + weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), $buffers_list,1 ); + weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" added to immune detach buffers"); + } + elsif ( $args eq "del" ) + { + return weechat::WEECHAT_RC_OK unless ( grep /^$buffers_name$/, @buffers_list ); # check if buffer is in list + @buffers_list = grep {$_ ne $buffers_name} @buffers_list; # delete entry + my $buffers_list = &create_whitelist(\@buffers_list); + weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), $buffers_list,1 ); + weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" deleted from immune detach buffers"); + } + elsif ( $args eq "reset" ) + { + return weechat::WEECHAT_RC_OK if ( $immune_detach_buffers eq "" ); + weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), "",1 ); + weechat::print(weechat::current_buffer(), "immune detach buffers is empty, now..."); + } + return weechat::WEECHAT_RC_OK; +} +sub create_whitelist +{ + my @buffers_list = @{$_[0]}; + my $buffers_list = ""; + foreach (@buffers_list) + { + $buffers_list .= $_ .","; + } + chop $buffers_list; # remove last "," + return $buffers_list; +} + +# -------------------------------- [ config ] -------------------------------- +sub hook_timer_detach +{ + my $detach = $_[2]; + if ( $detach eq 0 ) + { + weechat::unhook($Hooks{timer_detach}) if $Hooks{timer_detach}; + $Hooks{timer_detach} = ""; + } + else + { + weechat::unhook($Hooks{timer_detach}) if $Hooks{timer_detach}; + $Hooks{timer_detach} = weechat::hook_timer( weechat::config_integer( $options{"detach"}) * 1000, 60, 0, "buffers_signal_buffer", ""); + } + weechat::bar_item_update("buffers"); + return weechat::WEECHAT_RC_OK; +} + +sub hook_timer_lag +{ + my $lag = $_[2]; + if ( $lag eq 0 ) + { + weechat::unhook($Hooks{timer_lag}) if $Hooks{timer_lag}; + $Hooks{timer_lag} = ""; + } + else + { + weechat::unhook($Hooks{timer_lag}) if $Hooks{timer_lag}; + $Hooks{timer_lag} = weechat::hook_timer( weechat::config_integer(weechat::config_get("irc.network.lag_refresh_interval")) * 1000, 0, 0, "buffers_signal_hotlist", ""); + } + weechat::bar_item_update("buffers"); + return weechat::WEECHAT_RC_OK; +} + +sub buffers_config_read +{ + return weechat::config_read($buffers_config_file) if ($buffers_config_file ne ""); +} +sub buffers_config_write +{ + return weechat::config_write($buffers_config_file) if ($buffers_config_file ne ""); +} +sub buffers_config_reload_cb +{ + my ($data,$config_file) = ($_[0], $_[1]); + return weechat::config_reload($config_file) +} +sub buffers_config_init +{ + $buffers_config_file = weechat::config_new($BUFFERS_CONFIG_FILE_NAME,"buffers_config_reload_cb",""); + return if ($buffers_config_file eq ""); + +my %default_options_color = +("color_current_fg" => ["current_fg", "color", "foreground color for current buffer", "", 0, 0,"lightcyan", "lightcyan", 0, "", "","buffers_signal_config", "", "", ""], + "color_current_bg" => ["current_bg", "color", "background color for current buffer", "", 0, 0,"red", "red", 0, "", "","buffers_signal_config", "", "", ""], + "color_default_fg" => ["default_fg", "color", "default foreground color for buffer name", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "color_default_bg" => ["default_bg", "color", "default background color for buffer name", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "color_hotlist_highlight_fg" => ["hotlist_highlight_fg", "color", "change foreground color of buffer name if a highlight messaged received","", 0, 0,"magenta", "magenta", 0, "", "","buffers_signal_config", "", "", ""], + "color_hotlist_highlight_bg" => ["hotlist_highlight_bg", "color", "change background color of buffer name if a highlight messaged received", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "color_hotlist_low_fg" => ["hotlist_low_fg", "color", "change foreground color of buffer name if a low message received", "", 0, 0,"white", "white", 0, "", "","buffers_signal_config", "", "", ""], + "color_hotlist_low_bg" => ["hotlist_low_bg", "color", "change background color of buffer name if a low message received", "", 0, 0, + "default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "color_hotlist_message_fg" => ["hotlist_message_fg", "color", "change foreground color of buffer name if a normal message received", "", 0, 0,"yellow", "yellow", 0, "", "","buffers_signal_config", "", "", ""], + "color_hotlist_message_bg" => ["hotlist_message_bg", "color", "change background color of buffer name if a normal message received", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "color_hotlist_private_fg" => ["hotlist_private_fg", "color", "change foreground color of buffer name if a private message received", "", 0, 0,"lightgreen", "lightgreen", 0, "", "","buffers_signal_config", "", "", ""], + "color_hotlist_private_bg" => ["hotlist_private_bg", "color", "change background color of buffer name if a private message received", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "color_number" => ["number", "color", "color for buffer number", "", 0, 0,"lightgreen", "lightgreen", 0, "", "","buffers_signal_config", "", "", ""], + "color_number_char" => ["number_char", "color", "color for buffer number char", "", 0, 0,"lightgreen", "lightgreen", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_default_fg" => ["whitelist_default_fg", "color", "default foreground color for whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_default_bg" => ["whitelist_default_bg", "color", "default background color for whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_low_fg" => ["whitelist_low_fg", "color", "low color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_low_bg" => ["whitelist_low_bg", "color", "low color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_message_fg" => ["whitelist_message_fg", "color", "message color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_message_bg" => ["whitelist_message_bg", "color", "message color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_private_fg" => ["whitelist_private_fg", "color", "private color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_private_bg" => ["whitelist_private_bg", "color", "private color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_highlight_fg" => ["whitelist_highlight_fg", "color", "highlight color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_whitelist_highlight_bg" => ["whitelist_highlight_bg", "color", "highlight color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""], + "color_none_channel_fg" => ["none_channel_fg", "color", "foreground color for none channel buffer (e.g.: core/server/plugin buffer)", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "color_none_channel_bg" => ["none_channel_bg", "color", "background color for none channel buffer (e.g.: core/server/plugin buffer)", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "queries_default_fg" => ["queries_default_fg", "color", "foreground color for query buffer without message", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "queries_default_bg" => ["queries_default_bg", "color", "background color for query buffer without message", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "queries_message_fg" => ["queries_message_fg", "color", "foreground color for query buffer with unread message", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "queries_message_bg" => ["queries_message_bg", "color", "background color for query buffer with unread message", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "queries_highlight_fg" => ["queries_highlight_fg", "color", "foreground color for query buffer with unread highlight", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], + "queries_highlight_bg" => ["queries_highlight_bg", "color", "background color for query buffer with unread highlight", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""], +); + +my %default_options_look = +( + "hotlist_counter" => ["hotlist_counter","boolean","show number of message for the buffer (this option needs WeeChat >= 0.3.5). The relevant option for notification is \"weechat.look.buffer_notify_default\"","",0,0,"off","off",0,"","","buffers_signal_config","","",""], + "show_lag" => ["show_lag","boolean","show lag behind servername. This option is using \"irc.color.item_lag_finished\", \"irc.network.lag_min_show\" and \"irc.network.lag_refresh_interval\"","",0,0,"off","off",0,"","","buffers_signal_config","","",""], + "look_whitelist_buffers" => ["whitelist_buffers", "string", "comma separated list of buffers for using a differnt color scheme (for example: freenode.#weechat,freenode.#weechat-fr)", "", 0, 0,"", "", 0, "", "", "buffers_signal_config_whitelist", "", "", ""], + "hide_merged_buffers" => ["hide_merged_buffers", "integer", "hide merged buffers. The value determines which merged buffers should be hidden, keepserver meaning 'all except server buffers'. Other values correspondent to the buffer type.", "server|channel|private|keepserver|all|none", 0, 0,"none", "none", 0, "", "", "buffers_signal_config", "", "", ""], + "indenting" => ["indenting", "integer", "use indenting for channel and query buffers. This option only takes effect if bar is left/right positioned", "off|on|under_name", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""], + "indenting_number" => ["indenting_number", "boolean", "use indenting for numbers. This option only takes effect if bar is left/right positioned", "", 0, 0,"on", "on", 0, "", "", "buffers_signal_config", "", "", ""], + "short_names" => ["short_names", "boolean", "display short names (remove text before first \".\" in buffer name)", "", 0, 0,"on", "on", 0, "", "", "buffers_signal_config", "", "", ""], + "show_number" => ["show_number", "boolean", "display channel number in front of buffername", "", 0, 0,"on", "on", 0, "", "", "buffers_signal_config", "", "", ""], + "show_number_char" => ["number_char", "string", "display a char after channel number", "", 0, 0,".", ".", 0, "", "", "buffers_signal_config", "", "", ""], + "show_prefix" => ["prefix", "boolean", "show your prefix for channel", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""], + "show_prefix_empty" => ["prefix_empty", "boolean", "use a placeholder for channels without prefix", "", 0, 0,"on", "on", 0, "", "", "buffers_signal_config", "", "", ""], + "sort" => ["sort", "integer", "sort buffer-list by \"number\" or \"name\"", "number|name", 0, 0,"number", "number", 0, "", "", "buffers_signal_config", "", "", ""], + "core_to_front" => ["core_to_front", "boolean", "core buffer and buffers with free content will be listed first. Take only effect if buffer sort is by name", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""], + "jump_prev_next_visited_buffer" => ["jump_prev_next_visited_buffer", "boolean", "jump to previously or next visited buffer if you click with left/right mouse button on currently visiting buffer", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""], + "name_size_max" => ["name_size_max","integer","maximum size of buffer name. 0 means no limitation","",0,256,0,0,0, "", "", "buffers_signal_config", "", "", ""], + "name_crop_suffix" => ["name_crop_suffix","string","contains an optional char(s) that is appended when buffer name is shortened","",0,0,"+","+",0,"","","buffers_signal_config", "", "", ""], + "detach" => ["detach", "integer","detach channel from buffers list after a specific period of time (in seconds) without action (weechat ≥ 0.3.8 required)", "", 0, 31536000,0, "number", 0, "", "", "buffers_signal_config", "", "", ""], + "immune_detach_buffers"=> ["immune_detach_buffers", "string", "Comma seperated list of buffers to NOT automatically detatch. Allows \"*\" wildcard. Ex: \"BitlBee,freenode.*\"", "", 0, 0,"", "", 0, "", "", "buffers_signal_config_immune_detach_buffers", "", "", ""], + "detach_query" => ["detach_query", "boolean", "query buffer will be detachted", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""], + "detach_free_content" => ["detach_free_content", "boolean", "buffers with free content will be detached (Ex: iset, chanmon)", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""], + "mark_inactive" => ["mark_inactive", "boolean", "if option is \"on\", inactive buffers (those you are not in) will have parentesis around them. An inactive buffer will not be detached.", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""], +); + # section "color" + my $section_color = weechat::config_new_section($buffers_config_file,"color", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_color eq "") + { + weechat::config_free($buffers_config_file); + return; + } + foreach my $option (keys %default_options_color) + { + $options{$option} = weechat::config_new_option($buffers_config_file, $section_color, + $default_options_color{$option}[0],$default_options_color{$option}[1],$default_options_color{$option}[2], + $default_options_color{$option}[3],$default_options_color{$option}[4],$default_options_color{$option}[5], + $default_options_color{$option}[6],$default_options_color{$option}[7],$default_options_color{$option}[8], + $default_options_color{$option}[9],$default_options_color{$option}[10],$default_options_color{$option}[11], + $default_options_color{$option}[12],$default_options_color{$option}[13],$default_options_color{$option}[14]); + } + + # section "look" + my $section_look = weechat::config_new_section($buffers_config_file,"look", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_look eq "") + { + weechat::config_free($buffers_config_file); + return; + } + foreach my $option (keys %default_options_look) + { + $options{$option} = weechat::config_new_option($buffers_config_file, $section_look, + $default_options_look{$option}[0],$default_options_look{$option}[1],$default_options_look{$option}[2], + $default_options_look{$option}[3],$default_options_look{$option}[4],$default_options_look{$option}[5], + $default_options_look{$option}[6],$default_options_look{$option}[7],$default_options_look{$option}[8], + $default_options_look{$option}[9],$default_options_look{$option}[10],$default_options_look{$option}[11], + $default_options_look{$option}[12],$default_options_look{$option}[13],$default_options_look{$option}[14]); + } +} + +sub build_buffers +{ + my $str = ""; + + # get bar position (left/right/top/bottom) + my $position = "left"; + my $option_position = weechat::config_get("weechat.bar.buffers.position"); + if ($option_position ne "") + { + $position = weechat::config_string($option_position); + } + + # read hotlist + my %hotlist; + my $infolist = weechat::infolist_get("hotlist", "", ""); + while (weechat::infolist_next($infolist)) + { + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")} = + weechat::infolist_integer($infolist, "priority"); + if ( weechat::config_boolean( $options{"hotlist_counter"} ) eq 1 and $weechat_version >= 0x00030500) + { + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_00"} = + weechat::infolist_integer($infolist, "count_00"); # low message + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_01"} = + weechat::infolist_integer($infolist, "count_01"); # channel message + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_02"} = + weechat::infolist_integer($infolist, "count_02"); # private message + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_03"} = + weechat::infolist_integer($infolist, "count_03"); # highlight message + } + } + weechat::infolist_free($infolist); + + # read buffers list + @buffers_focus = (); + my @buffers; + my @current1 = (); + my @current2 = (); + my $old_number = -1; + my $max_number = 0; + my $max_number_digits = 0; + my $active_seen = 0; + $infolist = weechat::infolist_get("buffer", "", ""); + while (weechat::infolist_next($infolist)) + { + my $buffer; + my $number = weechat::infolist_integer($infolist, "number"); + if ($number ne $old_number) + { + @buffers = (@buffers, @current2, @current1); + @current1 = (); + @current2 = (); + $active_seen = 0; + } + if ($number > $max_number) + { + $max_number = $number; + } + $old_number = $number; + my $active = weechat::infolist_integer($infolist, "active"); + if ($active) + { + $active_seen = 1; + } + $buffer->{"pointer"} = weechat::infolist_pointer($infolist, "pointer"); + $buffer->{"number"} = $number; + $buffer->{"active"} = $active; + $buffer->{"current_buffer"} = weechat::infolist_integer($infolist, "current_buffer"); + $buffer->{"plugin_name"} = weechat::infolist_string($infolist, "plugin_name"); + $buffer->{"name"} = weechat::infolist_string($infolist, "name"); + $buffer->{"short_name"} = weechat::infolist_string($infolist, "short_name"); + $buffer->{"full_name"} = $buffer->{"plugin_name"}.".".$buffer->{"name"}; + $buffer->{"type"} = weechat::buffer_get_string($buffer->{"pointer"},"localvar_type"); +# weechat::print("",$buffer->{"type"}); + + # check if buffer is active (or maybe a /part, /kick channel) + if ($buffer->{"type"} eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1) + { + my $server = weechat::buffer_get_string($buffer->{"pointer"},"localvar_server"); + my $channel = weechat::buffer_get_string($buffer->{"pointer"},"localvar_channel"); + my $infolist_channel = weechat::infolist_get("irc_channel","",$server.",".$channel); + if ($infolist_channel) + { + weechat::infolist_next($infolist_channel); + $buffer->{"nicks_count"} = weechat::infolist_integer($infolist_channel,"nicks_count"); + }else + { + $buffer->{"nicks_count"} = 0; + } + weechat::infolist_free($infolist_channel); + } + + my $result = check_immune_detached_buffers($buffer->{"name"}); # checking for wildcard + unless ($result) + { + my $detach_time = weechat::config_integer( $options{"detach"}); + my $current_time = time(); + # set timer for buffers with no hotlist action + $buffers_timer{$buffer->{"pointer"}} = $current_time + if ( not exists $hotlist{$buffer->{"pointer"}} + and $buffer->{"type"} eq "channel" + and not exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0); + + $buffers_timer{$buffer->{"pointer"}} = $current_time + if (weechat::config_boolean($options{"detach_query"}) eq 1 + and not exists $hotlist{$buffer->{"pointer"}} + and $buffer->{"type"} eq "private" + and not exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0); + + $detach_time = 0 + if (weechat::config_boolean($options{"detach_query"}) eq 0 + and $buffer->{"type"} eq "private"); + + # free content buffer + $buffers_timer{$buffer->{"pointer"}} = $current_time + if (weechat::config_boolean($options{"detach_free_content"}) eq 1 + and not exists $hotlist{$buffer->{"pointer"}} + and $buffer->{"type"} eq "" + and not exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0); + $detach_time = 0 + if (weechat::config_boolean($options{"detach_free_content"}) eq 0 + and $buffer->{"type"} eq ""); + + $detach_time = 0 if (weechat::config_boolean($options{"mark_inactive"}) eq 1 and defined $buffer->{"nicks_count"} and $buffer->{"nicks_count"} == 0); + + # check for detach + unless ( $buffer->{"current_buffer"} eq 0 + and not exists $hotlist{$buffer->{"pointer"}} +# and $buffer->{"type"} eq "channel" + and exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0 + and $weechat_version >= 0x00030800 + and $current_time - $buffers_timer{$buffer->{"pointer"}} >= $detach_time) + { + if ($active_seen) + { + push(@current2, $buffer); + } + else + { + push(@current1, $buffer); + } + } + } + else # buffer in "immune_detach_buffers" + { + if ($active_seen) + { + push(@current2, $buffer); + } + else + { + push(@current1, $buffer); + } + } + } # while end + + + if ($max_number >= 1) + { + $max_number_digits = length(int($max_number)); + } + @buffers = (@buffers, @current2, @current1); + weechat::infolist_free($infolist); + + # sort buffers by number, name or shortname + my %sorted_buffers; + if (1) + { + my $number = 0; + for my $buffer (@buffers) + { + my $key; + if (weechat::config_integer( $options{"sort"} ) eq 1) # number = 0; name = 1 + { + my $name = $buffer->{"name"}; + $name = $buffer->{"short_name"} if (weechat::config_boolean( $options{"short_names"} ) eq 1); + if (weechat::config_integer($options{"name_size_max"}) >= 1){ + $name = encode("UTF-8", substr(decode("UTF-8", $name), 0, weechat::config_integer($options{"name_size_max"}))); + } + if ( weechat::config_boolean($options{"core_to_front"}) eq 1) + { + if ( (weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "channel" ) and ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "private") ) + { + my $type = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type"); + if ( $type eq "" and $name ne "weechat") + { + $name = " " . $name + }else + { + $name = " " . $name; + } + } + } + $key = sprintf("%s%08d", lc($name), $buffer->{"number"}); + } + else + { + $key = sprintf("%08d", $number); + } + $sorted_buffers{$key} = $buffer; + $number++; + } + } + + # build string with buffers + $old_number = -1; + foreach my $key (sort keys %sorted_buffers) + { + my $buffer = $sorted_buffers{$key}; + + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "server" ) + { + # buffer type "server" or merged with core? + if ( ($buffer->{"type"} eq "server" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) ) + { + next; + } + } + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "channel" ) + { + # buffer type "channel" or merged with core? + if ( ($buffer->{"type"} eq "channel" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) ) + { + next; + } + } + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "private" ) + { + # buffer type "private" or merged with core? + if ( ($buffer->{"type"} eq "private" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) ) + { + next; + } + } + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "keepserver" ) + { + if ( ($buffer->{"type"} ne "server" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) ) + { + next; + } + } + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "all" ) + { + if ( ! $buffer->{"active"} ) + { + next; + } + } + + push(@buffers_focus, $buffer); # buffer > buffers_focus, for mouse support + my $color = ""; + my $bg = ""; + + $color = weechat::config_color( $options{"color_default_fg"} ); + $bg = weechat::config_color( $options{"color_default_bg"} ); + + if ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "private" ) + { + if ( (weechat::config_color($options{"queries_default_bg"})) ne "default" || (weechat::config_color($options{"queries_default_fg"})) ne "default" ) + { + $bg = weechat::config_color( $options{"queries_default_bg"} ); + $color = weechat::config_color( $options{"queries_default_fg"} ); + } + } + # check for core and buffer with free content + if ( (weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "channel" ) and ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "private") ) + { + $color = weechat::config_color( $options{"color_none_channel_fg"} ); + $bg = weechat::config_color( $options{"color_none_channel_bg"} ); + } + # default whitelist buffer? + if (grep {$_ eq $buffer->{"name"}} @whitelist_buffers) + { + $color = weechat::config_color( $options{"color_whitelist_default_fg"} ); + $bg = weechat::config_color( $options{"color_whitelist_default_bg"} ); + } + + $color = "default" if ($color eq ""); + + # color for channel and query buffer + if (exists $hotlist{$buffer->{"pointer"}}) + { + delete $buffers_timer{$buffer->{"pointer"}}; + # check if buffer is in whitelist buffer + if (grep {$_ eq $buffer->{"name"}} @whitelist_buffers) + { + $bg = weechat::config_color( $options{"color_whitelist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} ); + $color = weechat::config_color( $options{"color_whitelist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} ); + } + elsif ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "private" ) + { + # queries_default_fg/bg and buffers.color.queries_message_fg/bg + if ( (weechat::config_color($options{"queries_highlight_fg"})) ne "default" || + (weechat::config_color($options{"queries_highlight_bg"})) ne "default" || + (weechat::config_color($options{"queries_message_fg"})) ne "default" || + (weechat::config_color($options{"queries_message_bg"})) ne "default" ) + { + if ( ($hotlist{$buffer->{"pointer"}}) == 2 ) + { + $bg = weechat::config_color( $options{"queries_message_bg"} ); + $color = weechat::config_color( $options{"queries_message_fg"} ); + } + + elsif ( ($hotlist{$buffer->{"pointer"}}) == 3 ) + { + $bg = weechat::config_color( $options{"queries_highlight_bg"} ); + $color = weechat::config_color( $options{"queries_highlight_fg"} ); + } + }else + { + $bg = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} ); + $color = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} ); + } + }else + { + $bg = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} ); + $color = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} ); + } + } + + if ($buffer->{"current_buffer"}) + { + $color = weechat::config_color( $options{"color_current_fg"} ); + $bg = weechat::config_color( $options{"color_current_bg"} ); + } + my $color_bg = ""; + $color_bg = weechat::color(",".$bg) if ($bg ne ""); + + # create channel number for output + if ( weechat::config_boolean( $options{"show_number"} ) eq 1 ) # on + { + if (( weechat::config_boolean( $options{"indenting_number"} ) eq 1) + && (($position eq "left") || ($position eq "right"))) + { + $str .= weechat::color("default").$color_bg + .(" " x ($max_number_digits - length(int($buffer->{"number"})))); + } + if ($old_number ne $buffer->{"number"}) + { + $str .= weechat::color( weechat::config_color( $options{"color_number"} ) ) + .$color_bg + .$buffer->{"number"} + .weechat::color("default") + .$color_bg + .weechat::color( weechat::config_color( $options{"color_number_char"} ) ) + .weechat::config_string( $options{"show_number_char"} ) + .$color_bg; + } + else + { + my $indent = ""; + $indent = ((" " x length($buffer->{"number"}))." ") if (($position eq "left") || ($position eq "right")); + $str .= weechat::color("default") + .$color_bg + .$indent; + } + } + + if (( weechat::config_integer( $options{"indenting"} ) ne 0 ) # indenting NOT off + && (($position eq "left") || ($position eq "right"))) + { + my $type = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type"); + if (($type eq "channel") || ($type eq "private")) + { + if ( weechat::config_integer( $options{"indenting"} ) eq 1 ) + { + $str .= " "; + } + elsif ( (weechat::config_integer($options{"indenting"}) eq 2) and (weechat::config_integer($options{"indenting_number"}) eq 0) ) #under_name + { + if ( weechat::config_boolean( $options{"show_number"} ) eq 0 ) + { + $str .= " "; + }else + { + $str .= ( (" " x ( $max_number_digits - length($buffer->{"number"}) ))." " ); + } + } + } + } + if (weechat::config_boolean( $options{"show_prefix"} ) eq 1) + { + my $nickname = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_nick"); + if ($nickname ne "") + { + # with version >= 0.3.2, this infolist will return only nick + # with older versions, whole nicklist is returned for buffer, and this can be very slow + my $infolist_nick = weechat::infolist_get("nicklist", $buffer->{"pointer"}, "nick_".$nickname); + if ($infolist_nick ne "") + { + my $version = weechat::info_get("version_number", ""); + $version = 0 if ($version eq ""); + while (weechat::infolist_next($infolist_nick)) + { + if ((weechat::infolist_string($infolist_nick, "type") eq "nick") + && (weechat::infolist_string($infolist_nick, "name") eq $nickname)) + { + my $prefix = weechat::infolist_string($infolist_nick, "prefix"); + if (($prefix ne " ") or (weechat::config_boolean( $options{"show_prefix_empty"} ) eq 1)) + { + # with version >= 0.3.5, it is now a color name (for older versions: option name with color) + if (int($version) >= 0x00030500) + { + $str .= weechat::color(weechat::infolist_string($infolist_nick, "prefix_color")); + } + else + { + $str .= weechat::color(weechat::config_color( + weechat::config_get( + weechat::infolist_string($infolist_nick, "prefix_color")))); + } + $str .= $prefix; + } + last; + } + } + weechat::infolist_free($infolist_nick); + } + } + } + if ($buffer->{"type"} eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1 and $buffer->{"nicks_count"} == 0) + { + $str .= "("; + } + + $str .= weechat::color($color) . weechat::color(",".$bg); + + if (weechat::config_boolean( $options{"short_names"} ) eq 1) + { + if (weechat::config_integer($options{"name_size_max"}) >= 1) # check max_size of buffer name + { + $str .= encode("UTF-8", substr(decode("UTF-8", $buffer->{"short_name"}), 0, weechat::config_integer($options{"name_size_max"}))); + $str .= weechat::color(weechat::config_color( $options{"color_number_char"})).weechat::config_string($options{"name_crop_suffix"}) if (length($buffer->{"short_name"}) > weechat::config_integer($options{"name_size_max"})); + $str .= add_inactive_parentless($buffer->{"type"},$buffer->{"nicks_count"}); + $str .= add_hotlist_count($buffer->{"pointer"},%hotlist); + } + else + { + #$str .= weechat::buffer_get_string($buffer->{"pointer"},"localvar_server"); + #$str .= "/"; + $str .= $buffer->{"short_name"}; + $str .= add_inactive_parentless($buffer->{"type"},$buffer->{"nicks_count"}); + $str .= add_hotlist_count($buffer->{"pointer"},%hotlist); + } + } + else + { + if (weechat::config_integer($options{"name_size_max"}) >= 1) # check max_size of buffer name + { + $str .= encode("UTF-8", substr(decode("UTF-8", $buffer->{"name"},), 0, weechat::config_integer($options{"name_size_max"}))); + $str .= weechat::color(weechat::config_color( $options{"color_number_char"})).weechat::config_string($options{"name_crop_suffix"}) if (length($buffer->{"name"}) > weechat::config_integer($options{"name_size_max"})); + $str .= add_inactive_parentless($buffer->{"type"},$buffer->{"nicks_count"}); + $str .= add_hotlist_count($buffer->{"pointer"},%hotlist); + } + else + { + $str .= $buffer->{"name"}; + $str .= add_inactive_parentless($buffer->{"type"},$buffer->{"nicks_count"}); + $str .= add_hotlist_count($buffer->{"pointer"},%hotlist); + } + } + if ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "server" and weechat::config_boolean($options{"show_lag"}) eq 1) + { + my $color_lag = weechat::config_color(weechat::config_get("irc.color.item_lag_finished")); + my $min_lag = weechat::config_integer(weechat::config_get("irc.network.lag_min_show")); + my $infolist_server = weechat::infolist_get("irc_server","",$buffer->{"short_name"}); + weechat::infolist_next($infolist_server); + my $lag = (weechat::infolist_integer($infolist_server, "lag")); + weechat::infolist_free($infolist_server); + if ( int($lag) > int($min_lag) ) + { + $lag = $lag / 1000; + $str .= weechat::color("default") . " (" . weechat::color($color_lag) . $lag . weechat::color("default") . ")"; + } + } + $str .= "\n"; + $old_number = $buffer->{"number"}; + } + + return $str; +} + +sub add_inactive_parentless +{ +my ($buf_type, $buf_nicks_count) = @_; +my $str = ""; + if ($buf_type eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1 and $buf_nicks_count == 0) + { + $str .= weechat::color(weechat::config_color( $options{"color_number_char"})); + $str .= ")"; + } +return $str; +} + +sub add_hotlist_count +{ +my ($bufpointer,%hotlist) = @_; + +return "" if ( weechat::config_boolean( $options{"hotlist_counter"} ) eq 0 or ($weechat_version < 0x00030500)); # off +my $col_number_char = weechat::color(weechat::config_color( $options{"color_number_char"}) ); +my $str = " ".$col_number_char."("; + +# 0 = low level +if (defined $hotlist{$bufpointer."_count_00"}) +{ + my $bg = weechat::config_color( $options{"color_hotlist_low_bg"} ); + my $color = weechat::config_color( $options{"color_hotlist_low_fg"} ); + $str .= weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_00"} if ($hotlist{$bufpointer."_count_00"} ne "0"); +} + +# 1 = message +if (defined $hotlist{$bufpointer."_count_01"}) +{ + my $bg = weechat::config_color( $options{"color_hotlist_message_bg"} ); + my $color = weechat::config_color( $options{"color_hotlist_message_fg"} ); + if ($str =~ /[0-9]$/) + { + $str .= ",". + weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_01"} if ($hotlist{$bufpointer."_count_01"} ne "0"); + }else + { + $str .= weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_01"} if ($hotlist{$bufpointer."_count_01"} ne "0"); + } +} +# 2 = private +if (defined $hotlist{$bufpointer."_count_02"}) +{ + my $bg = weechat::config_color( $options{"color_hotlist_private_bg"} ); + my $color = weechat::config_color( $options{"color_hotlist_private_fg"} ); + if ($str =~ /[0-9]$/) + { + $str .= ",". + weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_02"} if ($hotlist{$bufpointer."_count_02"} ne "0"); + }else + { + $str .= weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_02"} if ($hotlist{$bufpointer."_count_02"} ne "0"); + } +} +# 3 = highlight +if (defined $hotlist{$bufpointer."_count_03"}) +{ + my $bg = weechat::config_color( $options{"color_hotlist_highlight_bg"} ); + my $color = weechat::config_color( $options{"color_hotlist_highlight_fg"} ); + if ($str =~ /[0-9]$/) + { + $str .= ",". + weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_03"} if ($hotlist{$bufpointer."_count_03"} ne "0"); + }else + { + $str .= weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_03"} if ($hotlist{$bufpointer."_count_03"} ne "0"); + } +} +$str .= $col_number_char. ")"; + +$str = "" if (weechat::string_remove_color($str, "") eq " ()"); # remove color and check for buffer with no messages +return $str; +} + +sub buffers_signal_buffer +{ +my ($data, $signal, $signal_data) = @_; + # check for buffer_switch and set or remove detach time + if ($weechat_version >= 0x00030800) + { + if ($signal eq "buffer_switch") + { + my $pointer = weechat::hdata_get_list (weechat::hdata_get("buffer"), "gui_buffer_last_displayed"); # get switched buffer + my $current_time = time(); + if ( weechat::buffer_get_string($pointer, "localvar_type") eq "channel") + { + $buffers_timer{$pointer} = $current_time; + } + else + { + delete $buffers_timer{$pointer}; + } + } + if ($signal eq "buffer_opened") + { + my $current_time = time(); + $buffers_timer{$signal_data} = $current_time; + } + if ($signal eq "buffer_closing") + { + delete $buffers_timer{$signal_data}; + } + } + + weechat::bar_item_update("buffers"); + return weechat::WEECHAT_RC_OK; +} + +sub buffers_signal_hotlist +{ + weechat::bar_item_update("buffers"); + return weechat::WEECHAT_RC_OK; +} + + +sub buffers_signal_config_whitelist +{ + @whitelist_buffers = (); + @whitelist_buffers = split( /,/, weechat::config_string( $options{"look_whitelist_buffers"} ) ); + weechat::bar_item_update("buffers"); + return weechat::WEECHAT_RC_OK; +} +sub buffers_signal_config_immune_detach_buffers +{ + @immune_detach_buffers = (); + @immune_detach_buffers = split( /,/, weechat::config_string( $options{"immune_detach_buffers"} ) ); + weechat::bar_item_update("buffers"); + return weechat::WEECHAT_RC_OK; +} + +sub buffers_signal_config +{ + weechat::bar_item_update("buffers"); + return weechat::WEECHAT_RC_OK; +} + +# called when mouse click occured in buffers item: this callback returns buffer +# hash according to line of item where click occured +sub buffers_focus_buffers +{ + my %info = %{$_[1]}; + my $item_line = int($info{"_bar_item_line"}); + undef my $hash; + if (($info{"_bar_item_name"} eq "buffers") && ($item_line >= 0) && ($item_line <= $#buffers_focus)) + { + $hash = $buffers_focus[$item_line]; + } + else + { + $hash = {}; + my $hash_focus = $buffers_focus[0]; + foreach my $key (keys %$hash_focus) + { + $hash->{$key} = "?"; + } + } + return $hash; +} + +# called when a mouse action is done on buffers item, to execute action +# possible actions: jump to a buffer or move buffer in list (drag & drop of buffer) +sub buffers_hsignal_mouse +{ + my ($data, $signal, %hash) = ($_[0], $_[1], %{$_[2]}); + my $current_buffer = weechat::buffer_get_integer(weechat::current_buffer(), "number"); # get current buffer number + + if ( $hash{"_key"} eq "button1" ) # left mouse button + { + if ($hash{"number"} eq $hash{"number2"}) + { + if ( weechat::config_integer($options{"jump_prev_next_visited_buffer"}) eq 1 ) + { + if ( $current_buffer eq $hash{"number"} ) + { + weechat::command("","/input jump_previously_visited_buffer"); + } + else + { + weechat::command("", "/buffer ".$hash{"full_name"}); + } + } + else + { + weechat::command("", "/buffer ".$hash{"full_name"}); + } + } + else + { + move_buffer(%hash); + } + } + elsif ( ($hash{"_key"} eq "button2") && (weechat::config_integer($options{"jump_prev_next_visited_buffer"}) eq 1) )# right mouse button + { + if ( $current_buffer eq $hash{"number2"} ) + { + weechat::command("","/input jump_next_visited_buffer"); + } + } + else + { + my $infolist = weechat::infolist_get("hook", "", "command,menu"); + my $has_menu_command = weechat::infolist_next($infolist); + weechat::infolist_free($infolist); + + if ( $has_menu_command && $hash{"_key"} =~ /button2/ ) + { + if ($hash{"number"} eq $hash{"number2"}) + { + weechat::command($hash{"pointer"}, "/menu buffer1 $hash{short_name} $hash{number}"); + } + else + { + weechat::command($hash{"pointer"}, "/menu buffer2 $hash{short_name}/$hash{short_name2} $hash{number} $hash{number2}") + } + } + else + { + move_buffer(%hash); + } + } +} + +sub move_buffer +{ + my %hash = @_; + my $number2 = $hash{"number2"}; + if ($number2 eq "?") + { + # if number 2 is not known (end of gesture outside buffers list), then set it + # according to mouse gesture + $number2 = "999999"; + $number2 = "1" if (($hash{"_key"} =~ /gesture-left/) || ($hash{"_key"} =~ /gesture-up/)); + } + my $ptrbuf = weechat::current_buffer(); + weechat::command($hash{"pointer"}, "/buffer move ".$number2); +} + +sub check_immune_detached_buffers +{ + my ($buffername) = @_; + foreach ( @immune_detach_buffers ){ + my $immune_buffer = weechat::string_mask_to_regex($_); + if ($buffername =~ /^$immune_buffer$/i) + { + return 1; + } + } + return 0; +} diff --git a/weechat/perl/highmon.pl b/weechat/perl/highmon.pl new file mode 100644 index 0000000..b7e0aae --- /dev/null +++ b/weechat/perl/highmon.pl @@ -0,0 +1,1064 @@ +# +# highmon.pl - Highlight Monitoring for weechat 0.3.0 +# Version 2.3.2 +# +# Add 'Highlight Monitor' buffer/bar to log all highlights in one spot +# +# Usage: +# /highmon [help] | [monitor [channel [server]]] | [clean default|orphan|all] +# Command wrapper for highmon commands +# +# /highmon clean default|orphan|all will clean the config section of default 'on' entries, +# channels you are no longer joined, or both +# +# /highmon monitor [channel] [server] is used to toggle a highlight monitoring on and off, this +# can be used in the channel buffer for the channel you wish to toggle, or be given +# with arguments e.g. /highmon monitor #weechat freenode +# +# /set plugins.var.perl.highmon.alignment +# The config setting "alignment" can be changed to; +# "channel", "schannel", "nchannel", "channel,nick", "schannel,nick", "nchannel,nick" +# to change how the monitor appears +# The 'channel' value will show: "#weechat" +# The 'schannel' value will show: "6" +# The 'nchannel' value will show: "6:#weechat" +# +# /set plugins.var.perl.highmon.short_names +# Setting this to 'on' will trim the network name from highmon, ala buffers.pl +# +# /set plugins.var.perl.highmon.merge_private +# Setting this to 'on' will merge private messages to highmon's display +# +# /set plugins.var.perl.highmon.color_buf +# This turns colored buffer names on or off, you can also set a single fixed color by using a weechat color name. +# This *must* be a valid color name, or weechat will likely do unexpected things :) +# +# /set plugins.var.perl.highmon.hotlist_show +# Setting this to 'on' will let the highmon buffer appear in hotlists +# (status bar/buffer.pl) +# +# /set plugins.var.perl.highmon.away_only +# Setting this to 'on' will only put messages in the highmon buffer when +# you set your status to away +# +# /set plugins.var.perl.highmon.logging +# Toggles logging status for highmon buffer (default: off) +# +# /set plugins.var.perl.highmon.output +# Changes where output method of highmon; takes either "bar" or "buffer" (default; buffer) +# /set plugins.var.perl.highmon.bar_lines +# Changes the amount of lines the output bar will hold. +# (Only appears once output has been set to bar, defaults to 10) +# /set plugins.var.perl.highmon.bar_scrolldown +# Toggles the bar scrolling at the bottom when new highlights are received +# (Only appears once output has been set to bar, defaults to off) +# +# /set plugins.var.perl.highmon.nick_prefix +# /set plugins.var.perl.highmon.nick_suffix +# Sets the prefix and suffix chars in the highmon buffer +# (Defaults to <> if nothing set, and blank if there is) +# +# servername.#channel +# servername is the internal name for the server (set when you use /server add) +# #channel is the channel name, (where # is whatever channel type that channel happens to be) +# + +# Bugs and feature requests at: https://github.com/KenjiE20/highmon + +# History: +# 2013-01-15, KenjiE20 : +# v2.3.2: -fix: Let bar output use the string set in weechat's config option +# -add: github info +# 2012-04-15, KenjiE20 : +# v2.3.1: -fix: Colour tags in bar timestamp string +# 2012-02-28, KenjiE20 : +# v2.3: -feature: Added merge_private option to display private messages (default: off) +# -fix: Channel name colours now show correctly when set to on +# 2011-08-07, Sitaktif : +# v2.2.1: -feature: Add "bar_scrolldown" option to have the bar display the latest hl at anytime +# -fix: Set up bar-specific config at startup if 'output' is already configured as 'bar' +# 2010-12-22, KenjiE20 : +# v2.2: -change: Use API instead of config to find channel colours, ready for 0.3.4 and 256 colours +# 2010-12-13, idl0r & KenjiE20 : +# v2.1.3: -fix: perl errors caused by bar line counter +# -fix: Add command list to inbuilt help +# 2010-09-30, KenjiE20 : +# v2.1.2: -fix: logging config was not correctly toggling back on (thanks to sleo for noticing) +# -version sync w/ chanmon +# 2010-08-27, KenjiE20 : +# v2.1: -feature: Add 'nchannel' option to alignment to display buffer and name +# 2010-04-25, KenjiE20 : +# v2.0: Release as version 2.0 +# 2010-04-24, KenjiE20 : +# v1.9: Rewrite for v2.0 +# Bring feature set in line with chanmon 2.0 +# -code change: Made more subs to shrink the code down in places +# -fix: Stop highmon attempting to double load/hook +# -fix: Add version dependant check for away status +# 2010-01-25, KenjiE20 : +# v1.7: -fixture: Let highmon be aware of nick_prefix/suffix +# and allow custom prefix/suffix for chanmon buffer +# (Defaults to <> if nothing set, and blank if there is) +# (Thanks to m4v for these) +# 2009-09-07, KenjiE20 : +# v1.6: -feature: colored buffer names +# -change: version sync with chanmon +# 2009-09-05, KenjiE20 : +# v1.2: -fix: disable buffer highlight +# 2009-09-02, KenjiE20 : +# v.1.1.1 -change: Stop unsightly text block on '/help' +# 2009-08-10, KenjiE20 : +# v1.1: In-client help added +# 2009-08-02, KenjiE20 : +# v1.0: Initial Public Release + +# Copyright (c) 2009 by KenjiE20 +# +# 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 . +# + +@bar_lines = (); +@bar_lines_time = (); +# Replicate info earlier for in-client help + +$highmonhelp = weechat::color("bold")."/highmon [help] | [monitor [channel [server]]] | [clean default|orphan|all]".weechat::color("-bold")." + Command wrapper for highmon commands + +".weechat::color("bold")."/highmon clean default|orphan|all".weechat::color("-bold")." will clean the config section of default 'on' entries, channels you are no longer joined, or both + +".weechat::color("bold")."/highmon monitor [channel] [server]".weechat::color("-bold")." is used to toggle a highlight monitoring on and off, this can be used in the channel buffer for the channel you wish to toggle, or be given with arguments e.g. /highmon monitor #weechat freenode + +".weechat::color("bold")."/set plugins.var.perl.highmon.alignment".weechat::color("-bold")." + The config setting \"alignment\" can be changed to; + \"channel\", \"schannel\", \"nchannel\", \"channel,nick\", \"schannel,nick\", \"nchannel,nick\" + to change how the monitor appears + The 'channel' value will show: \"#weechat\" + The 'schannel' value will show: \"6\" + The 'nchannel' value will show: \"6:#weechat\" + +".weechat::color("bold")."/set plugins.var.perl.highmon.short_names".weechat::color("-bold")." + Setting this to 'on' will trim the network name from highmon, ala buffers.pl + +".weechat::color("bold")."/set plugins.var.perl.highmon.merge_private".weechat::color("-bold")." + Setting this to 'on' will merge private messages to highmon's display + +".weechat::color("bold")."/set plugins.var.perl.highmon.color_buf".weechat::color("-bold")." + This turns colored buffer names on or off, you can also set a single fixed color by using a weechat color name. + This ".weechat::color("bold")."must".weechat::color("-bold")." be a valid color name, or weechat will likely do unexpected things :) + +".weechat::color("bold")."/set plugins.var.perl.highmon.hotlist_show".weechat::color("-bold")." +Setting this to 'on' will let the highmon buffer appear in hotlists (status bar/buffer.pl) + +".weechat::color("bold")."/set plugins.var.perl.highmon.away_only".weechat::color("-bold")." +Setting this to 'on' will only put messages in the highmon buffer when you set your status to away + +".weechat::color("bold")."/set plugins.var.perl.highmon.logging".weechat::color("-bold")." + Toggles logging status for highmon buffer (default: off) + +".weechat::color("bold")."/set plugins.var.perl.highmon.output".weechat::color("-bold")." + Changes where output method of highmon; takes either \"bar\" or \"buffer\" (default; buffer) +".weechat::color("bold")."/set plugins.var.perl.highmon.bar_lines".weechat::color("-bold")." + Changes the amount of lines the output bar will hold. + (Only appears once output has been set to bar, defaults to 10) +".weechat::color("bold")."/set plugins.var.perl.highmon.bar_scrolldown".weechat::color("-bold")." + Toggles the bar scrolling at the bottom when new highlights are received + (Only appears once output has been set to bar, defaults to off) + +".weechat::color("bold")."/set plugins.var.perl.highmon.nick_prefix".weechat::color("-bold")." +".weechat::color("bold")."/set plugins.var.perl.highmon.nick_suffix".weechat::color("-bold")." + Sets the prefix and suffix chars in the highmon buffer + (Defaults to <> if nothing set, and blank if there is) + +".weechat::color("bold")."servername.#channel".weechat::color("-bold")." + servername is the internal name for the server (set when you use /server add) + #channel is the channel name, (where # is whatever channel type that channel happens to be)"; +# Print verbose help +sub print_help +{ + weechat::print("", "\t".weechat::color("bold")."Highmon Help".weechat::color("-bold")."\n\n"); + weechat::print("", "\t".$highmonhelp); + return weechat::WEECHAT_RC_OK; +} + +# Bar item build +sub highmon_bar_build +{ + # Get max lines + $max_lines = weechat::config_get_plugin("bar_lines"); + $max_lines = $max_lines ? $max_lines : 10; + $str = ''; + $align_num = 0; + $count = 0; + # Keep lines within max + while ($#bar_lines > $max_lines) + { + shift(@bar_lines); + shift(@bar_lines_time); + } + # So long as we have some lines, build a string + if (@bar_lines) + { + # Build loop + $sep = " ".weechat::config_string(weechat::config_get("weechat.look.prefix_suffix"))." "; + foreach(@bar_lines) + { + # Find max align needed + $prefix_num = (index(weechat::string_remove_color($_, ""), $sep)); + $align_num = $prefix_num if ($prefix_num > $align_num); + } + foreach(@bar_lines) + { + # Get align for this line + $prefix_num = (index(weechat::string_remove_color($_, ""), $sep)); + + # Make string + $str = $str.$bar_lines_time[$count]." ".(" " x ($align_num - $prefix_num)).$_."\n"; + # Increment count for sync with time list + $count++; + } + } + return $str; +} + +# Make a new bar +sub highmon_bar_open +{ + # Make the bar item + weechat::bar_item_new("highmon", "highmon_bar_build", ""); + + $highmon_bar = weechat::bar_new ("highmon", "off", 100, "root", "", "bottom", "vertical", "vertical", 0, 0, "default", "cyan", "default", "on", "highmon"); + + return weechat::WEECHAT_RC_OK; +} +# Close bar +sub highmon_bar_close +{ + # Find if bar exists + $highmon_bar = weechat::bar_search("highmon"); + # If is does, close it + if ($highmon_bar ne "") + { + weechat::bar_remove($highmon_bar); + } + + # Find if bar item exists + $highmon_bar_item = weechat::bar_item_search("highmon_bar"); + # If is does, close it + if ($highmon_bar_item ne "") + { + weechat::bar_remove($highmon_bar_item); + } + + @bar_lines = (); + return weechat::WEECHAT_RC_OK; +} + +# Make a new buffer +sub highmon_buffer_open +{ + # Search for pre-existing buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + + # Make a new buffer + if ($highmon_buffer eq "") + { + $highmon_buffer = weechat::buffer_new("highmon", "highmon_buffer_input", "", "highmon_buffer_close", ""); + } + + # Turn off notify, highlights + if ($highmon_buffer ne "") + { + if (weechat::config_get_plugin("hotlist_show" eq "off")) + { + weechat::buffer_set($highmon_buffer, "notify", "0"); + } + weechat::buffer_set($highmon_buffer, "highlight_words", "-"); + weechat::buffer_set($highmon_buffer, "title", "Highlight Monitor"); + # Set no_log + if (weechat::config_get_plugin("logging") eq "off") + { + weechat::buffer_set($highmon_buffer, "localvar_set_no_log", "1"); + } + } + return weechat::WEECHAT_RC_OK; +} +# Buffer input has no action +sub highmon_buffer_input +{ + return weechat::WEECHAT_RC_OK; +} +# Close up +sub highmon_buffer_close +{ + $highmon_buffer = ""; + return weechat::WEECHAT_RC_OK; +} + +# Highmon command wrapper +sub highmon_command_cb +{ + $data = $_[0]; + $buffer = $_[1]; + $args = $_[2]; + my $cmd = ''; + my $arg = ''; + + if ($args ne "") + { + # Split argument up + @arg_array = split(/ /,$args); + # Take first as command + $cmd = shift(@arg_array); + # Rebuild string to pass to subs + if (@arg_array) + { + $arg = join(" ", @arg_array); + } + } + + # Help command + if ($cmd eq "" || $cmd eq "help") + { + print_help(); + } + # /monitor command + elsif ($cmd eq "monitor") + { + highmon_toggle($data, $buffer, $arg); + } + # /highclean command + elsif ($cmd eq "clean") + { + highmon_config_clean($data, $buffer, $arg); + } + return weechat::WEECHAT_RC_OK; +} + +# Clean up config entries +sub highmon_config_clean +{ + $data = $_[0]; + $buffer = $_[1]; + $args = $_[2]; + + # Don't do anything if bad option given + if ($args ne "default" && $args ne "orphan" && $args ne "all") + { + weechat::print("", "\thighmon.pl: Unknown option"); + return weechat::WEECHAT_RC_OK; + } + + @chans = (); + # Load an infolist of highmon options + $infolist = weechat::infolist_get("option", "", "*highmon*"); + while (weechat::infolist_next($infolist)) + { + $name = weechat::infolist_string($infolist, "option_name"); + $name =~ s/perl\.highmon\.(\w*)\.([#&\+!])(.*)/$1.$2$3/; + if ($name =~ /^(.*)\.([#&\+!])(.*)$/) + { + $action = 0; + # Clean up all 'on's + if ($args eq "default" || $args eq "all") + { + # If value in config is "on" + if (weechat::config_get_plugin($name) eq "on") + { + # Unset and if successful flag as changed + $rc = weechat::config_unset_plugin($name); + if ($rc eq weechat::WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED) + { + $action = 1; + } + } + } + # Clean non joined + if ($args eq "orphan" || $args eq "all") + { + # If we can't find the buffer for this entry + if (weechat::buffer_search("irc", $name) eq "") + { + # Unset and if successful flag as changed + $rc = weechat::config_unset_plugin($name); + if ($rc eq weechat::WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED) + { + $action = 1; + } + } + } + # Add changed entry names to list + push (@chans, $name) if ($action); + } + } + weechat::infolist_free($infolist); + # If channels were cleaned from config + if (@chans) + { + # If only one entry + if (@chans == 1) + { + $str = "\thighmon.pl: Cleaned ".@chans." entry from the config:"; + } + else + { + $str = "\thighmon.pl: Cleaned ".@chans." entries from the config:"; + } + # Build a list of channels + foreach(@chans) + { + $str = $str." ".$_; + } + # Print what happened + weechat::print("",$str); + } + # Config seemed to be clean + else + { + weechat::print("", "\thighmon.pl: No entries removed"); + } + return weechat::WEECHAT_RC_OK; +} + +# Check config elements +sub highmon_config_init +{ + # Alignment default + if (!(weechat::config_is_set_plugin ("alignment"))) + { + weechat::config_set_plugin("alignment", "channel"); + } + if (weechat::config_get_plugin("alignment") eq "") + { + weechat::config_set_plugin("alignment", "none"); + } + + # Short name default + if (!(weechat::config_is_set_plugin ("short_names"))) + { + weechat::config_set_plugin("short_names", "off"); + } + + # Coloured names default + if (!(weechat::config_is_set_plugin ("color_buf"))) + { + weechat::config_set_plugin("color_buf", "on"); + } + + # Hotlist show default + if (!(weechat::config_is_set_plugin ("hotlist_show"))) + { + weechat::config_set_plugin("hotlist_show", "off"); + } + + # Away only default + if (!(weechat::config_is_set_plugin ("away_only"))) + { + weechat::config_set_plugin("away_only", "off"); + } + + # highmon log default + if (!(weechat::config_is_set_plugin ("logging"))) + { + weechat::config_set_plugin("logging", "off"); + } + + # Output default + if (!(weechat::config_is_set_plugin ("output"))) + { + weechat::config_set_plugin("output", "buffer"); + } + + # Private message merging + if (!(weechat::config_is_set_plugin ("merge_private"))) + { + weechat::config_set_plugin("merge_private", "off"); + } + + # Set bar config in case output was set to "bar" before even changing the setting + if (weechat::config_get_plugin("output") eq "bar") + { + # Output bar lines default + if (!(weechat::config_is_set_plugin ("bar_lines"))) + { + weechat::config_set_plugin("bar_lines", "10"); + } + if (!(weechat::config_is_set_plugin ("bar_scrolldown"))) + { + weechat::config_set_plugin("bar_scrolldown", "off"); + } + } + + # Check for exisiting prefix/suffix chars, and setup accordingly + $prefix = weechat::config_get("irc.look.nick_prefix"); + $prefix = weechat::config_string($prefix); + $suffix = weechat::config_get("irc.look.nick_suffix"); + $suffix = weechat::config_string($suffix); + + if (!(weechat::config_is_set_plugin("nick_prefix"))) + { + if ($prefix eq "" && $suffix eq "") + { + weechat::config_set_plugin("nick_prefix", "<"); + } + else + { + weechat::config_set_plugin("nick_prefix", ""); + } + } + + if (!(weechat::config_is_set_plugin("nick_suffix"))) + { + if ($prefix eq "" && $suffix eq "") + { + weechat::config_set_plugin("nick_suffix", ">"); + } + else + { + weechat::config_set_plugin("nick_suffix", ""); + } + } +} + +# Get config updates +sub highmon_config_cb +{ + $point = $_[0]; + $name = $_[1]; + $value = $_[2]; + + $name =~ s/^plugins\.var\.perl\.highmon\.//; + + # Set logging on buffer + if ($name eq "logging") + { + # Search for pre-existing buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + if ($value eq "off") + { + weechat::buffer_set($highmon_buffer, "localvar_set_no_log", "1"); + } + else + { + weechat::buffer_set($highmon_buffer, "localvar_del_no_log", ""); + } + } + # Output changer + elsif ($name eq "output") + { + if ($value eq "bar") + { + # Search for pre-existing buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + # Close if it exists + if ($highmon_buffer ne "") + { + weechat::buffer_close($highmon_buffer) + } + + # Output bar lines default + if (!(weechat::config_is_set_plugin ("bar_lines"))) + { + weechat::config_set_plugin("bar_lines", "10"); + } + if (!(weechat::config_is_set_plugin ("bar_scrolldown"))) + { + weechat::config_set_plugin("bar_scrolldown", "off"); + } + # Make a bar if doesn't exist + highmon_bar_open(); + } + elsif ($value eq "buffer") + { + # If a bar exists, close it + highmon_bar_close(); + # Open buffer + highmon_buffer_open(); + } + + } + # Change if hotlist config changes + elsif ($name eq "hotlist_show") + { + # Search for pre-existing buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + if ($value eq "off" && $highmon_buffer) + { + weechat::buffer_set($highmon_buffer, "notify", "0"); + } + elsif ($value ne "off" && $highmon_buffer) + { + weechat::buffer_set($highmon_buffer, "notify", "3"); + } + } + elsif ($name eq "weechat.look.prefix_suffix") + { + if (weechat::config_get_plugin("output") eq "bar") + { + @bar_lines = (); + weechat::print("", "\thighmon: weechat.look.prefix_suffix changed, clearing highmon bar"); + weechat::bar_item_update("highmon"); + } + } + return weechat::WEECHAT_RC_OK; +} + +# Set up weechat hooks / commands +sub highmon_hook +{ + weechat::hook_print("", "", "", 0, "highmon_new_message", ""); + weechat::hook_command("highclean", "Highmon config clean up", "default|orphan|all", " default: Cleans all config entries with the default \"on\" value\n orphan: Cleans all config entries for channels you aren't currently joined\n all: Does both defaults and orphan", "default|orphan|all", "highmon_config_clean", ""); + + weechat::hook_command("highmon", "Highmon help", "[help] | [monitor [channel [server]]] | [clean default|orphan|all]", " help: Print help on config options for highmon\n monitor: Toggles monitoring for a channel\n clean: Highmon config clean up (/highclean)", "help || monitor %(irc_channels) %(irc_servers) || clean default|orphan|all", "highmon_command_cb", ""); + + weechat::hook_config("plugins.var.perl.highmon.*", "highmon_config_cb", ""); + weechat::hook_config("weechat.look.prefix_suffix", "highmon_config_cb", ""); +} + +# Main body, Callback for hook_print +sub highmon_new_message +{ + my $net = ""; + my $chan = ""; + my $nick = ""; + my $outstr = ""; + my $window_displayed = ""; + my $dyncheck = "0"; + +# DEBUG point +# $string = "\t"."0: ".$_[0]." 1: ".$_[1]." 2: ".$_[2]." 3: ".$_[3]." 4: ".$_[4]." 5: ".$_[5]." 6: ".$_[6]." 7: ".$_[7]; +# weechat::print("", "\t".$string); + + $cb_datap = $_[0]; + $cb_bufferp = $_[1]; + $cb_date = $_[2]; + $cb_tags = $_[3]; + $cb_disp = $_[4]; + $cb_high = $_[5]; + $cb_prefix = $_[6]; + $cb_msg = $_[7]; + + # Only work on highlighted messages or private message when enabled + if ($cb_high == "1" || (weechat::config_get_plugin("merge_private") eq "on" && $cb_tags =~ /notify_private/)) + { + # Pre bug #29618 (0.3.3) away detect + if (weechat::info_get("version_number", "") <= 197120) + { + $away = ''; + # Get infolist for this server + $infolist = weechat::infolist_get("irc_server", "", weechat::buffer_get_string($cb_bufferp, "localvar_server")); + while (weechat::infolist_next($infolist)) + { + # Get away message is is_away is on + $away = weechat::infolist_string($infolist, "away_message") if (weechat::infolist_integer($infolist, "is_away")); + } + weechat::infolist_free($infolist); + } + # Post bug #29618 fix + else + { + $away = weechat::buffer_get_string($cb_bufferp, "localvar_away"); + } + if (weechat::config_get_plugin("away_only") ne "on" || ($away ne "")) + { + # Check buffer name is an IRC channel + $bufname = weechat::buffer_get_string($cb_bufferp, 'name'); + if ($bufname =~ /(.*)\.([#&\+!])(.*)/) + { + # Are we running on this channel + if (weechat::config_get_plugin($bufname) ne "off" && $cb_disp eq "1") + { + # Format nick + # Line isn't action or topic notify + if (!($cb_tags =~ /irc_action/) && !($cb_tags =~ /irc_topic/)) + { + # Strip nick colour + $uncolnick = weechat::string_remove_color($cb_prefix, ""); + # Format nick + $nick = " ".weechat::config_get_plugin("nick_prefix").weechat::color("chat_highlight").$uncolnick.weechat::color("reset").weechat::config_get_plugin("nick_suffix"); + } + # Topic line + elsif ($cb_tags =~ /irc_topic/) + { + $nick = " ".$cb_prefix.weechat::color("reset"); + } + # Action line + else + { + $uncolnick = weechat::string_remove_color($cb_prefix, ""); + $nick = weechat::color("chat_highlight").$uncolnick.weechat::color("reset"); + } + # Send to output + highmon_print ($cb_msg, $cb_bufferp, $nick); + } + } + # Or is private message + elsif (weechat::config_get_plugin("merge_private") eq "on" && $cb_tags =~ /notify_private/) + { + # Strip nick colour + $uncolnick = weechat::buffer_get_string($cb_bufferp, 'short_name'); + # Format nick + $nick = " ".weechat::config_get_plugin("nick_prefix").weechat::color("chat_highlight").$uncolnick.weechat::color("reset").weechat::config_get_plugin("nick_suffix"); + #Send to output + highmon_print ($cb_msg, $cb_bufferp, $nick); + } + } + } + return weechat::WEECHAT_RC_OK; +} + +# Output formatter and printer takes (msg bufpointer nick) +sub highmon_print +{ + $cb_msg = $_[0]; + my $cb_bufferp = $_[1] if ($_[1]); + my $nick = $_[2] if ($_[2]); + + #Normal channel message + if ($cb_bufferp && $nick) + { + # Format buffer name + $bufname = format_buffer_name($cb_bufferp); + + # If alignment is #channel | nick msg + if (weechat::config_get_plugin("alignment") eq "channel") + { + $nick =~ s/\s(.*)/$1/; + # Build string + $outstr = $bufname."\t".$nick." ".$cb_msg; + } + # or if it is channel number | nick msg + elsif (weechat::config_get_plugin("alignment") eq "schannel") + { + $nick =~ s/\s(.*)/$1/; + # Use channel number instead + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset"); + # Build string + $outstr = $bufname."\t".$nick." ".$cb_msg; + } + # or if it is number:#channel | nick msg + elsif (weechat::config_get_plugin("alignment") eq "nchannel") + { + $nick =~ s/\s(.*)/$1/; + # Place channel number in front of formatted name + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname; + # Build string + $outstr = $bufname."\t".$nick." ".$cb_msg; + } + # or if it is #channel nick | msg + elsif (weechat::config_get_plugin("alignment") eq "channel,nick") + { + # Build string + $outstr = $bufname.":".$nick."\t".$cb_msg; + } + # or if it is channel number nick | msg + elsif (weechat::config_get_plugin("alignment") eq "schannel,nick") + { + # Use channel number instead + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset"); + # Build string + $outstr = $bufname.":".$nick."\t".$cb_msg; + } + # or if it is number:#channel nick | msg + elsif (weechat::config_get_plugin("alignment") eq "nchannel,nick") + { + # Place channel number in front of formatted name + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname; + # Build string + $outstr = $bufname.":".$nick."\t".$cb_msg; + } + # or finally | #channel nick msg + else + { + # Build string + $outstr = "\t".$bufname.":".$nick." ".$cb_msg; + } + } + # highmon channel toggle message + elsif ($cb_bufferp && !$nick) + { + # Format buffer name + $bufname = format_buffer_name($cb_bufferp); + + # If alignment is #channel * | * + if (weechat::config_get_plugin("alignment") =~ /channel/) + { + # If it's actually channel number * | * + if (weechat::config_get_plugin("alignment") =~ /schannel/) + { + # Use channel number instead + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset"); + } + # Or if it's actually number:#channel * | * + if (weechat::config_get_plugin("alignment") =~ /nchannel/) + { + # Place channel number in front of formatted name + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname; + } + $outstr = $bufname."\t".$cb_msg; + } + # or if alignment is | * + else + { + $outstr = $bufname.": ".$cb_msg; + } + } + # highmon dynmon + elsif (!$cb_bufferp && !$nick) + { + $outstr = "\t".$cb_msg; + } + + # Send string to buffer + if (weechat::config_get_plugin("output") eq "buffer") + { + # Search for and confirm buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + # Print + weechat::print($highmon_buffer, $outstr); + } + elsif (weechat::config_get_plugin("output") eq "bar") + { + # Add time string + use POSIX qw(strftime); + $time = strftime(weechat::config_string(weechat::config_get("weechat.look.buffer_time_format")), localtime); + # Colourise + if ($time =~ /\$\{\w+\}/) # Coloured string + { + while ($time =~ /\$\{(\w+)\}/) + { + $color = weechat::color($1); + $time =~ s/\$\{\w+\}/$color/; + } + } + else # Default string + { + $colour = weechat::color(weechat::config_string(weechat::config_get("weechat.color.chat_time_delimiters"))); + $reset = weechat::color("reset"); + $time =~ s/(\d*)(.)(\d*)/$1$colour$2$reset$3/g; + } + # Push updates to bar lists + push (@bar_lines_time, $time); + + # Change tab char + $delim = " ".weechat::color(weechat::config_string(weechat::config_get("weechat.color.chat_delimiters"))).weechat::config_string(weechat::config_get("weechat.look.prefix_suffix")).weechat::color("reset")." "; + $outstr =~ s/\t/$delim/; + + push (@bar_lines, $outstr); + # Trigger update + weechat::bar_item_update("highmon"); + + if (weechat::config_get_plugin("bar_scrolldown") eq "on") + { + weechat::command("", "/bar scroll highmon * ye") + } + } +} + +# Start the output display +sub highmon_start +{ + if (weechat::config_get_plugin("output") eq "buffer") + { + highmon_buffer_open(); + } + elsif (weechat::config_get_plugin("output") eq "bar") + { + highmon_bar_open(); + } +} + +# Takes two optional args (channel server), toggles monitoring on/off +sub highmon_toggle +{ + $data = $_[0]; + $buffer = $_[1]; + $args = $_[2]; + + # Check if we've been told what channel to act on + if ($args ne "") + { + # Split argument up + @arg_array = split(/ /,$args); + # Check if a server was given + if ($arg_array[1]) + { + # Find matching + $bufp = weechat::buffer_search("irc", $arg_array[1].".".$arg_array[0]); + } + else + { + $found_chans = 0; + # Loop through defined servers + $infolist = weechat::infolist_get("buffer", "", ""); + while (weechat::infolist_next($infolist)) + { + # Only interesting in IRC buffers + if (weechat::infolist_string($infolist, "plugin_name") eq "irc") + { + # Find buffers that maych + $sname = weechat::infolist_string($infolist, "short_name"); + if ($sname eq $arg_array[0]) + { + $found_chans++; + $bufp = weechat::infolist_pointer($infolist, "pointer"); + } + } + } + weechat::infolist_free($infolist); + # If the infolist found more than one channel, halt as we need to know which one + if ($found_chans > 1) + { + weechat::print("", "Channel name is not unique, please define server"); + return weechat::WEECHAT_RC_OK; + } + } + # Something didn't return right + if ($bufp eq "") + { + weechat::print("", "Could not find buffer"); + return weechat::WEECHAT_RC_OK; + } + } + else + { + # Get pointer from where we are + $bufp = weechat::current_buffer(); + } + # Get buffer name + $bufname = weechat::buffer_get_string($bufp, 'name'); + # Test if buffer is an IRC channel + if ($bufname =~ /(.*)\.([#&\+!])(.*)/) + { + if (weechat::config_get_plugin($bufname) eq "off") + { + # If currently off, set on + weechat::config_set_plugin($bufname, "on"); + + # Send to output formatter + highmon_print("Highlight Monitoring Enabled", $bufp); + return weechat::WEECHAT_RC_OK; + } + elsif (weechat::config_get_plugin($bufname) eq "on" || weechat::config_get_plugin($bufname) eq "") + { + # If currently on, set off + weechat::config_set_plugin($bufname, "off"); + + # Send to output formatter + highmon_print("Highlight Monitoring Disabled", $bufp); + return weechat::WEECHAT_RC_OK; + } + } +} + +# Takes a buffer pointer and returns a formatted name +sub format_buffer_name +{ + $cb_bufferp = $_[0]; + $bufname = weechat::buffer_get_string($cb_bufferp, 'name'); + + # Set colour from buffer name + if (weechat::config_get_plugin("color_buf") eq "on") + { + # Determine what colour to use + $color = weechat::info_get("irc_nick_color", $bufname); + if (!$color) + { + $color = 0; + @char_array = split(//,$bufname); + foreach $char (@char_array) + { + $color += ord($char); + } + $color %= 10; + $color = sprintf "weechat.color.chat_nick_color%02d", $color+1; + $color = weechat::config_get($color); + $color = weechat::config_string($color); + $color = weechat::color($color); + } + + # Private message just show network + if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private") + { + $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server"); + } + # Format name to short or 'nicename' + elsif (weechat::config_get_plugin("short_names") eq "on") + { + $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name'); + } + else + { + $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/; + } + + # Build a coloured string + $bufname = $color.$bufname.weechat::color("reset"); + } + # User set colour name + elsif (weechat::config_get_plugin("color_buf") ne "off") + { + # Private message just show network + if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private") + { + $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server"); + } + # Format name to short or 'nicename' + elsif (weechat::config_get_plugin("short_names") eq "on") + { + $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name'); + } + else + { + $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/; + } + + $color = weechat::config_get_plugin("color_buf"); + $bufname = weechat::color($color).$bufname.weechat::color("reset"); + } + # Stick with default colour + else + { + # Private message just show network + if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private") + { + $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server"); + } + # Format name to short or 'nicename' + elsif (weechat::config_get_plugin("short_names") eq "on") + { + $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name'); + } + else + { + $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/; + } + } + + return $bufname; +} + +# Check result of register, and attempt to behave in a sane manner +if (!weechat::register("highmon", "KenjiE20", "2.3.2", "GPL3", "Highlight Monitor", "", "")) +{ + # Double load + weechat::print ("", "\tHighmon is already loaded"); + return weechat::WEECHAT_RC_OK; +} +else +{ + # Start everything + highmon_hook(); + highmon_config_init(); + highmon_start(); +} diff --git a/weechat/perl/iset.pl b/weechat/perl/iset.pl new file mode 100644 index 0000000..d27ec92 --- /dev/null +++ b/weechat/perl/iset.pl @@ -0,0 +1,1394 @@ +# +# Copyright (C) 2008-2012 Sebastien Helleu +# Copyright (C) 2010-2012 Nils Görs +# +# 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 . +# +# Set WeeChat and plugins options interactively. +# +# History: +# +# 2013-04-30, arza : +# version 3.0: simpler title, fix refresh on unset +# 2012-12-16, nils_2 : +# version 2.9: fix focus window with iset buffer on mouse click +# 2012-08-25, nils_2 : +# version 2.8: most important key and mouse bindings for iset buffer added to title-bar (idea The-Compiler) +# 2012-07-31, nils_2 : +# version 2.7: add combined option and value search (see /help iset) +# : add exact value search (see /help iset) +# : fix problem with metacharacter in value search +# : fix use of uninitialized value for unset option and reset value of option +# 2012-07-25, nils_2 : +# version 2.6: switch to iset buffer (if existing) when command /iset is called with arguments +# 2012-03-17, Sebastien Helleu : +# version 2.5: fix check of sections when creating config file +# 2012-03-09, Sebastien Helleu : +# version 2.4: fix reload of config file +# 2012-02-02, nils_2 : +# version 2.3: fixed: refresh problem with new search results and cursor was outside window. +# : add: new option "current_line" in title bar +# version 2.2: fixed: refresh error when toggling plugins description +# 2011-11-05, nils_2 : +# version 2.1: use own config file (iset.conf), fix own help color (used immediately) +# 2011-10-16, nils_2 : +# version 2.0: add support for left-mouse-button and more sensitive mouse gesture (for integer/color options) +# add help text for mouse support +# 2011-09-20, Sebastien Helleu : +# version 1.9: add mouse support, fix iset buffer, fix errors on first load under FreeBSD +# 2011-07-21, nils_2 : +# version 1.8: added: option "show_plugin_description" (alt+p) +# fixed: typos in /help iset (lower case for alt+'x' keys) +# 2011-05-29, nils_2 : +# version 1.7: added: version check for future needs +# added: new option (scroll_horiz) and usage of scroll_horiz function (weechat >= 0.3.6 required) +# fixed: help_bar did not pop up immediately using key-shortcut +# 2011-02-19, nils_2 : +# version 1.6: added: display of all possible values in help bar (show_help_extra_info) +# fixed: external user options never loaded when starting iset first time +# 2011-02-13, Sebastien Helleu : +# version 1.5: use new help format for command arguments +# 2011-02-03, nils_2 : +# version 1.4: fixed: restore value filter after /upgrade using buffer local variable. +# 2011-01-14, nils_2 : +# version 1.3: added function to search for values (option value_search_char). +# code optimization. +# 2010-12-26, Sebastien Helleu : +# version 1.2: improve speed of /upgrade when iset buffer is open, +# restore filter used after /upgrade using buffer local variable, +# use /iset filter argument if buffer is open. +# 2010-11-21, drubin : +# version 1.1.1: fix bugs with cursor position +# 2010-11-20, nils_2 : +# version 1.1: cursor position set to value +# 2010-08-03, Sebastien Helleu : +# version 1.0: move misplaced call to infolist_free() +# 2010-02-02, rettub : +# version 0.9: turn all the help stuff off if option 'show_help_bar' is 'off', +# new key binding - to toggle help_bar and help stuff on/off +# 2010-01-30, nils_2 : +# version 0.8: fix error when option does not exist +# 2010-01-24, Sebastien Helleu : +# version 0.7: display iset bar only on iset buffer +# 2010-01-22, nils_2 and drubin: +# version 0.6: add description in a bar, fix singular/plural bug in title bar, +# fix selected line when switching buffer +# 2009-06-21, Sebastien Helleu : +# version 0.5: fix bug with iset buffer after /upgrade +# 2009-05-02, Sebastien Helleu : +# version 0.4: sync with last API changes +# 2009-01-04, Sebastien Helleu : +# version 0.3: open iset buffer when /iset command is executed +# 2009-01-04, Sebastien Helleu : +# version 0.2: use null values for options, add colors, fix refresh bugs, +# use new keys to reset/unset options, sort options by name, +# display number of options in buffer's title +# 2008-11-05, Sebastien Helleu : +# version 0.1: first official version +# 2008-04-19, Sebastien Helleu : +# script creation + +use strict; + +my $PRGNAME = "iset"; +my $VERSION = "3.0"; +my $DESCR = "Interactive Set for configuration options"; +my $AUTHOR = "Sebastien Helleu "; +my $LICENSE = "GPL3"; +my $LANG = "perl"; +my $ISET_CONFIG_FILE_NAME = "iset"; + +my $iset_config_file; +my $iset_buffer = ""; +my $wee_version_number = 0; +my @iset_focus = (); +my @options_names = (); +my @options_types = (); +my @options_values = (); +my @options_is_null = (); +my $option_max_length = 0; +my $current_line = 0; +my $filter = "*"; +my $description = ""; +my $options_name_copy = ""; +my $iset_filter_title = ""; +# search modes: 0 = index() on value, 1 = grep() on value, 2 = grep() on option, 3 = grep on option & value +my $search_mode = 2; +my $search_value = ""; +my $help_text_keys = "alt + space: toggle, +/-: increase/decrease, enter: change, ir: reset, iu: unset, v: toggle help bar"; +my $help_text_mouse = "Mouse: left: select, right: toggle/set, right + drag left/right: increase/decrease"; +my %options_iset; + +my %mouse_keys = ("\@chat(perl.$PRGNAME):button1" => "hsignal:iset_mouse", + "\@chat(perl.$PRGNAME):button2*" => "hsignal:iset_mouse", + "\@chat(perl.$PRGNAME):wheelup" => "/repeat 5 /iset **up", + "\@chat(perl.$PRGNAME):wheeldown" => "/repeat 5 /iset **down"); + + +sub iset_title +{ + if ($iset_buffer ne "") + { + my $current_line_counter = ""; + $current_line_counter = ($current_line + 1) . "/" if (weechat::config_boolean($options_iset{"show_current_line"}) == 1); + my $show_filter = ""; + if ($search_mode eq 0) + { + $iset_filter_title = "(value) "; + $show_filter = $search_value; + if ( substr($show_filter,0,1) eq weechat::config_string($options_iset{"value_search_char"}) ) + { + $show_filter = substr($show_filter,1,length($show_filter)); + } + } + elsif ($search_mode eq 1) + { + $iset_filter_title = "(value) "; + $show_filter = "*".$search_value."*"; + } + elsif ($search_mode eq 2) + { + $iset_filter_title = ""; + $filter = "*" if ($filter eq ""); + $show_filter = $filter; + } + elsif ($search_mode eq 3) + { + $iset_filter_title = "(option) "; + $show_filter = $filter + .weechat::color("default") + ." / (value) " + .weechat::color("yellow") + ."*".$search_value."*"; + } + weechat::buffer_set($iset_buffer, "title", + $iset_filter_title + .weechat::color("yellow") + .$show_filter + .weechat::color("default")." | " + .$current_line_counter + .@options_names + ." | " + .$help_text_keys + ." | " + .$help_text_mouse); + } +} + +sub iset_create_filter +{ + $filter = $_[0]; + if ( $search_mode == 3 ) + { + my @cmd_array = split(/ /,$filter); + my $array_count = @cmd_array; + $filter = $cmd_array[0]; + $filter = $cmd_array[0] . " " . $cmd_array[1] if ( $array_count >2 ); + } + $filter = "$1.*" if ($filter =~ /f (.*)/); # search file + $filter = "*.$1.*" if ($filter =~ /s (.*)/); # search section + if ((substr($filter, 0, 1) ne "*") && (substr($filter, -1, 1) ne "*")) + { + $filter = "*".$filter."*"; + } + if ($iset_buffer ne "") + { + weechat::buffer_set($iset_buffer, "localvar_set_iset_filter", $filter); + } +} + +sub iset_buffer_input +{ + my ($data, $buffer, $string) = ($_[0], $_[1], $_[2]); + $search_value = ""; + my @cmd_array = split(/ /,$string); + my $array_count = @cmd_array; + my $string2 = substr($string, 0, 1); + if ($string2 eq weechat::config_string($options_iset{"value_search_char"}) + or (defined $cmd_array[0] and $cmd_array[0] eq weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})) ) + { + $search_mode = 1; + $search_value = substr($string, 1); + iset_get_values($search_value); + if ($iset_buffer ne "") + { + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + } + } + else + { + $search_mode = 2; + if ( $array_count >= 2 and $cmd_array[0] ne "f" or $cmd_array[0] ne "s") + { + if ( defined $cmd_array[1] and substr($cmd_array[1], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) + or defined $cmd_array[2] and substr($cmd_array[2], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) ) + { + $search_mode = 3; + $search_value = substr($cmd_array[1], 1); # cut value_search_char + $search_value = substr($cmd_array[2], 1) if ( $array_count > 2); # cut value_search_char + } + } + if ( $search_mode == 3) + { + iset_create_filter($string); + iset_get_options($search_value); + }else + { + iset_create_filter($string); + iset_get_options(""); + } + } + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_clear($buffer); + $current_line = 0; + iset_refresh(); + return weechat::WEECHAT_RC_OK; +} + +sub iset_buffer_close +{ + $iset_buffer = ""; + + return weechat::WEECHAT_RC_OK; +} + +sub iset_init +{ + $current_line = 0; + $iset_buffer = weechat::buffer_search($LANG, $PRGNAME); + if ($iset_buffer eq "") + { + $iset_buffer = weechat::buffer_new($PRGNAME, "iset_buffer_input", "", "iset_buffer_close", ""); + } + else + { + my $new_filter = weechat::buffer_get_string($iset_buffer, "localvar_iset_filter"); + $search_mode = weechat::buffer_get_string($iset_buffer, "localvar_iset_search_mode"); + $search_value = weechat::buffer_get_string($iset_buffer, "localvar_iset_search_value"); + $filter = $new_filter if ($new_filter ne ""); + } + if ($iset_buffer ne "") + { + weechat::buffer_set($iset_buffer, "type", "free"); + iset_title(); + weechat::buffer_set($iset_buffer, "key_bind_ctrl-L", "/iset **refresh"); + weechat::buffer_set($iset_buffer, "key_bind_meta2-A", "/iset **up"); + weechat::buffer_set($iset_buffer, "key_bind_meta2-B", "/iset **down"); + weechat::buffer_set($iset_buffer, "key_bind_meta2-23~", "/iset **left"); + weechat::buffer_set($iset_buffer, "key_bind_meta2-24~" , "/iset **right"); + weechat::buffer_set($iset_buffer, "key_bind_meta- ", "/iset **toggle"); + weechat::buffer_set($iset_buffer, "key_bind_meta-+", "/iset **incr"); + weechat::buffer_set($iset_buffer, "key_bind_meta--", "/iset **decr"); + weechat::buffer_set($iset_buffer, "key_bind_meta-imeta-r", "/iset **reset"); + weechat::buffer_set($iset_buffer, "key_bind_meta-imeta-u", "/iset **unset"); + weechat::buffer_set($iset_buffer, "key_bind_meta-ctrl-J", "/iset **set"); + weechat::buffer_set($iset_buffer, "key_bind_meta-ctrl-M", "/iset **set"); + weechat::buffer_set($iset_buffer, "key_bind_meta-meta2-1~", "/iset **scroll_top"); + weechat::buffer_set($iset_buffer, "key_bind_meta-meta2-4~", "/iset **scroll_bottom"); + weechat::buffer_set($iset_buffer, "key_bind_meta-v", "/iset **toggle_help"); + weechat::buffer_set($iset_buffer, "key_bind_meta-p", "/iset **toggle_show_plugin_desc"); + weechat::buffer_set($iset_buffer, "localvar_set_iset_filter", $filter); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + } +} + +sub iset_get_options +{ + my $var_value = $_[0]; + $var_value = "" if (not defined $var_value); + $var_value = lc($var_value); + $search_value = $var_value; + @iset_focus = (); + @options_names = (); + @options_types = (); + @options_values = (); + @options_is_null = (); + $option_max_length = 0; + my %options_internal = (); + my $i = 0; + my $key; + my $iset_struct; + my %iset_struct; + + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $var_value) if ($search_mode == 3); + + my $infolist = weechat::infolist_get("option", "", $filter); + while (weechat::infolist_next($infolist)) + { + $key = sprintf("%08d", $i); + my $name = weechat::infolist_string($infolist, "full_name"); + next if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 0 and index ($name, "plugins.desc.") != -1); + my $type = weechat::infolist_string($infolist, "type"); + my $value = weechat::infolist_string($infolist, "value"); + my $is_null = weechat::infolist_integer($infolist, "value_is_null"); + if ($search_mode == 3) + { + my $value = weechat::infolist_string($infolist, "value"); + if ( grep /\Q$var_value/,lc($value) ) + { + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + $iset_struct{$key} = $options_internal{$name}; + push(@iset_focus, $iset_struct{$key}); + } + } + else + { + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + $iset_struct{$key} = $options_internal{$name}; + push(@iset_focus, $iset_struct{$key}); + } + $i++; + } + weechat::infolist_free($infolist); + + foreach my $name (sort keys %options_internal) + { + push(@options_names, $name); + push(@options_types, $options_internal{$name}{"type"}); + push(@options_values, $options_internal{$name}{"value"}); + push(@options_is_null, $options_internal{$name}{"is_null"}); + } +} + +sub iset_get_values +{ + my $var_value = $_[0]; + $var_value = lc($var_value); + if (substr($var_value,0,1) eq weechat::config_string($options_iset{"value_search_char"}) and $var_value ne weechat::config_string($options_iset{"value_search_char"})) + { + $var_value = substr($var_value,1,length($var_value)); + $search_mode = 0; + } + iset_search_values($var_value,$search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $var_value); + $search_value = $var_value; +} +sub iset_search_values +{ + my ($var_value,$search_mode) = ($_[0],$_[1]); + @options_names = (); + @options_types = (); + @options_values = (); + @options_is_null = (); + $option_max_length = 0; + my %options_internal = (); + my $i = 0; + my $infolist = weechat::infolist_get("option", "", "*"); + while (weechat::infolist_next($infolist)) + { + my $name = weechat::infolist_string($infolist, "full_name"); + next if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 0 and index ($name, "plugins.desc.") != -1); + my $type = weechat::infolist_string($infolist, "type"); + my $is_null = weechat::infolist_integer($infolist, "value_is_null"); + my $value = weechat::infolist_string($infolist, "value"); + if ($search_mode) + { + if ( grep /\Q$var_value/,lc($value) ) + { + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + } + } + else + { +# if ($value =~ /\Q$var_value/si) + if (lc($value) eq $var_value) + { + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + } + } + $i++; + } + weechat::infolist_free($infolist); + foreach my $name (sort keys %options_internal) + { + push(@options_names, $name); + push(@options_types, $options_internal{$name}{"type"}); + push(@options_values, $options_internal{$name}{"value"}); + push(@options_is_null, $options_internal{$name}{"is_null"}); + } +} + +sub iset_refresh_line +{ + if ($iset_buffer ne "") + { + my $y = $_[0]; + if ($y <= $#options_names) + { + return if (! defined($options_types[$y])); + my $format = sprintf("%%s%%-%ds %%s %%-7s %%s %%s%%s%%s", $option_max_length); + my $around = ""; + $around = "\"" if ((!$options_is_null[$y]) && ($options_types[$y] eq "string")); + + my $color1 = weechat::color(weechat::config_color($options_iset{"color_option"})); + my $color2 = weechat::color(weechat::config_color($options_iset{"color_type"})); + my $color3 = ""; + if ($options_is_null[$y]) + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_undef"})); + } + else + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value"})); + } + if ($y == $current_line) + { + $color1 = weechat::color(weechat::config_color($options_iset{"color_option_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + $color2 = weechat::color(weechat::config_color($options_iset{"color_type_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + if ($options_is_null[$y]) + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_undef_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + } + else + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + } + } + my $value = $options_values[$y]; + $value = "(undef)" if ($options_is_null[$y]); + my $strline = sprintf($format, + $color1, $options_names[$y], + $color2, $options_types[$y], + $color3, $around, $value, $around); + weechat::print_y($iset_buffer, $y, $strline); + } + } +} + +sub iset_refresh +{ + iset_title(); + if (($iset_buffer ne "") && ($#options_names >= 0)) + { + foreach my $y (0 .. $#options_names) + { + iset_refresh_line($y); + } + } + + weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1); +} + +sub iset_full_refresh +{ + $iset_buffer = weechat::buffer_search($LANG, $PRGNAME); + if ($iset_buffer ne "") + { + weechat::buffer_clear($iset_buffer) unless defined $_[0]; # iset_full_refresh(1) does a full refresh without clearing buffer + # search for "*" in $filter. + if ($filter =~ m/\*/ and $search_mode == 2) + { + iset_get_options(""); + } + else + { + if ($search_mode == 0) + { + $search_value = "=" . $search_value; + iset_get_values($search_value); + } + elsif ($search_mode == 1) + { + iset_get_values($search_value); + } + elsif ($search_mode == 3) + { + iset_create_filter($filter); + iset_get_options($search_value); + } + } + if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 1) + { + iset_set_current_line($current_line); + }else + { + $current_line = $#options_names if ($current_line > $#options_names); + } + iset_refresh(); + weechat::command($iset_buffer, "/window refresh"); + } +} + +sub iset_set_current_line +{ + my $new_current_line = $_[0]; + my $old_current_line = $current_line; + $current_line = $new_current_line; + $current_line = $#options_names if ($current_line > $#options_names); + if ($old_current_line != $current_line) + { + iset_refresh_line($old_current_line); + iset_refresh_line($current_line); + weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1); + } +} + +sub iset_signal_window_scrolled_cb +{ + my ($data, $signal, $signal_data) = ($_[0], $_[1], $_[2]); + if ($iset_buffer ne "") + { + my $infolist = weechat::infolist_get("window", $signal_data, ""); + if (weechat::infolist_next($infolist)) + { + if (weechat::infolist_pointer($infolist, "buffer") eq $iset_buffer) + { + my $old_current_line = $current_line; + my $new_current_line = $current_line; + my $start_line_y = weechat::infolist_integer($infolist, "start_line_y"); + my $chat_height = weechat::infolist_integer($infolist, "chat_height"); + $new_current_line += $chat_height if ($new_current_line < $start_line_y); + $new_current_line -= $chat_height if ($new_current_line >= $start_line_y + $chat_height); + $new_current_line = $start_line_y if ($new_current_line < $start_line_y); + $new_current_line = $start_line_y + $chat_height - 1 if ($new_current_line >= $start_line_y + $chat_height); + iset_set_current_line($new_current_line); + } + } + weechat::infolist_free($infolist); + } + + return weechat::WEECHAT_RC_OK; +} + +sub iset_get_window_number +{ + if ($iset_buffer ne "") + { + my $window = weechat::window_search_with_buffer($iset_buffer); + return "-window ".weechat::window_get_integer ($window, "number")." " if ($window ne ""); + } + return ""; +} + +sub iset_check_line_outside_window +{ + if ($iset_buffer ne "") + { + undef my $infolist; + if ($wee_version_number >= 0x00030500) + { + my $window = weechat::window_search_with_buffer($iset_buffer); + $infolist = weechat::infolist_get("window", $window, "") if $window; + } + else + { + $infolist = weechat::infolist_get("window", "", "current"); + } + if ($infolist) + { + if (weechat::infolist_next($infolist)) + { + my $start_line_y = weechat::infolist_integer($infolist, "start_line_y"); + my $chat_height = weechat::infolist_integer($infolist, "chat_height"); + my $window_number = ""; + if ($wee_version_number >= 0x00030500) + { + $window_number = "-window ".weechat::infolist_integer($infolist, "number")." "; + } + if ($start_line_y > $current_line) + { + weechat::command($iset_buffer, "/window scroll ".$window_number."-".($start_line_y - $current_line)); + } + else + { + if ($start_line_y <= $current_line - $chat_height) + { + weechat::command($iset_buffer, "/window scroll ".$window_number."+".($current_line - $start_line_y - $chat_height + 1)); + + } + } + } + weechat::infolist_free($infolist); + } + } +} + +sub iset_get_option_name_index +{ + my $option_name = $_[0]; + my $index = 0; + while ($index <= $#options_names) + { + return -1 if ($options_names[$index] gt $option_name); + return $index if ($options_names[$index] eq $option_name); + $index++; + } + return -1; +} + +sub iset_config_cb +{ + my ($data, $option_name, $value) = ($_[0], $_[1], $_[2]); + + if ($iset_buffer ne "") + { + return weechat::WEECHAT_RC_OK if (weechat::info_get("weechat_upgrading", "") eq "1"); + + my $index = iset_get_option_name_index($option_name); + if ($index >= 0) + { + # refresh info about changed option + my $infolist = weechat::infolist_get("option", "", $option_name); + if ($infolist) + { + weechat::infolist_next($infolist); + if (weechat::infolist_fields($infolist)) + { + $options_types[$index] = weechat::infolist_string($infolist, "type"); + $options_values[$index] = weechat::infolist_string($infolist, "value"); + $options_is_null[$index] = weechat::infolist_integer($infolist, "value_is_null"); + iset_refresh_line($index); + iset_title() if ($option_name eq "iset.look.show_current_line"); + } + else + { + iset_full_refresh(1); # if not found, refresh fully without clearing buffer + weechat::print_y($iset_buffer, $#options_names + 1, ""); + } + weechat::infolist_free($infolist); + } + } + else + { + iset_full_refresh() if ($option_name ne "weechat.bar.isetbar.hidden"); + } + } + + return weechat::WEECHAT_RC_OK; +} + +sub iset_set_option +{ + my ($option, $value) = ($_[0],$_[1]); + if (defined $option and defined $value) + { + $option = weechat::config_get($option); + weechat::config_option_set($option, $value, 1) if ($option ne ""); + } +} + +sub iset_reset_option +{ + my $option = $_[0]; + if (defined $option) + { + $option = weechat::config_get($option); + weechat::config_option_reset($option, 1) if ($option ne ""); + } +} + +sub iset_unset_option +{ + my $option = $_[0]; + if (defined $option) + { + $option = weechat::config_get($option); + weechat::config_option_unset($option) if ($option ne ""); + } +} + + +sub iset_cmd_cb +{ + my ($data, $buffer, $args) = ($_[0], $_[1], $_[2]); + my $filter_set = 0; +# $search_value = ""; + if (($args ne "") && (substr($args, 0, 2) ne "**")) + { + my @cmd_array = split(/ /,$args); + my $array_count = @cmd_array; + if (substr($args, 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) + or (defined $cmd_array[0] and $cmd_array[0] eq weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})) ) + { + $search_mode = 1; + my $search_value = substr($args, 1); # cut value_search_char + if ($iset_buffer ne "") + { + weechat::buffer_clear($iset_buffer); + weechat::command($iset_buffer, "/window refresh"); + } + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + iset_init(); + iset_get_values($search_value); + iset_refresh(); + weechat::buffer_set($iset_buffer, "display", "1"); +# $filter = $var_value; + return weechat::WEECHAT_RC_OK; + } + else + { + # f/s option =value + # option =value + $search_mode = 2; + if ( $array_count >= 2 and $cmd_array[0] ne "f" or $cmd_array[0] ne "s") + { + if ( defined $cmd_array[1] and substr($cmd_array[1], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) + or defined $cmd_array[2] and substr($cmd_array[2], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) ) + { + $search_mode = 3; + $search_value = substr($cmd_array[1], 1); # cut value_search_char + $search_value = substr($cmd_array[2], 1) if ( $array_count > 2); # cut value_search_char + } + } + iset_create_filter($args); + $filter_set = 1; + my $ptrbuf = weechat::buffer_search($LANG, $PRGNAME); + if ($ptrbuf eq "") + { + iset_init(); + iset_get_options($search_value); + iset_full_refresh(); + weechat::buffer_set(weechat::buffer_search($LANG, $PRGNAME), "display", "1"); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + return weechat::WEECHAT_RC_OK; + } + else + { + iset_get_options($search_value); + iset_full_refresh(); + weechat::buffer_set($ptrbuf, "display", "1"); + } + } + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + } + if ($iset_buffer eq "") + { + iset_init(); + iset_get_options(""); + iset_refresh(); + } + else + { +# iset_get_options($search_value); + iset_full_refresh() if ($filter_set); + } + + if ($args eq "") + { + weechat::buffer_set($iset_buffer, "display", "1"); + } + else + { + if ($args eq "**refresh") + { + iset_full_refresh(); + } + if ($args eq "**up") + { + if ($current_line > 0) + { + $current_line--; + iset_refresh_line($current_line + 1); + iset_refresh_line($current_line); + iset_check_line_outside_window(); + } + } + if ($args eq "**down") + { + if ($current_line < $#options_names) + { + $current_line++; + iset_refresh_line($current_line - 1); + iset_refresh_line($current_line); + iset_check_line_outside_window(); + } + } + if ($args eq "**left" && $wee_version_number >= 0x00030600) + { + weechat::command($iset_buffer, "/window scroll_horiz ".iset_get_window_number()."-".weechat::config_integer($options_iset{"scroll_horiz"})."%"); + } + if ($args eq "**right" && $wee_version_number >= 0x00030600) + { + weechat::command($iset_buffer, "/window scroll_horiz ".iset_get_window_number().weechat::config_integer($options_iset{"scroll_horiz"})."%"); + } + if ($args eq "**scroll_top") + { + my $old_current_line = $current_line; + $current_line = 0; + iset_refresh_line ($old_current_line); + iset_refresh_line ($current_line); + iset_title(); + weechat::command($iset_buffer, "/window scroll_top ".iset_get_window_number()); + } + if ($args eq "**scroll_bottom") + { + my $old_current_line = $current_line; + $current_line = $#options_names; + iset_refresh_line ($old_current_line); + iset_refresh_line ($current_line); + iset_title(); + weechat::command($iset_buffer, "/window scroll_bottom ".iset_get_window_number()); + } + if ($args eq "**toggle") + { + if ($options_types[$current_line] eq "boolean") + { + iset_set_option($options_names[$current_line], "toggle"); + } + } + if ($args eq "**incr") + { + if (($options_types[$current_line] eq "integer") + || ($options_types[$current_line] eq "color")) + { + iset_set_option($options_names[$current_line], "++1"); + } + } + if ($args eq "**decr") + { + if (($options_types[$current_line] eq "integer") + || ($options_types[$current_line] eq "color")) + { + iset_set_option($options_names[$current_line], "--1"); + } + } + if ($args eq "**reset") + { + iset_reset_option($options_names[$current_line]); + } + if ($args eq "**unset") + { + iset_unset_option($options_names[$current_line]); + } + if ($args eq "**toggle_help") + { + if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1) + { + weechat::config_option_set($options_iset{"show_help_bar"},0,1); + iset_show_bar(0); + } + else + { + weechat::config_option_set($options_iset{"show_help_bar"},1,1); + iset_show_bar(1); + } + } + if ($args eq "**toggle_show_plugin_desc") + { + if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 1) + { + weechat::config_option_set($options_iset{"show_plugin_description"},0,1); + iset_full_refresh(); + iset_check_line_outside_window(); + iset_title(); + } + else + { + weechat::config_option_set($options_iset{"show_plugin_description"},1,1); + iset_full_refresh(); + iset_check_line_outside_window(); + iset_title(); + } + } + if ($args eq "**set") + { + my $quote = ""; + my $value = $options_values[$current_line]; + if ($options_is_null[$current_line]) + { + $value = "null"; + } + else + { + $quote = "\"" if ($options_types[$current_line] eq "string"); + } + weechat::buffer_set($iset_buffer, "input", "/set ".$options_names[$current_line]." ".$quote.$value.$quote); + weechat::command($iset_buffer, "/input move_beginning_of_line"); + weechat::command($iset_buffer, "/input move_next_word"); + weechat::command($iset_buffer, "/input move_next_word"); + weechat::command($iset_buffer, "/input move_next_char"); + weechat::command($iset_buffer, "/input move_next_char") if ($quote ne ""); + } + } + weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1); + return weechat::WEECHAT_RC_OK; +} + +sub iset_get_help +{ + my ($redraw) = ($_[0]); + + return '' if (weechat::config_boolean($options_iset{"show_help_bar"}) == 0); + + if (not defined $options_names[$current_line]) + { + return "No option selected. Set a new filter using command line (use '*' to see all options)"; + } + if ($options_name_copy eq $options_names[$current_line] and not defined $redraw) + { + return $description; + } + $options_name_copy = $options_names[$current_line]; + my $optionlist =""; + $optionlist = weechat::infolist_get("option", "", $options_names[$current_line]); + weechat::infolist_next($optionlist); + my $full_name = weechat::infolist_string($optionlist,"full_name"); + my $option_desc = ""; + my $option_default_value = ""; + my $option_range = ""; + my $possible_values = ""; + my $re = qq(\Q$full_name); + if (grep (/^$re$/,$options_names[$current_line])) + { + $option_desc = weechat::infolist_string($optionlist, "description_nls"); + $option_desc = weechat::infolist_string($optionlist, "description") if ($option_desc eq ""); + $option_desc = "No help found" if ($option_desc eq ""); + $option_default_value = weechat::infolist_string($optionlist, "default_value"); + $possible_values = weechat::infolist_string($optionlist, "string_values") if (weechat::infolist_string($optionlist, "string_values") ne ""); + if ((weechat::infolist_string($optionlist, "type") eq "integer") && ($possible_values eq "")) + { + $option_range = weechat::infolist_integer($optionlist, "min") + ." .. ".weechat::infolist_integer($optionlist, "max"); + } + } + weechat::infolist_free($optionlist); + iset_title(); + + $description = weechat::color(weechat::config_color($options_iset{"color_help_option_name"})).$options_names[$current_line] + .weechat::color("bar_fg").": " + .weechat::color(weechat::config_color($options_iset{"color_help_text"})).$option_desc; + + # show additional infos like default value and possible values + + if (weechat::config_boolean($options_iset{"show_help_extra_info"}) == 1) + { + $description .= + weechat::color("bar_delim")." [" + .weechat::color("bar_fg")."default: " + .weechat::color("bar_delim")."\"" + .weechat::color(weechat::config_color($options_iset{"color_help_default_value"})).$option_default_value + .weechat::color("bar_delim")."\""; + if ($option_range ne "") + { + $description .= weechat::color("bar_fg").", values: ".$option_range; + } + if ($possible_values ne "") + { + $possible_values =~ s/\|/", "/g; # replace '|' to '", "' + $description .= weechat::color("bar_fg").", values: ". "\"" . $possible_values . "\""; + + } + $description .= weechat::color("bar_delim")."]"; + } + return $description; +} + +sub iset_check_condition_isetbar_cb +{ + my ($data, $modifier, $modifier_data, $string) = ($_[0], $_[1], $_[2], $_[3]); + my $buffer = weechat::window_get_pointer($modifier_data, "buffer"); + if ($buffer ne "") + { + if ((weechat::buffer_get_string($buffer, "plugin") eq $LANG) + && (weechat::buffer_get_string($buffer, "name") eq $PRGNAME)) + { + return "1"; + } + } + return "0"; +} + +sub iset_show_bar +{ + my $show = $_[0]; + my $barhidden = weechat::config_get("weechat.bar.isetbar.hidden"); + if ($barhidden) + { + if ($show) + { + if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1) + { + if (weechat::config_boolean($barhidden)) + { + weechat::config_option_set($barhidden, 0, 1); + } + } + } + else + { + if (!weechat::config_boolean($barhidden)) + { + weechat::config_option_set($barhidden, 1, 1); + } + } + } +} + +sub iset_signal_buffer_switch_cb +{ + my $buffer_pointer = $_[2]; + my $show_bar = 0; + $show_bar = 1 if (weechat::buffer_get_integer($iset_buffer, "num_displayed") > 0); + iset_show_bar($show_bar); + iset_check_line_outside_window() if ($buffer_pointer eq $iset_buffer); + return weechat::WEECHAT_RC_OK; +} + +sub iset_item_cb +{ + return iset_get_help(); +} + +sub iset_upgrade_ended +{ + iset_full_refresh(); +} + +sub iset_end +{ + # when script is unloaded, we hide bar + iset_show_bar(0); +} + +# -------------------------------[ mouse support ]------------------------------------- + +sub hook_focus_iset_cb +{ + my %info = %{$_[1]}; + my $bar_item_line = int($info{"_bar_item_line"}); + undef my $hash; + if (($info{"_buffer_name"} eq $PRGNAME) && $info{"_buffer_plugin"} eq $LANG && ($bar_item_line >= 0) && ($bar_item_line <= $#iset_focus)) + { + $hash = $iset_focus[$bar_item_line]; + } + else + { + $hash = {}; + my $hash_focus = $iset_focus[0]; + foreach my $key (keys %$hash_focus) + { + $hash->{$key} = "?"; + } + } + return $hash; +} + +# _chat_line_y contains selected line +sub iset_hsignal_mouse_cb +{ + my ($data, $signal, %hash) = ($_[0], $_[1], %{$_[2]}); + + if ($hash{"_buffer_name"} eq $PRGNAME && ($hash{"_buffer_plugin"} eq $LANG)) + { + if ($hash{"_key"} eq "button1") + { + $current_line = $hash{"_chat_line_y"}; + iset_refresh_line($current_line); + iset_refresh(); + } + elsif ($hash{"_key"} eq "button2") + { + if ($options_types[$hash{"_chat_line_y"}] eq "boolean") + { + iset_set_option($options_names[$hash{"_chat_line_y"}], "toggle"); + $current_line = $hash{"_chat_line_y"}; + iset_refresh_line($current_line); + iset_refresh(); + } + elsif ($options_types[$hash{"_chat_line_y"}] eq "string") + { + $current_line = $hash{"_chat_line_y"}; + iset_refresh_line($current_line); + iset_refresh(); + weechat::command("", "/$PRGNAME **set"); + } + } + elsif ($hash{"_key"} eq "button2-gesture-left" or $hash{"_key"} eq "button2-gesture-left-long") + { + if ($options_types[$hash{"_chat_line_y"}] eq "integer" or ($options_types[$hash{"_chat_line_y"}] eq "color")) + { + $current_line = $hash{"_chat_line_y"}; + iset_refresh_line($current_line); + iset_refresh(); + my $distance = distance($hash{"_chat_line_x"},$hash{"_chat_line_x2"}); + weechat::command("", "/repeat $distance /$PRGNAME **decr"); + } + } + elsif ($hash{"_key"} eq "button2-gesture-right" or $hash{"_key"} eq "button2-gesture-right-long") + { + if ($options_types[$hash{"_chat_line_y"}] eq "integer" or ($options_types[$hash{"_chat_line_y"}] eq "color")) + { + $current_line = $hash{"_chat_line_y"}; + iset_refresh_line($current_line); + iset_refresh(); + my $distance = distance($hash{"_chat_line_x"},$hash{"_chat_line_x2"}); + weechat::command("", "/repeat $distance /$PRGNAME **incr"); + } + } + } + window_switch(); +} + +sub window_switch +{ + my $current_window = weechat::current_window(); + my $dest_window = weechat::window_search_with_buffer(weechat::buffer_search("perl","iset")); + return 0 if ($dest_window eq "" or $current_window eq $dest_window); + + my $infolist = weechat::infolist_get("window", $dest_window, ""); + weechat::infolist_next($infolist); + my $number = weechat::infolist_integer($infolist, "number"); + weechat::infolist_free($infolist); + weechat::command("","/window " . $number); +} + +sub distance +{ + my ($x1,$x2) = ($_[0], $_[1]); + my $distance; + $distance = $x1 - $x2; + $distance = abs($distance); + if ($distance > 0) + { + use integer; + $distance = $distance / 3; + $distance = 1 if ($distance == 0); + } + elsif ($distance == 0) + { + $distance = 1; + } + return $distance; +} + +# -----------------------------------[ config ]--------------------------------------- + +sub iset_config_init +{ + $iset_config_file = weechat::config_new($ISET_CONFIG_FILE_NAME,"iset_config_reload_cb",""); + return if ($iset_config_file eq ""); + + # section "color" + my $section_color = weechat::config_new_section($iset_config_file,"color", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_color eq "") + { + weechat::config_free($iset_config_file); + return; + } + $options_iset{"color_option"} = weechat::config_new_option( + $iset_config_file, $section_color, + "option", "color", "Color for option name in iset buffer", "", 0, 0, + "default", "default", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_option_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "option_selected", "color", "Color for selected option name in iset buffer", "", 0, 0, + "white", "white", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_type"} = weechat::config_new_option( + $iset_config_file, $section_color, + "type", "color", "Color for option type (integer, boolean, string)", "", 0, 0, + "brown", "brown", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_type_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "type_selected", "color", "Color for selected option type (integer, boolean, string)", "", 0, 0, + "yellow", "yellow", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value", "color", "Color for option value", "", 0, 0, + "cyan", "cyan", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value_selected", "color", "Color for selected option value", "", 0, 0, + "lightcyan", "lightcyan", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value_undef"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value_undef", "color", "Color for option value undef", "", 0, 0, + "green", "green", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value_undef_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value_undef_selected", "color", "Color for selected option value undef", "", 0, 0, + "lightgreen", "lightgreen", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_bg_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "bg_selected", "color", "Background color for current selected option", "", 0, 0, + "red", "red", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_help_option_name"} = weechat::config_new_option( + $iset_config_file, $section_color, + "help_option_name", "color", "Color for option name in help-bar", "", 0, 0, + "white", "white", 0, "", "", "bar_refresh", "", "", ""); + $options_iset{"color_help_text"} = weechat::config_new_option( + $iset_config_file, $section_color, + "help_text", "color", "Color for option description in help-bar", "", 0, 0, + "default", "default", 0, "", "", "bar_refresh", "", "", ""); + $options_iset{"color_help_default_value"} = weechat::config_new_option( + $iset_config_file, $section_color, + "help_default_value", "color", "Color for default option value in help-bar", "", 0, 0, + "green", "green", 0, "", "", "bar_refresh", "", "", ""); + + # section "help" + my $section_help = weechat::config_new_section($iset_config_file,"help", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_help eq "") + { + weechat::config_free($iset_config_file); + return; + } + $options_iset{"show_help_bar"} = weechat::config_new_option( + $iset_config_file, $section_help, + "show_help_bar", "boolean", "Show help bar", "", 0, 0, + "on", "on", 0, "", "", "toggle_help_cb", "", "", ""); + $options_iset{"show_help_extra_info"} = weechat::config_new_option( + $iset_config_file, $section_help, + "show_help_extra_info", "boolean", "Show additional information in help bar (default value, max./min. value) ", "", 0, 0, + "on", "on", 0, "", "", "", "", "", ""); + $options_iset{"show_plugin_description"} = weechat::config_new_option( + $iset_config_file, $section_help, + "show_plugin_description", "boolean", "Show plugin description in iset buffer", "", 0, 0, + "off", "off", 0, "", "", "full_refresh_cb", "", "", ""); + + # section "look" + my $section_look = weechat::config_new_section($iset_config_file, "look", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_look eq "") + { + weechat::config_free($iset_config_file); + return; + } + $options_iset{"value_search_char"} = weechat::config_new_option( + $iset_config_file, $section_look, + "value_search_char", "string", "Trigger char to tell iset to search for value instead of option (for example: =red)", "", 0, 0, + "=", "=", 0, "", "", "", "", "", ""); + $options_iset{"scroll_horiz"} = weechat::config_new_option( + $iset_config_file, $section_look, + "scroll_horiz", "integer", "scroll content of iset buffer n%", "", 1, 100, + "10", "10", 0, "", "", "", "", "", ""); + $options_iset{"show_current_line"} = weechat::config_new_option( + $iset_config_file, $section_look, + "show_current_line", "boolean", "show current line in title bar.", "", 0, 0, + "on", "on", 0, "", "", "", "", "", ""); +} + +sub iset_config_reload_cb +{ + my ($data,$config_file) = ($_[0], $_[1]); + return weechat::config_reload($config_file) +} + +sub iset_config_read +{ + return weechat::config_read($iset_config_file) if ($iset_config_file ne ""); +} + +sub iset_config_write +{ + return weechat::config_write($iset_config_file) if ($iset_config_file ne ""); +} + +sub full_refresh_cb +{ + iset_full_refresh(); + return weechat::WEECHAT_RC_OK; +} + +sub bar_refresh +{ + iset_get_help(1); + weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1); + return weechat::WEECHAT_RC_OK; +} + +sub toggle_help_cb +{ + my $value = weechat::config_boolean($options_iset{"show_help_bar"}); + iset_show_bar($value); + return weechat::WEECHAT_RC_OK; +} + +# -----------------------------------[ main ]----------------------------------------- + +weechat::register($PRGNAME, $AUTHOR, $VERSION, $LICENSE, + $DESCR, "iset_end", ""); + +$wee_version_number = weechat::info_get("version_number", "") || 0; + +iset_config_init(); +iset_config_read(); + +weechat::hook_command($PRGNAME, "Interactive set", "f || s
|| [=][=]", + "f file : show options for a file\n". + "s section: show options for a section\n". + "text : show options with 'text' in name\n". + weechat::config_string($options_iset{"value_search_char"})."text : show options with 'text' in value\n". + weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})."text : show options with exact 'text' in value\n\n". + "Keys for iset buffer:\n". + "f11,f12 : move iset content left/right\n". + "up,down : move one option up/down\n". + "pgup,pdwn : move one page up/down\n". + "home,end : move to first/last option\n". + "ctrl+'L' : refresh options and screen\n". + "alt+space : toggle boolean on/off\n". + "alt+'+' : increase value (for integer or color)\n". + "alt+'-' : decrease value (for integer or color)\n". + "alt+'i',alt+'r': reset value of option\n". + "alt+'i',alt+'u': unset option\n". + "alt+enter : set new value for option (edit it with command line)\n". + "text,enter : set a new filter using command line (use '*' to see all options)\n". + "alt+'v' : toggle help bar on/off\n". + "alt+'p' : toggle option \"show_plugin_description\" on/off\n". + "\n". + "Mouse actions:\n". + "wheel up/down : move cursor up/down\n". + "left button : select an option from list\n". + "right button : toggle boolean (on/off) or set a new value for option (edit it with command line)\n". + "right button + drag left/right: increase/decrease value (for integer or color)\n". + "\n". + "Examples:\n". + " show options for file 'weechat'\n". + " /iset f weechat\n". + " show options for file 'irc'\n". + " /iset f irc\n". + " show options for section 'look'\n". + " /iset s look\n". + " show all options with text 'nicklist' in name\n". + " /iset nicklist\n". + " show all values which contain 'red'. ('" . weechat::config_string($options_iset{"value_search_char"}) . "' is a trigger char).\n". + " /iset ". weechat::config_string($options_iset{"value_search_char"}) ."red\n". + " show all values which hit 'off'. ('" . weechat::config_string($options_iset{"value_search_char"}) . weechat::config_string($options_iset{"value_search_char"}) . "' is a trigger char).\n". + " /iset ". weechat::config_string($options_iset{"value_search_char"}) . weechat::config_string($options_iset{"value_search_char"}) ."off\n". + " show options for file 'weechat' which contains value 'off'\n". + " /iset f weechat ".weechat::config_string($options_iset{"value_search_char"})."off\n". + "", + "", "iset_cmd_cb", ""); +weechat::hook_signal("upgrade_ended", "iset_upgrade_ended", ""); +weechat::hook_signal("window_scrolled", "iset_signal_window_scrolled_cb", ""); +weechat::hook_signal("buffer_switch", "iset_signal_buffer_switch_cb",""); +weechat::bar_item_new("isetbar_help", "iset_item_cb", ""); +weechat::bar_new("isetbar", "on", "0", "window", "", "top", "horizontal", + "vertical", "3", "3", "default", "cyan", "default", "1", + "isetbar_help"); +weechat::hook_modifier("bar_condition_isetbar", "iset_check_condition_isetbar_cb", ""); +weechat::hook_config("*", "iset_config_cb", ""); +$iset_buffer = weechat::buffer_search($LANG, $PRGNAME); +iset_init() if ($iset_buffer ne ""); + +if ($wee_version_number >= 0x00030600) +{ + weechat::hook_focus("chat", "hook_focus_iset_cb", ""); + weechat::hook_hsignal($PRGNAME."_mouse", "iset_hsignal_mouse_cb", ""); + weechat::key_bind("mouse", \%mouse_keys); +} diff --git a/weechat/perl/stalker.pl b/weechat/perl/stalker.pl new file mode 100644 index 0000000..813ef42 --- /dev/null +++ b/weechat/perl/stalker.pl @@ -0,0 +1,1408 @@ +# +# Copyright (c) 2013 by Nils Görs +# Copyright (c) 2013 by Stefan Wold +# based on irssi script stalker.pl from Kaitlyn Parkhurst (SymKat) +# https://github.com/symkat/Stalker +# +# Records and correlates nick!user@host information +# +# 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 . +# +# History: +# +# version 1.1:nils_2@freenode.#weechat +# 2013-10-31: add: flood-protection on JOINs +# +# version 1.0:nils_2@freenode.#weechat +# 2013-10-28: add: option 'additional_join_info' (idea by: arch_bcn) +# add: option 'timeout' time to wait for result of hook_process() +# add: localvar 'drop_additional_join_info' +# add: hook_process() to prevent blocking weechat on slower machines (like rpi) +# add: more DEBUG informations +# +# version 0.9: Ratler@freenode.#weechat +# 2013-08-11: fix: removed trailing whitespaces +# fix: only add index if it doesn't exist +# fix: dynamically create or upgrade database based on missing tables or columns +# fix: allow dynamically creating indices for future tables +# +# version 0.8: Ratler@freenode.#weechat +# 2013-08-09: add: case insensitive nick search +# add: show "server.nickname" in search results when search_this_network_only is set to off +# fix: type no longer needed for _ignore_guests() +# +# version 0.7: nils_2@freenode.#weechat +# 2013-08-04: add: support of colors with format "${color:xxx}" (>= WeeChat 0.4.2) +# add: function "remove_nick_from_host" (patch by FiXato) +# +# version 0.6: nils_2@freenode.#weechat +# 2013-05-27: cleanup code +# +# version 0.5: nils_2@freenode.#weechat +# 2013-05-26: add: function 'count' +# +# version 0.4: nils_2@freenode.#weechat +# 2013-05-18: add: option 'tags' +# +# version 0.3: nils_2@freenode.#weechat +# 2013-05-05: fix: typos in help and description option (thanks FiXato) +# add: 'ChanServ' to option 'guest_nick_regex' +# +# version 0.2: nils_2@freenode.#weechat +# 2013-05-01: fix: bug with regular expressions using /whois +# removed: option 'allow_regex_for_search' +# add: command option '-regex' +# +# version 0.1: nils_2@freenode.#weechat +# 2013-04-23: - initial release - +# +# thanks to firebird and mave_ for testing... +# +# Development is currently hosted at +# https://github.com/weechatter/weechat-scripts +# +# Requires: +# DBI +# DBD::SQLite +# +# How to install DBI: +# with cpan : install DBI +# with deb-package: sudo apt-get install libdbi-perl +# +# How to install DBD::SQLite: +# with cpan : install DBD::SQLite +# with deb-package: sudo apt-get install libdbd-sqlite3-perl libdbd-sqlite3 sqlite3-pcre + +#use strict; +use warnings; +use File::Spec; +use DBI; + +my $SCRIPT_NAME = "stalker"; +my $SCRIPT_VERSION = "1.1"; +my $SCRIPT_AUTHOR = "Nils Görs "; +my $SCRIPT_LICENCE = "GPL3"; +my $SCRIPT_DESC = "Records and correlates nick!user\@host information"; + + +# internal values +my $weechat_version = ""; +my $ptr_hook_timer = ""; +my $flood_counter = 0; # counter to take care of JOINs, e.g. after netsplit + +# default values +my %options = ('db_name' => '%h/nicks.db', + 'debug' => 'off', + 'max_recursion' => '20', + 'recursive_search' => 'on', + 'ignore_guest_hosts' => 'off', + 'ignore_guest_nicks' => 'on', + 'guest_nick_regex' => '^(guest|weebot|Floodbot|ChanServ).*', + 'guest_host_regex' => '^webchat', + 'normalize_nicks' => 'on', + 'search_this_network_only' => 'on', + 'use_localvar' => 'off', + 'ignore_nickchange' => 'off', + 'ignore_whois' => 'off', + 'tags' => '', + 'additional_join_info' => 'off', + 'timeout' => '1', + 'flood_timer' => '10', + 'flood_max_nicks' => '20', +# '' => '', +); +my %desc_options = ('db_name' => 'file containing the SQLite database where information is recorded. This database is created on loading of ' . $SCRIPT_NAME . ' if it does not exist. ("%h" will be replaced by WeeChat home, "~/.weechat" by default) (default: %h/nicks.db)', + 'debug' => 'Prints debug output to core buffer so you know exactly what is going on. This is far too verbose to be enabled when not actively debugging something. (default: off)', + 'max_recursion' => 'For each correlation between nick <-> host that happens, one point of recursion happens. A corrupt database, general evilness, or misfortune can cause the recursion to skyrocket. This is a ceiling number that says if after this many correlation attempts we have not found all nickname and hostname correlations, stop the process and return the list to this point. Use this option with care on slower machines like raspberry pi.', + 'recursive_search' => 'When enabled, recursive search causes stalker to function better than a simple hostname to nickname map. Disabling the recursive search in effect turns stalker into a more standard hostname -> nickname map.', + 'ignore_guest_hosts'=> 'See option guest_host_regex', + 'guest_host_regex' => 'regex mask to ignore host masks', + 'ignore_guest_nicks'=> 'See option guest_nick_regex', + 'guest_nick_regex' => 'Some networks set default nicknames when a user fails to identify to nickserv, other networks using relay-bots, some irc clients set default nicknames when someone connects and often these change from network to network depending on who is configuring the java irc clients. This allows a regular expression to be entered. When a nickname matches the regular expression and "ignore_guest_nicks" is enabled the nickname is dropped from the search as if it had never been seen. (default: ^(guest|weebot|Floodbot).*)', + 'normalize_nicks' => 'this option will truncate special chars from username (like: ~) (default: on)', + 'search_this_network_only' => 'When enabled searches are limited to within the network the window is currently set on. Turning this off is really only useful if multiple networks don\'t encode the hostmask. (default: on)', + 'use_localvar' => 'When enabled, only channels with a localvar \'stalker\' will be monitored. This option will not affect /NICK and /WHOIS monitoring. It\'s only for /JOIN messages. (default: off)', + 'ignore_nickchange' => 'When enabled, /NICK changes won\'t be monitored. (default: off)', + 'ignore_whois' => 'When enabled, /WHOIS won\'t be monitored. (default: off)', + 'tags' => 'comma separated list of tags used for messages printed by stalker. See documentation for possible tags (e.g. \'no_log\', \'no_highlight\'). This option does not effect DEBUG messages.', + 'additional_join_info' => 'add a line below the JOIN message that will display alternative nicks (tags: "irc_join", "irc_smart_filter" will be add to additional_join_info). You can use a localvar to drop additional join info for specific buffer(s) "stalker_drop_additional_join_info" (default: off)', + 'timeout' => 'timeout in seconds for hook_process(), used with option "additional_join_info". On slower machines, like raspberry pi, increase time. (default: 1)', + 'flood_timer' => 'Time in seconds for which flood protection is active. Once max_nicks is reached, joins will be ignored for the remaining duration of the timer. (default:10)', + 'flood_max_nicks' => 'Maximum number of joins to allow in flood_timer length of time. Once maximum number of joins is reached, joins will be ignored until the timer ends (default:20)', +); + +my $count; +my %data; +my $str; +my $DBH; +my $DBH_child; +my $DBH_fork; +my $last_nick = ""; +my $last_host = ""; + +# SQLite table definition +my %tables = ( + 'records' => [ + { 'column' => 'nick', 'type' => 'TEXT NOT NULL' }, + { 'column' => 'user', 'type' => 'TEXT NOT NULL' }, + { 'column' => 'host', 'type' => 'TEXT NOT NULL' }, + { 'column' => 'serv', 'type' => 'TEXT NOT NULL' }, + { 'column' => 'added', 'type' => 'DATE NOT NULL DEFAULT CURRENT_TIMESTAMP' }, + ], + ); + +# SQLite index definitions +my %indices = ( + 'records' => [ + { 'name' => 'index1', 'column' => 'nick' }, + { 'name' => 'index2', 'column' => 'host' }, + ], + ); + +# ---------------[ external routines for hook_process() ]--------------------- +if ($#ARGV == 8 ) # (0-8) nine arguments given? +{ + my $db_filename = $ARGV[0]; + my ($db_user, $db_pass); + $DBH_fork = DBI->connect( + 'dbi:SQLite:dbname='.$db_filename, $db_user, $db_pass, + { + RaiseError => 1, +# AutoCommit => 1, + sqlite_use_immediate_transaction => 1, + } + ); + + exit if (not defined $DBH_fork); + + if ($ARGV[1] eq 'additional_join_info') + { + my $nick = $ARGV[2]; + my $user = $ARGV[3]; + my $host = $ARGV[4]; + my $serv = $ARGV[5]; + my $max_recursion = $ARGV[6]; + my $ignore_guest_nicks = $ARGV[7]; + my $guest_nick_regex = $ARGV[8]; + + my $nicks_found = join( ", ", (get_nick_records_fork($nick, $serv, $max_recursion, $ignore_guest_nicks, $guest_nick_regex))); + + print "$nicks_found"; + $DBH_fork->disconnect(); + exit; + } + elsif ($ARGV[1] eq 'db_add_record') + { + my $nick = $ARGV[2]; + my $user = $ARGV[3]; + my $host = $ARGV[4]; + my $serv = $ARGV[5]; + +# DEBUG("info", "Adding to DB: nick = $nick, user = $user, host = $host, serv = $serv" ); + + # We don't have the record, add it. Test for record is done in add_record() + $sth = $DBH_fork->prepare("INSERT INTO records (nick,user,host,serv) VALUES( ?, ?, ?, ? )" ); + eval { $sth->execute( $nick, $user, $host, $serv ) }; + $DBH_fork->disconnect(); + if ($@) + { + print "error Failed to process record, database said: $@"; + exit; + } + print "info Added record for $nick!$user\@$host to $serv"; + } +exit; +} + +my $count2; +my %data_fork; +sub get_nick_records_fork +{ + my ( $nick, $serv, $max_recursion, $ignore_guest_nicks, $guest_nick_regex ) = @_; + my $type = 'nick'; + my @return; + $count2 = 0; %data_fork = ( ); + @return = _r_search_fork( $serv, $type, $max_recursion, $ignore_guest_nicks, $guest_nick_regex, ({ $type => $nick }) ); + + # remove original nick + @return = grep {$_ ne $nick} @return; + # case-insensitive sort + return sort {uc($a) cmp uc($b)} @return; +} + +my @nicks_found; +sub _r_search_fork +{ + my ( $serv, $type, $max_recursion, $ignore_guest_nicks, $guest_nick_regex, @input ) = @_; + return @nicks_found = &del_double(@nicks_found) if $count2 > $max_recursion; + + if ( $type eq 'nick' ) + { + $count2++; + for my $row ( @input ) + { + my $nick = $row->{nick}; + next if exists $data_fork{$nick}; + + $data_fork{$nick} = 'nick'; + my @hosts = _get_hosts_from_nick_fork( $nick, $serv, $ignore_guest_nicks, $guest_nick_regex ); + _r_search_fork ( $serv, 'host', $max_recursion, $ignore_guest_nicks, $guest_nick_regex, @hosts ); + } + } + elsif ( $type eq 'host' ) + { + $count2++; + for my $row ( @input ) + { + my $host = $row->{host}; + next if exists $data_fork{$host}; + $data_fork{$host} = 'host'; + + my @nicks = _get_nicks_from_host_fork ( $host, $serv, $ignore_guest_nicks, $guest_nick_regex ); + next if (scalar(@nicks) <= 0); + push @nicks_found, map { $_->{nick} } @nicks; + # search only current network +# $output_nicks = join( ", ", map { $_->{nick} } @nicks ); + + # use regex only for host search! + _r_search_fork( $serv, 'nick', $max_recursion, $ignore_guest_nicks, $guest_nick_regex, @nicks ); + } + } + return @nicks_found = &del_double(@nicks_found); +# return %data_fork; +} + +sub _get_hosts_from_nick_fork +{ + my ( $nick, $serv, $ignore_guest_nicks, $guest_nick_regex, @return ) = @_; + + my $sth = $DBH_fork->prepare( "SELECT nick, host FROM records WHERE nick = ? COLLATE NOCASE AND serv = ?" ); + $sth->execute( $nick, $serv ); + + return _ignore_guests_fork( $sth, $ignore_guest_nicks, $guest_nick_regex ); +} + +sub _get_nicks_from_host_fork +{ + my ( $host, $serv, $ignore_guest_nicks, $guest_nick_regex, @return ) = @_; + my $sth = $DBH_fork->prepare( "SELECT nick, host FROM records WHERE host = ? AND serv = ?" ); + $sth->execute( $host, $serv ); + + return _ignore_guests_fork( $sth,$ignore_guest_nicks, $guest_nick_regex ); +} + +sub del_double +{ + my %all=(); + @all{@_}=1; + return (keys %all); +} + +sub _ignore_guests_fork +{ + my ( $sth, $ignore_guest_nicks, $guest_nick_regex ) = @_; + my @return; + + while ( my $row = $sth->fetchrow_hashref ) + { + if ( lc($ignore_guest_nicks) eq "on" ) + { + my $regex = $guest_nick_regex; + next if( $row->{nick} =~ m/$regex/i ); + } + push @return, $row; + } + return @return; +} + +# -----------------------------[ Database ]----------------------------------- +sub open_database +{ + my $db = weechat_dir(); + + stat_database( $db ); + my ($db_user, $db_pass); + # my $db_host = '127.0.0.1'; + # my $db_port = 3306; + + $DBH = DBI->connect( + 'dbi:SQLite:dbname='.$db, $db_user, $db_pass, + { + RaiseError => 1, +# AutoCommit => 1, + sqlite_use_immediate_transaction => 1, + } + ); + + # DBI::SQLite and fork() don't mix. Do it anyhow but keep the parent and child DBH separate? + # Ideally the child should open its own connection. + $DBH_child = DBI->connect( + 'dbi:SQLite:dbname='.$db, $db_user, $db_pass, + { + RaiseError => 1, +# AutoCommit => 1, + sqlite_use_immediate_transaction => 1, + } + ); + + # async data + my @records_to_add; # Queue of records to add +} + +# Automatic Database Creation And Checking +sub stat_database { + my ( $db_file ) = @_; + + DEBUG('info', 'Stat database'); + if ( ! -e $db_file ) { + open my $fh, '>', $db_file + or die 'Cannot create database file. Abort.'; + close $fh; + } + my $DBH = DBI->connect( + 'dbi:SQLite:dbname='.$db_file, "", "", + { + RaiseError => 1, +# AutoCommit => 1, + sqlite_use_immediate_transaction => 1, + } + ); + + create_or_upgrade_database( $DBH ); + + index_db( $DBH ); +} + +sub create_or_upgrade_database { + my ( $DBH ) = @_; + + # This part will always add missing tables or columns defined in @tables (ie create or upgrade the database) + DEBUG("info", "Checking database table structure"); + my %col_exists; + for my $table (keys %tables) { + for my $col ( @{ $DBH->selectall_arrayref ( "PRAGMA TABLE_INFO($table)" ) } ) { + $col_exists{$table}{$col->[1]} = 1; + } + } + for my $table (keys %tables) { + my $upgrade = 0; + + # Create missing tables + unless ( exists( $col_exists{$table} ) ) { + create_table( $DBH, $table ); + next; + } + + # Check for missing columns + my @cols_not_null; + for my $col ( @{$tables{$table}} ) { + unless ( $col_exists{$table}{$col->{column}} ) { + if ( ($col->{type} =~ /NOT NULL/) and ($col->{type} !~ /DEFAULT/) ) { + push @cols_not_null, $col->{column}; + } + $upgrade = 1; + } + } + + # Due to limitations in ALTER TABLE in sqlite this cumbersome method is necessary to alter a table + if ( $upgrade ) { + DEBUG("info", "Upgrade required for table '$table', please wait..."); + # Save the old records + $DBH->do( "ALTER TABLE $table RENAME TO old_$table" ); + + # Preserve old column names for copying of data later + my $old_columns = join( ", ", map { $_->[1] } @{ $DBH->selectall_arrayref( "PRAGMA TABLE_INFO(old_$table)" ) } ); + + # Create the new table + create_table( $DBH, $table ); + + # Special care for NOT NULL columns, we set value 1 for all missing columns defined with NOT NULL or the copy will fail + my $old_select; + if ( scalar(@cols_not_null) > 0 ) { + $old_select = $old_columns . ", " . join(", ", map { 1 } @cols_not_null ); + $old_columns .= ", " . join(", ", @cols_not_null); + } else { + $old_select = $old_columns; + } + + # Copy the old records over and drop them + my @queries = ( + "INSERT INTO $table ($old_columns) SELECT $old_select FROM old_$table", + "DROP TABLE old_$table", + ); + for my $query (@queries) { + my $sth = $DBH->prepare($query) or die "Failed to prepare '$query'. " . $sth->err; + $sth->execute() or die "Failed to execute '$query'. " . $sth->err; + } + DEBUG( "info", "Table '$table' has been successfully upgraded" ) unless ( $DBH->err ); + } + } +} + +# Create table +sub create_table { + my ( $DBH, $table_name ) = @_; + + my @queries; + + DEBUG("info", "Creating table '$table_name'"); + push @queries, "DROP TABLE IF EXISTS $table_name"; + push @queries, "CREATE TABLE $table_name (" . join(", ", map { "$_->{column} $_->{type}" } @{ $tables{$table_name} }) . ")"; + + for my $query (@queries) { + my $sth = $DBH->prepare($query) or die "Failed to prepare '$query'. " . $sth->err; + $sth->execute() or die "Failed to execute '$query'. " . $sth->err; + } +} + +# Add indices to the DB. +sub index_db { + my ( $DBH ) = @_; + + for my $table (keys %indices) { + my %idx_exists; + for my $index ( @{ $DBH->selectall_arrayref( "PRAGMA INDEX_LIST($table)" ) } ) { + $idx_exists{$index->[1]} = 1; + } + + $DBH->{RaiseError} = 0; + $DBH->{PrintError} = 0; + for my $index ( @{$indices{$table}} ) { + $DBH->do( "CREATE INDEX $index->{name} ON $table ($index->{column})" ) unless ( $idx_exists{$index->{name}} ); + } + $DBH->{RaiseError} = 1; + $DBH->{PrintError} = 1; + } +} + +sub normalize +{ + my ( @nicks ) = @_; + my ( %nicks, %ret ) = map { $_, 1 } @nicks; + + for my $nick ( @nicks ) + { + (my $base = $nick ) =~ s/[\Q-_~^`\E]//g; + $ret{ exists $nicks{$base} ? $base : $nick }++; + } + return keys %ret; +} + +sub add_record +{ + my ( $nick, $user, $host, $serv ) = @_; + return unless ($nick and $user and $host and $serv); + + # Check if we already have this record, before using a hook_process() + my $sth = $DBH_child->prepare( "SELECT nick FROM records WHERE nick = ? AND user = ? AND host = ? AND serv = ?" ); + $sth->execute( $nick, $user, $host, $serv ); + my $result = $sth->fetchrow_hashref; + + if ( defined $result->{nick} ) + { + if ( $result->{nick} eq $nick ) { + DEBUG( "info", "Record for $nick skipped - already exists." ); + return weechat::WEECHAT_RC_OK; + } + } + + my $filename = get_script_filename(); + return weechat::WEECHAT_RC_OK if ($filename eq ""); + + my $db_filename = weechat_dir(); + DEBUG("info", "Start hook_process(), to add $nick $user\@$host on $serv to database"); + weechat::hook_process("perl $filename $db_filename 'db_add_record' '$nick' '$user' '$host' '$serv' 'dummy' 'dummy' 'dummy'", 1000 * $options{'timeout'},"db_add_record_cb",""); +} + +# function called when data from child is available, or when child has ended, arguments and return value +sub db_add_record_cb +{ + my ( $data, $command, $return_code, $out, $err ) = @_; + return weechat::WEECHAT_RC_OK if ( $return_code > 0 or $out eq ""); # something wrong! + + my ($DEBUG_prefix,$message) = split(/ /,$out,2); + DEBUG($DEBUG_prefix, $message); + return weechat::WEECHAT_RC_OK; +} + +sub get_host_records { + # suppress output? yes|no + # type = host|nick, $query = name, $serv = server, @return = "." + my ( $suppress, $type, $query, $serv, @return ) = @_; + + $count = 0; %data = ( ); + my %data = _r_search( $suppress, $serv, $type, $query ); + for my $k ( keys %data ) { + DEBUG( "info", "$type query for records on $query from server $serv returned: $k" ); + push @return, $k if $data{$k} eq 'host'; + } + + # case-insensitive sort + return sort {uc($a) cmp uc($b)} @return; +} + +sub get_nick_records +{ + # type = host|nick, $query = nick, $serv = server, use_regex = 0|1, @return = "." + my ( $suppress, $type, $query, $serv, $use_regex, @return ) = @_; + + $count = 0; %data = ( ); + my %data = _r_search( $suppress, $serv, $type, $use_regex, ({ $type => $query }) ); + for my $k ( keys %data ) { + DEBUG( "info", "$type query for database records on $query from server $serv. returned: $k" ); + push @return, $k if $data{$k} eq 'nick'; + } + + if (lc($options{'normalize_nicks'}) eq "on" ) { + @return = normalize(@return); + } + + # remove original nick + @return = grep {$_ ne $query} @return; + + # case-insensitive sort + return sort {uc($a) cmp uc($b)} @return; +} + +sub _r_search +{ + my ( $suppress, $serv, $type, $use_regex, @input ) = @_; + + return %data if $count > 1000; + return %data if $count > $options{'max_recursion'}; + return %data if $count == 2 and ! $options{'recursive_search'}; + + DEBUG( "info", "Recursion Level: $count" ); + + if ( $type eq 'nick' ) + { + $count++; + for my $row ( @input ) + { + my $nick = $row->{nick}; + next if exists $data{$nick}; + + $data{$nick} = 'nick'; + my @hosts = _get_hosts_from_nick( $nick, $serv, $use_regex ); + # use regex only for nick search! + $use_regex = 0 if ( $use_regex ); + _r_search( $suppress, $serv, 'host', $use_regex, @hosts ); + } + } elsif ( $type eq 'host' ) + { + $count++; + for my $row ( @input ) + { + my $host = $row->{host}; + next if exists $data{$host}; + $data{$host} = 'host'; + my @nicks = _get_nicks_from_host( $host, $serv, $use_regex ); + next if (scalar(@nicks) <= 0); + + my $output_nicks; + if ( lc($options{'search_this_network_only'}) eq "on" ) + { + $output_nicks = join( ", ", map { $_->{nick} } @nicks ); + } + else { + $output_nicks = join( ", ", map { $_->{serv} . "." . $_->{nick} } @nicks ); + } + + if ($suppress eq 'no') + { + my $ptr_buffer = weechat::current_buffer(); + + my $output = weechat::color('chat_prefix_network'). + weechat::prefix('network'). + weechat::color('chat_delimiters'). + "[". + weechat::color('chat_nick'). + $SCRIPT_NAME. + weechat::color('chat_delimiters'). + "] ". + weechat::color('reset'). + "Found nicks: $output_nicks". + " from host $host"; + + OUTPUT($ptr_buffer,$output); + } + + # use regex only for host search! + $use_regex = 0 if ( $use_regex ); + _r_search( $suppress, $serv, 'nick', $use_regex, @nicks ); + } + } + return %data; +} + +sub _get_hosts_from_nick { + my ( $nick, $serv, $use_regex, @return ) = @_; + + my $sth; + + if ( lc($options{'search_this_network_only'}) eq "on" ) + { + if ( $use_regex ) + { + $sth = $DBH->prepare( "SELECT nick, host FROM records WHERE nick REGEXP ? AND serv = ?" ); + $sth->execute( $nick, $serv ); + } + else + { + $sth = $DBH->prepare( "SELECT nick, host FROM records WHERE nick = ? COLLATE NOCASE AND serv = ?" ); + $sth->execute( $nick, $serv ); + } + } + else + { + if ( $use_regex ) + { + $sth = $DBH->prepare( "SELECT nick, host, serv FROM records WHERE nick REGEXP ?"); + } + else + { + $sth = $DBH->prepare( "SELECT nick, host, serv FROM records WHERE nick = ? COLLATE NOCASE" ); + } + $sth->execute( $nick ); + } + # nothing found in database +# return '' if (not defined $sth->fetchrow_hashref); + return _ignore_guests( $sth ); +} + +sub _get_nicks_from_host { + my ( $host, $serv, $use_regex, @return ) = @_; + + my $sth; + if ( lc($options{'search_this_network_only'}) eq "on" ) + { + if ( $use_regex ) + { + $sth = $DBH->prepare( "SELECT nick, host FROM records WHERE host REGEXP ? AND serv = ?" ); +# $sth->execute( $host, $serv ); + } + else + { + $sth = $DBH->prepare( "SELECT nick, host FROM records WHERE host = ? AND serv = ?" ); + } + $sth->execute( $host, $serv ); + } + else + { + if ( $use_regex ) + { + $sth = $DBH->prepare( "SELECT nick, host, serv FROM records WHERE host REGEXP ?" ); + } + else + { + $sth = $DBH->prepare( "SELECT nick, host, serv FROM records WHERE host = ?" ); + } + $sth->execute( $host ); + } + # nothing found in database +# return '' if (not defined $sth->fetchrow_hashref); + return _ignore_guests( $sth ); +} + +sub _ignore_guests +{ + my ( $sth ) = @_; + my @return; + + while ( my $row = $sth->fetchrow_hashref ) + { + if ( lc($options{'ignore_guest_nicks'}) eq "on" ) + { + my $regex = $options{'guest_nick_regex'}; + next if( $row->{nick} =~ m/$regex/i ); + } + if ( lc($options{'ignore_guest_hosts'}) eq "on" ) + { + my $regex = $options{'guest_host_regex'}; + next if( $row->{host} =~ m/$regex/i ); + } + push @return, $row; + } + return @return; +} + +sub _deassociate_nick_from_host +{ + my ( $nick, $host, $serv, $use_regex, @return ) = @_; + + my $sth; + if ( lc($options{'search_this_network_only'}) eq "on" ) + { + if ( $use_regex ) + { + $sth = $DBH->prepare( "DELETE FROM records WHERE host REGEXP ? AND nick REGEXP ? AND serv = ?" ); + } + else + { + $sth = $DBH->prepare( "DELETE FROM records WHERE host = ? AND nick = ? AND serv = ?" ); + } + $sth->execute( $host, $nick, $serv ); + } + else + { + if ( $use_regex ) + { + $sth = $DBH->prepare( "DELETE FROM records WHERE host REGEXP ? AND nick REGEXP ?" ); + } + else + { + $sth = $DBH->prepare( "DELETE FROM records WHERE host = ? AND nick = ?" ); + } + $sth->execute( $host, $nick ); + } + return $sth->rows; +} + +# ------------------------[ OUTPUT with tags ]------------------------------ +sub OUTPUT +{ + my ($ptr_buffer,$output) = @_; + + if ( $options{'tags'} ne '' ) + { + weechat::print_date_tags($ptr_buffer,0,$options{'tags'},$output); + } + else + { + weechat::print($ptr_buffer,$output); + } +} +# -----------------------------[ debug ]----------------------------------- +sub DEBUG +{ + my $DEBUG_prefix; + my $color; + + return if (lc($options{debug}) eq 'off'); + + if ( $_[0] eq 'info') + { + $DEBUG_prefix = 'info'; + $color = "default"; + } + elsif ( $_[0] eq 'error') + { + $DEBUG_prefix = weechat::config_string(weechat::config_get("weechat.look.prefix_error")); + $color = weechat::color(weechat::config_color(weechat::config_get("weechat.color.chat_prefix_error"))); + } + else + { + $DEBUG_prefix = '***'; + $color = 'default'; + } + weechat::print('', _color_str($color, $DEBUG_prefix) . "\t$SCRIPT_NAME: $_[1]"); +} + +sub _color_str +{ + my ($color_name, $string) = @_; + # use eval for colors-codes (${color:red} eg in weechat.look.prefix_error) + $string = weechat::string_eval_expression($string, {}, {},{}) if ($weechat_version >= 0x00040200); + weechat::color($color_name) . $string . weechat::color('reset'); +} +# -------------------------------[ subroutines ]------------------------------------- +sub weechat_dir +{ + my $dir = $options{'db_name'}; + if ( $dir =~ /%h/ ) + { + my $weechat_dir = weechat::info_get( 'weechat_dir', ''); + $dir =~ s/%h/$weechat_dir/; + } + return $dir; +} +# -------------------------------[ main ]------------------------------------- +sub stalker_command_cb +{ + my ($data, $buffer, $args) = ($_[0], $_[1], $_[2]); + my @args_array=split(/ /,$args); + my $number = @args_array; + + return weechat::WEECHAT_RC_OK if ($number <= 0); + + if (lc($args_array[0]) eq 'count') + { +# my $ptr_buffer = weechat::current_buffer(); + my ($count) = $DBH->selectrow_array("SELECT count(*) FROM records"); + my $output = weechat::color('chat_prefix_network'). + weechat::prefix('network'). + weechat::color('chat_delimiters'). + "[". + weechat::color('chat_nick'). + $SCRIPT_NAME. + weechat::color('chat_delimiters'). + "] ". + weechat::color('reset'). + "number of rows: ". + $count; + + OUTPUT($buffer,$output); + return weechat::WEECHAT_RC_OK; + } + # get localvar from current buffer + my $name = weechat::buffer_get_string($buffer,'localvar_name'); + my $server = weechat::buffer_get_string($buffer,'localvar_server'); + my $type = weechat::buffer_get_string($buffer,'localvar_type'); + + if ( weechat::buffer_get_string($buffer,'plugin') ne 'irc' and lc($args_array[0]) eq 'scan' ) + { + command_must_be_executed_on_irc_buffer(); + return weechat::WEECHAT_RC_OK; + } + + if (lc($args_array[0]) eq 'scan' && $type eq 'channel' && $number == 1) + { + channel_scan($buffer); +# channel_scan_41(weechat::current_buffer()); + return weechat::WEECHAT_RC_OK; + } + + # at least, we have two arguments + return weechat::WEECHAT_RC_OK if ($number <= 1); + + my $use_regex = 0; + + if (lc($args_array[0]) eq 'scan' && $args_array[1] ne "") + { + $args_array[1] =~ s/\./,/; # info_get() needs an "," instead of "." + my $ptr_buffer = weechat::info_get('irc_buffer',$args_array[1]); +# channel_scan_41($ptr_buffer) if ( $ptr_buffer ne ""); + channel_scan($ptr_buffer) if ( $ptr_buffer ne ""); + } + elsif (lc($args_array[0]) eq 'nick' or lc($args_array[0]) eq 'host') + { + if ( defined $args_array[2] and $args_array[2] eq "-regex" ) + { + $use_regex = 1; + } + else + { + $server = $args_array[2] if ( defined $args_array[2] and $args_array[2] ne "" ); + } + + if ( defined $args_array[3] and $args_array[3] eq "-regex" ) + { + $use_regex = 1; + } + + if ( $server eq "" ) + { + command_must_be_executed_on_irc_buffer(); + return weechat::WEECHAT_RC_OK; + } + # $args_array[0]: 'nick' or 'host', $args_array[1]: nick or host name + # list will be print in subroutine! + my $nicks_found = join( ", ", (get_nick_records('no', $args_array[0], $args_array[1], $server, $use_regex))); + } + elsif (lc($args_array[0]) eq 'remove_nick_from_host') + { + $use_regex = 1 if ( grep{ $args_array[$_] eq '-regex' }0..$#args_array ); + + my $server = weechat::buffer_get_string($buffer,'localvar_server'); + + if ( $server eq "" ) + { + command_must_be_executed_on_irc_buffer(); + return weechat::WEECHAT_RC_OK; + } + my $affected_rows = _deassociate_nick_from_host( $args_array[1], $args_array[2], $server, $use_regex ); + my $color = weechat::color(weechat::config_color(weechat::config_get('weechat.color.chat_prefix_error'))); + my $DEBUG_prefix = weechat::config_string(weechat::config_get('weechat.look.prefix_error')); + weechat::print($buffer, _color_str($color, $DEBUG_prefix) . "\t$SCRIPT_NAME: $affected_rows deleted"); + } + return weechat::WEECHAT_RC_OK; +} + +sub command_must_be_executed_on_irc_buffer +{ + my $text = 'command must be executed on irc buffer (server or channel) or a server must be given'; + my $color = weechat::color(weechat::config_color(weechat::config_get('weechat.color.chat_prefix_error'))); + my $DEBUG_prefix = weechat::config_string(weechat::config_get('weechat.look.prefix_error')); + weechat::print('', _color_str($color, $DEBUG_prefix) . "\t$SCRIPT_NAME: $text"); +} +# hdata_search() +# hdata: hdata pointer +# pointer: pointer to a WeeChat/plugin object +# search: expression to evaluate, default pointer in expression is the name of hdata (and this pointer changes for each element in list); for help on expression, see command /eval in WeeChat User’s guide +# move: number of jump(s) to execute after unsuccessful search (negative or positive integer, different from 0) + +sub channel_scan_41 +{ + my $ptr_buffer = $_[0]; + + my $server_name = weechat::buffer_get_string($ptr_buffer, "localvar_server"); + my $channel_name = weechat::buffer_get_string($ptr_buffer, "localvar_channel"); + return if ($server_name eq "" or $channel_name eq ""); + +#my %hdata = { map { $_ => weechat::hdata_get( "irc_" . $_ ) } qw( server channel nick ) }; + my $hdata_server = weechat::hdata_get("irc_server"); + my $hdata_channel = weechat::hdata_get("irc_channel"); + my $hdata_nick = weechat::hdata_get("irc_nick"); + + my $ptr_server = weechat::hdata_search($hdata_server, weechat::hdata_get_list($hdata_server, 'irc_servers'), '${irc_server.name} == ' . $server_name, 1); + if ($ptr_server) + { + my $ptr_channel = weechat::hdata_search($hdata_channel, weechat::hdata_pointer($hdata_server, $ptr_server, 'channels'), '${irc_channel.name} == ' . $channel_name, 1); + + if ($ptr_channel) + { + my $nick = weechat::hdata_pointer($hdata_channel, $ptr_channel, 'nicks'); + while ( $nick ) + { + my $nick_name = weechat::hdata_string($hdata_nick, $nick, 'name'); + my $host_name = weechat::hdata_string($hdata_nick, $nick, 'host'); + $host_name =~ /(.*)\@/; + my $user_name = $1; + + add_record( $nick_name, $user_name, $host_name, $server_name); + + $nick = weechat::hdata_move($hdata_nick, $nick, 1); + } + } + + } +# weechat::print("",$ptr_buffer); +# weechat::print("",$server_name); + +# if ($ptr_servers) +# { +# my $channel = weechat::hdata_search(hdata['channel'], weechat.hdata_pointer(hdata['server'], server, 'channels'), '${irc_channel.name} == #test', 1) +# } +} +sub channel_scan +{ + my $ptr_buffer = $_[0]; + my $infolist = weechat::infolist_get('nicklist', $ptr_buffer, ''); + # don't stalk yourself + my $my_nick = weechat::buffer_get_string($ptr_buffer,'localvar_nick'); + + my $nick_counter; + + while (weechat::infolist_next($infolist)) + { + my $nick = weechat::infolist_string($infolist, 'name'); + if ((weechat::infolist_string($infolist, 'type') eq 'nick') + && ($nick ne $my_nick)) + { + my $ptr_nick = weechat::nicklist_search_nick($ptr_buffer, '', $nick); + my $localvar_server = weechat::buffer_get_string($ptr_buffer,'localvar_server'); + my $localvar_channel = weechat::buffer_get_string($ptr_buffer,'localvar_channel'); + + my $infolist_nick = weechat::infolist_get('irc_nick','',$localvar_server.','.$localvar_channel.','.$nick); + weechat::infolist_next($infolist_nick); + my $host = weechat::infolist_string($infolist_nick,'host'); + weechat::infolist_free($infolist_nick); + + next unless ($nick or $host or $localvar_server); + $host =~ /(.*)\@/; + $user = $1; + + add_record( $nick, $user, $host, $localvar_server); + +# $user=~ s/[\Q-_~^`\E]//g; +# my $hdata = weechat::hdata_get("irc_nick"); +# my $hdata_host = weechat::hdata_string($hdata, $ptr_nick, "host"); +# next if ($host eq $name); + + } + } + weechat::infolist_free($infolist); +} + +# simple check for last nick/host +# to prevent multiple requests (e.g. "/nick|join nick" for several channels!) +# 0 = failed +# 1 = found +sub check_last_nick_host +{ + my ($nick,$host) = @_; + my $rc = 0; + + $rc = 1 if ($nick eq $last_nick && $host eq $last_host); + + $last_nick = $nick; + $last_host = $host; + return $rc; +} +# -------------------------------[ hooks ]------------------------------------- +# :old_nick!~user@host NICK :new_nick +# /NICK command called +# this is a server command +sub irc_in2_nick_cb +{ + my ($signal, $callback, $callback_data) = @_; + my ($server,undef) = split(',',$callback); + + return weechat::WEECHAT_RC_OK if ( lc($options{'ignore_nickchange'}) eq "on" ); + + DEBUG('info', 'weechat_hook_signal(): NICK change'); + + my $hashtable = weechat::info_get_hashtable("irc_message_parse" => + { "message" => $callback_data }); + + # $old_nick = $hashtable->{nick} + my ($old_nick, $host) = split('!', $hashtable->{host}); + my $nick = $hashtable->{arguments}; + $nick =~ s/^.//; # remove leading ":" + my ($user,undef) = split("@",$host); + + return weechat::WEECHAT_RC_OK if check_last_nick_host($nick,$host); + + add_record( $nick, $user, $host, $server); + + return weechat::WEECHAT_RC_OK; +} + +sub irc_in2_whois_cb +{ + my ($signal, $callback, $callback_data) = @_; + my ($server,undef) = split(',',$callback); + + my $ptr_buffer = ''; + + my (undef, undef, undef, $nick, $user, $host, undef) = split(' ', $callback_data); + my $msgbuffer_whois = weechat::config_string(weechat::config_get('irc.msgbuffer.whois')); + + + DEBUG('info', 'weechat_hook_signal(): WHOIS'); + + # check for nick_regex + if ( lc($options{'ignore_guest_nicks'}) eq "on" ) + { + my $regex = $options{'guest_nick_regex'}; + return weechat::WEECHAT_RC_OK if( $nick =~ m/$regex/i ); + } + + my $complete_host = $user."@".$host; + + unless ( check_last_nick_host($nick,$complete_host) or lc($options{'ignore_whois'}) eq "on" ) + { + add_record( $nick, $user, $complete_host, $server); + } + + # output for /whois + if ($msgbuffer_whois eq 'server') + { + $ptr_buffer = weechat::info_get('irc_buffer',$server); +# $ptr_buffer = weechat::buffer_search('irc', 'server.' . $server); + } + elsif ($msgbuffer_whois eq 'weechat') + { + $ptr_buffer = weechat::buffer_search_main(); + } + elsif ($msgbuffer_whois eq 'current') + { + $ptr_buffer = weechat::current_buffer(); + } + elsif ($msgbuffer_whois eq 'private') + { + $ptr_buffer = weechat::info_get('irc_buffer',$server.','.$nick); + if ($ptr_buffer eq '') + { + $msgbuffer_whois = weechat::config_string(weechat::config_get('irc.look.msgbuffer_fallback')); + $ptr_buffer = weechat::info_get('irc_buffer', $server) if ($msgbuffer_whois eq 'server'); + } + } + + my $use_regex = 0; + my $nicks_found = join( ", ", (get_nick_records('yes', 'nick', $nick, $server, $use_regex))); +# my $nicks_found = join( ", ", (get_nick_records('no', 'nick', $nick, $server, $use_regex))); + + # only the given nick is returned? + return weechat::WEECHAT_RC_OK if ($nicks_found eq $nick or $nicks_found eq ""); + + # more than one nick was returned from sqlite + my $prefix_network = weechat::prefix('network'); + my $color_chat_delimiter = weechat::color('chat_delimiters'); + my $color_chat_nick = weechat::color('chat_nick'); + + my $output = weechat::color('chat_prefix_network'). + weechat::prefix('network'). + weechat::color('chat_delimiters'). + "[". + weechat::color('chat_nick'). + $SCRIPT_NAME. + weechat::color('chat_delimiters'). + "] ". + $nicks_found; + + # fallback buffer.. + $ptr_buffer = weechat::buffer_search_main() unless ($ptr_buffer); + + # print /WHOIS with [stalker] line + OUTPUT($ptr_buffer,$output); + + return weechat::WEECHAT_RC_OK; +} + +# callback_data: :nick!~user_2@host JOIN #channel +sub irc_in2_join_cb +{ + my ($data, $buffer, $date, $tags, $displayed, $highlight, $prefix, $message) = @_; + + + # get nick, user and host. format: nick (user@host) translated join message + my ($nick,$user,$host) = ($message =~ /(.*) \((.*)\@(.*)\)/); + return weechat::WEECHAT_RC_OK if (not defined $nick or $nick eq "" + or not defined $user or $user eq "" + or not defined $host or $host eq ""); + + my $my_nick = weechat::buffer_get_string($buffer,'localvar_nick'); + my $server = weechat::buffer_get_string($buffer,'localvar_server'); + my $name = weechat::buffer_get_string($buffer,'localvar_name'); + + # don't stalk yourself + return weechat::WEECHAT_RC_OK if ($nick eq $my_nick); + + return weechat::WEECHAT_RC_OK if check_last_nick_host($nick,$host); + + DEBUG('info', 'weechat_hook_signal(): JOIN'); + + # check for localvar "stalker" + if ( lc($options{'use_localvar'}) eq "on" ) + { + return weechat::WEECHAT_RC_OK if (not weechat::config_string_to_boolean(weechat::buffer_get_string($buffer, 'localvar_stalker')) ); + } + + # check if "flood_timer" is activated + if ( $options{'flood_timer'} > 0 ) + { + # reset ptr_hook_timer and flood_counter if hook_timer() does not exists anymore + if ( $ptr_hook_timer ne "" and search_hook('hook',$ptr_hook_timer) eq 0 ) + { + $ptr_hook_timer = ""; + $flood_counter = 0; + } + # timer still running, add counter + else + { + $flood_counter++; + } + + if ($ptr_hook_timer eq "") + { + # call timer only once + $ptr_hook_timer = weechat::hook_timer($options{'flood_timer'} * 1000, 0, 1, 'my_hook_timer_cb', ''); + } + + if ( $ptr_hook_timer ne "" and $flood_counter > $options{'flood_max_nicks'} ) + { + DEBUG("info", "flood protection activated for: $nick with $user\@$host on $server"); + return weechat::WEECHAT_RC_OK; + } + } + # end of flood protection + + add_record( $nick, $user, $host, $server); + + return weechat::WEECHAT_RC_OK if (weechat::config_string_to_boolean(weechat::buffer_get_string($buffer, 'localvar_stalker_drop_additional_join_info')) ); + + if ( lc($options{'additional_join_info'}) eq "on" ) + { + my $filename = get_script_filename(); + return weechat::WEECHAT_RC_OK if ($filename eq ""); + + # get tags for stalker output + my $my_tags = $options{'tags'}; + # add tag 'irc_smart_filter' or 'irc_join' to list of tags, if tag(s) exists in original JOIN message + $my_tags = $my_tags . ',irc_smart_filter' if (index($tags,'irc_smart_filter') >= 0); + $my_tags = $my_tags . ',irc_join' if (index($tags,'irc_join') >= 0); + + my $db_filename = weechat_dir(); + DEBUG("info", "Start hook_process(), get additional info from $nick with $user\@$host on $name"); + weechat::hook_process("perl $filename $db_filename 'additional_join_info' '$nick' '$user' '$host' '$server' $options{'max_recursion'} $options{'ignore_guest_nicks'} '$options{'guest_nick_regex'}'", 1000 * $options{'timeout'},"hook_process_get_nicks_records_cb","$nick $buffer $my_tags"); + } + return weechat::WEECHAT_RC_OK; +} + +# get absolute path of script +sub get_script_filename +{ + my $infolist_ptr = weechat::infolist_get("perl_script","",$SCRIPT_NAME); + weechat::infolist_next($infolist_ptr); + my $filename = weechat::infolist_string($infolist_ptr,"filename"); + weechat::infolist_free($infolist_ptr); + return $filename; +} + +sub hook_process_get_nicks_records_cb +{ + my ($data, $command, $return_code, $out, $err) = @_; + DEBUG("info", "hook_process_get_nicks_records_cb: data=$data command=$command, rc=$return_code out=$out err=$err"); + + return weechat::WEECHAT_RC_OK if ( $return_code > 0 or $out eq ""); # something wrong! + + my ($nick,$buffer_ptr,$tags) = split(/ /,$data); + my $nicks_found = $out; + # don't print output if there is no other nick used + return weechat::WEECHAT_RC_OK if ($nick eq $nicks_found or $nicks_found eq ''); + + my $string = weechat::color('chat_prefix_network'). + weechat::prefix('network'). + weechat::color('chat_delimiters'). + "[". + weechat::color('chat_nick'). + $SCRIPT_NAME. + weechat::color('chat_delimiters'). + "] ". + weechat::color('reset'). + $nick. + " is also known as: ". + $nicks_found; + + weechat::print_date_tags($buffer_ptr,0,$tags,$string); + return weechat::WEECHAT_RC_OK; +} + +sub search_hook +{ + my ($hook, $ptr_hook) = @_; + my $hook_found = 0; + my $infolist = weechat::infolist_get($hook, $ptr_hook, ''); + while ( weechat::infolist_next($infolist) ) + { + $hook_found = 1 if ( weechat::infolist_pointer($infolist,'pointer') eq $ptr_hook ); + } + weechat::infolist_free($infolist); + + return $hook_found; +} + +sub my_hook_timer_cb +{ + # simply add the flood_counter + $flood_counter++; + 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}); + } + else{ + $options{$option} = weechat::config_get_plugin($option); + } + } + # set help text for options + if ( ($weechat_version ne '') && (weechat::info_get('version_number', '') >= 0x00030500) ) { # v0.3.5 + foreach my $desc_options (keys %desc_options) + { + weechat::config_set_desc_plugin($desc_options,$desc_options{$desc_options}); + } + } + +} + +sub toggle_config_by_set +{ + my ($pointer, $name, $value) = @_; + $name = substr($name, length("plugins.var.perl.$SCRIPT_NAME."), length($name)); + $options{$name} = $value; +# insert a refresh here + return weechat::WEECHAT_RC_OK; +} +# -----------------------------[ shutdown ]----------------------------------- +sub shutdown_cb +{ + # close database + $DBH->disconnect(); + $DBH_child->disconnect(); + return weechat::WEECHAT_RC_OK; +} + +# -------------------------------[ init ]------------------------------------- +# first function called by a WeeChat-script. +weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION, + $SCRIPT_LICENCE, $SCRIPT_DESC, 'shutdown_cb', ''); + + $weechat_version = weechat::info_get('version_number', ''); + + if ( ($weechat_version ne '') && (weechat::info_get('version_number', '') <= 0x00030400) ) + { + OUTPUT('',weechat::prefix('error') . 'You need WeeChat >= 0.3.4. Visit: www.weechat.org'); + weechat::command('',"/wait 1ms /perl unload $SCRIPT_NAME"); + } + else + { + init_config(); + open_database(); + + weechat::hook_command($SCRIPT_NAME, $SCRIPT_DESC, "host [server] [-regex] || nick [server] [-regex] || scan [] || count", + " host : look for hostname\n". + " nick : look for nick\n". + " scan : scan a channel (be careful; scanning large channels takes a while!)\n". + " you should manually /WHO #channel first or use /quote PROTOCTL UHNAMES\n". + " count: display the number of rows in database\n". + "remove_nick_from_host: remove a nick from a given host\n". + "\n\n". + "Stalker will add nick!user\@host to database monitoring JOIN/WHOIS/NICK messages.\n\n". + "\n". + "Monitor specific channels:\n". + "==========================\n". + "Set following option:\n". + " /set plugins.var.perl.".$SCRIPT_NAME.".use_localvar \"on\" (default: off)\n". + "Now you'll have to set a localvar for those channels to monitor:\n". + " /buffer set localvar_set_stalker [value]\n". + " values: \"on\", \"true\", \"t\", \"yes\", \"y\", \"1\")\n". + "\n". + "Display additional information below join message:\n". + "=================================================\n". + "Example: [stalker] nils_2 is also known as: nils_2_\n". + " /set plugins.var.perl.".$SCRIPT_NAME.".additional_join_info \"on\" (default: off)\n". + "If you want to drop informations for specific channels (especially channels with lot of nicks):\n". + " /buffer set localvar_set_stalker_drop_additional_join_info [value]\n". + " values: \"on\", \"true\", \"t\", \"yes\", \"y\", \"1\")\n". + "\n". + "Regex:\n". + "======\n". + "$SCRIPT_NAME performs standard perl regular expression matching with option '-regex'.\n". + "Note that regex matching will not use SQLite indices, but will iterate over all rows, so it could be quite costly in terms of performance.\n". + "\n". + "Tags:\n". + "======\n". + $SCRIPT_NAME." can use tags to display messages. See documentation for most commonly used tags and add them in following option:\n". + " /set plugins.var.perl.".$SCRIPT_NAME.".tags \"no_log\"\n". + "\n". + "Examples:\n". + " search for nick 'nils_2'\n". + " /".$SCRIPT_NAME." nick nils_2\n". + " search for nick 'nils_2' on a different server named 'unknown'\n". + " /".$SCRIPT_NAME." nick nils_2 unknown\n". + " search for nicks starting with 'ni'\n". + " /".$SCRIPT_NAME." nick \\bni.* -regex\n". + " search all hosts located in '.de'\n". + " /".$SCRIPT_NAME." host .*\\.de -regex\n". + " remove nick from an association host'\n". + " /".$SCRIPT_NAME." remove_nick_from_host TheNick ~the\@bad.users.host\n". + "", + "count %-||". + "host %% %(irc_servers)|-regex %-||". + "nick %(nick) %(irc_servers)|-regex -regex %-||". + "remove_nick_from_host %(nick) |-regex -regex %-||". + "scan %(buffers_names) %-", "stalker_command_cb", ""); + + weechat::hook_config("plugins.var.perl.$SCRIPT_NAME.*", "toggle_config_by_set", ""); +# weechat::hook_signal('*,irc_in2_join', 'irc_in2_join_cb', ''); + weechat::hook_print('','irc_join','',1,'irc_in2_join_cb',''); + weechat::hook_signal('*,irc_in2_311', 'irc_in2_whois_cb', ''); + weechat::hook_signal('*,irc_in2_NICK', 'irc_in2_nick_cb', ''); + } diff --git a/weechat/perl/yaurls.pl b/weechat/perl/yaurls.pl new file mode 100644 index 0000000..caae3e2 --- /dev/null +++ b/weechat/perl/yaurls.pl @@ -0,0 +1,301 @@ +# Copyright (c) 2012 by R1cochet R1cochet@hushmail.com +# All rights reserved +# +# 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 . +# +# +# yaURLs, version 1.9, for weechat version 0.3.7 or later +# will shorten URL's in channels +# +# Shorten URL's using any of the following services: +# durl.me, is.gd, ln-s.net, lytn.it, metamark.net, sapo.pt, safe.mn, tinyURL.com +# +# Default color theme in 256color terminal +# header: 46 +# prefix/suffix: *200 +# url: *190 +# domain: 196 +# +# +# Changelog: +# 2012-09-21, R1cochet +# version 1.9: Added more shortening services +# 2012-03-09, Sebastien Helleu +# version 1.8: Fix reload of config file +# 2012-03-08, R1cochet +# version 1.7: Removed need for Regexp::Common and URI::Escape modules. Cleaned up some code +# 2012-03-04, R1cochet +# version 1.6: Fixed error with twitter links not being recognized. Added module URI::Escape to properly format URL's before shortening +# 2012-02-28, R1cochet +# version 1.5: Initial release + +use strict; +use warnings; + +my $SCRIPT_NAME = "yaurls"; +my $SCRIPT_AUTHOR = "R1cochet"; +my $VERSION = "1.9"; +my $SCRIPT_LICENSE = "GPL3"; +my $SCRIPT_DESC = "yes, another URL shortener"; + +# initialize global variables +my $config_file; # config pointer +my %config_section; # config section pointer +my %config_options; # init config options +my $incoming_nick = ""; + +my %Unsafe = (RFC3986 => qr/[^A-Za-z0-9\-\._~]/,); +my %escapes; +for (0..255) { + $escapes{chr($_)} = sprintf("%%%02X", $_); +} + +weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $VERSION, $SCRIPT_LICENSE, $SCRIPT_DESC, "", ""); + +### initial config +sub init_config { + $config_file = weechat::config_new("yaurls", "config_reload_cb", ""); + return if (!$config_file); + + # create new section in config file + $config_section{'blacklists'} = weechat::config_new_section($config_file, "blacklists", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if (!$config_section{'blacklists'}) { + weechat::config_free($config_file); + return; + } + # add the options to the section + $config_options{'channel_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "channel_blacklist", "string", + "Comma seperated list of Channels to ignore", "", 0, 0, "", "", 1, "", "", "", "", "", "",); + $config_options{'nick_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "nick_blacklist", "string", + "Comma seperated list of Nicks to ignore", "", 0, 0, "", "", 1, "", "", "", "", "", "",); + $config_options{'server_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "server_blacklist", "string", + "Comma seperated list of Servers to ignore", "", 0, 0, "", "", 1, "", "", "", "", "", "",); + $config_options{'string_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "string_blacklist", "string", + "Comma seperated list of Strings to ignore", "", 0, 0, "", "", 1, "", "", "", "", "", "",); + $config_options{'url_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "url_blacklist", "string", + "Comma seperated list of URL's to ignore", "", 0, 0, "youtube.com", "youtube.com", 1, "", "", "", "", "", "",); + + $config_section{'colors'} = weechat::config_new_section($config_file, "colors", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if (!$config_section{'colors'}) { + weechat::config_free($config_file); + return; + } + $config_options{'header_color'} = weechat::config_new_option($config_file, $config_section{'colors'}, "header_color", "color", + "Set the color of the header", "", 0, 0, "green", "green", 0, "", "", "", "", "", "",); + $config_options{'prefix_color'} = weechat::config_new_option($config_file, $config_section{'colors'}, "prefix_suffix_color", "color", + "Set the color of the prefix and suffix", "", 0, 0, "magenta", "magenta", 0, "", "", "", "", "", "",); + $config_options{'url_color'} = weechat::config_new_option($config_file, $config_section{'colors'}, "url_color", "color", + "Set the color of the tinyURL link", "", 0, 0, "yellow", "yellow", 0, "", "", "", "", "", "",); + $config_options{'domain_color'} = weechat::config_new_option($config_file, $config_section{'colors'}, "domain_color", "color", + "Set the color of the domain name", "", 0, 0, "blue", "blue", 0, "", "", "", "", "", "",); + + $config_section{'engine'} = weechat::config_new_section($config_file, "engine", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if (!$config_section{'engine'}) { + weechat::config_free($config_file); + return; + } + $config_options{'service'} = weechat::config_new_option($config_file, $config_section{'engine'}, "service", "integer", + "Set which shortener service to use (durl = durl.me, is.gd = is.gd, ln-s = ln-s.net, lytn = lytn.it, ". + "metamark = metamark.net, punyURL = sapo.pt, safe = safe.mn, tinyURL = tinyURL.com)", + "durl|is.gd|ln-s|lytn|metamark|punyURL|safe|tinyURL", 0, 0, "tinyURL", "tinyURL", 0, "", "", "", "", "", ""); + $config_options{'convert_own'} = weechat::config_new_option($config_file, $config_section{'engine'}, "convert_own", "boolean", + "Convert own links sent to buffer", "", 0, 0, "off", "off", 0, "", "", "", "", "", "",); + $config_options{'maximum_length'} = weechat::config_new_option($config_file, $config_section{'engine'}, "maximum_length", "integer", + "Set the maximum length of URL's to be converted (anything equal to or larger will be converted)", "", 20, 500, "35", "35", 0, "", "", "", "", "", ""); + $config_options{'timeout'} = weechat::config_new_option($config_file, $config_section{'engine'}, "timeout", "integer", + "Set the maximum time limit for fetching the short URL (time in seconds)", "", 10, 120, "20", "20", 0, "", "", "", "", "", ""); + + $config_section{'look'} = weechat::config_new_section($config_file, "look", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if (!$config_section{'look'}) { + weechat::config_free($config_file); + return; + } + $config_options{'header'} = weechat::config_new_option($config_file, $config_section{'look'}, "header", "string", + "Set the header string", "", 0, 0, "yaURLs", "yaURLs", 1, "", "", "", "", "", "",); + $config_options{'header_prefix'} = weechat::config_new_option($config_file, $config_section{'look'}, "header_prefix", "string", + "Set the header prefix", "", 0, 0, "{", "{", 1, "", "", "", "", "", "",); + $config_options{'header_suffix'} = weechat::config_new_option($config_file, $config_section{'look'}, "header_suffix", "string", + "Set the header suffix", "", 0, 0, "}~>", "}~>", 1, "", "", "", "", "", "",); + $config_options{'format'} = weechat::config_new_option($config_file, $config_section{'look'}, "format", "string", + "Set the print format (%H = Header, %U = tinyURL, %D = Domain)", "", 0, 0, "%H %U %D", "%H %U %D", 0, "", "", "", "", "", "",); +} +# intit callbacks +sub config_reload_cb { # reload config file + return weechat::config_reload($config_file); +} + +sub config_read { # read my config file + return weechat::config_read($config_file); +} + +sub config_write { # write to my config file + return weechat::config_write($config_file); +} + +init_config(); # load config +config_read(); # get options if already in config file + +weechat::hook_print( "", "irc_privmsg", "://", 1, "print_hook_cb", ""); # Hook into print + +sub build_header { + my $header = weechat::color(weechat::config_color($config_options{'header_color'})) . weechat::config_string($config_options{'header'}) . weechat::color("reset"); + $header = weechat::color(weechat::config_color($config_options{'prefix_color'})) . weechat::config_string($config_options{'header_prefix'}) . weechat::color("reset") . $header; + $header = $header . weechat::color(weechat::config_color($config_options{'prefix_color'})) . weechat::config_string($config_options{'header_suffix'}) . weechat::color("reset"); + return $header; +} + +sub black_list1 { # match url, string + my ($string, $black_list) = @_; + my @black_list = split ",", $black_list; + foreach(@black_list) { + return 1 if $string =~ /\Q$_\E/i; + } + return 0; +} + +sub black_list2 { # match nick, server, channel; front to end + my ($string, $black_list) = @_; + my @black_list = split ",", $black_list; + foreach(@black_list) { + return 1 if $string =~ /^\Q$_\E\z/; + } + return 0; +} + +sub uri_escape { + my $url = shift; + utf8::encode($url); + $url =~ s/($Unsafe{RFC3986})/$escapes{$1}/ge; + return $url; +} + +sub service_url { + my $url = shift; + $url = uri_escape($url); + + if (weechat::config_string($config_options{'service'}) eq "durl") { + $url = "http://durl.me/api/Create.do?longurl=$url"; + } + elsif (weechat::config_string($config_options{'service'}) eq "is.gd") { + $url = "http://is.gd/create.php?format=simple&url=$url"; + } + elsif (weechat::config_string($config_options{'service'}) eq "ln-s") { + $url = "http://ln-s.net/home/api.jsp?url=$url"; + } + elsif (weechat::config_string($config_options{'service'}) eq "lytn") { + $url = "http://lytn.it/api.php?rel=2&link=$url"; + } + elsif (weechat::config_string($config_options{'service'}) eq "metamark") { + $url = "http://metamark.net/api/rest/simple?long_url=$url"; + } + elsif (weechat::config_string($config_options{'service'}) eq "punyURL") { + $url = "http://services.sapo.pt/PunyURL/GetCompressedURLByURL?url=$url"; + } + elsif (weechat::config_string($config_options{'service'}) eq "safe") { + $url = "http://safe.mn/api/?format=text&url=$url"; + } + else { + $url = "http://tinyurl.com/api-create.php?url=$url"; + } + + return $url; +} + +sub process_cb { + my ($buffer_domain, $command, $return_code, $out, $err) = @_; + + if ($return_code != 0) { # weechat::WEECHAT_HOOK_PROCESS_ERROR + weechat::print("", "Error with command: $command"); + weechat::print("", "An error occured: $err") if ($err ne ""); + weechat::print("", "ret code: $return_code"); + } + elsif ($out) { + my ($buffer, $domain) = split "_:_", $buffer_domain, 2; + my $header = build_header(); + $domain = weechat::color(weechat::config_color($config_options{'domain_color'})) . "($domain)" . weechat::color("reset"); + + if (weechat::config_string($config_options{'service'}) eq "durl") { + ($out) = $out =~ m/(http:\/\/durl\.me\/\w+)/; + } + elsif (weechat::config_string($config_options{'service'}) eq "ln-s") { + $out =~ s/^(\d{3}\s)|\n*$//g; + } + elsif (weechat::config_string($config_options{'service'}) eq "punyURL") { + weechat::print("", "punyURL called"); + ($out) = $out =~ m/.+\(.+)\<\/ascii\>/; + } + elsif (weechat::config_string($config_options{'service'}) eq "safe") { + $out =~ s/\n*//g; + } + + my $short_url = weechat::color(weechat::config_color($config_options{'url_color'})) . $out . weechat::color("reset"); + my $tiny_url = weechat::config_string($config_options{'format'}); + + $tiny_url =~ s/%H/$header/; + $tiny_url =~ s/%U/$short_url/; + $tiny_url =~ s/%D/$domain/; + weechat::print($buffer, "$tiny_url"); + } + return weechat::WEECHAT_RC_OK; +} + +sub print_hook_cb { + my ($data, $buffer, $date, $tags, $displayed, $highlight, $prefix, $msg) = @_; + return weechat::WEECHAT_RC_OK if ($displayed != 1); # return if initial message wont be shown + + if ((weechat::config_string($config_options{'string_blacklist'})) ne "") { # check message against "string blacklist" + return weechat::WEECHAT_RC_OK if (black_list1($msg, weechat::config_string($config_options{'string_blacklist'}))); # return if string is blacklisted + } + + my $hdata = weechat::hdata_get("buffer"); + my $buffer_name = weechat::hdata_string($hdata, $buffer, "name"); + my ($server, $channel) = split /\./, $buffer_name; # can be done with a match + $channel =~ s/#//; + + if ((weechat::config_string($config_options{'server_blacklist'})) ne "") { # check message against "server blacklist" + return weechat::WEECHAT_RC_OK if (black_list2($server, weechat::config_string($config_options{'server_blacklist'}))); # return if server is blacklisted + } + + if ((weechat::config_string($config_options{'channel_blacklist'})) ne "") { # check message against "channel blacklist" + return weechat::WEECHAT_RC_OK if (black_list2($channel, weechat::config_string($config_options{'channel_blacklist'}))); # return if nick is blacklisted + } + + ($incoming_nick = $tags) =~ s/.*nick_//i; + $incoming_nick =~ s/,.*//i; + my $own_nick = weechat::info_get("irc_nick", $server); + + if (!weechat::config_boolean($config_options{'convert_own'})) { # check if converting own + return weechat::WEECHAT_RC_OK if $incoming_nick =~ /^\Q$own_nick\E\z/; + } + + if ((weechat::config_string($config_options{'nick_blacklist'})) ne "") { # check message against "nick blacklist" + return weechat::WEECHAT_RC_OK if (black_list2($incoming_nick, weechat::config_string($config_options{'nick_blacklist'}))); # return if nick is blacklisted + } + + my @msg = split " ", $msg; + foreach(@msg) { + if ($_ =~ /^(ht|f)tp/ && $_ =~ m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|) { + next if (length($_) <= weechat::config_integer($config_options{'maximum_length'})); # skip if url shorter than max + + if (weechat::config_string($config_options{'url_blacklist'}) ne "") { + next if (black_list1($_, weechat::config_string($config_options{'url_blacklist'}))); # skip if url is blacklisted + } + my $buffer_domain = $buffer."_:_$2"; + my $url = service_url($_); + + weechat::hook_process("url:$url", weechat::config_integer($config_options{'timeout'}) * 1000, "process_cb", $buffer_domain); + } + } + return weechat::WEECHAT_RC_OK; +} -- cgit v1.2.3-70-g09d2